flowbars 0.1.0__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.
- flowbars/__init__.py +163 -0
- flowbars/_version.py +8 -0
- flowbars/adapters/__init__.py +29 -0
- flowbars/adapters/polars.py +1115 -0
- flowbars/bars/__init__.py +3 -0
- flowbars/bars/accumulators.py +731 -0
- flowbars/bars/constructor.py +1254 -0
- flowbars/bars/information/__init__.py +41 -0
- flowbars/bars/information/imbalance_dollar_bars.py +200 -0
- flowbars/bars/information/imbalance_tick_bars.py +206 -0
- flowbars/bars/information/imbalance_volume_bars.py +200 -0
- flowbars/bars/information/run_dollar_bars.py +225 -0
- flowbars/bars/information/run_tick_bars.py +231 -0
- flowbars/bars/information/run_volume_bars.py +225 -0
- flowbars/bars/minute/__init__.py +99 -0
- flowbars/bars/minute/accumulators.py +303 -0
- flowbars/bars/minute/engine.py +244 -0
- flowbars/bars/minute/information.py +622 -0
- flowbars/bars/minute/numba.py +1043 -0
- flowbars/bars/minute/registry.py +22 -0
- flowbars/bars/minute/standard.py +261 -0
- flowbars/bars/minute/structural.py +474 -0
- flowbars/bars/numba_backend.py +1227 -0
- flowbars/bars/output.py +106 -0
- flowbars/bars/registry.py +47 -0
- flowbars/bars/spec.py +367 -0
- flowbars/bars/standard/__init__.py +17 -0
- flowbars/bars/standard/dollar_bars.py +168 -0
- flowbars/bars/standard/tick_bars.py +166 -0
- flowbars/bars/standard/time_bars.py +192 -0
- flowbars/bars/standard/volume_bars.py +168 -0
- flowbars/benchmarks.py +420 -0
- flowbars/calendars.py +368 -0
- flowbars/core.py +109 -0
- flowbars/py.typed +0 -0
- flowbars/quality.py +393 -0
- flowbars/sample_data/__init__.py +28 -0
- flowbars/sample_data/tick_data.csv +501 -0
- flowbars/schema.py +476 -0
- flowbars/thresholds.py +1167 -0
- flowbars/tick_rule.py +89 -0
- flowbars-0.1.0.dist-info/METADATA +650 -0
- flowbars-0.1.0.dist-info/RECORD +46 -0
- flowbars-0.1.0.dist-info/WHEEL +5 -0
- flowbars-0.1.0.dist-info/licenses/LICENSE +21 -0
- flowbars-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1115 @@
|
|
|
1
|
+
"""Polars adapter — mirror functions for every ``compute_*_bars()``.
|
|
2
|
+
|
|
3
|
+
These functions accept ``polars.DataFrame`` as input and return
|
|
4
|
+
``polars.DataFrame`` as output. Internally they convert
|
|
5
|
+
polars → pandas, delegate to the core functions, then convert
|
|
6
|
+
the result back to polars.
|
|
7
|
+
|
|
8
|
+
Polars uses Apache Arrow under the hood, so ``to_pandas()`` /
|
|
9
|
+
``from_pandas()`` are near-zero-copy when pyarrow is installed.
|
|
10
|
+
|
|
11
|
+
Batch-only — no streaming equivalent for polars.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import TYPE_CHECKING, Any, Literal, cast
|
|
17
|
+
|
|
18
|
+
import polars as pl # type: ignore
|
|
19
|
+
|
|
20
|
+
# Import pandas compute functions with _pd_ prefix to avoid
|
|
21
|
+
# shadowing the polars functions defined in this module.
|
|
22
|
+
from flowbars.bars.information import (
|
|
23
|
+
compute_imbalance_dollar_bars as _pd_compute_imbalance_dollar_bars,
|
|
24
|
+
)
|
|
25
|
+
from flowbars.bars.information import (
|
|
26
|
+
compute_imbalance_tick_bars as _pd_compute_imbalance_tick_bars,
|
|
27
|
+
)
|
|
28
|
+
from flowbars.bars.information import (
|
|
29
|
+
compute_imbalance_volume_bars as _pd_compute_imbalance_volume_bars,
|
|
30
|
+
)
|
|
31
|
+
from flowbars.bars.information import (
|
|
32
|
+
compute_run_dollar_bars as _pd_compute_run_dollar_bars,
|
|
33
|
+
)
|
|
34
|
+
from flowbars.bars.information import (
|
|
35
|
+
compute_run_tick_bars as _pd_compute_run_tick_bars,
|
|
36
|
+
)
|
|
37
|
+
from flowbars.bars.information import (
|
|
38
|
+
compute_run_volume_bars as _pd_compute_run_volume_bars,
|
|
39
|
+
)
|
|
40
|
+
from flowbars.bars.minute import (
|
|
41
|
+
compute_dollar_bars_from_minutes as _pd_compute_dollar_bars_from_minutes,
|
|
42
|
+
)
|
|
43
|
+
from flowbars.bars.minute import (
|
|
44
|
+
compute_hybrid_bars_from_minutes as _pd_compute_hybrid_bars_from_minutes,
|
|
45
|
+
)
|
|
46
|
+
from flowbars.bars.minute import (
|
|
47
|
+
compute_imbalance_dollar_bars_from_minutes as _pd_compute_imbalance_dollar_bars_from_minutes,
|
|
48
|
+
)
|
|
49
|
+
from flowbars.bars.minute import (
|
|
50
|
+
compute_imbalance_volume_bars_from_minutes as _pd_compute_imbalance_volume_bars_from_minutes,
|
|
51
|
+
)
|
|
52
|
+
from flowbars.bars.minute import (
|
|
53
|
+
compute_range_bars_from_minutes as _pd_compute_range_bars_from_minutes,
|
|
54
|
+
)
|
|
55
|
+
from flowbars.bars.minute import (
|
|
56
|
+
compute_renko_bars_from_minutes as _pd_compute_renko_bars_from_minutes,
|
|
57
|
+
)
|
|
58
|
+
from flowbars.bars.minute import (
|
|
59
|
+
compute_run_dollar_bars_from_minutes as _pd_compute_run_dollar_bars_from_minutes,
|
|
60
|
+
)
|
|
61
|
+
from flowbars.bars.minute import (
|
|
62
|
+
compute_run_volume_bars_from_minutes as _pd_compute_run_volume_bars_from_minutes,
|
|
63
|
+
)
|
|
64
|
+
from flowbars.bars.minute import (
|
|
65
|
+
compute_volatility_bars_from_minutes as _pd_compute_volatility_bars_from_minutes,
|
|
66
|
+
)
|
|
67
|
+
from flowbars.bars.minute import (
|
|
68
|
+
compute_volume_bars_from_minutes as _pd_compute_volume_bars_from_minutes,
|
|
69
|
+
)
|
|
70
|
+
from flowbars.bars.standard import (
|
|
71
|
+
compute_dollar_bars as _pd_compute_dollar_bars,
|
|
72
|
+
)
|
|
73
|
+
from flowbars.bars.standard import (
|
|
74
|
+
compute_tick_bars as _pd_compute_tick_bars,
|
|
75
|
+
)
|
|
76
|
+
from flowbars.bars.standard import (
|
|
77
|
+
compute_time_bars as _pd_compute_time_bars,
|
|
78
|
+
)
|
|
79
|
+
from flowbars.bars.standard import (
|
|
80
|
+
compute_volume_bars as _pd_compute_volume_bars,
|
|
81
|
+
)
|
|
82
|
+
from flowbars.calendars import TradingCalendar
|
|
83
|
+
from flowbars.schema import MinuteSchemaMapping, SchemaMapping
|
|
84
|
+
|
|
85
|
+
if TYPE_CHECKING:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
__all__ = [
|
|
89
|
+
"compute_dollar_bars",
|
|
90
|
+
"compute_dollar_bars_from_minutes",
|
|
91
|
+
"compute_hybrid_bars_from_minutes",
|
|
92
|
+
"compute_imbalance_dollar_bars",
|
|
93
|
+
"compute_imbalance_dollar_bars_from_minutes",
|
|
94
|
+
"compute_imbalance_tick_bars",
|
|
95
|
+
"compute_imbalance_volume_bars",
|
|
96
|
+
"compute_imbalance_volume_bars_from_minutes",
|
|
97
|
+
"compute_range_bars_from_minutes",
|
|
98
|
+
"compute_renko_bars_from_minutes",
|
|
99
|
+
"compute_run_dollar_bars",
|
|
100
|
+
"compute_run_dollar_bars_from_minutes",
|
|
101
|
+
"compute_run_tick_bars",
|
|
102
|
+
"compute_run_volume_bars",
|
|
103
|
+
"compute_run_volume_bars_from_minutes",
|
|
104
|
+
"compute_tick_bars",
|
|
105
|
+
"compute_time_bars",
|
|
106
|
+
"compute_volatility_bars_from_minutes",
|
|
107
|
+
"compute_volume_bars",
|
|
108
|
+
"compute_volume_bars_from_minutes",
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
112
|
+
# Standard bars
|
|
113
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def compute_tick_bars(
|
|
117
|
+
ticks_df: pl.DataFrame,
|
|
118
|
+
threshold: int,
|
|
119
|
+
schema: SchemaMapping | None = None,
|
|
120
|
+
watermark: str | None = "timestamp",
|
|
121
|
+
strict_ordering: bool = False,
|
|
122
|
+
calendar: TradingCalendar | None = None,
|
|
123
|
+
multiplier: float = 1.0,
|
|
124
|
+
volume_type: str = "base",
|
|
125
|
+
warmup_bars: int = 0,
|
|
126
|
+
warmup_minutes: int | None = None,
|
|
127
|
+
) -> pl.DataFrame:
|
|
128
|
+
"""Build tick bars from a Polars DataFrame of ticks.
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
ticks_df : pl.DataFrame
|
|
133
|
+
Tick-level data with user-mapped columns.
|
|
134
|
+
threshold : int
|
|
135
|
+
Number of ticks per bar. Must be positive.
|
|
136
|
+
schema : SchemaMapping, optional
|
|
137
|
+
Maps user column names to internal keys.
|
|
138
|
+
calendar : TradingCalendar, optional
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
pl.DataFrame
|
|
143
|
+
Completed bars.
|
|
144
|
+
"""
|
|
145
|
+
pd_ticks = ticks_df.to_pandas()
|
|
146
|
+
pd_bars = _pd_compute_tick_bars(
|
|
147
|
+
pd_ticks,
|
|
148
|
+
threshold=threshold,
|
|
149
|
+
schema=schema,
|
|
150
|
+
calendar=calendar,
|
|
151
|
+
watermark=watermark,
|
|
152
|
+
strict_ordering=strict_ordering,
|
|
153
|
+
multiplier=multiplier,
|
|
154
|
+
volume_type=volume_type,
|
|
155
|
+
warmup_bars=warmup_bars,
|
|
156
|
+
warmup_minutes=warmup_minutes,
|
|
157
|
+
)
|
|
158
|
+
return pl.from_pandas(pd_bars)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def compute_volume_bars(
|
|
162
|
+
ticks_df: pl.DataFrame,
|
|
163
|
+
threshold: float,
|
|
164
|
+
schema: SchemaMapping | None = None,
|
|
165
|
+
watermark: str | None = "timestamp",
|
|
166
|
+
strict_ordering: bool = False,
|
|
167
|
+
calendar: TradingCalendar | None = None,
|
|
168
|
+
multiplier: float = 1.0,
|
|
169
|
+
volume_type: str = "base",
|
|
170
|
+
warmup_bars: int = 0,
|
|
171
|
+
warmup_minutes: int | None = None,
|
|
172
|
+
) -> pl.DataFrame:
|
|
173
|
+
"""Build volume bars from a Polars DataFrame of ticks.
|
|
174
|
+
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
ticks_df : pl.DataFrame
|
|
178
|
+
Tick-level data with user-mapped columns.
|
|
179
|
+
threshold : float
|
|
180
|
+
Volume threshold per bar.
|
|
181
|
+
schema : SchemaMapping, optional
|
|
182
|
+
calendar : TradingCalendar, optional
|
|
183
|
+
|
|
184
|
+
Returns
|
|
185
|
+
-------
|
|
186
|
+
pl.DataFrame
|
|
187
|
+
Completed bars.
|
|
188
|
+
"""
|
|
189
|
+
pd_ticks = ticks_df.to_pandas()
|
|
190
|
+
pd_bars = _pd_compute_volume_bars(
|
|
191
|
+
pd_ticks,
|
|
192
|
+
threshold=threshold,
|
|
193
|
+
schema=schema,
|
|
194
|
+
calendar=calendar,
|
|
195
|
+
watermark=watermark,
|
|
196
|
+
strict_ordering=strict_ordering,
|
|
197
|
+
multiplier=multiplier,
|
|
198
|
+
volume_type=volume_type,
|
|
199
|
+
warmup_bars=warmup_bars,
|
|
200
|
+
warmup_minutes=warmup_minutes,
|
|
201
|
+
)
|
|
202
|
+
return pl.from_pandas(pd_bars)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def compute_dollar_bars(
|
|
206
|
+
ticks_df: pl.DataFrame,
|
|
207
|
+
threshold: float,
|
|
208
|
+
schema: SchemaMapping | None = None,
|
|
209
|
+
watermark: str | None = "timestamp",
|
|
210
|
+
strict_ordering: bool = False,
|
|
211
|
+
calendar: TradingCalendar | None = None,
|
|
212
|
+
multiplier: float = 1.0,
|
|
213
|
+
volume_type: str = "base",
|
|
214
|
+
warmup_bars: int = 0,
|
|
215
|
+
warmup_minutes: int | None = None,
|
|
216
|
+
) -> pl.DataFrame:
|
|
217
|
+
"""Build dollar bars from a Polars DataFrame of ticks.
|
|
218
|
+
|
|
219
|
+
Parameters
|
|
220
|
+
----------
|
|
221
|
+
ticks_df : pl.DataFrame
|
|
222
|
+
Tick-level data with user-mapped columns.
|
|
223
|
+
threshold : float
|
|
224
|
+
Notional-value threshold per bar (e.g. 1_000_000.0 for $1M bars).
|
|
225
|
+
schema : SchemaMapping, optional
|
|
226
|
+
calendar : TradingCalendar, optional
|
|
227
|
+
|
|
228
|
+
Returns
|
|
229
|
+
-------
|
|
230
|
+
pl.DataFrame
|
|
231
|
+
Completed bars.
|
|
232
|
+
"""
|
|
233
|
+
pd_ticks = ticks_df.to_pandas()
|
|
234
|
+
pd_bars = _pd_compute_dollar_bars(
|
|
235
|
+
pd_ticks,
|
|
236
|
+
threshold=threshold,
|
|
237
|
+
schema=schema,
|
|
238
|
+
calendar=calendar,
|
|
239
|
+
watermark=watermark,
|
|
240
|
+
strict_ordering=strict_ordering,
|
|
241
|
+
multiplier=multiplier,
|
|
242
|
+
volume_type=volume_type,
|
|
243
|
+
warmup_bars=warmup_bars,
|
|
244
|
+
warmup_minutes=warmup_minutes,
|
|
245
|
+
)
|
|
246
|
+
return pl.from_pandas(pd_bars)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def compute_time_bars(
|
|
250
|
+
ticks_df: pl.DataFrame,
|
|
251
|
+
interval_ms: int,
|
|
252
|
+
anchor: str = "clock",
|
|
253
|
+
schema: SchemaMapping | None = None,
|
|
254
|
+
watermark: str | None = "timestamp",
|
|
255
|
+
strict_ordering: bool = False,
|
|
256
|
+
calendar: TradingCalendar | None = None,
|
|
257
|
+
multiplier: float = 1.0,
|
|
258
|
+
volume_type: str = "base",
|
|
259
|
+
warmup_bars: int = 0,
|
|
260
|
+
warmup_minutes: int | None = None,
|
|
261
|
+
) -> pl.DataFrame:
|
|
262
|
+
"""Build time bars from a Polars DataFrame of ticks.
|
|
263
|
+
|
|
264
|
+
Parameters
|
|
265
|
+
----------
|
|
266
|
+
ticks_df : pl.DataFrame
|
|
267
|
+
Tick-level data with user-mapped columns.
|
|
268
|
+
interval_ms : int
|
|
269
|
+
Bar interval in milliseconds.
|
|
270
|
+
anchor : str, default ``"clock"``
|
|
271
|
+
``"clock"`` or ``"first_tick"``.
|
|
272
|
+
schema : SchemaMapping, optional
|
|
273
|
+
calendar : TradingCalendar, optional
|
|
274
|
+
|
|
275
|
+
Returns
|
|
276
|
+
-------
|
|
277
|
+
pl.DataFrame
|
|
278
|
+
Completed bars.
|
|
279
|
+
"""
|
|
280
|
+
pd_ticks = ticks_df.to_pandas()
|
|
281
|
+
pd_bars = _pd_compute_time_bars(
|
|
282
|
+
pd_ticks,
|
|
283
|
+
interval_ms=interval_ms,
|
|
284
|
+
anchor=anchor,
|
|
285
|
+
schema=schema,
|
|
286
|
+
calendar=calendar,
|
|
287
|
+
watermark=watermark,
|
|
288
|
+
strict_ordering=strict_ordering,
|
|
289
|
+
multiplier=multiplier,
|
|
290
|
+
volume_type=volume_type,
|
|
291
|
+
warmup_bars=warmup_bars,
|
|
292
|
+
warmup_minutes=warmup_minutes,
|
|
293
|
+
)
|
|
294
|
+
return pl.from_pandas(pd_bars)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
298
|
+
# Information-driven bars — imbalance
|
|
299
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def compute_imbalance_tick_bars(
|
|
303
|
+
ticks_df: pl.DataFrame,
|
|
304
|
+
span: float = 20.0,
|
|
305
|
+
halflife: float | None = None,
|
|
306
|
+
initial_ewa_t: float = 1.0,
|
|
307
|
+
initial_ewa_proportion: float = 0.5,
|
|
308
|
+
warmup_bars: int = 0,
|
|
309
|
+
warmup_minutes: int | None = None,
|
|
310
|
+
schema: SchemaMapping | None = None,
|
|
311
|
+
watermark: str | None = "timestamp",
|
|
312
|
+
strict_ordering: bool = False,
|
|
313
|
+
calendar: TradingCalendar | None = None,
|
|
314
|
+
multiplier: float = 1.0,
|
|
315
|
+
volume_type: str = "base",
|
|
316
|
+
) -> pl.DataFrame:
|
|
317
|
+
"""Build tick-imbalance bars from a Polars DataFrame of ticks.
|
|
318
|
+
|
|
319
|
+
Parameters
|
|
320
|
+
----------
|
|
321
|
+
ticks_df : pl.DataFrame
|
|
322
|
+
Tick-level data with user-mapped columns.
|
|
323
|
+
span : float, default 20.0
|
|
324
|
+
EWMA span for the adaptive threshold.
|
|
325
|
+
halflife : float or None, default None
|
|
326
|
+
EWMA halflife (takes precedence over *span*).
|
|
327
|
+
initial_ewa_t : float, default 1.0
|
|
328
|
+
Initial seed for expected tick count per bar.
|
|
329
|
+
initial_ewa_proportion : float, default 0.5
|
|
330
|
+
Initial seed for expected imbalance proportion.
|
|
331
|
+
warmup_bars : int, default 0
|
|
332
|
+
Number of initial bars to discard.
|
|
333
|
+
schema : SchemaMapping, optional
|
|
334
|
+
calendar : TradingCalendar, optional
|
|
335
|
+
|
|
336
|
+
Returns
|
|
337
|
+
-------
|
|
338
|
+
pl.DataFrame
|
|
339
|
+
Completed bars.
|
|
340
|
+
"""
|
|
341
|
+
pd_ticks = ticks_df.to_pandas()
|
|
342
|
+
pd_bars = _pd_compute_imbalance_tick_bars(
|
|
343
|
+
pd_ticks,
|
|
344
|
+
span=span,
|
|
345
|
+
halflife=halflife,
|
|
346
|
+
initial_ewa_t=initial_ewa_t,
|
|
347
|
+
initial_ewa_proportion=initial_ewa_proportion,
|
|
348
|
+
warmup_bars=warmup_bars,
|
|
349
|
+
warmup_minutes=warmup_minutes,
|
|
350
|
+
schema=schema,
|
|
351
|
+
calendar=calendar,
|
|
352
|
+
watermark=watermark,
|
|
353
|
+
strict_ordering=strict_ordering,
|
|
354
|
+
multiplier=multiplier,
|
|
355
|
+
volume_type=volume_type,
|
|
356
|
+
)
|
|
357
|
+
return pl.from_pandas(pd_bars)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def compute_imbalance_volume_bars(
|
|
361
|
+
ticks_df: pl.DataFrame,
|
|
362
|
+
span: float = 20.0,
|
|
363
|
+
halflife: float | None = None,
|
|
364
|
+
initial_ewa_t: float = 1.0,
|
|
365
|
+
initial_ewa_proportion: float = 0.5,
|
|
366
|
+
warmup_bars: int = 0,
|
|
367
|
+
warmup_minutes: int | None = None,
|
|
368
|
+
schema: SchemaMapping | None = None,
|
|
369
|
+
watermark: str | None = "timestamp",
|
|
370
|
+
strict_ordering: bool = False,
|
|
371
|
+
calendar: TradingCalendar | None = None,
|
|
372
|
+
multiplier: float = 1.0,
|
|
373
|
+
volume_type: str = "base",
|
|
374
|
+
) -> pl.DataFrame:
|
|
375
|
+
"""Build volume-imbalance bars from a Polars DataFrame of ticks.
|
|
376
|
+
|
|
377
|
+
Parameters
|
|
378
|
+
----------
|
|
379
|
+
ticks_df : pl.DataFrame
|
|
380
|
+
Tick-level data with user-mapped columns.
|
|
381
|
+
span : float, default 20.0
|
|
382
|
+
EWMA span for the adaptive threshold.
|
|
383
|
+
halflife : float or None, default None
|
|
384
|
+
EWMA halflife (takes precedence over *span*).
|
|
385
|
+
initial_ewa_t : float, default 1.0
|
|
386
|
+
Initial seed for expected volume per bar.
|
|
387
|
+
initial_ewa_proportion : float, default 0.5
|
|
388
|
+
Initial seed for expected imbalance proportion.
|
|
389
|
+
warmup_bars : int, default 0
|
|
390
|
+
Number of initial bars to discard.
|
|
391
|
+
schema : SchemaMapping, optional
|
|
392
|
+
calendar : TradingCalendar, optional
|
|
393
|
+
|
|
394
|
+
Returns
|
|
395
|
+
-------
|
|
396
|
+
pl.DataFrame
|
|
397
|
+
Completed bars.
|
|
398
|
+
"""
|
|
399
|
+
pd_ticks = ticks_df.to_pandas()
|
|
400
|
+
pd_bars = _pd_compute_imbalance_volume_bars(
|
|
401
|
+
pd_ticks,
|
|
402
|
+
span=span,
|
|
403
|
+
halflife=halflife,
|
|
404
|
+
initial_ewa_t=initial_ewa_t,
|
|
405
|
+
initial_ewa_proportion=initial_ewa_proportion,
|
|
406
|
+
warmup_bars=warmup_bars,
|
|
407
|
+
warmup_minutes=warmup_minutes,
|
|
408
|
+
schema=schema,
|
|
409
|
+
calendar=calendar,
|
|
410
|
+
watermark=watermark,
|
|
411
|
+
strict_ordering=strict_ordering,
|
|
412
|
+
multiplier=multiplier,
|
|
413
|
+
volume_type=volume_type,
|
|
414
|
+
)
|
|
415
|
+
return pl.from_pandas(pd_bars)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def compute_imbalance_dollar_bars(
|
|
419
|
+
ticks_df: pl.DataFrame,
|
|
420
|
+
span: float = 20.0,
|
|
421
|
+
halflife: float | None = None,
|
|
422
|
+
initial_ewa_t: float = 1.0,
|
|
423
|
+
initial_ewa_proportion: float = 0.5,
|
|
424
|
+
warmup_bars: int = 0,
|
|
425
|
+
warmup_minutes: int | None = None,
|
|
426
|
+
schema: SchemaMapping | None = None,
|
|
427
|
+
watermark: str | None = "timestamp",
|
|
428
|
+
strict_ordering: bool = False,
|
|
429
|
+
calendar: TradingCalendar | None = None,
|
|
430
|
+
multiplier: float = 1.0,
|
|
431
|
+
volume_type: str = "base",
|
|
432
|
+
) -> pl.DataFrame:
|
|
433
|
+
"""Build dollar-imbalance bars from a Polars DataFrame of ticks.
|
|
434
|
+
|
|
435
|
+
Parameters
|
|
436
|
+
----------
|
|
437
|
+
ticks_df : pl.DataFrame
|
|
438
|
+
Tick-level data with user-mapped columns.
|
|
439
|
+
span : float, default 20.0
|
|
440
|
+
EWMA span for the adaptive threshold.
|
|
441
|
+
halflife : float or None, default None
|
|
442
|
+
EWMA halflife (takes precedence over *span*).
|
|
443
|
+
initial_ewa_t : float, default 1.0
|
|
444
|
+
Initial seed for expected dollar value per bar.
|
|
445
|
+
initial_ewa_proportion : float, default 0.5
|
|
446
|
+
Initial seed for expected imbalance proportion.
|
|
447
|
+
warmup_bars : int, default 0
|
|
448
|
+
Number of initial bars to discard.
|
|
449
|
+
schema : SchemaMapping, optional
|
|
450
|
+
calendar : TradingCalendar, optional
|
|
451
|
+
|
|
452
|
+
Returns
|
|
453
|
+
-------
|
|
454
|
+
pl.DataFrame
|
|
455
|
+
Completed bars.
|
|
456
|
+
"""
|
|
457
|
+
pd_ticks = ticks_df.to_pandas()
|
|
458
|
+
pd_bars = _pd_compute_imbalance_dollar_bars(
|
|
459
|
+
pd_ticks,
|
|
460
|
+
span=span,
|
|
461
|
+
halflife=halflife,
|
|
462
|
+
initial_ewa_t=initial_ewa_t,
|
|
463
|
+
initial_ewa_proportion=initial_ewa_proportion,
|
|
464
|
+
warmup_bars=warmup_bars,
|
|
465
|
+
warmup_minutes=warmup_minutes,
|
|
466
|
+
schema=schema,
|
|
467
|
+
calendar=calendar,
|
|
468
|
+
watermark=watermark,
|
|
469
|
+
strict_ordering=strict_ordering,
|
|
470
|
+
multiplier=multiplier,
|
|
471
|
+
volume_type=volume_type,
|
|
472
|
+
)
|
|
473
|
+
return pl.from_pandas(pd_bars)
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
477
|
+
# Information-driven bars — run
|
|
478
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def compute_run_tick_bars(
|
|
482
|
+
ticks_df: pl.DataFrame,
|
|
483
|
+
span: float = 20.0,
|
|
484
|
+
halflife: float | None = None,
|
|
485
|
+
initial_ewa_t: float = 1.0,
|
|
486
|
+
initial_ewa_proportion: float = 0.5,
|
|
487
|
+
warmup_bars: int = 0,
|
|
488
|
+
warmup_minutes: int | None = None,
|
|
489
|
+
min_run_length: int = 0,
|
|
490
|
+
schema: SchemaMapping | None = None,
|
|
491
|
+
watermark: str | None = "timestamp",
|
|
492
|
+
strict_ordering: bool = False,
|
|
493
|
+
calendar: TradingCalendar | None = None,
|
|
494
|
+
multiplier: float = 1.0,
|
|
495
|
+
volume_type: str = "base",
|
|
496
|
+
) -> pl.DataFrame:
|
|
497
|
+
"""Build tick-run bars from a Polars DataFrame of ticks.
|
|
498
|
+
|
|
499
|
+
Parameters
|
|
500
|
+
----------
|
|
501
|
+
ticks_df : pl.DataFrame
|
|
502
|
+
Tick-level data with user-mapped columns.
|
|
503
|
+
span : float, default 20.0
|
|
504
|
+
EWMA span for the adaptive threshold.
|
|
505
|
+
halflife : float or None, default None
|
|
506
|
+
EWMA halflife (takes precedence over *span*).
|
|
507
|
+
initial_ewa_t : float, default 1.0
|
|
508
|
+
Initial seed for expected run length per bar.
|
|
509
|
+
initial_ewa_proportion : float, default 0.5
|
|
510
|
+
Initial seed for expected buy-run proportion.
|
|
511
|
+
warmup_bars : int, default 0
|
|
512
|
+
Number of initial bars to discard.
|
|
513
|
+
min_run_length : int, default 0
|
|
514
|
+
Minimum ticks per bar to return.
|
|
515
|
+
schema : SchemaMapping, optional
|
|
516
|
+
calendar : TradingCalendar, optional
|
|
517
|
+
|
|
518
|
+
Returns
|
|
519
|
+
-------
|
|
520
|
+
pl.DataFrame
|
|
521
|
+
Completed bars.
|
|
522
|
+
"""
|
|
523
|
+
pd_ticks = ticks_df.to_pandas()
|
|
524
|
+
pd_bars = _pd_compute_run_tick_bars(
|
|
525
|
+
pd_ticks,
|
|
526
|
+
span=span,
|
|
527
|
+
halflife=halflife,
|
|
528
|
+
initial_ewa_t=initial_ewa_t,
|
|
529
|
+
initial_ewa_proportion=initial_ewa_proportion,
|
|
530
|
+
warmup_bars=warmup_bars,
|
|
531
|
+
warmup_minutes=warmup_minutes,
|
|
532
|
+
min_run_length=min_run_length,
|
|
533
|
+
schema=schema,
|
|
534
|
+
calendar=calendar,
|
|
535
|
+
watermark=watermark,
|
|
536
|
+
strict_ordering=strict_ordering,
|
|
537
|
+
multiplier=multiplier,
|
|
538
|
+
volume_type=volume_type,
|
|
539
|
+
)
|
|
540
|
+
return pl.from_pandas(pd_bars)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def compute_run_volume_bars(
|
|
544
|
+
ticks_df: pl.DataFrame,
|
|
545
|
+
span: float = 20.0,
|
|
546
|
+
halflife: float | None = None,
|
|
547
|
+
initial_ewa_t: float = 1.0,
|
|
548
|
+
initial_ewa_proportion: float = 0.5,
|
|
549
|
+
warmup_bars: int = 0,
|
|
550
|
+
warmup_minutes: int | None = None,
|
|
551
|
+
min_run_length: int = 0,
|
|
552
|
+
schema: SchemaMapping | None = None,
|
|
553
|
+
watermark: str | None = "timestamp",
|
|
554
|
+
strict_ordering: bool = False,
|
|
555
|
+
calendar: TradingCalendar | None = None,
|
|
556
|
+
multiplier: float = 1.0,
|
|
557
|
+
volume_type: str = "base",
|
|
558
|
+
) -> pl.DataFrame:
|
|
559
|
+
"""Build volume-run bars from a Polars DataFrame of ticks.
|
|
560
|
+
|
|
561
|
+
Parameters
|
|
562
|
+
----------
|
|
563
|
+
ticks_df : pl.DataFrame
|
|
564
|
+
Tick-level data with user-mapped columns.
|
|
565
|
+
span : float, default 20.0
|
|
566
|
+
EWMA span for the adaptive threshold.
|
|
567
|
+
halflife : float or None, default None
|
|
568
|
+
EWMA halflife (takes precedence over *span*).
|
|
569
|
+
initial_ewa_t : float, default 1.0
|
|
570
|
+
Initial seed for expected run length per bar.
|
|
571
|
+
initial_ewa_proportion : float, default 0.5
|
|
572
|
+
Initial seed for expected buy-run proportion.
|
|
573
|
+
warmup_bars : int, default 0
|
|
574
|
+
Number of initial bars to discard.
|
|
575
|
+
min_run_length : int, default 0
|
|
576
|
+
Minimum ticks per bar to return.
|
|
577
|
+
schema : SchemaMapping, optional
|
|
578
|
+
calendar : TradingCalendar, optional
|
|
579
|
+
|
|
580
|
+
Returns
|
|
581
|
+
-------
|
|
582
|
+
pl.DataFrame
|
|
583
|
+
Completed bars.
|
|
584
|
+
"""
|
|
585
|
+
pd_ticks = ticks_df.to_pandas()
|
|
586
|
+
pd_bars = _pd_compute_run_volume_bars(
|
|
587
|
+
pd_ticks,
|
|
588
|
+
span=span,
|
|
589
|
+
halflife=halflife,
|
|
590
|
+
initial_ewa_t=initial_ewa_t,
|
|
591
|
+
initial_ewa_proportion=initial_ewa_proportion,
|
|
592
|
+
warmup_bars=warmup_bars,
|
|
593
|
+
warmup_minutes=warmup_minutes,
|
|
594
|
+
min_run_length=min_run_length,
|
|
595
|
+
schema=schema,
|
|
596
|
+
calendar=calendar,
|
|
597
|
+
watermark=watermark,
|
|
598
|
+
strict_ordering=strict_ordering,
|
|
599
|
+
multiplier=multiplier,
|
|
600
|
+
volume_type=volume_type,
|
|
601
|
+
)
|
|
602
|
+
return pl.from_pandas(pd_bars)
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
def compute_run_dollar_bars(
|
|
606
|
+
ticks_df: pl.DataFrame,
|
|
607
|
+
span: float = 20.0,
|
|
608
|
+
halflife: float | None = None,
|
|
609
|
+
initial_ewa_t: float = 1.0,
|
|
610
|
+
initial_ewa_proportion: float = 0.5,
|
|
611
|
+
warmup_bars: int = 0,
|
|
612
|
+
warmup_minutes: int | None = None,
|
|
613
|
+
min_run_length: int = 0,
|
|
614
|
+
schema: SchemaMapping | None = None,
|
|
615
|
+
watermark: str | None = "timestamp",
|
|
616
|
+
strict_ordering: bool = False,
|
|
617
|
+
calendar: TradingCalendar | None = None,
|
|
618
|
+
multiplier: float = 1.0,
|
|
619
|
+
volume_type: str = "base",
|
|
620
|
+
) -> pl.DataFrame:
|
|
621
|
+
"""Build dollar-run bars from a Polars DataFrame of ticks.
|
|
622
|
+
|
|
623
|
+
Parameters
|
|
624
|
+
----------
|
|
625
|
+
ticks_df : pl.DataFrame
|
|
626
|
+
Tick-level data with user-mapped columns.
|
|
627
|
+
span : float, default 20.0
|
|
628
|
+
EWMA span for the adaptive threshold.
|
|
629
|
+
halflife : float or None, default None
|
|
630
|
+
EWMA halflife (takes precedence over *span*).
|
|
631
|
+
initial_ewa_t : float, default 1.0
|
|
632
|
+
Initial seed for expected run length per bar.
|
|
633
|
+
initial_ewa_proportion : float, default 0.5
|
|
634
|
+
Initial seed for expected buy-run proportion.
|
|
635
|
+
warmup_bars : int, default 0
|
|
636
|
+
Number of initial bars to discard.
|
|
637
|
+
min_run_length : int, default 0
|
|
638
|
+
Minimum ticks per bar to return.
|
|
639
|
+
schema : SchemaMapping, optional
|
|
640
|
+
calendar : TradingCalendar, optional
|
|
641
|
+
|
|
642
|
+
Returns
|
|
643
|
+
-------
|
|
644
|
+
pl.DataFrame
|
|
645
|
+
Completed bars.
|
|
646
|
+
"""
|
|
647
|
+
pd_ticks = ticks_df.to_pandas()
|
|
648
|
+
pd_bars = _pd_compute_run_dollar_bars(
|
|
649
|
+
pd_ticks,
|
|
650
|
+
span=span,
|
|
651
|
+
halflife=halflife,
|
|
652
|
+
initial_ewa_t=initial_ewa_t,
|
|
653
|
+
initial_ewa_proportion=initial_ewa_proportion,
|
|
654
|
+
warmup_bars=warmup_bars,
|
|
655
|
+
warmup_minutes=warmup_minutes,
|
|
656
|
+
min_run_length=min_run_length,
|
|
657
|
+
schema=schema,
|
|
658
|
+
calendar=calendar,
|
|
659
|
+
watermark=watermark,
|
|
660
|
+
strict_ordering=strict_ordering,
|
|
661
|
+
multiplier=multiplier,
|
|
662
|
+
volume_type=volume_type,
|
|
663
|
+
)
|
|
664
|
+
return pl.from_pandas(pd_bars)
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
668
|
+
# Minute bars
|
|
669
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def _minute_call(fn: Any, minutes_df: pl.DataFrame, *args: Any, **kwargs: Any) -> pl.DataFrame:
|
|
673
|
+
"""Convert, delegate to the pandas minute compute function, convert back."""
|
|
674
|
+
pd_bars = fn(minutes_df.to_pandas(), *args, **kwargs)
|
|
675
|
+
return cast(pl.DataFrame, pl.from_pandas(pd_bars))
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def compute_volume_bars_from_minutes(
|
|
679
|
+
minutes_df: pl.DataFrame,
|
|
680
|
+
threshold: float,
|
|
681
|
+
schema: MinuteSchemaMapping | None = None,
|
|
682
|
+
*,
|
|
683
|
+
warmup_bars: int = 0,
|
|
684
|
+
warmup_minutes: int | None = None,
|
|
685
|
+
backend: str = "python",
|
|
686
|
+
watermark: str | None = "timestamp",
|
|
687
|
+
strict_ordering: bool = False,
|
|
688
|
+
calendar: TradingCalendar | None = None,
|
|
689
|
+
stream_id: str = "default",
|
|
690
|
+
on_bar: Any = None,
|
|
691
|
+
on_threshold_update: Any = None,
|
|
692
|
+
multiplier: float = 1.0,
|
|
693
|
+
volume_type: str = "base",
|
|
694
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
695
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
696
|
+
) -> pl.DataFrame:
|
|
697
|
+
"""Build volume bars from a Polars DataFrame of minute OHLCV candles."""
|
|
698
|
+
return _minute_call(
|
|
699
|
+
_pd_compute_volume_bars_from_minutes,
|
|
700
|
+
minutes_df,
|
|
701
|
+
threshold,
|
|
702
|
+
schema,
|
|
703
|
+
warmup_bars=warmup_bars,
|
|
704
|
+
warmup_minutes=warmup_minutes,
|
|
705
|
+
backend=backend,
|
|
706
|
+
watermark=watermark,
|
|
707
|
+
strict_ordering=strict_ordering,
|
|
708
|
+
calendar=calendar,
|
|
709
|
+
stream_id=stream_id,
|
|
710
|
+
on_bar=on_bar,
|
|
711
|
+
on_threshold_update=on_threshold_update,
|
|
712
|
+
multiplier=multiplier,
|
|
713
|
+
volume_type=volume_type,
|
|
714
|
+
session_policy=session_policy,
|
|
715
|
+
session_estimator=session_estimator,
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def compute_dollar_bars_from_minutes(
|
|
720
|
+
minutes_df: pl.DataFrame,
|
|
721
|
+
threshold: float,
|
|
722
|
+
schema: MinuteSchemaMapping | None = None,
|
|
723
|
+
*,
|
|
724
|
+
warmup_bars: int = 0,
|
|
725
|
+
warmup_minutes: int | None = None,
|
|
726
|
+
backend: str = "python",
|
|
727
|
+
watermark: str | None = "timestamp",
|
|
728
|
+
strict_ordering: bool = False,
|
|
729
|
+
calendar: TradingCalendar | None = None,
|
|
730
|
+
stream_id: str = "default",
|
|
731
|
+
on_bar: Any = None,
|
|
732
|
+
on_threshold_update: Any = None,
|
|
733
|
+
multiplier: float = 1.0,
|
|
734
|
+
volume_type: str = "base",
|
|
735
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
736
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
737
|
+
) -> pl.DataFrame:
|
|
738
|
+
"""Build dollar bars from a Polars DataFrame of minute OHLCV candles."""
|
|
739
|
+
return _minute_call(
|
|
740
|
+
_pd_compute_dollar_bars_from_minutes,
|
|
741
|
+
minutes_df,
|
|
742
|
+
threshold,
|
|
743
|
+
schema,
|
|
744
|
+
warmup_bars=warmup_bars,
|
|
745
|
+
warmup_minutes=warmup_minutes,
|
|
746
|
+
backend=backend,
|
|
747
|
+
watermark=watermark,
|
|
748
|
+
strict_ordering=strict_ordering,
|
|
749
|
+
calendar=calendar,
|
|
750
|
+
stream_id=stream_id,
|
|
751
|
+
on_bar=on_bar,
|
|
752
|
+
on_threshold_update=on_threshold_update,
|
|
753
|
+
multiplier=multiplier,
|
|
754
|
+
volume_type=volume_type,
|
|
755
|
+
session_policy=session_policy,
|
|
756
|
+
session_estimator=session_estimator,
|
|
757
|
+
)
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
def compute_imbalance_volume_bars_from_minutes(
|
|
761
|
+
minutes_df: pl.DataFrame,
|
|
762
|
+
span: float = 20.0,
|
|
763
|
+
halflife: float | None = None,
|
|
764
|
+
initial_ewa_t: float = 1.0,
|
|
765
|
+
initial_ewa_proportion: float = 0.5,
|
|
766
|
+
warmup_bars: int = 0,
|
|
767
|
+
warmup_minutes: int | None = None,
|
|
768
|
+
schema: MinuteSchemaMapping | None = None,
|
|
769
|
+
*,
|
|
770
|
+
backend: str = "python",
|
|
771
|
+
watermark: str | None = "timestamp",
|
|
772
|
+
strict_ordering: bool = False,
|
|
773
|
+
calendar: TradingCalendar | None = None,
|
|
774
|
+
stream_id: str = "default",
|
|
775
|
+
on_bar: Any = None,
|
|
776
|
+
on_threshold_update: Any = None,
|
|
777
|
+
multiplier: float = 1.0,
|
|
778
|
+
volume_type: str = "base",
|
|
779
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
780
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
781
|
+
) -> pl.DataFrame:
|
|
782
|
+
"""Build volume-imbalance bars from a Polars DataFrame of minute candles."""
|
|
783
|
+
return _minute_call(
|
|
784
|
+
_pd_compute_imbalance_volume_bars_from_minutes,
|
|
785
|
+
minutes_df,
|
|
786
|
+
span,
|
|
787
|
+
halflife,
|
|
788
|
+
initial_ewa_t,
|
|
789
|
+
initial_ewa_proportion,
|
|
790
|
+
warmup_bars,
|
|
791
|
+
warmup_minutes,
|
|
792
|
+
schema,
|
|
793
|
+
backend=backend,
|
|
794
|
+
watermark=watermark,
|
|
795
|
+
strict_ordering=strict_ordering,
|
|
796
|
+
calendar=calendar,
|
|
797
|
+
stream_id=stream_id,
|
|
798
|
+
on_bar=on_bar,
|
|
799
|
+
on_threshold_update=on_threshold_update,
|
|
800
|
+
multiplier=multiplier,
|
|
801
|
+
volume_type=volume_type,
|
|
802
|
+
session_policy=session_policy,
|
|
803
|
+
session_estimator=session_estimator,
|
|
804
|
+
)
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
def compute_imbalance_dollar_bars_from_minutes(
|
|
808
|
+
minutes_df: pl.DataFrame,
|
|
809
|
+
span: float = 20.0,
|
|
810
|
+
halflife: float | None = None,
|
|
811
|
+
initial_ewa_t: float = 1.0,
|
|
812
|
+
initial_ewa_proportion: float = 0.5,
|
|
813
|
+
warmup_bars: int = 0,
|
|
814
|
+
warmup_minutes: int | None = None,
|
|
815
|
+
schema: MinuteSchemaMapping | None = None,
|
|
816
|
+
*,
|
|
817
|
+
backend: str = "python",
|
|
818
|
+
watermark: str | None = "timestamp",
|
|
819
|
+
strict_ordering: bool = False,
|
|
820
|
+
calendar: TradingCalendar | None = None,
|
|
821
|
+
stream_id: str = "default",
|
|
822
|
+
on_bar: Any = None,
|
|
823
|
+
on_threshold_update: Any = None,
|
|
824
|
+
multiplier: float = 1.0,
|
|
825
|
+
volume_type: str = "base",
|
|
826
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
827
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
828
|
+
) -> pl.DataFrame:
|
|
829
|
+
"""Build dollar-imbalance bars from a Polars DataFrame of minute candles."""
|
|
830
|
+
return _minute_call(
|
|
831
|
+
_pd_compute_imbalance_dollar_bars_from_minutes,
|
|
832
|
+
minutes_df,
|
|
833
|
+
span,
|
|
834
|
+
halflife,
|
|
835
|
+
initial_ewa_t,
|
|
836
|
+
initial_ewa_proportion,
|
|
837
|
+
warmup_bars,
|
|
838
|
+
warmup_minutes,
|
|
839
|
+
schema,
|
|
840
|
+
backend=backend,
|
|
841
|
+
watermark=watermark,
|
|
842
|
+
strict_ordering=strict_ordering,
|
|
843
|
+
calendar=calendar,
|
|
844
|
+
stream_id=stream_id,
|
|
845
|
+
on_bar=on_bar,
|
|
846
|
+
on_threshold_update=on_threshold_update,
|
|
847
|
+
multiplier=multiplier,
|
|
848
|
+
volume_type=volume_type,
|
|
849
|
+
session_policy=session_policy,
|
|
850
|
+
session_estimator=session_estimator,
|
|
851
|
+
)
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
def compute_run_volume_bars_from_minutes(
|
|
855
|
+
minutes_df: pl.DataFrame,
|
|
856
|
+
span: float = 20.0,
|
|
857
|
+
halflife: float | None = None,
|
|
858
|
+
initial_ewa_t: float = 1.0,
|
|
859
|
+
initial_ewa_proportion: float = 0.5,
|
|
860
|
+
warmup_bars: int = 0,
|
|
861
|
+
warmup_minutes: int | None = None,
|
|
862
|
+
min_run_length: int = 0,
|
|
863
|
+
schema: MinuteSchemaMapping | None = None,
|
|
864
|
+
*,
|
|
865
|
+
backend: str = "python",
|
|
866
|
+
watermark: str | None = "timestamp",
|
|
867
|
+
strict_ordering: bool = False,
|
|
868
|
+
calendar: TradingCalendar | None = None,
|
|
869
|
+
stream_id: str = "default",
|
|
870
|
+
on_bar: Any = None,
|
|
871
|
+
on_threshold_update: Any = None,
|
|
872
|
+
multiplier: float = 1.0,
|
|
873
|
+
volume_type: str = "base",
|
|
874
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
875
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
876
|
+
) -> pl.DataFrame:
|
|
877
|
+
"""Build volume-run bars from a Polars DataFrame of minute candles."""
|
|
878
|
+
return _minute_call(
|
|
879
|
+
_pd_compute_run_volume_bars_from_minutes,
|
|
880
|
+
minutes_df,
|
|
881
|
+
span,
|
|
882
|
+
halflife,
|
|
883
|
+
initial_ewa_t,
|
|
884
|
+
initial_ewa_proportion,
|
|
885
|
+
warmup_bars,
|
|
886
|
+
warmup_minutes,
|
|
887
|
+
min_run_length,
|
|
888
|
+
schema,
|
|
889
|
+
backend=backend,
|
|
890
|
+
watermark=watermark,
|
|
891
|
+
strict_ordering=strict_ordering,
|
|
892
|
+
calendar=calendar,
|
|
893
|
+
stream_id=stream_id,
|
|
894
|
+
on_bar=on_bar,
|
|
895
|
+
on_threshold_update=on_threshold_update,
|
|
896
|
+
multiplier=multiplier,
|
|
897
|
+
volume_type=volume_type,
|
|
898
|
+
session_policy=session_policy,
|
|
899
|
+
session_estimator=session_estimator,
|
|
900
|
+
)
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
def compute_run_dollar_bars_from_minutes(
|
|
904
|
+
minutes_df: pl.DataFrame,
|
|
905
|
+
span: float = 20.0,
|
|
906
|
+
halflife: float | None = None,
|
|
907
|
+
initial_ewa_t: float = 1.0,
|
|
908
|
+
initial_ewa_proportion: float = 0.5,
|
|
909
|
+
warmup_bars: int = 0,
|
|
910
|
+
warmup_minutes: int | None = None,
|
|
911
|
+
min_run_length: int = 0,
|
|
912
|
+
schema: MinuteSchemaMapping | None = None,
|
|
913
|
+
*,
|
|
914
|
+
backend: str = "python",
|
|
915
|
+
watermark: str | None = "timestamp",
|
|
916
|
+
strict_ordering: bool = False,
|
|
917
|
+
calendar: TradingCalendar | None = None,
|
|
918
|
+
stream_id: str = "default",
|
|
919
|
+
on_bar: Any = None,
|
|
920
|
+
on_threshold_update: Any = None,
|
|
921
|
+
multiplier: float = 1.0,
|
|
922
|
+
volume_type: str = "base",
|
|
923
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
924
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
925
|
+
) -> pl.DataFrame:
|
|
926
|
+
"""Build dollar-run bars from a Polars DataFrame of minute candles."""
|
|
927
|
+
return _minute_call(
|
|
928
|
+
_pd_compute_run_dollar_bars_from_minutes,
|
|
929
|
+
minutes_df,
|
|
930
|
+
span,
|
|
931
|
+
halflife,
|
|
932
|
+
initial_ewa_t,
|
|
933
|
+
initial_ewa_proportion,
|
|
934
|
+
warmup_bars,
|
|
935
|
+
warmup_minutes,
|
|
936
|
+
min_run_length,
|
|
937
|
+
schema,
|
|
938
|
+
backend=backend,
|
|
939
|
+
watermark=watermark,
|
|
940
|
+
strict_ordering=strict_ordering,
|
|
941
|
+
calendar=calendar,
|
|
942
|
+
stream_id=stream_id,
|
|
943
|
+
on_bar=on_bar,
|
|
944
|
+
on_threshold_update=on_threshold_update,
|
|
945
|
+
multiplier=multiplier,
|
|
946
|
+
volume_type=volume_type,
|
|
947
|
+
session_policy=session_policy,
|
|
948
|
+
session_estimator=session_estimator,
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
def compute_volatility_bars_from_minutes(
|
|
953
|
+
minutes_df: pl.DataFrame,
|
|
954
|
+
threshold: float,
|
|
955
|
+
schema: MinuteSchemaMapping | None = None,
|
|
956
|
+
*,
|
|
957
|
+
warmup_bars: int = 0,
|
|
958
|
+
warmup_minutes: int | None = None,
|
|
959
|
+
backend: str = "python",
|
|
960
|
+
watermark: str | None = "timestamp",
|
|
961
|
+
strict_ordering: bool = False,
|
|
962
|
+
calendar: TradingCalendar | None = None,
|
|
963
|
+
stream_id: str = "default",
|
|
964
|
+
on_bar: Any = None,
|
|
965
|
+
on_threshold_update: Any = None,
|
|
966
|
+
multiplier: float = 1.0,
|
|
967
|
+
volume_type: str = "base",
|
|
968
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
969
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
970
|
+
) -> pl.DataFrame:
|
|
971
|
+
"""Build volatility bars from a Polars DataFrame of minute candles."""
|
|
972
|
+
return _minute_call(
|
|
973
|
+
_pd_compute_volatility_bars_from_minutes,
|
|
974
|
+
minutes_df,
|
|
975
|
+
threshold,
|
|
976
|
+
schema,
|
|
977
|
+
warmup_bars=warmup_bars,
|
|
978
|
+
warmup_minutes=warmup_minutes,
|
|
979
|
+
backend=backend,
|
|
980
|
+
watermark=watermark,
|
|
981
|
+
strict_ordering=strict_ordering,
|
|
982
|
+
calendar=calendar,
|
|
983
|
+
stream_id=stream_id,
|
|
984
|
+
on_bar=on_bar,
|
|
985
|
+
on_threshold_update=on_threshold_update,
|
|
986
|
+
multiplier=multiplier,
|
|
987
|
+
volume_type=volume_type,
|
|
988
|
+
session_policy=session_policy,
|
|
989
|
+
session_estimator=session_estimator,
|
|
990
|
+
)
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
def compute_range_bars_from_minutes(
|
|
994
|
+
minutes_df: pl.DataFrame,
|
|
995
|
+
threshold: float,
|
|
996
|
+
schema: MinuteSchemaMapping | None = None,
|
|
997
|
+
*,
|
|
998
|
+
warmup_bars: int = 0,
|
|
999
|
+
warmup_minutes: int | None = None,
|
|
1000
|
+
backend: str = "python",
|
|
1001
|
+
watermark: str | None = "timestamp",
|
|
1002
|
+
strict_ordering: bool = False,
|
|
1003
|
+
calendar: TradingCalendar | None = None,
|
|
1004
|
+
stream_id: str = "default",
|
|
1005
|
+
on_bar: Any = None,
|
|
1006
|
+
on_threshold_update: Any = None,
|
|
1007
|
+
multiplier: float = 1.0,
|
|
1008
|
+
volume_type: str = "base",
|
|
1009
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
1010
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
1011
|
+
) -> pl.DataFrame:
|
|
1012
|
+
"""Build relative-range bars from a Polars DataFrame of minute candles."""
|
|
1013
|
+
return _minute_call(
|
|
1014
|
+
_pd_compute_range_bars_from_minutes,
|
|
1015
|
+
minutes_df,
|
|
1016
|
+
threshold,
|
|
1017
|
+
schema,
|
|
1018
|
+
warmup_bars=warmup_bars,
|
|
1019
|
+
warmup_minutes=warmup_minutes,
|
|
1020
|
+
backend=backend,
|
|
1021
|
+
watermark=watermark,
|
|
1022
|
+
strict_ordering=strict_ordering,
|
|
1023
|
+
calendar=calendar,
|
|
1024
|
+
stream_id=stream_id,
|
|
1025
|
+
on_bar=on_bar,
|
|
1026
|
+
on_threshold_update=on_threshold_update,
|
|
1027
|
+
multiplier=multiplier,
|
|
1028
|
+
volume_type=volume_type,
|
|
1029
|
+
session_policy=session_policy,
|
|
1030
|
+
session_estimator=session_estimator,
|
|
1031
|
+
)
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
def compute_renko_bars_from_minutes(
|
|
1035
|
+
minutes_df: pl.DataFrame,
|
|
1036
|
+
threshold: float,
|
|
1037
|
+
schema: MinuteSchemaMapping | None = None,
|
|
1038
|
+
*,
|
|
1039
|
+
warmup_bars: int = 0,
|
|
1040
|
+
warmup_minutes: int | None = None,
|
|
1041
|
+
backend: str = "python",
|
|
1042
|
+
watermark: str | None = "timestamp",
|
|
1043
|
+
strict_ordering: bool = False,
|
|
1044
|
+
calendar: TradingCalendar | None = None,
|
|
1045
|
+
stream_id: str = "default",
|
|
1046
|
+
on_bar: Any = None,
|
|
1047
|
+
on_threshold_update: Any = None,
|
|
1048
|
+
multiplier: float = 1.0,
|
|
1049
|
+
volume_type: str = "base",
|
|
1050
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
1051
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
1052
|
+
) -> pl.DataFrame:
|
|
1053
|
+
"""Build renko-displacement bars from a Polars DataFrame of minute candles."""
|
|
1054
|
+
return _minute_call(
|
|
1055
|
+
_pd_compute_renko_bars_from_minutes,
|
|
1056
|
+
minutes_df,
|
|
1057
|
+
threshold,
|
|
1058
|
+
schema,
|
|
1059
|
+
warmup_bars=warmup_bars,
|
|
1060
|
+
warmup_minutes=warmup_minutes,
|
|
1061
|
+
backend=backend,
|
|
1062
|
+
watermark=watermark,
|
|
1063
|
+
strict_ordering=strict_ordering,
|
|
1064
|
+
calendar=calendar,
|
|
1065
|
+
stream_id=stream_id,
|
|
1066
|
+
on_bar=on_bar,
|
|
1067
|
+
on_threshold_update=on_threshold_update,
|
|
1068
|
+
multiplier=multiplier,
|
|
1069
|
+
volume_type=volume_type,
|
|
1070
|
+
session_policy=session_policy,
|
|
1071
|
+
session_estimator=session_estimator,
|
|
1072
|
+
)
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
def compute_hybrid_bars_from_minutes(
|
|
1076
|
+
minutes_df: pl.DataFrame,
|
|
1077
|
+
dollar_threshold: float,
|
|
1078
|
+
volatility_threshold: float,
|
|
1079
|
+
schema: MinuteSchemaMapping | None = None,
|
|
1080
|
+
*,
|
|
1081
|
+
warmup_bars: int = 0,
|
|
1082
|
+
warmup_minutes: int | None = None,
|
|
1083
|
+
backend: str = "python",
|
|
1084
|
+
watermark: str | None = "timestamp",
|
|
1085
|
+
strict_ordering: bool = False,
|
|
1086
|
+
calendar: TradingCalendar | None = None,
|
|
1087
|
+
stream_id: str = "default",
|
|
1088
|
+
on_bar: Any = None,
|
|
1089
|
+
on_threshold_update: Any = None,
|
|
1090
|
+
multiplier: float = 1.0,
|
|
1091
|
+
volume_type: str = "base",
|
|
1092
|
+
session_policy: Literal["close", "carry", "discard"] = "close",
|
|
1093
|
+
session_estimator: Literal["persist", "reset"] = "persist",
|
|
1094
|
+
) -> pl.DataFrame:
|
|
1095
|
+
"""Build hybrid bars from a Polars DataFrame of minute candles."""
|
|
1096
|
+
return _minute_call(
|
|
1097
|
+
_pd_compute_hybrid_bars_from_minutes,
|
|
1098
|
+
minutes_df,
|
|
1099
|
+
dollar_threshold,
|
|
1100
|
+
volatility_threshold,
|
|
1101
|
+
schema,
|
|
1102
|
+
warmup_bars=warmup_bars,
|
|
1103
|
+
warmup_minutes=warmup_minutes,
|
|
1104
|
+
backend=backend,
|
|
1105
|
+
watermark=watermark,
|
|
1106
|
+
strict_ordering=strict_ordering,
|
|
1107
|
+
calendar=calendar,
|
|
1108
|
+
stream_id=stream_id,
|
|
1109
|
+
on_bar=on_bar,
|
|
1110
|
+
on_threshold_update=on_threshold_update,
|
|
1111
|
+
multiplier=multiplier,
|
|
1112
|
+
volume_type=volume_type,
|
|
1113
|
+
session_policy=session_policy,
|
|
1114
|
+
session_estimator=session_estimator,
|
|
1115
|
+
)
|