dukascript 0.0.4__py3-none-any.whl → 0.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dukascript/__init__.py CHANGED
@@ -31,19 +31,19 @@ INTERVAL_SEC_1 = f"1{TIME_UNIT_SEC}"
31
31
  INTERVAL_TICK = TIME_UNIT_TICK
32
32
 
33
33
  _interval_units = {
34
- INTERVAL_MONTH_1:TIME_UNIT_MONTH,
35
- INTERVAL_WEEK_1:TIME_UNIT_WEEK,
36
- INTERVAL_DAY_1:TIME_UNIT_DAY,
37
- INTERVAL_HOUR_4:TIME_UNIT_HOUR,
38
- INTERVAL_HOUR_1:TIME_UNIT_HOUR,
39
- INTERVAL_MIN_30:TIME_UNIT_MIN,
40
- INTERVAL_MIN_15:TIME_UNIT_MIN,
41
- INTERVAL_MIN_10:TIME_UNIT_MIN,
42
- INTERVAL_MIN_5:TIME_UNIT_MIN,
43
- INTERVAL_MIN_1:TIME_UNIT_MIN,
44
- INTERVAL_SEC_30:TIME_UNIT_SEC,
45
- INTERVAL_SEC_10:TIME_UNIT_SEC,
46
- INTERVAL_SEC_1:TIME_UNIT_SEC,
34
+ INTERVAL_MONTH_1: TIME_UNIT_MONTH,
35
+ INTERVAL_WEEK_1: TIME_UNIT_WEEK,
36
+ INTERVAL_DAY_1: TIME_UNIT_DAY,
37
+ INTERVAL_HOUR_4: TIME_UNIT_HOUR,
38
+ INTERVAL_HOUR_1: TIME_UNIT_HOUR,
39
+ INTERVAL_MIN_30: TIME_UNIT_MIN,
40
+ INTERVAL_MIN_15: TIME_UNIT_MIN,
41
+ INTERVAL_MIN_10: TIME_UNIT_MIN,
42
+ INTERVAL_MIN_5: TIME_UNIT_MIN,
43
+ INTERVAL_MIN_1: TIME_UNIT_MIN,
44
+ INTERVAL_SEC_30: TIME_UNIT_SEC,
45
+ INTERVAL_SEC_10: TIME_UNIT_SEC,
46
+ INTERVAL_SEC_1: TIME_UNIT_SEC,
47
47
  }
48
48
 
49
49
  OFFER_SIDE_BID = "B"
@@ -258,7 +258,7 @@ def fetch(
258
258
  debug=False,
259
259
  ):
260
260
  logger = _get_custom_logger(debug)
261
- time_unit=_interval_units[interval]
261
+ time_unit = _interval_units[interval]
262
262
  columns = _get_dataframe_columns_for_timeunit(time_unit)
263
263
 
264
264
  data = []
@@ -299,6 +299,7 @@ def live_fetch(
299
299
  debug=False,
300
300
  ):
301
301
  logger = _get_custom_logger(debug)
302
+ assert interval_value > 0
302
303
 
303
304
  # validate time unit
