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.
- {rangebar-11.7.0 → rangebar-12.0.1}/.mise.toml +36 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/CHANGELOG.md +25 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/CLAUDE.md +3 -3
- {rangebar-11.7.0 → rangebar-12.0.1}/Cargo.lock +9 -9
- {rangebar-11.7.0 → rangebar-12.0.1}/Cargo.toml +2 -2
- {rangebar-11.7.0 → rangebar-12.0.1}/PKG-INFO +205 -46
- rangebar-12.0.1/README.md +427 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/CLAUDE.md +12 -12
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/checkpoint.rs +8 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/processor.rs +14 -0
- rangebar-12.0.1/docs/research/2026-02-03-cfm-optimal-threshold-gemini-3-pro.md +510 -0
- rangebar-12.0.1/docs/verification/issue-62-verification-report.md +285 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/pyproject.toml +1 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/__init__.py +17 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/constants.py +6 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/exness.py +13 -4
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/count_bounded.py +3 -23
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/precompute.py +4 -7
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/range_bars.py +3 -20
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/processors/api.py +18 -3
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/processors/core.py +22 -1
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/streaming.py +20 -1
- rangebar-12.0.1/python/rangebar/threshold.py +453 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/gap_classification.py +2 -1
- rangebar-12.0.1/scripts/purge_crypto_low_threshold.py +116 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/src/lib.rs +20 -0
- rangebar-12.0.1/tests/conftest.py +115 -0
- rangebar-12.0.1/tests/test_crypto_minimum_threshold.py +306 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_edge_cases.py +4 -3
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_get_n_range_bars.py +22 -3
- rangebar-11.7.0/README.md +0 -268
- rangebar-11.7.0/tests/conftest.py +0 -50
- {rangebar-11.7.0 → rangebar-12.0.1}/.gitignore +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/.mcp.json +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/.pre-commit-config.yaml +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/.releaserc.yml +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/LICENSE +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/RESUME.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/STATISTICAL_VALIDITY_AUDIT.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/benches/rangebar_bench.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/build.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/CHANGELOG.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/Cargo.toml +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/README.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/arrow_export.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/fixed_point.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/interbar.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/drawdown.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/features.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/ith.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/mod.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/normalize.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/intrabar/types.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/lib.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/test_data_loader.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/test_utils/generators.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/test_utils/mod.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/timestamp.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/src/types.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/tests/cross_boundary_validation.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/tests/cross_date_real_data_validation.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/tests/cross_year_boundary_test.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-core/tests/incomplete_bar_continuation_proof.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/CHANGELOG.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/Cargo.toml +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/README.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/checksum.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/historical.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/mod.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/symbols.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/binance/websocket.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/builder.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/client.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/conversion.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/mod.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/exness/types.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-providers/src/lib.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/CHANGELOG.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/Cargo.toml +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/README.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/indicators.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/lib.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/processor.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/replay_buffer.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/stats.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/crates/rangebar-streaming/src/universal.rs +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/deny.toml +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/ARCHITECTURE.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/CONTEXT.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/MEMORY_REMEDIATION_PLAN.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/adr/2026-01-31-realtime-streaming-api.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/analysis/2025-10-10-flash-crash.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/api.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/development/PERFORMANCE.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/development/RELEASE.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/migration-v8.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/plans/issue-59-inter-bar-features.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/rangebar_core_api.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/2026-02-02-intrabar-microstructure-claude-opus.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/2026-02-02-intrabar-microstructure-gemini-3-pro.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/INDEX.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/adversarial-audit-methodology.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/external/time-to-convergence-stationarity-gap.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/labeling-for-ml.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/market-regime-patterns.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/multi-threshold-patterns.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/multifactor-patterns.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/pattern-research-summary.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/price-action-patterns.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/tda-parameter-sensitivity-audit.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/tda-regime-patterns.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/docs/research/volatility-regime-patterns.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/examples/README.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/examples/backtesting_integration.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/examples/basic_usage.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/examples/binance_csv_example.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/examples/get_range_bars_example.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/examples/validate_output.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/examples/with_clickhouse_cache.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/package-lock.json +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/package.json +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/CLAUDE.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/__init__.pyi +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/checkpoint.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/cli.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/CLAUDE.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/__init__.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/bulk_operations.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/cache.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/client.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/config.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/mixin.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/preflight.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/query_operations.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/schema.sql +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/clickhouse/tunnel.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/conversion.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/exceptions.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/hooks.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/logging.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/notify/__init__.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/notify/pushover.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/notify/telegram.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/__init__.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/helpers.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/models.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/orchestration/tick_fetcher.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/ouroboros.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/processors/__init__.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/resource_guard.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/storage/__init__.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/storage/checksum_registry.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/storage/parquet.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/__init__.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/cache_staleness.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/continuity.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/post_storage.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/tier1.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/python/rangebar/validation/tier2.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/rust-toolchain.toml +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/rustfmt.toml +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/adwin_regime_detection_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/analyze_flash_crash.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/bootstrap_permutation_validation_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/build-release.sh +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cache_clear.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cache_status.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/check-release-config.sh +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/coarse_to_fine_cascade.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/combined_pattern_audit_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/combined_regime_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/combined_rv_alignment_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cross_asset_correlation_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cross_regime_correlation_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/cross_threshold_alignment.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/dependency_monitor.sh +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/direction_patterns_reaudit.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/download_exness_eurusd.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/download_exness_forex.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/duration_autocorrelation.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/duration_autocorrelation_audit.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/duration_volatility_prediction.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fdr_corrected_patterns.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fill_all_symbols.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fill_gaps_2025_2026.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fill_gaps_littleblack.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/fill_gaps_retry.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/historical_formation_patterns_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/historical_formation_regime_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/hurst_adjusted_kelly_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/hurst_adjusted_psr_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/hurst_exponent_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/hurst_multi_estimator_audit.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/microstructure_clickhouse.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/microstructure_patterns.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/microstructure_simple.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/monitor_population.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multi_threshold_pattern_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multibar_continuation.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multibar_forward_returns_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multifactor_multigranularity_patterns.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multifactor_patterns.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multifactor_patterns_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multithreshold_combinations_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/multithreshold_regime_combinations_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/oos_validation_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/parameter_sensitivity_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/pattern_correlation_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/pattern_return_profiles_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/pattern_return_stats.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/populate_1000dbps.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/populate_250dbps.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/populate_250dbps_extended.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/populate_safe.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/position_sizing_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/process_exness_eurusd_to_cache.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/profiling_tools.sh +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/psr_mintrl_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/publish-to-pypi.sh +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/publish-wheels.sh +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regenerate_cache.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regime_analysis.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regime_analysis_50dbps_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regime_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/regime_transition_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/run_large_scale_benchmark.sh +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/run_length_momentum_analysis.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/run_length_momentum_multi_symbol.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/run_length_momentum_wfo.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/rv_return_profile_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/semantic-release.sh +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_break_event_alignment_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_conditioned_patterns.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_cupy_accelerated.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_gpu_analysis.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_hurst_by_regime_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_parameter_sweep_audit.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_regime_hurst_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_regime_pattern_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_ripser_plusplus.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_rolling_threshold.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_solusdt_250_audit.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_solusdt_250_littleblack.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_structural_break_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_volatility_forecast.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_wfo_3way.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_wfo_abstain.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/tda_wfo_audit.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/temporal_safe_patterns_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_bar_alignment_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_bar_pattern_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_bar_pattern_audit_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_factor_hurst_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/three_factor_pattern_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/transaction_cost_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/trend_filter_analysis.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/upload_eurusd_to_clickhouse.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/validate_clickhouse.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/validate_memory_efficiency.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/validate_microstructure_features.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/validate_n_range_bars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/volatility_regime_analysis_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/volatility_regime_audit_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/volume_conditioned_patterns.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/scripts/volume_conditioned_patterns_polars.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/test_data/BTCUSDT/BTCUSDT_aggTrades_20250901.csv +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/test_data/ETHUSDT/ETHUSDT_aggTrades_20250901.csv +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/test_data/README.md +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/fixtures/.gitignore +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/fixtures/BTCUSDT-aggTrades-2024-01-01.zip +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_cache_schema_evolution.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_clickhouse.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_clickhouse_integration.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_e2e_optimized.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_examples.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_get_range_bars_e2e.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_issue_5_reproduction.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_issues_7_8.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_microstructure_features.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_ouroboros.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_polars_only_downstream.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_preflight.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_python_api.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_real_data.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_rust_bindings.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_storage.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_streaming.py +0 -0
- {rangebar-11.7.0 → rangebar-12.0.1}/tests/test_validation_presets.py +0 -0
- {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` |
|
|
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) /
|
|
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) /
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 = "
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
44
|
+
High-performance range bar construction for quantitative trading, with Python bindings via PyO3/maturin.
|
|
43
45
|
|
|
44
46
|
[](https://pypi.org/project/rangebar/)
|
|
45
47
|
[](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="
|
|
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
|
|
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
|
|
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
|
|
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="
|
|
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
|
-
#
|
|
181
|
-
df = get_range_bars("
|
|
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=
|
|
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
|
|
268
|
-
|
|
269
|
-
rangebar-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
| [
|
|
291
|
-
| [
|
|
292
|
-
| [
|
|
293
|
-
| [
|
|
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:
|
|
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
|
}
|