rangebar 11.7.0__tar.gz → 12.0.1__tar.gz

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 (289) hide show
  1. {rangebar-11.7.0 → rangebar-12.0.1}/.mise.toml +36 -0
  2. {rangebar-11.7.0 → rangebar-12.0.1}/CHANGELOG.md +25 -0
  3. {rangebar-11.7.0 → rangebar-12.0.1}/CLAUDE.md +3 -3
  4. {rangebar-11.7.0 → rangebar-12.0.1}/Cargo.lock +9 -9
  5. {rangebar-11.7.0 → rangebar-12.0.1}/Cargo.toml +2 -2
  6. {rangebar-11.7.0 → rangebar-12.0.1}/PKG-INFO +205 -46
  7. rangebar-12.0.1/README.md +427 -0
  8. {rangebar-11.7.0 → rangebar-12.0.1}/crates/CLAUDE.md +12 -12
  9. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/checkpoint.rs +8 -0
  10. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/processor.rs +14 -0
  11. rangebar-12.0.1/docs/research/2026-02-03-cfm-optimal-threshold-gemini-3-pro.md +510 -0
  12. rangebar-12.0.1/docs/verification/issue-62-verification-report.md +285 -0
  13. {rangebar-11.7.0 → rangebar-12.0.1}/pyproject.toml +1 -0
  14. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/__init__.py +17 -0
  15. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/constants.py +6 -0
  16. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/exness.py +13 -4
  17. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/count_bounded.py +3 -23
  18. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/precompute.py +4 -7
  19. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/range_bars.py +3 -20
  20. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/processors/api.py +18 -3
  21. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/processors/core.py +22 -1
  22. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/streaming.py +20 -1
  23. rangebar-12.0.1/python/rangebar/threshold.py +453 -0
  24. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/gap_classification.py +2 -1
  25. rangebar-12.0.1/scripts/purge_crypto_low_threshold.py +116 -0
  26. {rangebar-11.7.0 → rangebar-12.0.1}/src/lib.rs +20 -0
  27. rangebar-12.0.1/tests/conftest.py +115 -0
  28. rangebar-12.0.1/tests/test_crypto_minimum_threshold.py +306 -0
  29. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_edge_cases.py +4 -3
  30. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_get_n_range_bars.py +22 -3
  31. rangebar-11.7.0/README.md +0 -268
  32. rangebar-11.7.0/tests/conftest.py +0 -50
  33. {rangebar-11.7.0 → rangebar-12.0.1}/.gitignore +0 -0
  34. {rangebar-11.7.0 → rangebar-12.0.1}/.mcp.json +0 -0
  35. {rangebar-11.7.0 → rangebar-12.0.1}/.pre-commit-config.yaml +0 -0
  36. {rangebar-11.7.0 → rangebar-12.0.1}/.releaserc.yml +0 -0
  37. {rangebar-11.7.0 → rangebar-12.0.1}/LICENSE +0 -0
  38. {rangebar-11.7.0 → rangebar-12.0.1}/RESUME.md +0 -0
  39. {rangebar-11.7.0 → rangebar-12.0.1}/STATISTICAL_VALIDITY_AUDIT.md +0 -0
  40. {rangebar-11.7.0 → rangebar-12.0.1}/benches/rangebar_bench.rs +0 -0
  41. {rangebar-11.7.0 → rangebar-12.0.1}/build.rs +0 -0
  42. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/CHANGELOG.md +0 -0
  43. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/Cargo.toml +0 -0
  44. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/README.md +0 -0
  45. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/arrow_export.rs +0 -0
  46. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/fixed_point.rs +0 -0
  47. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/interbar.rs +0 -0
  48. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/drawdown.rs +0 -0
  49. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/features.rs +0 -0
  50. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/ith.rs +0 -0
  51. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/mod.rs +0 -0
  52. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/normalize.rs +0 -0
  53. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/types.rs +0 -0
  54. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/lib.rs +0 -0
  55. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/test_data_loader.rs +0 -0
  56. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/test_utils/generators.rs +0 -0
  57. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/test_utils/mod.rs +0 -0
  58. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/timestamp.rs +0 -0
  59. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/types.rs +0 -0
  60. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/tests/cross_boundary_validation.rs +0 -0
  61. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/tests/cross_date_real_data_validation.rs +0 -0
  62. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/tests/cross_year_boundary_test.rs +0 -0
  63. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/tests/incomplete_bar_continuation_proof.rs +0 -0
  64. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/CHANGELOG.md +0 -0
  65. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/Cargo.toml +0 -0
  66. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/README.md +0 -0
  67. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/checksum.rs +0 -0
  68. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/historical.rs +0 -0
  69. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/mod.rs +0 -0
  70. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/symbols.rs +0 -0
  71. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/websocket.rs +0 -0
  72. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/builder.rs +0 -0
  73. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/client.rs +0 -0
  74. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/conversion.rs +0 -0
  75. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/mod.rs +0 -0
  76. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/types.rs +0 -0
  77. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/lib.rs +0 -0
  78. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/CHANGELOG.md +0 -0
  79. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/Cargo.toml +0 -0
  80. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/README.md +0 -0
  81. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/indicators.rs +0 -0
  82. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/lib.rs +0 -0
  83. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/processor.rs +0 -0
  84. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/replay_buffer.rs +0 -0
  85. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/stats.rs +0 -0
  86. {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/universal.rs +0 -0
  87. {rangebar-11.7.0 → rangebar-12.0.1}/deny.toml +0 -0
  88. {rangebar-11.7.0 → rangebar-12.0.1}/docs/ARCHITECTURE.md +0 -0
  89. {rangebar-11.7.0 → rangebar-12.0.1}/docs/CONTEXT.md +0 -0
  90. {rangebar-11.7.0 → rangebar-12.0.1}/docs/MEMORY_REMEDIATION_PLAN.md +0 -0
  91. {rangebar-11.7.0 → rangebar-12.0.1}/docs/adr/2026-01-31-realtime-streaming-api.md +0 -0
  92. {rangebar-11.7.0 → rangebar-12.0.1}/docs/analysis/2025-10-10-flash-crash.md +0 -0
  93. {rangebar-11.7.0 → rangebar-12.0.1}/docs/api.md +0 -0
  94. {rangebar-11.7.0 → rangebar-12.0.1}/docs/development/PERFORMANCE.md +0 -0
  95. {rangebar-11.7.0 → rangebar-12.0.1}/docs/development/RELEASE.md +0 -0
  96. {rangebar-11.7.0 → rangebar-12.0.1}/docs/migration-v8.md +0 -0
  97. {rangebar-11.7.0 → rangebar-12.0.1}/docs/plans/issue-59-inter-bar-features.md +0 -0
  98. {rangebar-11.7.0 → rangebar-12.0.1}/docs/rangebar_core_api.md +0 -0
  99. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/2026-02-02-intrabar-microstructure-claude-opus.md +0 -0
  100. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/2026-02-02-intrabar-microstructure-gemini-3-pro.md +0 -0
  101. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/INDEX.md +0 -0
  102. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/adversarial-audit-methodology.md +0 -0
  103. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/external/time-to-convergence-stationarity-gap.md +0 -0
  104. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/labeling-for-ml.md +0 -0
  105. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/market-regime-patterns.md +0 -0
  106. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/multi-threshold-patterns.md +0 -0
  107. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/multifactor-patterns.md +0 -0
  108. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/pattern-research-summary.md +0 -0
  109. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/price-action-patterns.md +0 -0
  110. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/tda-parameter-sensitivity-audit.md +0 -0
  111. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/tda-regime-patterns.md +0 -0
  112. {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/volatility-regime-patterns.md +0 -0
  113. {rangebar-11.7.0 → rangebar-12.0.1}/examples/README.md +0 -0
  114. {rangebar-11.7.0 → rangebar-12.0.1}/examples/backtesting_integration.py +0 -0
  115. {rangebar-11.7.0 → rangebar-12.0.1}/examples/basic_usage.py +0 -0
  116. {rangebar-11.7.0 → rangebar-12.0.1}/examples/binance_csv_example.py +0 -0
  117. {rangebar-11.7.0 → rangebar-12.0.1}/examples/get_range_bars_example.py +0 -0
  118. {rangebar-11.7.0 → rangebar-12.0.1}/examples/validate_output.py +0 -0
  119. {rangebar-11.7.0 → rangebar-12.0.1}/examples/with_clickhouse_cache.py +0 -0
  120. {rangebar-11.7.0 → rangebar-12.0.1}/package-lock.json +0 -0
  121. {rangebar-11.7.0 → rangebar-12.0.1}/package.json +0 -0
  122. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/CLAUDE.md +0 -0
  123. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/__init__.pyi +0 -0
  124. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/checkpoint.py +0 -0
  125. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/cli.py +0 -0
  126. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/CLAUDE.md +0 -0
  127. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/__init__.py +0 -0
  128. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/bulk_operations.py +0 -0
  129. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/cache.py +0 -0
  130. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/client.py +0 -0
  131. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/config.py +0 -0
  132. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/mixin.py +0 -0
  133. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/preflight.py +0 -0
  134. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/query_operations.py +0 -0
  135. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/schema.sql +0 -0
  136. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/tunnel.py +0 -0
  137. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/conversion.py +0 -0
  138. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/exceptions.py +0 -0
  139. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/hooks.py +0 -0
  140. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/logging.py +0 -0
  141. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/notify/__init__.py +0 -0
  142. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/notify/pushover.py +0 -0
  143. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/notify/telegram.py +0 -0
  144. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/__init__.py +0 -0
  145. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/helpers.py +0 -0
  146. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/models.py +0 -0
  147. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/tick_fetcher.py +0 -0
  148. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/ouroboros.py +0 -0
  149. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/processors/__init__.py +0 -0
  150. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/resource_guard.py +0 -0
  151. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/storage/__init__.py +0 -0
  152. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/storage/checksum_registry.py +0 -0
  153. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/storage/parquet.py +0 -0
  154. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/__init__.py +0 -0
  155. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/cache_staleness.py +0 -0
  156. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/continuity.py +0 -0
  157. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/post_storage.py +0 -0
  158. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/tier1.py +0 -0
  159. {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/tier2.py +0 -0
  160. {rangebar-11.7.0 → rangebar-12.0.1}/rust-toolchain.toml +0 -0
  161. {rangebar-11.7.0 → rangebar-12.0.1}/rustfmt.toml +0 -0
  162. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/adwin_regime_detection_polars.py +0 -0
  163. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/analyze_flash_crash.py +0 -0
  164. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/bootstrap_permutation_validation_polars.py +0 -0
  165. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/build-release.sh +0 -0
  166. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cache_clear.py +0 -0
  167. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cache_status.py +0 -0
  168. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/check-release-config.sh +0 -0
  169. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/coarse_to_fine_cascade.py +0 -0
  170. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/combined_pattern_audit_polars.py +0 -0
  171. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/combined_regime_analysis_polars.py +0 -0
  172. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/combined_rv_alignment_analysis_polars.py +0 -0
  173. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cross_asset_correlation_polars.py +0 -0
  174. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cross_regime_correlation_polars.py +0 -0
  175. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cross_threshold_alignment.py +0 -0
  176. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/dependency_monitor.sh +0 -0
  177. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/direction_patterns_reaudit.py +0 -0
  178. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/download_exness_eurusd.py +0 -0
  179. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/download_exness_forex.py +0 -0
  180. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/duration_autocorrelation.py +0 -0
  181. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/duration_autocorrelation_audit.py +0 -0
  182. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/duration_volatility_prediction.py +0 -0
  183. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fdr_corrected_patterns.py +0 -0
  184. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fill_all_symbols.py +0 -0
  185. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fill_gaps_2025_2026.py +0 -0
  186. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fill_gaps_littleblack.py +0 -0
  187. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fill_gaps_retry.py +0 -0
  188. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/historical_formation_patterns_polars.py +0 -0
  189. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/historical_formation_regime_polars.py +0 -0
  190. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/hurst_adjusted_kelly_polars.py +0 -0
  191. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/hurst_adjusted_psr_analysis_polars.py +0 -0
  192. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/hurst_exponent_analysis_polars.py +0 -0
  193. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/hurst_multi_estimator_audit.py +0 -0
  194. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/microstructure_clickhouse.py +0 -0
  195. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/microstructure_patterns.py +0 -0
  196. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/microstructure_simple.py +0 -0
  197. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/monitor_population.py +0 -0
  198. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multi_threshold_pattern_analysis_polars.py +0 -0
  199. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multibar_continuation.py +0 -0
  200. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multibar_forward_returns_polars.py +0 -0
  201. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multifactor_multigranularity_patterns.py +0 -0
  202. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multifactor_patterns.py +0 -0
  203. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multifactor_patterns_polars.py +0 -0
  204. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multithreshold_combinations_polars.py +0 -0
  205. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multithreshold_regime_combinations_polars.py +0 -0
  206. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/oos_validation_polars.py +0 -0
  207. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/parameter_sensitivity_polars.py +0 -0
  208. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/pattern_correlation_analysis_polars.py +0 -0
  209. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/pattern_return_profiles_polars.py +0 -0
  210. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/pattern_return_stats.py +0 -0
  211. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/populate_1000dbps.py +0 -0
  212. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/populate_250dbps.py +0 -0
  213. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/populate_250dbps_extended.py +0 -0
  214. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/populate_safe.py +0 -0
  215. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/position_sizing_analysis_polars.py +0 -0
  216. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/process_exness_eurusd_to_cache.py +0 -0
  217. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/profiling_tools.sh +0 -0
  218. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/psr_mintrl_analysis_polars.py +0 -0
  219. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/publish-to-pypi.sh +0 -0
  220. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/publish-wheels.sh +0 -0
  221. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regenerate_cache.py +0 -0
  222. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regime_analysis.py +0 -0
  223. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regime_analysis_50dbps_polars.py +0 -0
  224. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regime_analysis_polars.py +0 -0
  225. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regime_transition_analysis_polars.py +0 -0
  226. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/run_large_scale_benchmark.sh +0 -0
  227. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/run_length_momentum_analysis.py +0 -0
  228. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/run_length_momentum_multi_symbol.py +0 -0
  229. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/run_length_momentum_wfo.py +0 -0
  230. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/rv_return_profile_analysis_polars.py +0 -0
  231. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/semantic-release.sh +0 -0
  232. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_break_event_alignment_polars.py +0 -0
  233. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_conditioned_patterns.py +0 -0
  234. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_cupy_accelerated.py +0 -0
  235. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_gpu_analysis.py +0 -0
  236. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_hurst_by_regime_polars.py +0 -0
  237. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_parameter_sweep_audit.py +0 -0
  238. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_regime_hurst_analysis_polars.py +0 -0
  239. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_regime_pattern_analysis_polars.py +0 -0
  240. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_ripser_plusplus.py +0 -0
  241. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_rolling_threshold.py +0 -0
  242. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_solusdt_250_audit.py +0 -0
  243. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_solusdt_250_littleblack.py +0 -0
  244. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_structural_break_analysis_polars.py +0 -0
  245. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_volatility_forecast.py +0 -0
  246. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_wfo_3way.py +0 -0
  247. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_wfo_abstain.py +0 -0
  248. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_wfo_audit.py +0 -0
  249. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/temporal_safe_patterns_polars.py +0 -0
  250. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_bar_alignment_analysis_polars.py +0 -0
  251. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_bar_pattern_analysis_polars.py +0 -0
  252. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_bar_pattern_audit_polars.py +0 -0
  253. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_factor_hurst_analysis_polars.py +0 -0
  254. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_factor_pattern_analysis_polars.py +0 -0
  255. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/transaction_cost_analysis_polars.py +0 -0
  256. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/trend_filter_analysis.py +0 -0
  257. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/upload_eurusd_to_clickhouse.py +0 -0
  258. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/validate_clickhouse.py +0 -0
  259. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/validate_memory_efficiency.py +0 -0
  260. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/validate_microstructure_features.py +0 -0
  261. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/validate_n_range_bars.py +0 -0
  262. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/volatility_regime_analysis_polars.py +0 -0
  263. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/volatility_regime_audit_polars.py +0 -0
  264. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/volume_conditioned_patterns.py +0 -0
  265. {rangebar-11.7.0 → rangebar-12.0.1}/scripts/volume_conditioned_patterns_polars.py +0 -0
  266. {rangebar-11.7.0 → rangebar-12.0.1}/test_data/BTCUSDT/BTCUSDT_aggTrades_20250901.csv +0 -0
  267. {rangebar-11.7.0 → rangebar-12.0.1}/test_data/ETHUSDT/ETHUSDT_aggTrades_20250901.csv +0 -0
  268. {rangebar-11.7.0 → rangebar-12.0.1}/test_data/README.md +0 -0
  269. {rangebar-11.7.0 → rangebar-12.0.1}/tests/fixtures/.gitignore +0 -0
  270. {rangebar-11.7.0 → rangebar-12.0.1}/tests/fixtures/BTCUSDT-aggTrades-2024-01-01.zip +0 -0
  271. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_cache_schema_evolution.py +0 -0
  272. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_clickhouse.py +0 -0
  273. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_clickhouse_integration.py +0 -0
  274. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_e2e_optimized.py +0 -0
  275. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_examples.py +0 -0
  276. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_get_range_bars_e2e.py +0 -0
  277. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_issue_5_reproduction.py +0 -0
  278. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_issues_7_8.py +0 -0
  279. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_microstructure_features.py +0 -0
  280. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_ouroboros.py +0 -0
  281. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_polars_only_downstream.py +0 -0
  282. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_preflight.py +0 -0
  283. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_python_api.py +0 -0
  284. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_real_data.py +0 -0
  285. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_rust_bindings.py +0 -0
  286. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_storage.py +0 -0
  287. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_streaming.py +0 -0
  288. {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_validation_presets.py +0 -0
  289. {rangebar-11.7.0 → rangebar-12.0.1}/uv.lock +0 -0
@@ -1,4 +1,40 @@
1
1
  [env]
2
+ # =============================================================================
3
+ # SSoT: Minimum Thresholds by Asset Class (Issue #62)
4
+ # =============================================================================
5
+ # These are the canonical values for threshold validation. Change here, affects
6
+ # all entry points (Python API + Rust core).
7
+ #
8
+ # Values are in decimal basis points (dbps): 1000 dbps = 1%
9
+ # Research: docs/research/2026-02-03-cfm-optimal-threshold-gemini-3-pro.md
10
+ #
11
+ # Resolution order (highest priority first):
12
+ # 1. Per-symbol: RANGEBAR_MIN_THRESHOLD_<SYMBOL>
13
+ # 2. Asset-class: RANGEBAR_<ASSET_CLASS>_MIN_THRESHOLD
14
+ # 3. Fallback defaults in code (with warning)
15
+
16
+ # Crypto: Default minimum (1% - cannot overcome trading costs below this)
17
+ # CFM formula validates this as "conservative guardrails"
18
+ RANGEBAR_CRYPTO_MIN_THRESHOLD = "1000"
19
+
20
+ # Forex: Default minimum (tighter spreads allow lower)
21
+ RANGEBAR_FOREX_MIN_THRESHOLD = "50"
22
+
23
+ # Equities: Default minimum
24
+ RANGEBAR_EQUITIES_MIN_THRESHOLD = "100"
25
+
26
+ # Unknown: Fallback (no enforcement)
27
+ RANGEBAR_UNKNOWN_MIN_THRESHOLD = "1"
28
+
29
+ # =============================================================================
30
+ # Per-Symbol Overrides (Optional - uncomment to enable)
31
+ # =============================================================================
32
+ # Override specific symbols when research justifies different thresholds:
33
+ #
34
+ # RANGEBAR_MIN_THRESHOLD_BTCUSDT = "1500" # BTC needs higher threshold
35
+ # RANGEBAR_MIN_THRESHOLD_XAUUSD = "200" # Gold needs higher than forex
36
+ # RANGEBAR_MIN_THRESHOLD_EURUSD = "25" # EUR/USD can go lower
37
+
2
38
  # =============================================================================
3
39
  # GitHub Account Isolation (CRITICAL for multi-account setups)
4
40
  # =============================================================================
@@ -1,3 +1,28 @@
1
+ # [12.0.0](https://github.com/terrylica/rangebar-py/compare/v11.7.0...v12.0.0) (2026-02-03)
2
+
3
+
4
+ ### Features
5
+
6
+ * **threshold:** enforce configurable minimum threshold for crypto (Issue [#64](https://github.com/terrylica/rangebar-py/issues/64)) ([4030c7d](https://github.com/terrylica/rangebar-py/commit/4030c7dc9e6789a4c9ae11f21c03261dc56e6c95))
7
+
8
+
9
+ ### BREAKING CHANGES
10
+
11
+ * **threshold:** ThresholdError raised for crypto symbols with threshold < 1000 dbps
12
+
13
+ - Add threshold.py module with hierarchical SSoT configuration
14
+ - Per-symbol override: RANGEBAR_MIN_THRESHOLD_<SYMBOL>
15
+ - Asset-class default: RANGEBAR_<ASSET_CLASS>_MIN_THRESHOLD
16
+ - Default crypto minimum: 1000 dbps (1%) per CFM research
17
+ - Add validation to all Python entry points (21 locations)
18
+ - Add validation to Rust checkpoint restoration (lib.rs, processor.rs)
19
+ - Add NDJSON logging and Pushover alerts for violations
20
+ - Add cache purge script for invalidating low-threshold data
21
+ - Add 32 comprehensive tests for threshold enforcement
22
+
23
+ SRED-Type: applied-research
24
+ SRED-Claim: THRESHOLD
25
+
1
26
  # [11.7.0](https://github.com/terrylica/rangebar-py/compare/v11.6.1...v11.7.0) (2026-02-02)
2
27
 
3
28
 
@@ -135,16 +135,16 @@ mise run bench:validate # Verify 1M ticks < 100ms
135
135
 
136
136
  | Feature | Formula | Range |
137
137
  | ---------------------- | ------------------------------------------- | ------------ |
138
- | `duration_us` | (close_time - open_time) \* 1000 | [0, +inf) |
138
+ | `duration_us` | close_time - open_time | [0, +inf) |
139
139
  | `ofi` | (buy_vol - sell_vol) / total | [-1, 1] |
140
- | `vwap_close_deviation` | (close - vwap) / range | ~[-1, 1] |
140
+ | `vwap_close_deviation` | (close - vwap) / (high - low) | ~[-1, 1] |
141
141
  | `price_impact` | abs(close - open) / volume | [0, +inf) |
142
142
  | `kyle_lambda_proxy` | ((close-open)/open) / (imbalance/total_vol) | (-inf, +inf) |
143
143
  | `trade_intensity` | trades / duration_sec | [0, +inf) |
144
144
  | `volume_per_trade` | volume / trade_count | [0, +inf) |
145
145
  | `aggression_ratio` | buy_count / sell_count | [0, 100] |
146
146
  | `aggregation_density` | individual_count / agg_count | [1, +inf) |
147
- | `turnover_imbalance` | (buy_turn - sell_turn) / volume | [-1, 1] |
147
+ | `turnover_imbalance` | (buy_turn - sell_turn) / total_turnover | [-1, 1] |
148
148
 
149
149
  **Full details**: [crates/CLAUDE.md](/crates/CLAUDE.md#microstructure-features-v70)
150
150
 
@@ -3430,7 +3430,7 @@ dependencies = [
3430
3430
 
3431
3431
  [[package]]
3432
3432
  name = "rangebar"
3433
- version = "11.7.0"
3433
+ version = "12.0.1"
3434
3434
  dependencies = [
3435
3435
  "chrono",
3436
3436
  "insta",
@@ -3452,7 +3452,7 @@ dependencies = [
3452
3452
 
3453
3453
  [[package]]
3454
3454
  name = "rangebar-batch"
3455
- version = "11.7.0"
3455
+ version = "12.0.1"
3456
3456
  dependencies = [
3457
3457
  "polars",
3458
3458
  "rangebar-core",
@@ -3464,7 +3464,7 @@ dependencies = [
3464
3464
 
3465
3465
  [[package]]
3466
3466
  name = "rangebar-cli"
3467
- version = "11.7.0"
3467
+ version = "12.0.1"
3468
3468
  dependencies = [
3469
3469
  "chrono",
3470
3470
  "clap",
@@ -3489,7 +3489,7 @@ dependencies = [
3489
3489
 
3490
3490
  [[package]]
3491
3491
  name = "rangebar-config"
3492
- version = "11.7.0"
3492
+ version = "12.0.1"
3493
3493
  dependencies = [
3494
3494
  "chrono",
3495
3495
  "config",
@@ -3501,7 +3501,7 @@ dependencies = [
3501
3501
 
3502
3502
  [[package]]
3503
3503
  name = "rangebar-core"
3504
- version = "11.7.0"
3504
+ version = "12.0.1"
3505
3505
  dependencies = [
3506
3506
  "ahash",
3507
3507
  "arrow",
@@ -3518,7 +3518,7 @@ dependencies = [
3518
3518
 
3519
3519
  [[package]]
3520
3520
  name = "rangebar-io"
3521
- version = "11.7.0"
3521
+ version = "12.0.1"
3522
3522
  dependencies = [
3523
3523
  "polars",
3524
3524
  "rangebar-core",
@@ -3528,7 +3528,7 @@ dependencies = [
3528
3528
 
3529
3529
  [[package]]
3530
3530
  name = "rangebar-providers"
3531
- version = "11.7.0"
3531
+ version = "12.0.1"
3532
3532
  dependencies = [
3533
3533
  "chrono",
3534
3534
  "csv",
@@ -3548,7 +3548,7 @@ dependencies = [
3548
3548
 
3549
3549
  [[package]]
3550
3550
  name = "rangebar-py"
3551
- version = "11.7.0"
3551
+ version = "12.0.1"
3552
3552
  dependencies = [
3553
3553
  "arrow",
3554
3554
  "arrow-array",
@@ -3567,7 +3567,7 @@ dependencies = [
3567
3567
 
3568
3568
  [[package]]
3569
3569
  name = "rangebar-streaming"
3570
- version = "11.7.0"
3570
+ version = "12.0.1"
3571
3571
  dependencies = [
3572
3572
  "async-trait",
3573
3573
  "chrono",
@@ -10,7 +10,7 @@ resolver = "2"
10
10
  [workspace.package]
11
11
  # CRITICAL: Prevent crates.io publishing - this is a PyPI-only project
12
12
  publish = false
13
- version = "11.7.0"
13
+ version = "12.0.1"
14
14
  authors = ["Terry Li <terry@eonlabs.com>"]
15
15
  categories = ["algorithms", "data-structures", "finance"]
16
16
  documentation = "https://docs.rs/rangebar"
@@ -97,7 +97,7 @@ criterion = { version = "0.5", features = ["html_reports"] }
97
97
 
98
98
  [package]
99
99
  name = "rangebar-py"
100
- version = "11.7.0"
100
+ version.workspace = true
101
101
  edition = "2021"
102
102
  authors = ["Terry Li"]
103
103
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rangebar
3
- Version: 11.7.0
3
+ Version: 12.0.1
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Financial and Insurance Industry
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -37,9 +37,11 @@ Project-URL: Documentation, https://github.com/terrylica/rangebar-py#readme
37
37
  Project-URL: Repository, https://github.com/terrylica/rangebar-py
38
38
  Project-URL: Upstream (Rust), https://github.com/terrylica/rangebar
39
39
 
40
+ [//]: # SSoT-OK
41
+
40
42
  # rangebar-py
41
43
 
42
- Python bindings for the [rangebar](https://github.com/terrylica/rangebar-py/tree/main/crates) Rust crates via PyO3/maturin.
44
+ High-performance range bar construction for quantitative trading, with Python bindings via PyO3/maturin.
43
45
 
44
46
  [![PyPI](https://img.shields.io/pypi/v/rangebar.svg)](https://pypi.org/project/rangebar/)
45
47
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/terrylica/rangebar-py/blob/main/LICENSE)
@@ -85,6 +87,45 @@ bt = Backtest(df, MyStrategy, cash=10000, commission=0.0002)
85
87
  stats = bt.run()
86
88
  ```
87
89
 
90
+ ## Minimum Threshold Enforcement (v12.0+)
91
+
92
+ **Breaking change in v12.0**: Crypto symbols now enforce a minimum threshold of 1000 dbps (1%) by default. Thresholds below this cannot overcome trading costs sufficiently for crypto assets.
93
+
94
+ ```python
95
+ from rangebar import get_range_bars, ThresholdError
96
+
97
+ # This raises ThresholdError for crypto (below 1000 dbps minimum)
98
+ try:
99
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", threshold_decimal_bps=250)
100
+ except ThresholdError as e:
101
+ print(e) # Threshold 250 dbps below minimum 1000 dbps for crypto symbol 'BTCUSDT'
102
+
103
+ # Use valid threshold for crypto (>= 1000 dbps)
104
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", threshold_decimal_bps=1000)
105
+
106
+ # Forex allows lower thresholds (minimum 50 dbps)
107
+ df = get_range_bars("EURUSD", "2024-01-01", "2024-01-31", threshold_decimal_bps=50, source="exness")
108
+ ```
109
+
110
+ **Override for research/testing**:
111
+
112
+ ```bash
113
+ # Lower crypto minimum for research
114
+ RANGEBAR_CRYPTO_MIN_THRESHOLD=100 python my_research_script.py
115
+
116
+ # Override specific symbol
117
+ RANGEBAR_MIN_THRESHOLD_BTCUSDT=250 python btc_analysis.py
118
+ ```
119
+
120
+ **Default minimums by asset class**:
121
+
122
+ | Asset Class | Minimum | Env Var |
123
+ | ----------- | --------- | --------------------------------- |
124
+ | Crypto | 1000 dbps | `RANGEBAR_CRYPTO_MIN_THRESHOLD` |
125
+ | Forex | 50 dbps | `RANGEBAR_FOREX_MIN_THRESHOLD` |
126
+ | Equities | 100 dbps | `RANGEBAR_EQUITIES_MIN_THRESHOLD` |
127
+ | Unknown | 1 dbps | `RANGEBAR_UNKNOWN_MIN_THRESHOLD` |
128
+
88
129
  ## API Reference
89
130
 
90
131
  ### get_range_bars (Date-Bounded)
@@ -94,28 +135,28 @@ The entry point for date-bounded range bar generation with automatic data fetchi
94
135
  ```python
95
136
  from rangebar import get_range_bars
96
137
 
97
- # Basic usage - Binance spot
98
- df = get_range_bars("BTCUSDT", "2024-01-01", "2024-06-30")
138
+ # Basic usage - Binance spot (crypto requires threshold >= 1000 dbps)
139
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-06-30", threshold_decimal_bps=1000)
99
140
 
100
- # Using threshold presets
101
- df = get_range_bars("BTCUSDT", "2024-01-01", "2024-03-31", threshold_decimal_bps="tight")
141
+ # Using threshold presets (only "macro" and "wide" valid for crypto)
142
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-03-31", threshold_decimal_bps="macro")
102
143
 
103
144
  # Binance USD-M Futures
104
- df = get_range_bars("BTCUSDT", "2024-01-01", "2024-03-31", market="futures-um")
145
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-03-31", market="futures-um", threshold_decimal_bps=1000)
105
146
 
106
- # With microstructure data (vwap, buy_volume, sell_volume)
107
- df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", include_microstructure=True)
147
+ # With microstructure features (62 total columns)
148
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", threshold_decimal_bps=1000, include_microstructure=True)
108
149
  ```
109
150
 
110
151
  **Parameters**:
111
152
 
112
- - `symbol`: Trading symbol (e.g., "BTCUSDT", "ETHUSDT")
153
+ - `symbol`: Trading symbol (e.g., "BTCUSDT", "ETHUSDT", "EURUSD")
113
154
  - `start_date`: Start date in YYYY-MM-DD format
114
155
  - `end_date`: End date in YYYY-MM-DD format
115
- - `threshold_decimal_bps`: Threshold in decimal basis points or preset name (default: 250 = 25bps = 0.25%)
156
+ - `threshold_decimal_bps`: Threshold in decimal basis points or preset name (default: 250, but crypto requires >= 1000)
116
157
  - `source`: Data source - "binance" or "exness" (default: "binance")
117
158
  - `market`: Market type - "spot", "futures-um"/"um", "futures-cm"/"cm" (default: "spot")
118
- - `include_microstructure`: Include vwap, buy_volume, sell_volume columns (default: False)
159
+ - `include_microstructure`: Include 57 microstructure feature columns (default: False)
119
160
  - `use_cache`: Cache tick data locally (default: True)
120
161
 
121
162
  **Returns**: pandas DataFrame with DatetimeIndex and columns `Open`, `High`, `Low`, `Close`, `Volume`
@@ -128,21 +169,21 @@ Get exactly N range bars - useful for ML training, walk-forward optimization, an
128
169
  from rangebar import get_n_range_bars
129
170
 
130
171
  # Get last 10,000 bars for ML training
131
- df = get_n_range_bars("BTCUSDT", n_bars=10000)
172
+ df = get_n_range_bars("BTCUSDT", n_bars=10000, threshold_decimal_bps=1000)
132
173
  assert len(df) == 10000
133
174
 
134
175
  # Get 5,000 bars ending at specific date
135
- df = get_n_range_bars("BTCUSDT", n_bars=5000, end_date="2024-06-01")
176
+ df = get_n_range_bars("BTCUSDT", n_bars=5000, end_date="2024-06-01", threshold_decimal_bps=1000)
136
177
 
137
178
  # With safety limit (won't fetch more than 30 days of data)
138
- df = get_n_range_bars("BTCUSDT", n_bars=1000, max_lookback_days=30)
179
+ df = get_n_range_bars("BTCUSDT", n_bars=1000, max_lookback_days=30, threshold_decimal_bps=1000)
139
180
  ```
140
181
 
141
182
  **Parameters**:
142
183
 
143
184
  - `symbol`: Trading symbol (e.g., "BTCUSDT")
144
185
  - `n_bars`: Number of bars to retrieve (must be > 0)
145
- - `threshold_decimal_bps`: Threshold in decimal basis points or preset name (default: 250)
186
+ - `threshold_decimal_bps`: Threshold in decimal basis points or preset name (default: 250, but crypto requires >= 1000)
146
187
  - `end_date`: End date (YYYY-MM-DD) or None for most recent data
147
188
  - `source`: Data source - "binance" or "exness" (default: "binance")
148
189
  - `market`: Market type (default: "spot")
@@ -162,29 +203,96 @@ df = get_n_range_bars("BTCUSDT", n_bars=1000, max_lookback_days=30)
162
203
 
163
204
  Use string presets for common threshold values:
164
205
 
165
- | Preset | Value | Percentage | Use Case |
166
- | ------------ | ----- | ------------- | ---------------- |
167
- | `"micro"` | 10 | 0.01% (1bps) | Scalping |
168
- | `"tight"` | 50 | 0.05% (5bps) | Day trading |
169
- | `"standard"` | 100 | 0.1% (10bps) | Swing trading |
170
- | `"medium"` | 250 | 0.25% (25bps) | Default |
171
- | `"wide"` | 500 | 0.5% (50bps) | Position trading |
172
- | `"macro"` | 1000 | 1% (100bps) | Long-term |
206
+ | Preset | Value | Percentage | Crypto | Forex | Use Case |
207
+ | ------------ | ----- | ------------- | ------ | ----- | ---------------- |
208
+ | `"micro"` | 10 | 0.01% (1bps) | No | No | Scalping |
209
+ | `"tight"` | 50 | 0.05% (5bps) | No | Yes | Day trading |
210
+ | `"standard"` | 100 | 0.1% (10bps) | No | Yes | Swing trading |
211
+ | `"medium"` | 250 | 0.25% (25bps) | No | Yes | Default |
212
+ | `"wide"` | 500 | 0.5% (50bps) | No | Yes | Position trading |
213
+ | `"macro"` | 1000 | 1% (100bps) | Yes | Yes | Long-term |
173
214
 
174
215
  ```python
175
216
  from rangebar import get_range_bars, THRESHOLD_PRESETS
176
217
 
177
- # Using preset string
178
- df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", threshold_decimal_bps="tight")
218
+ # Using preset string (only "macro" valid for crypto)
219
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", threshold_decimal_bps="macro")
179
220
 
180
- # Or numeric value
181
- df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", threshold_decimal_bps=50)
221
+ # Forex allows all presets
222
+ df = get_range_bars("EURUSD", "2024-01-01", "2024-01-31", threshold_decimal_bps="tight", source="exness")
182
223
 
183
224
  # View all presets
184
225
  print(THRESHOLD_PRESETS)
185
226
  # {'micro': 10, 'tight': 50, 'standard': 100, 'medium': 250, 'wide': 500, 'macro': 1000}
186
227
  ```
187
228
 
229
+ ### Threshold Validation Utilities (v12.0+)
230
+
231
+ ```python
232
+ from rangebar import (
233
+ ThresholdError,
234
+ get_min_threshold,
235
+ get_min_threshold_for_symbol,
236
+ resolve_and_validate_threshold,
237
+ clear_threshold_cache,
238
+ detect_asset_class,
239
+ AssetClass,
240
+ )
241
+
242
+ # Get minimum threshold for asset class
243
+ crypto_min = get_min_threshold(AssetClass.CRYPTO) # 1000
244
+ forex_min = get_min_threshold(AssetClass.FOREX) # 50
245
+
246
+ # Get minimum threshold for specific symbol
247
+ btc_min = get_min_threshold_for_symbol("BTCUSDT") # 1000
248
+ eur_min = get_min_threshold_for_symbol("EURUSD") # 50
249
+
250
+ # Validate and resolve threshold (raises ThresholdError if invalid)
251
+ threshold = resolve_and_validate_threshold("BTCUSDT", "macro") # 1000
252
+
253
+ # Detect asset class
254
+ assert detect_asset_class("BTCUSDT") == AssetClass.CRYPTO
255
+ assert detect_asset_class("EURUSD") == AssetClass.FOREX
256
+
257
+ # Clear cache after changing env vars at runtime
258
+ clear_threshold_cache()
259
+ ```
260
+
261
+ ### Microstructure Features (v7.0+)
262
+
263
+ When `include_microstructure=True`, the DataFrame includes 57 feature columns (62 total with OHLCV) organized into three categories:
264
+
265
+ **Base Microstructure (15 columns)**:
266
+
267
+ - `vwap`, `buy_volume`, `sell_volume`, `individual_trade_count`, `agg_record_count`
268
+ - `duration_us`, `ofi`, `vwap_close_deviation`, `price_impact`, `kyle_lambda_proxy`
269
+ - `trade_intensity`, `volume_per_trade`, `aggression_ratio`, `aggregation_density`, `turnover_imbalance`
270
+
271
+ **Intra-Bar Features (22 columns, Issue #59)** - Computed from trades WITHIN each bar:
272
+
273
+ - Epoch analysis: `intra_bull_epoch_density`, `intra_bear_epoch_density`, `intra_bull_excess_gain`, `intra_bear_excess_gain`, `intra_bull_cv`, `intra_bear_cv`
274
+ - Price path: `intra_max_drawdown`, `intra_max_runup`
275
+ - Volume/trade: `intra_trade_count`, `intra_ofi`, `intra_duration_us`, `intra_intensity`
276
+ - Advanced: `intra_vwap_position`, `intra_count_imbalance`, `intra_kyle_lambda`, `intra_burstiness`
277
+ - Statistical: `intra_volume_skew`, `intra_volume_kurt`, `intra_kaufman_er`, `intra_garman_klass_vol`, `intra_hurst`, `intra_permutation_entropy`
278
+
279
+ **Inter-Bar Features (16 columns, Issue #59)** - Computed from lookback window BEFORE each bar:
280
+
281
+ - `lookback_trade_count`, `lookback_ofi`, `lookback_duration_us`, `lookback_intensity`
282
+ - `lookback_vwap_raw`, `lookback_vwap_position`, `lookback_count_imbalance`, `lookback_kyle_lambda`
283
+ - `lookback_burstiness`, `lookback_volume_skew`, `lookback_volume_kurt`, `lookback_price_range`
284
+ - `lookback_kaufman_er`, `lookback_garman_klass_vol`, `lookback_hurst`, `lookback_permutation_entropy`
285
+
286
+ ```python
287
+ from rangebar import get_range_bars, MICROSTRUCTURE_COLUMNS, INTRA_BAR_FEATURE_COLUMNS, INTER_BAR_FEATURE_COLUMNS
288
+
289
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-07", threshold_decimal_bps=1000, include_microstructure=True)
290
+
291
+ print(f"Base microstructure: {len(MICROSTRUCTURE_COLUMNS)} columns")
292
+ print(f"Intra-bar features: {len(INTRA_BAR_FEATURE_COLUMNS)} columns")
293
+ print(f"Inter-bar features: {len(INTER_BAR_FEATURE_COLUMNS)} columns")
294
+ ```
295
+
188
296
  ### Configuration Constants
189
297
 
190
298
  ```python
@@ -213,7 +321,10 @@ from rangebar import process_trades_to_dataframe
213
321
  # Load your own trade data
214
322
  trades = pd.read_csv("BTCUSDT-aggTrades.csv")
215
323
 
216
- # Convert to range bars
324
+ # Convert to range bars (symbol required for threshold validation)
325
+ df = process_trades_to_dataframe(trades, threshold_decimal_bps=1000, symbol="BTCUSDT")
326
+
327
+ # Without symbol, no asset-class validation (use for custom data)
217
328
  df = process_trades_to_dataframe(trades, threshold_decimal_bps=250)
218
329
  ```
219
330
 
@@ -227,11 +338,11 @@ from rangebar import process_trades_polars
227
338
 
228
339
  # LazyFrame - predicates pushed to I/O layer (10-100x memory reduction)
229
340
  lazy_df = pl.scan_parquet("trades/*.parquet").filter(pl.col("timestamp") >= start_ts)
230
- bars = process_trades_polars(lazy_df, threshold_decimal_bps=250)
341
+ bars = process_trades_polars(lazy_df, threshold_decimal_bps=1000, symbol="BTCUSDT")
231
342
 
232
343
  # Or with eager DataFrame
233
344
  df = pl.read_parquet("trades.parquet")
234
- bars = process_trades_polars(df)
345
+ bars = process_trades_polars(df, threshold_decimal_bps=1000, symbol="BTCUSDT")
235
346
  ```
236
347
 
237
348
  **Performance benefits**:
@@ -249,10 +360,32 @@ Memory-safe processing for large datasets:
249
360
  from rangebar import process_trades_chunked
250
361
 
251
362
  # Process 10M+ trades without OOM
252
- for bars_df in process_trades_chunked(iter(trades), chunk_size=50_000):
363
+ for bars_df in process_trades_chunked(iter(trades), chunk_size=50_000, symbol="BTCUSDT", threshold_decimal_bps=1000):
253
364
  process_batch(bars_df)
254
365
  ```
255
366
 
367
+ ### Streaming API
368
+
369
+ Real-time range bar generation from Binance WebSocket:
370
+
371
+ ```python
372
+ from rangebar import stream_binance_live, ReconnectionConfig
373
+
374
+ # Basic streaming (uses threshold_bps, not threshold_decimal_bps)
375
+ async for bar in stream_binance_live("BTCUSDT", threshold_bps=1000):
376
+ print(f"New bar: {bar}")
377
+
378
+ # With reconnection configuration
379
+ reconnect_config = ReconnectionConfig(
380
+ max_retries=5,
381
+ initial_delay_s=1.0,
382
+ max_delay_s=60.0,
383
+ backoff_factor=2.0,
384
+ )
385
+ async for bar in stream_binance_live("BTCUSDT", threshold_bps=1000, reconnect_config=reconnect_config):
386
+ process_bar(bar)
387
+ ```
388
+
256
389
  ## Requirements
257
390
 
258
391
  **Runtime**: Python >= 3.13, pandas >= 2.0, numpy >= 1.24, polars >= 1.0
@@ -264,13 +397,15 @@ for bars_df in process_trades_chunked(iter(trades), chunk_size=50_000):
264
397
  ## Architecture
265
398
 
266
399
  ```
267
- rangebar (Rust crate)
268
- Cargo dependency
269
- rangebar-py (this package)
270
- ├── src/lib.rs (PyO3 bindings)
271
- └── python/rangebar/ (Python API)
272
- pip install
273
- Python applications
400
+ rangebar-py/
401
+ ├── crates/ 8 Rust crates (core algorithm)
402
+ │ └── rangebar-core/ Core processor, microstructure features
403
+ ├── src/lib.rs PyO3 bindings
404
+ ├── python/rangebar/ Python API layer
405
+ │ ├── clickhouse/ ClickHouse cache
406
+ │ ├── validation/ Microstructure validation
407
+ │ └── threshold.py Threshold validation (v12.0+)
408
+ └── pyproject.toml Maturin config
274
409
  ```
275
410
 
276
411
  ## Development
@@ -283,14 +418,38 @@ maturin develop --features data-providers
283
418
  pytest tests/
284
419
  ```
285
420
 
421
+ ## Migration from v11.x to v12.0
422
+
423
+ **Breaking changes**:
424
+
425
+ 1. **ThresholdError** raised for crypto symbols with threshold < 1000 dbps
426
+ 2. Presets "micro", "tight", "standard", "medium" will error for crypto symbols
427
+ 3. Checkpoints with low thresholds fail to restore
428
+
429
+ **Migration options**:
430
+
431
+ ```python
432
+ # Option 1: Use valid threshold for crypto
433
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", threshold_decimal_bps=1000)
434
+
435
+ # Option 2: Override minimum via environment variable
436
+ import os
437
+ os.environ["RANGEBAR_CRYPTO_MIN_THRESHOLD"] = "250"
438
+ from rangebar import clear_threshold_cache
439
+ clear_threshold_cache()
440
+
441
+ # Option 3: Use "macro" preset (1000 dbps)
442
+ df = get_range_bars("BTCUSDT", "2024-01-01", "2024-01-31", threshold_decimal_bps="macro")
443
+ ```
444
+
286
445
  ## Documentation
287
446
 
288
- | Document | Description |
289
- | ------------------------------------------------------------------------------------------------------- | --------------------- |
290
- | [Examples](https://github.com/terrylica/rangebar-py/tree/main/examples) | Usage examples |
291
- | [CLAUDE.md](https://github.com/terrylica/rangebar-py/blob/main/CLAUDE.md) | Project context |
292
- | [Architecture](https://github.com/terrylica/rangebar-py/blob/main/docs/ARCHITECTURE.md) | System design |
293
- | [Performance Guide](https://github.com/terrylica/rangebar-py/blob/main/docs/development/PERFORMANCE.md) | Benchmark methodology |
447
+ | Document | Description |
448
+ | ------------------------------------------------------------------------------------------------------- | ---------------------------- |
449
+ | [API Reference](https://github.com/terrylica/rangebar-py/blob/main/docs/api.md) | Full API documentation |
450
+ | [Architecture](https://github.com/terrylica/rangebar-py/blob/main/docs/ARCHITECTURE.md) | System design |
451
+ | [Performance Guide](https://github.com/terrylica/rangebar-py/blob/main/docs/development/PERFORMANCE.md) | Benchmark methodology |
452
+ | [CLAUDE.md](https://github.com/terrylica/rangebar-py/blob/main/CLAUDE.md) | AI assistant project context |
294
453
 
295
454
  ## License
296
455
 
@@ -300,7 +459,7 @@ MIT License. See [LICENSE](https://github.com/terrylica/rangebar-py/blob/main/LI
300
459
 
301
460
  ```bibtex
302
461
  @software{rangebar-py,
303
- title = {rangebar-py: Python bindings for range bar construction},
462
+ title = {rangebar-py: High-performance range bar construction for quantitative trading},
304
463
  author = {Terry Li},
305
464
  url = {https://github.com/terrylica/rangebar-py}
306
465
  }