304
305
  _resample_to_nearest(
@@ -343,7 +344,9 @@ def live_fetch(
343
344
 
344
345
  yield df
345
346
 
346
- for row in datafeed:
347
+ last_tick_count = 0
348
+
349
+ for tick_count, row in enumerate(datafeed, 0):
347
350
 
348
351
  timestamp = _resample_to_nearest(
349
352
  pd.to_datetime(
@@ -355,19 +358,24 @@ def live_fetch(
355
358
  interval_value,
356
359
  )
357
360
 
358
- if time_unit == TIME_UNIT_TICK:
361
+ if last_timestamp == None:
362
+ last_timestamp = timestamp.timestamp()
363
+
364
+ if time_unit == TIME_UNIT_TICK and interval_value == 1:
359
365
  df.loc[timestamp] = [
360
366
  *row[1:],
361
367
  ]
362
368
  yield df
363
369
  continue
364
370
 
365
- if last_timestamp == None:
366
- last_timestamp = timestamp.timestamp()
371
+ new_tick_count = tick_count // interval_value
367
372
 
368
- if timestamp.timestamp() != last_timestamp:
373
+ if (
374
+ time_unit != TIME_UNIT_TICK
375
+ and timestamp.timestamp() != last_timestamp.timestamp()
376
+ ) or (time_unit == TIME_UNIT_TICK and last_tick_count != new_tick_count):
369
377
  if open is not None:
370
- df.loc[timestamp] = [
378
+ df.loc[last_timestamp] = [
371
379
  open,
372
380
  high,
373
381
  low,
@@ -376,7 +384,8 @@ def live_fetch(
376
384
  ]
377
385
 
378
386
  yield df
379
- last_timestamp = timestamp.timestamp()
387
+ last_timestamp = timestamp
388
+ last_tick_count = new_tick_count
380
389
  open = None
381
390
 
382
391
  if open is None:
@@ -398,4 +407,5 @@ def live_fetch(
398
407
  close,
399
408
  volume,
400
409
  ]
410
+
401
411
  yield df
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dukascript
3
- Version: 0.0.4
3
+ Version: 0.0.5
4
4
  Summary: Download tick data from Dukascopy Bank SA to local cache, and simulate time-ordered price streams
5
5
  Author-email: Eghosa Osayande <osayandeeghosam@gmail.com>
6
6
  License: MIT License
@@ -98,27 +98,39 @@ Both `fetch` and `live_fetch` share similar parameters:
98
98
  - **fetch**: Fetches static historical data. Returns **one** `DataFrame`.
99
99
  - **live_fetch**: Continuously fetches live updates. Returns a **generator** that yields the **same `DataFrame`** with updated data.
100
100
 
101
- When using intervals like `1HOUR`, `fetch()` may return delayed data due to DukasCopy’s aggregation policy. For up-to-date values, use `live_fetch()` which fetches tick data under the hood and reshapes it live.
101
+ When using intervals not based on ticks eg: `1HOUR`, `fetch()` will return delayed data. For up-to-date values, use `live_fetch()` which fetches tick data under the hood and reshapes it based on the `interval_value` and `time_unit`.
102
102
 
103
103
  ---
104
104
 
105
- ## 📊 DataFrame Format
105
+ ## 📊 DataFrame Columns
106
106
 
107
- ### For tick data:
107
+ ### When interval/time_unit is based on tick:
108
+ ie:
109
+
110
+ `interval = INTERVAL_TICK`
111
+
112
+ or
113
+
114
+ `interval_value = 1`
115
+ `time_units = TIME_UNIT_TICK`
108
116
 
109
117
  | Column | Description |
110
118
  |-------------|------------------------|
111
- | `timestamp` | Index (UTC) |
119
+ | `timestamp` | UTC datetime, Dataframe Index |
112
120
  | `bidPrice` | Bid price |
113
121
  | `askPrice` | Ask price |
114
122
  | `bidVolume` | Bid volume |
115
123
  | `askVolume` | Ask volume |
116
124
 
117
- ### For aggregated intervals:
125
+ ### When interval/time_unit is NOT based on tick
126
+ eg: 5 minutes OHLC candle data
127
+
128
+ `interval_value = 5`
129
+ `time_units = TIME_UNIT_MIN`
118
130
 
119
131
  | Column | Description |
120
132
  |-------------|------------------------|
121
- | `timestamp` | Index |
133
+ | `timestamp` | UTC datetime, Dataframe Index |
122
134
  | `open` | Opening price |
123
135
  | `high` | Highest price |
124
136
  | `low` | Lowest price |
@@ -218,7 +230,5 @@ MIT
218
230
 
219
231
  ## 👋 Contributing
220
232
 
221
- Pull requests and suggestions welcome!
222
- ```
233
+ Pull requests and suggestions are highly welcome!
223
234
 
224
- ---
@@ -0,0 +1,8 @@
1
+ dukascript/__init__.py,sha256=nxyrT1UGi2gBpRGsUMnZA2koMMnTwq7EZdoY_vq5J6E,11785
2
+ dukascript/_instrument_generator.py,sha256=WDTNS1bLa-J2uI3TmoBTg-WCHdAtkX6d6tq0xhqL4GI,24848
3
+ dukascript/instruments.py,sha256=OxKTWR8zx2sjaHtGtd81FsQwTdAMItjgUSojzuJ1waI,59069
4
+ dukascript-0.0.5.dist-info/licenses/LICENSE,sha256=SA8D35cWkNTiEI71ATLBPTzWgFwjPNZLeloeBJrAJr4,1061
5
+ dukascript-0.0.5.dist-info/METADATA,sha256=5h8k2mjIMRIZ2ARrs3bTod5VDXjT9Qh2DSwZadU8WQM,6484
6
+ dukascript-0.0.5.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
7
+ dukascript-0.0.5.dist-info/top_level.txt,sha256=h7GgEQykn3TuhHU4jJxZQ7oNjP_naNvjUwZAw6KU3VE,11
8
+ dukascript-0.0.5.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- dukascript/__init__.py,sha256=bPsw_EhL1g35ulDZLWuIZO3ueHncS-7dQ5AFvyT84nw,11412
2
- dukascript/_instrument_generator.py,sha256=WDTNS1bLa-J2uI3TmoBTg-WCHdAtkX6d6tq0xhqL4GI,24848
3
- dukascript/instruments.py,sha256=OxKTWR8zx2sjaHtGtd81FsQwTdAMItjgUSojzuJ1waI,59069
4
- dukascript-0.0.4.dist-info/licenses/LICENSE,sha256=SA8D35cWkNTiEI71ATLBPTzWgFwjPNZLeloeBJrAJr4,1061
5
- dukascript-0.0.4.dist-info/METADATA,sha256=PacypFzc983Mj5v0dmBu0VN5efRwTfOJgMC40ON3d-E,6230
6
- dukascript-0.0.4.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
7
- dukascript-0.0.4.dist-info/top_level.txt,sha256=h7GgEQykn3TuhHU4jJxZQ7oNjP_naNvjUwZAw6KU3VE,11
8
- dukascript-0.0.4.dist-info/RECORD,,