bquant 0.0.2__tar.gz → 0.0.4__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.
- bquant-0.0.4/CHANGELOG.md +185 -0
- {bquant-0.0.2/bquant.egg-info → bquant-0.0.4}/PKG-INFO +1 -1
- {bquant-0.0.2 → bquant-0.0.4}/bquant/__init__.py +1 -1
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/cache.py +6 -1
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/pipeline.py +5 -1
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/find_peaks.py +118 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/pivot_points.py +40 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/zigzag.py +50 -18
- {bquant-0.0.2 → bquant-0.0.4/bquant.egg-info}/PKG-INFO +1 -1
- {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/SOURCES.txt +6 -10
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/README.md +3 -3
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/pipeline.md +19 -3
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/strategies.md +33 -26
- bquant-0.0.2/docs/api/analysis/zones/pipeline.md → bquant-0.0.4/docs/api/analysis/zones/global_swings_pipeline.md +6 -2
- bquant-0.0.2/docs/api/analysis/zones/strategies.md → bquant-0.0.4/docs/api/analysis/zones/global_swings_strategies.md +5 -1
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/zones.md +9 -13
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/logging.md +1 -1
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/nb.md +2 -2
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/README.md +2 -2
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/loader.md +2 -2
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/extension_guide.md +4 -4
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/visualization/README.md +11 -7
- {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/zone_analyzer_deep_dive.md +2 -2
- {bquant-0.0.2 → bquant-0.0.4}/docs/index.rst +28 -6
- {bquant-0.0.2 → bquant-0.0.4}/docs/migration/MIGRATION_v2.md +2 -2
- {bquant-0.0.2 → bquant-0.0.4}/docs/migration/global_swings_migration.md +1 -1
- {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/README.md +1 -1
- {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/quick_start.md +1 -1
- bquant-0.0.4/docs/user_guide/swing_strategies.md +146 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/zone_analysis.md +2 -2
- {bquant-0.0.2 → bquant-0.0.4}/pyproject.toml +1 -1
- bquant-0.0.4/tests/fixtures/swing_coverage.py +85 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_pipeline_global_swings.py +1 -1
- bquant-0.0.4/tests/unit/test_docs_parity.py +131 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_pandas_ta_dynamic_loader.py +9 -2
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_swing_global_calculation.py +53 -3
- bquant-0.0.4/tests/unit/test_swing_replay_causal.py +185 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zigzag_swing_strategy.py +33 -0
- bquant-0.0.2/CHANGELOG.md +0 -122
- bquant-0.0.2/docs/BUILD_ISSUES.md +0 -260
- bquant-0.0.2/docs/analytics/zones/layerA_ii_representations_case_study.md +0 -68
- bquant-0.0.2/docs/analytics/zones/layerA_zone_structure_case_study.md +0 -73
- bquant-0.0.2/docs/analytics/zones/macd_zone_consistency_case_study.md +0 -64
- bquant-0.0.2/docs/analytics/zones/s1_swing_anatomy_case_study.md +0 -127
- bquant-0.0.2/docs/analytics/zones/swing.md +0 -64
- bquant-0.0.2/docs/user_guide/swing_analysis_results.md +0 -340
- bquant-0.0.2/docs/user_guide/swing_strategies.md +0 -139
- {bquant-0.0.2 → bquant-0.0.4}/LICENSE +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/MANIFEST.in +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/candlestick/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/chart/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/statistical/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/statistical/hypothesis_testing.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/statistical/regression.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/technical/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/timeseries/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/validation/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/validation/suite.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/analyzer.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/base.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/combined.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/line_crossing.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/preloaded.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/registry.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/threshold.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/zero_crossing.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/models.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/presets.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/sequence_analysis.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/base.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/divergence/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/divergence/classic.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/registry.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/shape/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/shape/statistical.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/thresholds.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/volatility/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/volatility/combined.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/volume/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/volume/standard.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/zone_features.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/cli.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/cache.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/config.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/exceptions.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/logging_config.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/nb.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/numpy_fix.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/performance.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/core/utils.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/loader.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/processor.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/datasets.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/embedded/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/embedded/mt_xauusd_m15.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/embedded/tv_xauusd_1h.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/generator.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/utils.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/schemas.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/data/validator.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/base.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/calculators.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/bollinger.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/ema.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/macd.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/rsi.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/sma.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/library/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/library/manager.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/library/pandas_ta.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/library/talib.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/macd.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/preloaded/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/preloaded/macd.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/ml/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/charts.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/export.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/statistical.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/themes.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/utils.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/zones.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/dependency_links.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/entry_points.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/requires.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/top_level.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/analytics/zones/macd_zone_consistency_case_study.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/analytics/zones/swing.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/analytics/zones/swing_strategy_comparison_case_study.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/base.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/pipeline.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/statistical.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/strategies.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/zones/models.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/zones/pipeline.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/zones/strategies.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/zones.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/config.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/exceptions.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/logging.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/nb.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/performance.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/utils.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/loader.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/processor.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/samples.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/schemas.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/validator.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/extension_guide.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/base.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/factory.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/library_manager.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/macd.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/preloaded.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/visualization/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/visualization/zones.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/analytical_philosophy.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/statistical_analysis_workflow.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/zone_analyzer_deep_dive.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/zone_detection_strategies.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/examples/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/index.rst.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/migration/MIGRATION_v2.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/migration/global_swings_migration.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/combined_rules_detection.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/macd_basic_pipeline.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/preloaded_zones_workflow.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/rsi_strategy_switching.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/README.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/best_practices.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/caching.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/core_concepts.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/quick_start.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/swing_analysis_results.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/swing_strategies.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/zone_analysis.md.txt +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/analytics/zones/swing_strategy_comparison_case_study.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/base.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/statistical.md +0 -0
- /bquant-0.0.2/docs/api/analysis/zones/models.md → /bquant-0.0.4/docs/api/analysis/zones/global_swings_models.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/config.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/exceptions.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/performance.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/utils.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/processor.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/samples.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/schemas.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/validator.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/base.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/factory.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/library_manager.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/macd.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/preloaded.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/api/visualization/zones.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/analytical_philosophy.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/statistical_analysis_workflow.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/zone_detection_strategies.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/examples/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/combined_rules_detection.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/macd_basic_pipeline.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/preloaded_zones_workflow.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/rsi_strategy_switching.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/best_practices.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/caching.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/core_concepts.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/zone_analysis_result.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/01_basic_indicators.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/02_macd_zone_analysis.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/02a_universal_zones.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/03_data_processing.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/04_comprehensive_analysis.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/05_strategies_demo.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/06_regression_demo.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/07_validation_demo.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/08_macd_swing_analysis.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/09_zones_visualization_demo.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/examples/zone_analysis_global_swings.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/analysis/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/analysis/batch_analysis.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/analysis/run_macd_analysis.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/analysis/test_hypotheses.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/data/data_loader.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/data/extract_samples.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/data/generate_samples.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/data_processing/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/deployment/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/scripts/publishing/README.md +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/setup.cfg +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/analysis/zones/test_pipeline_cache.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/analysis/zones/test_swing_presets.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/analysis/zones/test_swing_thresholds.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/conftest.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/fixtures/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/fixtures/swing_mocks.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_backward_compatibility.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_data_pipeline.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_full_pipeline.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_scripts_integration.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_truly_universal_zones.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_visualization_pipeline.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_zone_analysis_e2e.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/performance/test_swing_performance.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/__init__.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_all_indicator_types.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_analysis_structure.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_architecture_validation.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_builtin_migration.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_cache_versioning.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_classic_divergence_strategy.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_combined_volatility_strategy.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_compatibility_validation.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_core_modules.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_data_modules.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_divergence_strategy_universal.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_find_peaks_swing_strategy.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_imports_migration.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_indicator_factory.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_indicators_base.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_library_indicators.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_macd_analyzer.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_macd_backward_compatibility.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_performance.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_pivot_points_swing_strategy.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_preloaded_indicators.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_sample_data.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_sample_generator.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_shape_strategy_universal.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_standard_volume_strategy.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_statistical_hypothesis.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_statistical_shape_strategy.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_strategy_infrastructure.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_swing_context_memory.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_swing_edge_cases.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_time_metrics.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_universal_zone_analyzer.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_validation_suite.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_visualization.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_volume_strategy_universal.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_analysis_builder.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_detection_strategies.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_analyzer_context.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_divergence_integration.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_shape_integration.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_swing_integration.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_volatility_integration.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_volume_integration.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_models.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_pipeline.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_presets.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_regression_analyzer.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zones_analysis.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_infrastructure.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_swing_overlay.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_zone_metrics_aggregation.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_zone_metrics_display.py +0 -0
- {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_zones_visualization.py +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
## [0.0.4] - 2026-08-18
|
|
13
|
+
|
|
14
|
+
Релиз о **честности `confirmation_index`**: в 0.0.2/0.0.3 поле было заявлено как маркер
|
|
15
|
+
причинной доступности для leak-free потребителей, но ни одна из трёх свинг-стратегий не
|
|
16
|
+
удовлетворяла контракту строго. Теперь удовлетворяют все три — проверено оракулом, который
|
|
17
|
+
пере-прогоняет **реальный детектор** под усечением сырого OHLC.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **ZigZag `confirmation_index` теперь replay-causal (issue #110).** `calculate_global` вызывает
|
|
21
|
+
pandas-ta zigzag с `backtest=True` — не перерисовывающий поток вместо дефолтного центрированного
|
|
22
|
+
`backtest=False`, который под усечением сырого OHLC добавлял/двигал/удалял ранние пивоты.
|
|
23
|
+
`_confirmation_index` — дивиденс-ретрейс без искусственного floor; первый пивот наследует
|
|
24
|
+
confirmation второго (детектор не эмитит ничего до 2-й свинги). Repaint-нарушения на встроенном
|
|
25
|
+
сэмпле: **35% → 0%**, стабильно на legs∈{2,3,5}. (PR #111)
|
|
26
|
+
- **`find_peaks` и `pivot_points` доведены до строгой replay-safety (G14).** У `find_peaks`
|
|
27
|
+
причина оказалась не в prominence, как предполагалось изначально, а в **порядке фильтров
|
|
28
|
+
scipy**: `distance` применяется **до** `prominence`, жадно по высоте и по всему множеству сырых
|
|
29
|
+
локальных максимумов, поэтому экстремум, подавленный более высоким соседом, оживает, когда
|
|
30
|
+
сосед сам снимается ещё более высоким справа. Confirmation теперь ждёт устаканивания всей
|
|
31
|
+
цепочки подавления, а не фиксированного окна `index + distance`. У `pivot_points` N-баровый
|
|
32
|
+
паттерн локален и точен, но контекст не эмитится, пока экстремумов меньше двух, — поэтому
|
|
33
|
+
первый пивот наследует confirmation второго, как в ZigZag. Нарушений **0 на 12 конфигурациях**;
|
|
34
|
+
цена — 3 экстремума из 345 подтверждаются позже (в среднем +0.035 бара).
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- **`CACHE_VERSION` 2 → 4, `CACHE_SCHEMA_VERSION` 3 → 4** — сериализованная семантика свингов и
|
|
38
|
+
значения `confirmation_index` изменились дважды (ZigZag `backtest=True`; устаканивание
|
|
39
|
+
distance-цепочки и warm-up первого свинга). Старые кэши инвалидируются.
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
- **`tests/unit/test_swing_replay_causal.py`** — оракул replay-каузальности: пере-прогон реального
|
|
43
|
+
детектора под усечением, а не monkeypatch фиксированного списка пивотов. Покрывает обе стороны
|
|
44
|
+
контракта: свинг, объявленный доступным на баре `t`, обязан (а) уже присутствовать при расчёте
|
|
45
|
+
на `data[:t+1]` и (б) не исчезнуть из полной истории позже.
|
|
46
|
+
|
|
47
|
+
### Known limitations
|
|
48
|
+
- **Авто-prominence `find_peaks` не устойчив к усечению (G15).** При `prominence=None` — это
|
|
49
|
+
**дефолт** стратегии — порог выводится из наблюдённого диапазона цен и растёт по мере прихода
|
|
50
|
+
баров (на встроенном сэмпле 1.275 → 2.071). Экстремум, прошедший ранний меньший порог, позже
|
|
51
|
+
проваливает больший и исчезает. `confirmation_index` это не лечит: движется сам фильтр.
|
|
52
|
+
**Кому нужна replay-safety — задавайте `prominence` явно**, тогда нарушений нет. Исправление
|
|
53
|
+
требует смены семантики детекции и будет отдельным решением.
|
|
54
|
+
|
|
55
|
+
## [0.0.3] - 2026-07-24
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
- **`confirmation_index` для стратегий `find_peaks` и `pivot_points`** — маркер причинной
|
|
59
|
+
доступности свинга теперь заполняется всеми свинг-стратегиями, а не только ZigZag (0.0.2).
|
|
60
|
+
Для `pivot_points` это точное fractal-подтверждение (`index + right_bars`); для `find_peaks` —
|
|
61
|
+
causal leak-free (`max(index + distance, бар prominence-ретрейса справа)`). Позволяет строить
|
|
62
|
+
look-ahead-free потребителей на любой свинг-стратегии. (PR #108)
|
|
63
|
+
|
|
64
|
+
### Changed
|
|
65
|
+
- **`CACHE_SCHEMA_VERSION` повышена 2 → 3** — `find_peaks`/`pivot_points` теперь заполняют
|
|
66
|
+
`confirmation_index`, что меняет семантику кэшируемого вывода; старые кэши инвалидируются.
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
- **ZigZag: мягкая деградация при отсутствии pandas-ta `zigzag`.** В глобальном режиме
|
|
70
|
+
(`swing_scope='global'`) стратегия теперь возвращает пустой `SwingContext` с понятным
|
|
71
|
+
предупреждением вместо исключения, когда опциональный индикатор pandas-ta `zigzag`
|
|
72
|
+
недоступен — как уже делал per-zone режим. Пайплайн больше не логирует ошибку/traceback
|
|
73
|
+
на этом пути.
|
|
74
|
+
|
|
75
|
+
## [0.0.2] - 2026-07-20
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
- **`SwingPoint.confirmation_index`** — маркер причинной доступности свинга: индекс
|
|
79
|
+
бара, к которому пивот (и его `amplitude_to_next`) причинно подтверждён. Позволяет
|
|
80
|
+
строить leak-free / look-ahead-free потребителей (устранение утечки J1). Реализован
|
|
81
|
+
для ZigZag-стратегии; прочие свинг-стратегии оставляют `None` (контракт допускает
|
|
82
|
+
мягкую деградацию). Сериализуется в `SwingContext.to_dict()`. (PR #107)
|
|
83
|
+
|
|
84
|
+
### Changed
|
|
85
|
+
- **`CACHE_SCHEMA_VERSION` повышена до 2** — ключ дискового кэша зон-анализа теперь
|
|
86
|
+
учитывает версию схемы вывода, инвалидируя старые кэши без `confirmation_index`.
|
|
87
|
+
Инвариант: любое изменение схемы/семантики кэшируемого вывода обязано бампать
|
|
88
|
+
`CACHE_SCHEMA_VERSION`.
|
|
89
|
+
|
|
90
|
+
## [0.0.1] - 2026-01-12
|
|
91
|
+
|
|
92
|
+
### Added
|
|
93
|
+
- Initial release of BQuant package
|
|
94
|
+
- Complete migration from Quanto project
|
|
95
|
+
- Comprehensive technical analysis framework
|
|
96
|
+
- MACD zone analysis with statistical testing
|
|
97
|
+
- Advanced data processing and validation
|
|
98
|
+
- Professional visualization system
|
|
99
|
+
- Embedded sample data for testing
|
|
100
|
+
- CLI scripts for analysis automation
|
|
101
|
+
- Complete documentation and examples
|
|
102
|
+
- **Zone Metrics Visualization (v1.0)** - 2025-11-11
|
|
103
|
+
- Aggregate metrics display with `show_aggregate_metrics` parameter (compact/full modes)
|
|
104
|
+
- Swing points visualization on charts with `show_swings` parameter
|
|
105
|
+
- Detail mode zone metrics with `show_zone_metrics` parameter
|
|
106
|
+
- Date range filtering with automatic metrics recalculation for selected period
|
|
107
|
+
- Support for unbalanced swings in global swing mode
|
|
108
|
+
- See [docs/api/visualization/zones.md](docs/api/visualization/zones.md) for details
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
## [0.0.0] - 2024-08-25
|
|
112
|
+
|
|
113
|
+
### Added
|
|
114
|
+
- Foundation for BQuant project
|
|
115
|
+
- Basic project structure
|
|
116
|
+
- Core configuration system
|
|
117
|
+
- Initial test framework
|
|
118
|
+
- Initial beta release
|
|
119
|
+
- Basic MACD analysis functionality
|
|
120
|
+
- Core data processing capabilities
|
|
121
|
+
- Preliminary documentation
|
|
122
|
+
|
|
123
|
+
### Structure
|
|
124
|
+
|
|
125
|
+
- **Core Modules**: Configuration, exceptions, logging, performance, utilities
|
|
126
|
+
- **Data Modules**: Loader, processor, validator, samples, schemas
|
|
127
|
+
- **Indicators**: Base classes, MACD analyzer, factory pattern
|
|
128
|
+
- **Analysis**: Statistical analysis, zone analysis, hypothesis testing
|
|
129
|
+
- **Visualization**: Financial charts, zone visualization, statistical plots, themes
|
|
130
|
+
- **Research Structure**: Notebooks, methodology, experiments, studies
|
|
131
|
+
- **Scripts**: Analysis automation, data processing, deployment tools
|
|
132
|
+
- **Documentation**: Complete API reference, user guide, tutorials, examples
|
|
133
|
+
|
|
134
|
+
### Technical Features
|
|
135
|
+
- **MACD Zone Analysis**: Advanced MACD analysis with zone identification
|
|
136
|
+
- **Statistical Testing**: Comprehensive hypothesis testing framework
|
|
137
|
+
- **Data Processing**: Robust data loading, cleaning, and validation
|
|
138
|
+
- **Performance Optimization**: Caching system and optimized algorithms
|
|
139
|
+
- **Visualization**: Professional charts with multiple themes
|
|
140
|
+
- **Sample Data**: Embedded financial data for testing and examples
|
|
141
|
+
|
|
142
|
+
### Architecture
|
|
143
|
+
- **Modular Design**: Clean separation of concerns
|
|
144
|
+
- **Type Safety**: Full type hints and validation
|
|
145
|
+
- **Error Handling**: Comprehensive exception system
|
|
146
|
+
- **Logging**: Professional logging with multiple levels
|
|
147
|
+
- **Testing**: Complete test coverage with pytest
|
|
148
|
+
- **Documentation**: Sphinx-based documentation system
|
|
149
|
+
|
|
150
|
+
### Dependencies
|
|
151
|
+
- **Core**: pandas, numpy, matplotlib, seaborn
|
|
152
|
+
- **Analysis**: scipy, scikit-learn, statsmodels
|
|
153
|
+
- **Visualization**: plotly, seaborn
|
|
154
|
+
- **Development**: pytest, black, flake8, mypy
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Version History
|
|
159
|
+
|
|
160
|
+
### Semantic Versioning
|
|
161
|
+
- **MAJOR**: Incompatible API changes
|
|
162
|
+
- **MINOR**: New functionality in backward-compatible manner
|
|
163
|
+
- **PATCH**: Backward-compatible bug fixes
|
|
164
|
+
|
|
165
|
+
### Release Schedule
|
|
166
|
+
- **Major releases**: Every 6 months
|
|
167
|
+
- **Minor releases**: Every 2-4 weeks
|
|
168
|
+
- **Patch releases**: As needed for critical fixes
|
|
169
|
+
|
|
170
|
+
### Support Policy
|
|
171
|
+
- **Current version**: Full support
|
|
172
|
+
- **Previous major version**: Bug fixes only
|
|
173
|
+
- **Older versions**: No support
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Contributing
|
|
178
|
+
|
|
179
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
|
|
180
|
+
|
|
181
|
+
## Acknowledgments
|
|
182
|
+
|
|
183
|
+
- Original Quanto project contributors
|
|
184
|
+
- Open source financial analysis community
|
|
185
|
+
- Python packaging and documentation tools
|
|
@@ -27,7 +27,12 @@ class ZoneAnalysisCache:
|
|
|
27
27
|
entries are automatically invalidated when the schema version increases.
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
# v3 (issue #110): ZigZag swings now come from the non-repainting backtest=True
|
|
31
|
+
# detector, so serialized swing sets / confirmation_index differ from v2.
|
|
32
|
+
# v4 (G14): find_peaks confirmation waits for the distance-suppression chain to
|
|
33
|
+
# settle, and both find_peaks and pivot_points hold the first swing back to the
|
|
34
|
+
# second's confirmation — serialized confirmation_index values differ from v3.
|
|
35
|
+
CACHE_VERSION = 4
|
|
31
36
|
|
|
32
37
|
def __init__(self, cache_manager: Optional[Any]) -> None:
|
|
33
38
|
self._cache_manager = cache_manager
|
|
@@ -47,7 +47,11 @@ _SWING_CLASS_TO_NAME = {
|
|
|
47
47
|
# SwingPoint/ZoneInfo fields, changed swing computation, etc.), so that on-disk
|
|
48
48
|
# caches computed under an older schema are not silently served.
|
|
49
49
|
# v2 (2026-07): SwingPoint.confirmation_index added (causal availability).
|
|
50
|
-
|
|
50
|
+
# v3 (2026-07): confirmation_index now populated by find_peaks & pivot_points
|
|
51
|
+
# (previously only zigzag; changes cached swing output).
|
|
52
|
+
# v4 (2026-08): find_peaks & pivot_points confirmation_index made replay-safe
|
|
53
|
+
# (G14) — distance-chain settling + first-swing warm-up hold.
|
|
54
|
+
CACHE_SCHEMA_VERSION = 4
|
|
51
55
|
|
|
52
56
|
|
|
53
57
|
@dataclass
|
|
@@ -53,6 +53,20 @@ class FindPeaksSwingStrategy:
|
|
|
53
53
|
swing_points: List[SwingPoint] = []
|
|
54
54
|
indices: List[int] = []
|
|
55
55
|
|
|
56
|
+
high_arr = full_data['high'].to_numpy(dtype=float)
|
|
57
|
+
low_arr = full_data['low'].to_numpy(dtype=float)
|
|
58
|
+
full_len = len(full_data)
|
|
59
|
+
|
|
60
|
+
# Detection series per swing type (troughs are found on the negated lows,
|
|
61
|
+
# exactly as in `_detect_extrema`) plus their *unfiltered* local maxima —
|
|
62
|
+
# the raw input scipy's `distance` filter operates on, needed to settle
|
|
63
|
+
# that filter's verdict in `_distance_settled_bar`.
|
|
64
|
+
series_by_type = {'peak': high_arr, 'trough': -low_arr}
|
|
65
|
+
maxima_by_type = {
|
|
66
|
+
swing_type: find_peaks(series)[0]
|
|
67
|
+
for swing_type, series in series_by_type.items()
|
|
68
|
+
}
|
|
69
|
+
|
|
56
70
|
for point_id, point in enumerate(extrema):
|
|
57
71
|
timestamp = point['timestamp']
|
|
58
72
|
ts = (
|
|
@@ -74,6 +88,14 @@ class FindPeaksSwingStrategy:
|
|
|
74
88
|
0, int(next_point['index']) - index_position
|
|
75
89
|
)
|
|
76
90
|
|
|
91
|
+
confirmation_index = self._confirmation_index(
|
|
92
|
+
index_position,
|
|
93
|
+
prominence_value,
|
|
94
|
+
series_by_type[point['type']],
|
|
95
|
+
maxima_by_type[point['type']],
|
|
96
|
+
full_len,
|
|
97
|
+
)
|
|
98
|
+
|
|
77
99
|
swing_points.append(
|
|
78
100
|
SwingPoint(
|
|
79
101
|
point_id=point_id,
|
|
@@ -85,10 +107,22 @@ class FindPeaksSwingStrategy:
|
|
|
85
107
|
duration_to_next=duration_to_next,
|
|
86
108
|
strategy_name='find_peaks',
|
|
87
109
|
strategy_params=self._build_strategy_params(prominence_value),
|
|
110
|
+
confirmation_index=confirmation_index,
|
|
88
111
|
)
|
|
89
112
|
)
|
|
90
113
|
indices.append(index_position)
|
|
91
114
|
|
|
115
|
+
# Warm-up (issue #110 follow-up / G14): a context is only emitted once at
|
|
116
|
+
# least two extrema exist (see the guard above), so a lone first extremum
|
|
117
|
+
# is not yet observable at its own confirmation — it appears together with
|
|
118
|
+
# the second one. Pin its availability to the second's, as ZigZag does.
|
|
119
|
+
if len(swing_points) >= 2 and swing_points[0].confirmation_index is not None \
|
|
120
|
+
and swing_points[1].confirmation_index is not None:
|
|
121
|
+
swing_points[0].confirmation_index = max(
|
|
122
|
+
swing_points[0].confirmation_index,
|
|
123
|
+
swing_points[1].confirmation_index,
|
|
124
|
+
)
|
|
125
|
+
|
|
92
126
|
logger.info(
|
|
93
127
|
"FindPeaks global: detected %d swing points", len(swing_points)
|
|
94
128
|
)
|
|
@@ -387,6 +421,90 @@ class FindPeaksSwingStrategy:
|
|
|
387
421
|
|
|
388
422
|
return metrics
|
|
389
423
|
|
|
424
|
+
def _distance_settled_bar(
|
|
425
|
+
self, index: int, series: np.ndarray, maxima: np.ndarray
|
|
426
|
+
) -> int:
|
|
427
|
+
"""Bar by which scipy's ``distance`` verdict for ``index`` stops changing.
|
|
428
|
+
|
|
429
|
+
scipy applies ``distance`` *before* ``prominence``, greedily over **all**
|
|
430
|
+
raw local maxima by descending height: an extremum is dropped when a
|
|
431
|
+
higher one survives strictly within ``distance`` of it. That verdict is
|
|
432
|
+
therefore **not** settled at ``index + distance`` — the neighbour that
|
|
433
|
+
suppresses this extremum may itself be dropped later by a still higher
|
|
434
|
+
one further right, reviving this extremum. Observed on the embedded
|
|
435
|
+
sample: the peak at 178 is suppressed by 180 until 182 becomes visible
|
|
436
|
+
and removes 180, so 178 only appears two bars after ``index + distance``.
|
|
437
|
+
|
|
438
|
+
The verdict depends on the transitive *suppression chain*: every local
|
|
439
|
+
maximum within ``distance`` that is at least as high, then their own
|
|
440
|
+
suppressors, and so on (heights are non-decreasing along the chain, so it
|
|
441
|
+
terminates). A chain member at ``p`` has its own neighbourhood fully
|
|
442
|
+
observable at ``p + distance``; the chain — and hence this extremum's
|
|
443
|
+
verdict — is settled at the latest such bar.
|
|
444
|
+
"""
|
|
445
|
+
settled = index + self.distance
|
|
446
|
+
seen = {index}
|
|
447
|
+
frontier = [index]
|
|
448
|
+
|
|
449
|
+
while frontier:
|
|
450
|
+
q = frontier.pop()
|
|
451
|
+
lo = np.searchsorted(maxima, q - self.distance, side='right')
|
|
452
|
+
hi = np.searchsorted(maxima, q + self.distance, side='left')
|
|
453
|
+
for candidate in maxima[lo:hi]:
|
|
454
|
+
p = int(candidate)
|
|
455
|
+
# only an at-least-as-high neighbour can suppress; ties are taken
|
|
456
|
+
# as suppressors (conservative — never confirms too early)
|
|
457
|
+
if p in seen or series[p] < series[q]:
|
|
458
|
+
continue
|
|
459
|
+
seen.add(p)
|
|
460
|
+
frontier.append(p)
|
|
461
|
+
settled = max(settled, p + self.distance)
|
|
462
|
+
|
|
463
|
+
return settled
|
|
464
|
+
|
|
465
|
+
def _confirmation_index(
|
|
466
|
+
self,
|
|
467
|
+
index: int,
|
|
468
|
+
prominence: float,
|
|
469
|
+
series: np.ndarray,
|
|
470
|
+
maxima: np.ndarray,
|
|
471
|
+
full_len: int,
|
|
472
|
+
) -> Optional[int]:
|
|
473
|
+
"""Bar by which this find_peaks extremum is causally confirmed.
|
|
474
|
+
|
|
475
|
+
``series`` is the detection series for this extremum's type (highs for
|
|
476
|
+
peaks, negated lows for troughs, as in :meth:`_detect_extrema`), so the
|
|
477
|
+
extremum is a maximum of ``series`` either way; ``maxima`` are that
|
|
478
|
+
series' unfiltered local maxima.
|
|
479
|
+
|
|
480
|
+
An extremum survives the global pass only if it clears BOTH the
|
|
481
|
+
``distance`` and ``prominence`` filters, so it becomes causally known at
|
|
482
|
+
the later of two events:
|
|
483
|
+
|
|
484
|
+
* **distance settling** — the bar at which the suppression chain around
|
|
485
|
+
it resolves, see :meth:`_distance_settled_bar` (never earlier than
|
|
486
|
+
``index + distance``);
|
|
487
|
+
* **prominence retrace** — the first bar after ``index`` at which the
|
|
488
|
+
right base falls ``prominence`` below the pivot. Truncation can only
|
|
489
|
+
shorten the right-base interval, so the computed prominence grows
|
|
490
|
+
monotonically with observed bars: once this bar is reached the
|
|
491
|
+
prominence filter stays cleared. The left base does not depend on
|
|
492
|
+
truncation and already clears the threshold for a kept extremum.
|
|
493
|
+
|
|
494
|
+
Returns ``max`` of the two (both are necessary), or ``None`` if the pivot
|
|
495
|
+
cannot yet be confirmed within the available data (retrace not reached, or
|
|
496
|
+
the settling bar lies past the end — a still-forming tail swing). This is
|
|
497
|
+
the ``find_peaks`` realisation of the generic
|
|
498
|
+
:attr:`SwingPoint.confirmation_index` contract, verified replay-safe by
|
|
499
|
+
``tests/unit/test_swing_replay_causal`` (G14).
|
|
500
|
+
"""
|
|
501
|
+
hits = np.nonzero(series[index + 1:] <= series[index] - prominence)[0]
|
|
502
|
+
if not len(hits):
|
|
503
|
+
return None
|
|
504
|
+
prominence_bar = index + 1 + int(hits[0])
|
|
505
|
+
conf = max(self._distance_settled_bar(index, series, maxima), prominence_bar)
|
|
506
|
+
return conf if conf < full_len else None
|
|
507
|
+
|
|
390
508
|
def _empty_metrics(self) -> SwingMetrics:
|
|
391
509
|
return self._aggregate_metrics(
|
|
392
510
|
[],
|
|
@@ -92,6 +92,10 @@ class PivotPointsSwingStrategy:
|
|
|
92
92
|
0, int(next_point['index']) - index_position
|
|
93
93
|
)
|
|
94
94
|
|
|
95
|
+
confirmation_index = self._confirmation_index(
|
|
96
|
+
index_position, len(full_data)
|
|
97
|
+
)
|
|
98
|
+
|
|
95
99
|
swing_points.append(
|
|
96
100
|
SwingPoint(
|
|
97
101
|
point_id=point_id,
|
|
@@ -103,10 +107,23 @@ class PivotPointsSwingStrategy:
|
|
|
103
107
|
duration_to_next=duration_to_next,
|
|
104
108
|
strategy_name='pivot_points',
|
|
105
109
|
strategy_params=self._strategy_params(),
|
|
110
|
+
confirmation_index=confirmation_index,
|
|
106
111
|
)
|
|
107
112
|
)
|
|
108
113
|
indices.append(index_position)
|
|
109
114
|
|
|
115
|
+
# Warm-up (issue #110 follow-up / G14): a context is only emitted once at
|
|
116
|
+
# least two extrema exist (see the guard above), so a lone first pivot is
|
|
117
|
+
# not yet observable at its own fractal confirmation — it appears together
|
|
118
|
+
# with the second one. Pin its availability to the second pivot's, as
|
|
119
|
+
# ZigZag does. Later pivots confirm at or after that bar already.
|
|
120
|
+
if len(swing_points) >= 2 and swing_points[0].confirmation_index is not None \
|
|
121
|
+
and swing_points[1].confirmation_index is not None:
|
|
122
|
+
swing_points[0].confirmation_index = max(
|
|
123
|
+
swing_points[0].confirmation_index,
|
|
124
|
+
swing_points[1].confirmation_index,
|
|
125
|
+
)
|
|
126
|
+
|
|
110
127
|
logger.info(
|
|
111
128
|
"PivotPoints global: detected %d swing points", len(swing_points)
|
|
112
129
|
)
|
|
@@ -391,6 +408,29 @@ class PivotPointsSwingStrategy:
|
|
|
391
408
|
|
|
392
409
|
return metrics
|
|
393
410
|
|
|
411
|
+
def _confirmation_index(
|
|
412
|
+
self, index: int, full_data_length: int
|
|
413
|
+
) -> Optional[int]:
|
|
414
|
+
"""Bar by which this pivot is causally confirmed.
|
|
415
|
+
|
|
416
|
+
A classic N-bar pivot is defined by ``right_bars`` bars to its right that
|
|
417
|
+
are all lower (pivot high) or higher (pivot low). The pattern therefore
|
|
418
|
+
becomes complete — and the pivot causally known — exactly at
|
|
419
|
+
``index + right_bars``: the bar at which the last required right-side bar
|
|
420
|
+
is observed. This is the ``pivot_points`` realisation of the generic
|
|
421
|
+
:attr:`SwingPoint.confirmation_index` contract (a fractal swing confirms
|
|
422
|
+
after its fixed right-hand look-ahead window). Because pivots are only
|
|
423
|
+
detected for ``index <= len - right_bars - 1``, the confirmation bar always
|
|
424
|
+
lies inside the data; the guard returns ``None`` only defensively.
|
|
425
|
+
|
|
426
|
+
The N-bar pattern is purely local, so this is exact for every pivot but the
|
|
427
|
+
first, whose availability is additionally held back by the two-extrema
|
|
428
|
+
warm-up in :meth:`calculate_global` (see the note there). Verified
|
|
429
|
+
replay-safe by ``tests/unit/test_swing_replay_causal`` (G14).
|
|
430
|
+
"""
|
|
431
|
+
conf = index + self.right_bars
|
|
432
|
+
return conf if conf < full_data_length else None
|
|
433
|
+
|
|
394
434
|
def _empty_metrics(self) -> SwingMetrics:
|
|
395
435
|
return self._aggregate_metrics([], [])
|
|
396
436
|
|
|
@@ -60,13 +60,32 @@ class ZigZagSwingStrategy:
|
|
|
60
60
|
|
|
61
61
|
from .....indicators import LibraryManager
|
|
62
62
|
|
|
63
|
-
zigzag
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
# ZigZag relies on the optional pandas-ta 'zigzag' indicator. If pandas-ta
|
|
64
|
+
# is unavailable (skipped/not installed) or ships no zigzag, degrade to an
|
|
65
|
+
# empty context with a clean warning instead of crashing the pipeline —
|
|
66
|
+
# this mirrors the per-zone calculate() fallback below.
|
|
67
|
+
try:
|
|
68
|
+
zigzag = LibraryManager.create_indicator(
|
|
69
|
+
'pandas_ta',
|
|
70
|
+
'zigzag',
|
|
71
|
+
legs=self.legs,
|
|
72
|
+
deviation=self.deviation,
|
|
73
|
+
# Issue #110: the default (backtest=False) is a repainting, centred
|
|
74
|
+
# detector — truncating the raw series at as_of relocates/adds/drops
|
|
75
|
+
# earlier pivots, so a pivot with confirmation_index <= as_of is not
|
|
76
|
+
# actually observable then. backtest=True is the non-repainting
|
|
77
|
+
# stream: once a pivot is emitted it never changes under extension
|
|
78
|
+
# (verified empirically in tests/unit/test_swing_replay_causal.py).
|
|
79
|
+
backtest=True,
|
|
80
|
+
)
|
|
81
|
+
result = zigzag.calculate(full_data)
|
|
82
|
+
except Exception as exc:
|
|
83
|
+
logger.warning(
|
|
84
|
+
"ZigZag global: pandas-ta 'zigzag' unavailable (%s). "
|
|
85
|
+
"Returning empty SwingContext.",
|
|
86
|
+
exc,
|
|
87
|
+
)
|
|
88
|
+
return self._empty_context(len(full_data))
|
|
70
89
|
|
|
71
90
|
if result.data.shape[1] < 2:
|
|
72
91
|
logger.warning(
|
|
@@ -141,6 +160,19 @@ class ZigZagSwingStrategy:
|
|
|
141
160
|
)
|
|
142
161
|
indices.append(position)
|
|
143
162
|
|
|
163
|
+
# Warm-up (issue #110): the backtest=True detector emits nothing until the
|
|
164
|
+
# second swing forms, so the first two pivots become observable *together*.
|
|
165
|
+
# The first pivot's own deviation-retrace can therefore fall a few bars before
|
|
166
|
+
# the detector actually reports it — pin its availability to the second
|
|
167
|
+
# pivot's (the bar they both first appear at). Later pivots' retrace times are
|
|
168
|
+
# already safe (empirically confirmation_index >= first-appearance).
|
|
169
|
+
if len(swing_points) >= 2 and swing_points[0].confirmation_index is not None \
|
|
170
|
+
and swing_points[1].confirmation_index is not None:
|
|
171
|
+
swing_points[0].confirmation_index = max(
|
|
172
|
+
swing_points[0].confirmation_index,
|
|
173
|
+
swing_points[1].confirmation_index,
|
|
174
|
+
)
|
|
175
|
+
|
|
144
176
|
logger.info("ZigZag global: detected %d swing points", len(swing_points))
|
|
145
177
|
|
|
146
178
|
return SwingContext(
|
|
@@ -440,18 +472,18 @@ class ZigZagSwingStrategy:
|
|
|
440
472
|
found. ``deviation`` is a fraction (0.05 == 5%), matching the pivot scale.
|
|
441
473
|
"""
|
|
442
474
|
if next_position <= position:
|
|
443
|
-
|
|
444
|
-
if swing_type == 'peak':
|
|
445
|
-
threshold = price * (1.0 - self.deviation)
|
|
446
|
-
seg = low_arr[position + 1:next_position + 1]
|
|
447
|
-
hits = np.nonzero(seg <= threshold)[0]
|
|
475
|
+
conf = next_position
|
|
448
476
|
else:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
477
|
+
if swing_type == 'peak':
|
|
478
|
+
threshold = price * (1.0 - self.deviation)
|
|
479
|
+
seg = low_arr[position + 1:next_position + 1]
|
|
480
|
+
hits = np.nonzero(seg <= threshold)[0]
|
|
481
|
+
else:
|
|
482
|
+
threshold = price * (1.0 + self.deviation)
|
|
483
|
+
seg = high_arr[position + 1:next_position + 1]
|
|
484
|
+
hits = np.nonzero(seg >= threshold)[0]
|
|
485
|
+
conf = position + 1 + int(hits[0]) if len(hits) else next_position
|
|
486
|
+
return conf
|
|
455
487
|
|
|
456
488
|
def _empty_metrics(self) -> SwingMetrics:
|
|
457
489
|
return self._aggregate_metrics([], [])
|
|
@@ -187,7 +187,6 @@ bquant/visualization/statistical.py
|
|
|
187
187
|
bquant/visualization/themes.py
|
|
188
188
|
bquant/visualization/utils.py
|
|
189
189
|
bquant/visualization/zones.py
|
|
190
|
-
docs/BUILD_ISSUES.md
|
|
191
190
|
docs/README.md
|
|
192
191
|
docs/index.rst
|
|
193
192
|
docs/_build/html/_sources/index.rst.txt
|
|
@@ -247,11 +246,6 @@ docs/_build/html/_sources/user_guide/quick_start.md.txt
|
|
|
247
246
|
docs/_build/html/_sources/user_guide/swing_analysis_results.md.txt
|
|
248
247
|
docs/_build/html/_sources/user_guide/swing_strategies.md.txt
|
|
249
248
|
docs/_build/html/_sources/user_guide/zone_analysis.md.txt
|
|
250
|
-
docs/analytics/zones/layerA_ii_representations_case_study.md
|
|
251
|
-
docs/analytics/zones/layerA_zone_structure_case_study.md
|
|
252
|
-
docs/analytics/zones/macd_zone_consistency_case_study.md
|
|
253
|
-
docs/analytics/zones/s1_swing_anatomy_case_study.md
|
|
254
|
-
docs/analytics/zones/swing.md
|
|
255
249
|
docs/analytics/zones/swing_strategy_comparison_case_study.md
|
|
256
250
|
docs/api/README.md
|
|
257
251
|
docs/api/extension_guide.md
|
|
@@ -261,9 +255,9 @@ docs/api/analysis/pipeline.md
|
|
|
261
255
|
docs/api/analysis/statistical.md
|
|
262
256
|
docs/api/analysis/strategies.md
|
|
263
257
|
docs/api/analysis/zones.md
|
|
264
|
-
docs/api/analysis/zones/
|
|
265
|
-
docs/api/analysis/zones/
|
|
266
|
-
docs/api/analysis/zones/
|
|
258
|
+
docs/api/analysis/zones/global_swings_models.md
|
|
259
|
+
docs/api/analysis/zones/global_swings_pipeline.md
|
|
260
|
+
docs/api/analysis/zones/global_swings_strategies.md
|
|
267
261
|
docs/api/core/README.md
|
|
268
262
|
docs/api/core/config.md
|
|
269
263
|
docs/api/core/exceptions.md
|
|
@@ -303,7 +297,6 @@ docs/user_guide/best_practices.md
|
|
|
303
297
|
docs/user_guide/caching.md
|
|
304
298
|
docs/user_guide/core_concepts.md
|
|
305
299
|
docs/user_guide/quick_start.md
|
|
306
|
-
docs/user_guide/swing_analysis_results.md
|
|
307
300
|
docs/user_guide/swing_strategies.md
|
|
308
301
|
docs/user_guide/zone_analysis.md
|
|
309
302
|
docs/user_guide/zone_analysis_result.md
|
|
@@ -335,6 +328,7 @@ tests/analysis/zones/test_pipeline_cache.py
|
|
|
335
328
|
tests/analysis/zones/test_swing_presets.py
|
|
336
329
|
tests/analysis/zones/test_swing_thresholds.py
|
|
337
330
|
tests/fixtures/__init__.py
|
|
331
|
+
tests/fixtures/swing_coverage.py
|
|
338
332
|
tests/fixtures/swing_mocks.py
|
|
339
333
|
tests/integration/__init__.py
|
|
340
334
|
tests/integration/test_backward_compatibility.py
|
|
@@ -358,6 +352,7 @@ tests/unit/test_compatibility_validation.py
|
|
|
358
352
|
tests/unit/test_core_modules.py
|
|
359
353
|
tests/unit/test_data_modules.py
|
|
360
354
|
tests/unit/test_divergence_strategy_universal.py
|
|
355
|
+
tests/unit/test_docs_parity.py
|
|
361
356
|
tests/unit/test_find_peaks_swing_strategy.py
|
|
362
357
|
tests/unit/test_imports_migration.py
|
|
363
358
|
tests/unit/test_indicator_factory.py
|
|
@@ -379,6 +374,7 @@ tests/unit/test_strategy_infrastructure.py
|
|
|
379
374
|
tests/unit/test_swing_context_memory.py
|
|
380
375
|
tests/unit/test_swing_edge_cases.py
|
|
381
376
|
tests/unit/test_swing_global_calculation.py
|
|
377
|
+
tests/unit/test_swing_replay_causal.py
|
|
382
378
|
tests/unit/test_time_metrics.py
|
|
383
379
|
tests/unit/test_universal_zone_analyzer.py
|
|
384
380
|
tests/unit/test_validation_suite.py
|
|
@@ -56,9 +56,9 @@ Analysis модули содержат инструменты для стати
|
|
|
56
56
|
- **115 тестов, 100% pass rate** - доказательство универсальности
|
|
57
57
|
|
|
58
58
|
**Документация по глобальным свингам:**
|
|
59
|
-
- [Модели](zones/
|
|
60
|
-
- [Пайплайн](zones/
|
|
61
|
-
- [Стратегии](zones/
|
|
59
|
+
- [Модели](zones/global_swings_models.md) — `SwingPoint`, `SwingContext`, расширения `ZoneInfo`
|
|
60
|
+
- [Пайплайн](zones/global_swings_pipeline.md) — `_calculate_global_swings`, `_inject_swing_context`, `with_swing_scope()`
|
|
61
|
+
- [Стратегии](zones/global_swings_strategies.md) — протокол `SwingCalculationStrategy`, ZigZag/FindPeaks/PivotPoints
|
|
62
62
|
|
|
63
63
|
### 🎨 [bquant.analysis.zones.strategies](strategies.md) - Strategy Pattern (New)
|
|
64
64
|
|
|
@@ -135,6 +135,22 @@ result = (
|
|
|
135
135
|
.with_cache(enable=False)
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
+
#### `.with_swing_scope(scope)`
|
|
139
|
+
Режим расчёта свингов.
|
|
140
|
+
|
|
141
|
+
**Параметры:**
|
|
142
|
+
- `scope='global'` (по умолчанию) — свинги считаются один раз по всему датасету, затем
|
|
143
|
+
агрегируются в каждую зону (`calculate_global` + `aggregate_for_zone`).
|
|
144
|
+
- `scope='per_zone'` — свинги считаются локально внутри каждой зоны (совместимость).
|
|
145
|
+
|
|
146
|
+
**Пример:**
|
|
147
|
+
```python
|
|
148
|
+
.with_strategies(swing='zigzag').with_swing_scope('global')
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
> 📖 Внутренняя механика (`_calculate_global_swings`, `_inject_swing_context`, фолбэки) —
|
|
152
|
+
> в [Глобальные свинги: пайплайн](zones/global_swings_pipeline.md).
|
|
153
|
+
|
|
138
154
|
#### `.build()`
|
|
139
155
|
Запуск анализа и получение результата.
|
|
140
156
|
|
|
@@ -352,9 +368,9 @@ zone_features = result.zones[0].features.get('zone_type')
|
|
|
352
368
|
|
|
353
369
|
### 🎯 Learning Path
|
|
354
370
|
- **[Examples](../../examples/README.md)** - Готовые примеры использования
|
|
355
|
-
- **[Deep Dive Tutorial](
|
|
356
|
-
- **[Advanced Features](
|
|
357
|
-
- **[Migration Guide](
|
|
371
|
+
- **[Deep Dive Tutorial](../../../research/notebooks/03_zones_universal.py)** - Comprehensive analysis
|
|
372
|
+
- **[Advanced Features](../../../research/notebooks/03_analysis_new_features.py)** - Swing, divergence, regression
|
|
373
|
+
- **[Migration Guide](../../../examples/02_macd_zone_analysis.py)** - Переход с legacy API
|
|
358
374
|
|
|
359
375
|
### 🏗️ Developer Resources
|
|
360
376
|
- **[Architecture Patterns](../../developer_guide/README.md)** - Design Patterns, Extension Points
|