### live_fetch() example with end time Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/python.md Example of using live_fetch() with a start and end time. It fetches hourly data for EUR/USD and writes the final DataFrame to a CSV file. ```python from datetime import datetime, timedelta import dukascopy_python now = datetime.now() start = datetime(now.year, now.month, now.day) end = start + timedelta(hours=24) for df in dukascopy_python.live_fetch( instrument="EUR/USD", interval_value=1, time_unit=dukascopy_python.TIME_UNIT_HOUR, offer_side=dukascopy_python.OFFER_SIDE_BID, start=start, end=end, ): pass # df is the latest window; it grows on each yield df.to_csv("output.csv") ``` -------------------------------- ### Fetch dependencies via CLI Source: https://github.com/eghosa-osayande/dukascopy/blob/main/dart/dukascopy/README.md Run this command in your terminal to install the added dependency. ```bash dart pub get ``` -------------------------------- ### Install dukascopy-python Source: https://github.com/eghosa-osayande/dukascopy/blob/main/python/README.md Install the dukascopy-python package from PyPI. ```bash pip install dukascopy-python ``` -------------------------------- ### Basic fetch() call example Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/python.md Fetches hourly GBP/USD bid data for January 2025 and saves it to a CSV file. Uses the INSTRUMENT_FX_MAJORS_GBP_USD constant and INTERVAL_HOUR_1. ```python from datetime import datetime import dukascopy_python from dukascopy_python.instruments import INSTRUMENT_FX_MAJORS_GBP_USD df = dukascopy_python.fetch( instrument=INSTRUMENT_FX_MAJORS_GBP_USD, interval=dukascopy_python.INTERVAL_HOUR_1, offer_side=dukascopy_python.OFFER_SIDE_BID, start=datetime(2025, 1, 1), end=datetime(2025, 2, 1), ) df.to_csv("gbp_usd_1h.csv") ``` -------------------------------- ### Usage example for instrument groups, historical data, and tick streaming Source: https://github.com/eghosa-osayande/dukascopy/blob/main/dart/dukascopy/README.md Demonstrates how to fetch instrument groups, retrieve historical OHLC data for EUR/USD, and stream live tick data. ```Dart import 'package:dukascopy/dukascopy.dart'; void main() async { // Load instrument groups final groups = await fetchInstrumentGroups(); print('Groups: ${groups.keys}'); // Fetch 5 days of EUR/USD daily data: final start = DateTime.utc(2025,1,1); final dailyRows = await fetch( instrument: 'EUR/USD', interval: '1DAY', offerSide: 'B', lastUpdateMillis: start.millisecondsSinceEpoch, limit: 5, ); dailyRows.forEach((row) { print('Timestamp=${row[0]}, OHLC=[${row[1]},${row[2]},${row[3]},${row[4]}], vol=${row[5]}'); }); // Stream tick data for the next 10 seconds: final now = DateTime.now().toUtc(); await for (final tick in stream( instrument: 'EUR/USD', interval: 'TICK', offerSide: 'B', startMillis: now.millisecondsSinceEpoch, endMillis: now.add(const Duration(seconds: 10)).millisecondsSinceEpoch, limit: 10, )) { print('Tick @${tick[0]}: bid=${tick[1]}, ask=${tick[2]}'); } } ``` -------------------------------- ### Basic call to fetchInstrumentGroups Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md An example demonstrating how to call fetchInstrumentGroups and access the returned instrument group data. ```dart import 'package:dukascopy/dukascopy.dart'; Future main() async { final groups = await fetchInstrumentGroups(); print('Group ids: ${groups.keys}'); final forex = groups['FX']; print('FX title: ${forex?.title}'); print('FX instruments: ${forex?.instruments}'); } ``` -------------------------------- ### Performing a basic fetch call Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md An example of fetching daily OHLC data for EUR/USD starting from a specific date. ```dart import 'package:dukascopy/dukascopy.dart'; Future main() async { final rows = await fetch( instrument: 'EUR/USD', interval: '1DAY', offerSide: 'B', lastUpdateMillis: DateTime.utc(2025, 1, 1).millisecondsSinceEpoch, limit: 5, ); for (final row in rows) { print('ts=${row[0]} ohlc=${row[1]},${row[2]},${row[3]},${row[4]} vol=${row[5]}'); } } ``` -------------------------------- ### Live fetch with end time Source: https://github.com/eghosa-osayande/dukascopy/blob/main/python/README.md Live fetch hourly data for GBP/USD for 24 hours starting from today, then save the last DataFrame to CSV. ```python now = datetime.now() start = datetime(now.year, now.month, now.day) end = start + timedelta(hours=24) instrument = INSTRUMENT_FX_MAJORS_GBP_USD offer_side = dukascopy_python.OFFER_SIDE_BID iterator = dukascopy_python.live_fetch( instrument, 1, dukascopy_python.TIME_UNIT_HOUR, offer_side, start, end, ) for df in iterator: pass df.to_csv("output.csv") ``` -------------------------------- ### live_fetch() indefinite stream with error handling Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/python.md Example of using live_fetch() with end=None for an indefinite stream and max_retries=None for infinite retries. Includes exception handling for AssertionError and NotImplementedError. ```python from datetime import datetime import dukascopy_python try: iterator = dukascopy_python.live_fetch( instrument="BTC/USD", interval_value=1, time_unit=dukascopy_python.TIME_UNIT_SEC, offer_side=dukascopy_python.OFFER_SIDE_ASK, start=datetime(now.year, now.month, now.day), end=None, # stream forever max_retries=None, # retry forever on transient failures ) for df in iterator: latest = df.iloc[-1] print(latest.name, float(latest["close"])) except AssertionError: print("interval_value must be positive") except NotImplementedError as exc: print(f"unsupported time unit: {exc}") ``` -------------------------------- ### stream(...) Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md Documentation for the top-level `stream` function in the Dukascopy Dart SDK, including parameters, behavior, return type, and usage examples. ```APIDOC ## `stream(...)` ### Description Paginates through the Dukascopy API from `startMillis` toward `endMillis`, yielding each row as it is received. Rows are the same raw shapes as `fetch()`. ### Signature ```dart Stream> stream({ required String instrument, required String interval, required String offerSide, required int startMillis, int? endMillis, int maxRetries = 7, int? limit, http.Client? client, }) async* ``` ### Parameters | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `instrument` | `String` | yes | — | Instrument identifier, e.g. `'EUR/USD'` | | `interval` | `String` | yes | — | e.g. `'1DAY'`, `'5MIN'`, `'TICK'` | | `offerSide` | `String` | yes | — | `'B'` (bid) or `'A'` (ask) | | `startMillis` | `int` | yes | — | Initial cursor (epoch milliseconds) | | `endMillis` | `int?` | no | `null` | When set, the stream `return`s as soon as a row with `timestamp > endMillis` is seen; when `null` the stream never terminates and keeps polling | | `maxRetries` | `int` | no | `7` | Consecutive failures tolerated before rethrowing. Catch block: `if (++retries > maxRetries) rethrow;` with a 1 s delay between attempts — i.e. up to `maxRetries` retries, then the last exception propagates | | `limit` | `int?` | no | `null` | Per-page row limit, passed through to `fetch()` | | `client` | `http.Client?` | no | `null` | Shared/injected http client reused for every page request | ### Behavior details - Cursor deduplication: on pages after the first, if `updates[0][0] == cursor` the duplicate first row is removed (`updates.removeAt(0)`). - On an empty page: if `endMillis != null` the loop `break`s; otherwise it `continue`s (long poll). - After each yielded row the cursor advances to `row[0]`; on non-tick intervals the server returns only rows after the previous cursor. ### Return type `Stream>` — an async generator of raw rows (`[timestampMillis, ...ohlcOrTickFields]`). ### Throws The last internal exception is rethrown once `maxRetries` consecutive failures are exceeded. Any exception type thrown by `fetch()` can surface here. ### Example — basic use ```dart import 'package:dukascopy/dukascopy.dart'; Future main() async { final now = DateTime.now().toUtc(); await for (final tick in stream( instrument: 'EUR/USD', interval: 'TICK', offerSide: 'B', startMillis: now.millisecondsSinceEpoch, endMillis: now.add(const Duration(seconds: 10)).millisecondsSinceEpoch, limit: 10, )) { print('Tick @${tick[0]}: bid=${tick[1]}, ask=${tick[2]}'); } } ``` ### Example — indefinite stream with retry configuration ```dart import 'package:dukascopy/dukascopy.dart'; Future main() async { final start = DateTime.utc(2025, 1, 1).millisecondsSinceEpoch; try { await for (final row in stream( instrument: 'XAU/USD', interval: '1MIN', offerSide: 'A', startMillis: start, endMillis: null, // stream forever maxRetries: 3, limit: 1000, )) { // accumulate OHLC row [ts, open, high, low, close, volume] } } catch (e) { print('stream aborted after retries: $e'); } } ``` ``` -------------------------------- ### fetch(instrument, interval, offer_side, start, end, max_retries=7, limit=30_000, debug=False) Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/python.md Fetches static historical data for a time range and returns a single pandas.DataFrame. This is the primary function for retrieving market data from Dukascopy. ```APIDOC ## fetch(instrument, interval, offer_side, start, end, max_retries=7, limit=30_000, debug=False) ### Description Fetches static historical data for a time range and returns a single `pandas.DataFrame`. ### Method Function call ### Endpoint `dukascopy_python.fetch()` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **instrument** (str) - Required - Instrument identifier, e.g. `"EUR/USD"`, or a constant from `dukascopy_python.instruments` - **interval** (str) - Required - One of the `INTERVAL_*` constants (or any `` string) - **offer_side** (str) - Required - `OFFER_SIDE_BID` (`"B"`) or `OFFER_SIDE_ASK` (`"A"`) - **start** (datetime) - Required - Start of the range; converted to epoch milliseconds via `int(start.timestamp() * 1000)` - **end** (datetime) - Required - End of the range; rows with `timestamp > end` are dropped while streaming (converted to `end.timestamp() * 1000`) - **max_retries** (int) - Optional - Maximum tolerated consecutive errors before the underlying exception is re-raised (see [errors.md](../errors.md)); `None` retries forever. Default: `7` - **limit** (int) - Optional - Max rows per HTTP request ("max limit is 30_000", comment in `_fetch`). Default: `30_000` - **debug** (bool) - Optional - When `True`, the internal logger `"DUKASCRIPT"` is set to `DEBUG` level. Default: `False` ### Request Example ```python from datetime import datetime import dukascopy_python from dukascopy_python.instruments import INSTRUMENT_FX_MAJORS_GBP_USD df = dukascopy_python.fetch( instrument=INSTRUMENT_FX_MAJORS_GBP_USD, interval=dukascopy_python.INTERVAL_HOUR_1, offer_side=dukascopy_python.OFFER_SIDE_BID, start=datetime(2025, 1, 1), end=datetime(2025, 2, 1), ) df.to_csv("gbp_usd_1h.csv") ``` ### Response #### Success Response (200) - **pandas.DataFrame** - Indexed by a UTC `datetime` column named `timestamp` (`pd.to_datetime(..., unit="ms", utc=True)` then `set_index("timestamp")`). Column set depends on the time unit: - For `MONTH`, `WEEK`, `DAY`, `HOUR`, `MIN`, `SEC`: columns are `timestamp` (index), `open`, `high`, `low`, `close`, `volume` - For `TICK`: columns are `timestamp` (index), `bidPrice`, `askPrice`, `bidVolume`, `askVolume` - For tick data, `bidVolume`/`askVolume` (raw micro-units from the API) are divided by `1_000_000` in `_stream` before being returned. #### Response Example ```python # Example DataFrame structure (for hourly data) # timestamp (index) | open | high | low | close | volume # 2025-01-01 00:00:00+00:00 | 1.2500 | 1.2550 | 1.2490 | 1.2540 | 1000 ``` ### Throws | Error | Condition | |---|---| | `KeyError` | `interval` not present in `_interval_units` | | `requests`/`json` exceptions | Network failure, non-JSON response, or malformed JSONP — re-raised after `max_retries` is exhausted (see [errors.md](../errors.md)) | ### Example — error handling and options ```python from datetime import datetime import dukascopy_python try: df = dukascopy_python.fetch( instrument="XAU/USD", interval=dukascopy_python.INTERVAL_MIN_15, offer_side=dukascopy_python.OFFER_SIDE_ASK, start=datetime(2025, 6, 1), end=datetime(2025, 6, 2), max_retries=3, # stop after 3 tolerated failures + re-raise limit=10_000, # smaller pages debug=True, # DUKASCRIPT logger at DEBUG level ) except Exception as exc: print(f"fetch failed after retries: {exc}") ``` ``` -------------------------------- ### live_fetch(instrument, interval_value, time_unit, offer_side, start, end, max_retries=7, limit=30_000, debug=False) Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/python.md A generator function that streams tick data from the Dukascopy API and reshapes it into tick rows or OHLC candles. It yields a pandas DataFrame that grows with each iteration as new data arrives. ```APIDOC ## live_fetch(instrument, interval_value, time_unit, offer_side, start, end, max_retries=7, limit=30_000, debug=False) ### Description A generator function that streams tick data from the API (`INTERVAL_TICK` is always used under the hood) and continuously reshapes it into either tick rows or OHLC candles aggregated by `interval_value` + `time_unit`. The same `DataFrame` is yielded repeatedly, growing as new data arrives. ### Parameters | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `instrument` | `str` | yes | — | Instrument identifier, e.g. `"EUR/USD"` | | `interval_value` | `int` | yes | — | Aggregation factor; must be `> 0` (enforced by `assert interval_value > 0`) | | `time_unit` | `str` | yes | — | One of the `TIME_UNIT_*` constants from lines 10-16 | | `offer_side` | `str` | yes | — | `OFFER_SIDE_BID` / `OFFER_SIDE_ASK`; selects price index (`1`/`2`) and volume index (`-2`/`-1`) of each raw tick row | | `start` | `datetime` | yes | — | Start of the range | | `end` | `datetime` | yes (positional) | — (pass `None` for indefinite) | If `None`, streaming continues indefinitely (never `break`s on empty pages); otherwise rows with `timestamp > end` stop the stream | | `max_retries` | `int` | no | `7` | Retry budget before re-raising the underlying error; `None` retries forever | | `limit` | `int` | no | `30_000` | Max rows per HTTP request | | `debug` | `bool` | no | `False` | Debug logging for the `"DUKASCRIPT"` logger | ### Return Type A generator yielding `pandas.DataFrame` with the same column sets as `fetch()` (tick schema for `TIME_UNIT_TICK` with `interval_value == 1`, OHLC schema otherwise). The first yield happens before any data is fetched (an empty frame). Rows accumulate in index order, one row per resampled timestamp bucket; the last bucket for any timestamp is written when the timestamp changes (or per tick when `TIME_UNIT_TICK`, `interval_value == 1`). ### Throws | Error | Condition | |---|---| | `AssertionError` | `interval_value <= 0` (`assert interval_value > 0`, line 303) | | `NotImplementedError` | `time_unit` is not one of the 7 `TIME_UNIT_*` values (raised by `_resample_to_nearest`, line 112: `f"resampling not implemented for {time_unit}"`) — triggered during validation at generator start | | `KeyError` | `offer_side` is neither `"B"` nor `"A"` (dict lookups for `price_index`/`volume_index`) | | Underlying fetch errors | re-raised after `max_retries` exhausted, same as `fetch()` | All validation errors above surface at the first `next()`/loop iteration, since the body is a generator. ### Example — live fetch with an end time ```python from datetime import datetime, timedelta import dukascopy_python now = datetime.now() start = datetime(now.year, now.month, now.day) end = start + timedelta(hours=24) for df in dukascopy_python.live_fetch( instrument="EUR/USD", interval_value=1, time_unit=dukascopy_python.TIME_UNIT_HOUR, offer_side=dukascopy_python.OFFER_SIDE_BID, start=start, end=end, ): pass # df is the latest window; it grows on each yield df.to_csv("output.csv") ``` ### Example — indefinite stream and error handling ```python from datetime import datetime import dukascopy_python try: iterator = dukascopy_python.live_fetch( instrument="BTC/USD", interval_value=1, time_unit=dukascopy_python.TIME_UNIT_SEC, offer_side=dukascopy_python.OFFER_SIDE_ASK, start=datetime(now.year, now.month, now.day), end=None, # stream forever max_retries=None, # retry forever on transient failures ) for df in iterator: latest = df.iloc[-1] print(latest.name, float(latest["close"])) except AssertionError: print("interval_value must be positive") except NotImplementedError as exc: print(f"unsupported time unit: {exc}") ``` ``` -------------------------------- ### GET common/instruments Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/endpoints.md Fetches instrument groups from the Dukascopy API. The endpoint is called with a JSONP callback and returns a JSONP-wrapped JSON object containing a groups key with instrument group metadata. ```APIDOC ## GET common/instruments ### Description Fetches instrument groups from the Dukascopy API. The endpoint is called with a JSONP callback and returns a JSONP-wrapped JSON object containing a groups key with instrument group metadata. ### Method GET ### Endpoint common/instruments ### Parameters #### Query Parameters - **path** (string) - Required - Route selector, value: common/instruments - **jsonp** (string) - Required - JSONP callback, format: _callbacks____ + 9 random characters ### Request Example GET /common/instruments?path=common/instruments&jsonp=_callbacks____abcdefghi ### Response #### Success Response (200) - **groups** (object) - Object mapping group IDs to group objects - **** (object) - Instrument group object - **id** (string) - Group ID - **title** (string) - Display title - **parent** (string) - Optional parent group ID - **instruments** (array of strings) - Optional list of instrument symbols #### Response Example { "groups": { "FX": { "id": "FX", "title": "Forex", "instruments": ["EUR/USD", "GBP/USD"] }, "CMD": { "id": "CMD", "title": "Commodities", "parent": "" } } } ### Error Handling No status-code check is performed. Malformed body or missing groups key results in FormatException or TypeError. ``` -------------------------------- ### Top-level function stream signature Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md The signature for the stream function, which paginates through API data starting from a specified timestamp. ```dart Stream> stream({ required String instrument, required String interval, required String offerSide, required int startMillis, int? endMillis, int maxRetries = 7, int? limit, http.Client? client, }) async* ``` -------------------------------- ### Import dukascopy_python and instrument Source: https://github.com/eghosa-osayande/dukascopy/blob/main/python/README.md Import the required modules and the GBP/USD instrument constant. ```python from datetime import datetime, timedelta import dukascopy_python from dukascopy_python.instruments import INSTRUMENT_FX_MAJORS_GBP_USD ``` -------------------------------- ### fetch() with error handling and options Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/python.md Fetches 15-minute ask data for XAU/USD with custom retry, limit, and debug options. Demonstrates error handling with a try-except block. ```python from datetime import datetime import dukascopy_python try: df = dukascopy_python.fetch( instrument="XAU/USD", interval=dukascopy_python.INTERVAL_MIN_15, offer_side=dukascopy_python.OFFER_SIDE_ASK, start=datetime(2025, 6, 1), end=datetime(2025, 6, 2), max_retries=3, # stop after 3 tolerated failures + re-raise limit=10_000, # smaller pages debug=True, # DUKASCRIPT logger at DEBUG level ) except Exception as exc: print(f"fetch failed after retries: {exc}") ``` -------------------------------- ### Live fetch indefinitely with end=None Source: https://github.com/eghosa-osayande/dukascopy/blob/main/python/README.md Live fetch hourly data for GBP/USD indefinitely (end=None) and process each DataFrame in a loop. ```python now = datetime.now() start = datetime(now.year, now.month, now.day) end = None instrument = INSTRUMENT_FX_MAJORS_GBP_USD offer_side = dukascopy_python.OFFER_SIDE_BID df_iterator = dukascopy_python.live_fetch( instrument, 1, dukascopy_python.TIME_UNIT_HOUR, offer_side, start, end, ) for df in df_iterator: # Do something with latest data pass ``` -------------------------------- ### Importing the dukascopy library Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md The primary entry point for accessing the package functionality. ```dart import 'package:dukascopy/dukascopy.dart'; ``` -------------------------------- ### Fetch historical data with fetch() Source: https://github.com/eghosa-osayande/dukascopy/blob/main/python/README.md Fetch historical hourly data for GBP/USD from January 1 to February 1, 2025, and save it as JSON. ```python start = datetime(2025, 1, 1) end = datetime(2025, 2, 1) instrument = INSTRUMENT_FX_MAJORS_GBP_USD interval = dukascopy_python.INTERVAL_HOUR_1 offer_side = dukascopy_python.OFFER_SIDE_BID df = dukascopy_python.fetch( instrument, interval, offer_side, start, end, ) df.to_json("output.json") ``` -------------------------------- ### Indefinite stream with retry configuration Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md Shows how to set up an infinite stream with custom retry limits and error handling. ```dart import 'package:dukascopy/dukascopy.dart'; Future main() async { final start = DateTime.utc(2025, 1, 1).millisecondsSinceEpoch; try { await for (final row in stream( instrument: 'XAU/USD', interval: '1MIN', offerSide: 'A', startMillis: start, endMillis: null, // stream forever maxRetries: 3, limit: 1000, )) { // accumulate OHLC row [ts, open, high, low, close, volume] } } catch (e) { print('stream aborted after retries: $e'); } } ``` -------------------------------- ### Basic usage of stream Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md Demonstrates how to consume a stream of tick data for a specific instrument over a defined time window. ```dart import 'package:dukascopy/dukascopy.dart'; Future main() async { final now = DateTime.now().toUtc(); await for (final tick in stream( instrument: 'EUR/USD', interval: 'TICK', offerSide: 'B', startMillis: now.millisecondsSinceEpoch, endMillis: now.add(const Duration(seconds: 10)).millisecondsSinceEpoch, limit: 10, )) { print('Tick @${tick[0]}: bid=${tick[1]}, ask=${tick[2]}'); } } ``` -------------------------------- ### Handling errors with an injected HTTP client Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md Demonstrates how to use a custom http.Client and handle potential FormatException or network errors. ```dart import 'package:dukascopy/dukascopy.dart'; import 'package:http/http.dart' as http; Future main() async { try { final rows = await fetch( instrument: 'XAU/USD', interval: 'TICK', offerSide: 'A', lastUpdateMillis: 0, client: myHttpClient, // e.g. a retrying or authenticated wrapper ); // rows: [[ts, bid, ask, bidVol, askVol], ...] } on FormatException catch (e) { print('Invalid JSONP payload: $e'); } catch (e) { print('Request failed: $e'); } } ``` -------------------------------- ### live_fetch() function signature Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/python.md The function signature for live_fetch(), showing all parameters and their defaults. It is a generator that yields pandas DataFrames. ```python def live_fetch( instrument: str, interval_value: int, time_unit: str, offer_side: str, start: datetime, end: datetime, max_retries: int = 7, limit: int = 30_000, # max 30_000 debug=False, ): ``` -------------------------------- ### fetch() function signature Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/python.md The function signature for fetch(), showing parameters and defaults. It fetches historical data for a time range and returns a pandas DataFrame. ```python def fetch( instrument: str, interval: str, offer_side: str, start: datetime, end: datetime, max_retries: int = 7, limit: int = 30_000, # max 30_000 debug=False, ): ``` -------------------------------- ### Defining the fetch function signature Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md The signature for the top-level fetch function used to retrieve chart data. ```dart Future>> fetch({ required String instrument, required String interval, required String offerSide, required int lastUpdateMillis, int? limit, http.Client? client, }) async ``` -------------------------------- ### Add dependency to pubspec.yaml Source: https://github.com/eghosa-osayande/dukascopy/blob/main/dart/dukascopy/README.md Include the dukascopy package in your project's dependencies. ```yaml dependencies: dukascopy: ^0.1.3 ``` -------------------------------- ### fetchInstrumentGroups Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md Top-level function that fetches instrument groups from the Dukascopy API. ```APIDOC ## fetchInstrumentGroups ### Description Queries the instrument-groups endpoint (`path=common/instruments`) and parses the JSONP response into a map of group id → `InstrumentGroup`. ### Method GET ### Endpoint `path=common/instruments` ### Parameters #### Query Parameters - `path` (string) - Required - The endpoint path, fixed to `common/instruments`. #### Optional Parameters - `client` (`http.Client?`) - Optional - Injectable http client (used by the package tests). ### Return Type `Future>` — keyed by the group `id` (e.g. `'FX'`, `'CMD'`, `'STCK_CFD'`, `'France'`). The response shape parsed is `data['groups']`; each value is deserialized with `InstrumentGroup.fromJson`. Groups without an `instruments` payload in the response (e.g. `Hungary`, `Poland` in `_instrument_generator.py`) produce `instruments == []`. ### Throws - `FormatException` - Body is not valid JSON after JSONP stripping, or `groups` key is missing / not a map / not JSON-object valued. ### Example — basic call ```dart import 'package:dukascopy/dukascopy.dart'; Future main() async { final groups = await fetchInstrumentGroups(); print('Group ids: ${groups.keys}'); final forex = groups['FX']; print('FX title: ${forex?.title}'); print('FX instruments: ${forex?.instruments}'); } ``` ``` -------------------------------- ### fetch(...) Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md Top-level function to fetch historical OHLC or tick data from Dukascopy's charting API. ```APIDOC ## fetch(...) ### Description Performs a single JSONP request against the Dukascopy chart data endpoint and returns the parsed rows. ### Method Dart top-level function ### Endpoint `https://freeserv.dukascopy.com/2.0/index.php` (JSONP) ### Parameters - `instrument` (String) - Required - Instrument identifier, e.g. `'EUR/USD'` - `interval` (String) - Required - Interval string, e.g. `'1DAY'`, `'5MIN'`, `'TICK'` - `offerSide` (String) - Required - `'B'` (bid) or `'A'` (ask) - `lastUpdateMillis` (int) - Required - Cursor: epoch milliseconds; returned rows have `timestamp >= lastUpdateMillis` - `limit` (int?) - Optional - Max rows per response; when non-null it is appended to the query string (`'limit': limit.toString()`) - `client` (http.Client?) - Optional - Injectable `package:http` client — used for mocking in tests ### Return Type `Future>>` — the decoded JSON array. Each inner list is one raw row: `[timestampMillis, open, high, low, close, volume]` for OHLC intervals, `[timestampMillis, bid, ask, bidVolume, askVolume]` for `TICK`. ### Throws - `FormatException` - Response body is not valid JSON after JSONP stripping - `Exception` / `ClientException` from `package:http` - Network/transport failures — no retry logic and no HTTP status-code check in `fetch()` ### Example — basic call ```dart import 'package:dukascopy/dukascopy.dart'; Future main() async { final rows = await fetch( instrument: 'EUR/USD', interval: '1DAY', offerSide: 'B', lastUpdateMillis: DateTime.utc(2025, 1, 1).millisecondsSinceEpoch, limit: 5, ); for (final row in rows) { print('ts=${row[0]} ohlc=${row[1]},${row[2]},${row[3]},${row[4]} vol=${row[5]}'); } } ``` ### Example — error handling with an injected client ```dart import 'package:dukascopy/dukascopy.dart'; import 'package:http/http.dart' as http; Future main() async { try { final rows = await fetch( instrument: 'XAU/USD', interval: 'TICK', offerSide: 'A', lastUpdateMillis: 0, client: myHttpClient, // e.g. a retrying or authenticated wrapper ); // rows: [[ts, bid, ask, bidVol, askVol], ...] } on FormatException catch (e) { print('Invalid JSONP payload: $e'); } catch (e) { print('Request failed: $e'); } } ``` ``` -------------------------------- ### fetchInstrumentGroups function signature Source: https://github.com/eghosa-osayande/dukascopy/blob/main/_autodocs/api-reference/dart.md The function signature for fetching instrument groups from the Dukascopy API. ```dart Future> fetchInstrumentGroups({ http.Client? client, }) async ``` -------------------------------- ### Save DataFrame to CSV, Excel, and JSON Source: https://github.com/eghosa-osayande/dukascopy/blob/main/python/README.md Export the DataFrame to CSV, Excel, and JSON files using pandas methods. ```python df.to_csv("data.csv") df.to_excel("data.xlsx") df.to_json("data.json") ```