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.
Files changed (46) hide show
  1. flowbars/__init__.py +163 -0
  2. flowbars/_version.py +8 -0
  3. flowbars/adapters/__init__.py +29 -0
  4. flowbars/adapters/polars.py +1115 -0
  5. flowbars/bars/__init__.py +3 -0
  6. flowbars/bars/accumulators.py +731 -0
  7. flowbars/bars/constructor.py +1254 -0
  8. flowbars/bars/information/__init__.py +41 -0
  9. flowbars/bars/information/imbalance_dollar_bars.py +200 -0
  10. flowbars/bars/information/imbalance_tick_bars.py +206 -0
  11. flowbars/bars/information/imbalance_volume_bars.py +200 -0
  12. flowbars/bars/information/run_dollar_bars.py +225 -0
  13. flowbars/bars/information/run_tick_bars.py +231 -0
  14. flowbars/bars/information/run_volume_bars.py +225 -0
  15. flowbars/bars/minute/__init__.py +99 -0
  16. flowbars/bars/minute/accumulators.py +303 -0
  17. flowbars/bars/minute/engine.py +244 -0
  18. flowbars/bars/minute/information.py +622 -0
  19. flowbars/bars/minute/numba.py +1043 -0
  20. flowbars/bars/minute/registry.py +22 -0
  21. flowbars/bars/minute/standard.py +261 -0
  22. flowbars/bars/minute/structural.py +474 -0
  23. flowbars/bars/numba_backend.py +1227 -0
  24. flowbars/bars/output.py +106 -0
  25. flowbars/bars/registry.py +47 -0
  26. flowbars/bars/spec.py +367 -0
  27. flowbars/bars/standard/__init__.py +17 -0
  28. flowbars/bars/standard/dollar_bars.py +168 -0
  29. flowbars/bars/standard/tick_bars.py +166 -0
  30. flowbars/bars/standard/time_bars.py +192 -0
  31. flowbars/bars/standard/volume_bars.py +168 -0
  32. flowbars/benchmarks.py +420 -0
  33. flowbars/calendars.py +368 -0
  34. flowbars/core.py +109 -0
  35. flowbars/py.typed +0 -0
  36. flowbars/quality.py +393 -0
  37. flowbars/sample_data/__init__.py +28 -0
  38. flowbars/sample_data/tick_data.csv +501 -0
  39. flowbars/schema.py +476 -0
  40. flowbars/thresholds.py +1167 -0
  41. flowbars/tick_rule.py +89 -0
  42. flowbars-0.1.0.dist-info/METADATA +650 -0
  43. flowbars-0.1.0.dist-info/RECORD +46 -0
  44. flowbars-0.1.0.dist-info/WHEEL +5 -0
  45. flowbars-0.1.0.dist-info/licenses/LICENSE +21 -0
  46. flowbars-0.1.0.dist-info/top_level.txt +1 -0
flowbars/tick_rule.py ADDED
@@ -0,0 +1,89 @@
1
+ """Tick rule — derive trade direction from consecutive price moves.
2
+
3
+ Per AFML: sign(price_t − price_{t-1}), with equal-price carry-forward.
4
+ First tick has no sign (NaN). This is a well-known subtlety that existing
5
+ open implementations get wrong.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import numpy as np
11
+ import numpy.typing as npt
12
+
13
+
14
+ def derive_tick_sign(prices: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
15
+ """Derive trade signs from a price series using the tick rule.
16
+
17
+ Parameters
18
+ ----------
19
+ prices : ndarray of float64
20
+ 1-D array of trade prices in chronological order.
21
+
22
+ Returns
23
+ -------
24
+ ndarray of float64
25
+ Array of signs: ``+1.0`` (buy / uptick), ``-1.0`` (sell / downtick),
26
+ or ``NaN`` (undetermined — first tick, or carry-forward from first
27
+ tick when all early prices are equal).
28
+
29
+ Rule
30
+ ----
31
+ - First tick: ``NaN`` (no previous price to compare against).
32
+ - ``price_t > price_{t-1}`` → ``+1.0``
33
+ - ``price_t < price_{t-1}`` → ``-1.0``
34
+ - ``price_t == price_{t-1}`` → carry forward the previous tick's sign.
35
+ """
36
+ n = len(prices)
37
+ signs = np.empty(n, dtype=np.float64)
38
+
39
+ if n == 0:
40
+ return signs
41
+
42
+ # First tick has no sign
43
+ signs[0] = np.nan
44
+
45
+ if n == 1:
46
+ return signs
47
+
48
+ # Compute differences and assign signs
49
+ for i in range(1, n):
50
+ diff = prices[i] - prices[i - 1]
51
+ if diff > 0.0:
52
+ signs[i] = 1.0
53
+ elif diff < 0.0:
54
+ signs[i] = -1.0
55
+ else:
56
+ # Equal price → carry forward previous sign (which may be NaN)
57
+ signs[i] = signs[i - 1]
58
+
59
+ return signs
60
+
61
+
62
+ def resolve_tick_signs(
63
+ prices: npt.NDArray[np.float64],
64
+ supplied_sides: npt.NDArray[np.float64] | None,
65
+ ) -> npt.NDArray[np.float64]:
66
+ """Resolve trade signs: use supplied side column if provided, otherwise derive.
67
+
68
+ Parameters
69
+ ----------
70
+ prices : ndarray of float64
71
+ 1-D array of trade prices in chronological order.
72
+ supplied_sides : ndarray of float64 or None
73
+ User-supplied side values (+1, -1, NaN). If provided, returned as-is.
74
+ Values must already be validated (SchemaMapping handles this).
75
+
76
+ Returns
77
+ -------
78
+ ndarray of float64
79
+ Resolved signs array (same length as ``prices``).
80
+ """
81
+ if supplied_sides is not None:
82
+ if len(supplied_sides) != len(prices):
83
+ raise ValueError(
84
+ f"supplied_sides length ({len(supplied_sides)}) "
85
+ f"does not match prices length ({len(prices)})"
86
+ )
87
+ return supplied_sides.copy()
88
+
89
+ return derive_tick_sign(prices)