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.
Files changed (323) hide show
  1. bquant-0.0.4/CHANGELOG.md +185 -0
  2. {bquant-0.0.2/bquant.egg-info → bquant-0.0.4}/PKG-INFO +1 -1
  3. {bquant-0.0.2 → bquant-0.0.4}/bquant/__init__.py +1 -1
  4. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/cache.py +6 -1
  5. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/pipeline.py +5 -1
  6. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/find_peaks.py +118 -0
  7. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/pivot_points.py +40 -0
  8. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/zigzag.py +50 -18
  9. {bquant-0.0.2 → bquant-0.0.4/bquant.egg-info}/PKG-INFO +1 -1
  10. {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/SOURCES.txt +6 -10
  11. {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/README.md +3 -3
  12. {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/pipeline.md +19 -3
  13. {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/strategies.md +33 -26
  14. bquant-0.0.2/docs/api/analysis/zones/pipeline.md → bquant-0.0.4/docs/api/analysis/zones/global_swings_pipeline.md +6 -2
  15. bquant-0.0.2/docs/api/analysis/zones/strategies.md → bquant-0.0.4/docs/api/analysis/zones/global_swings_strategies.md +5 -1
  16. {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/zones.md +9 -13
  17. {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/logging.md +1 -1
  18. {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/nb.md +2 -2
  19. {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/README.md +2 -2
  20. {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/loader.md +2 -2
  21. {bquant-0.0.2 → bquant-0.0.4}/docs/api/extension_guide.md +4 -4
  22. {bquant-0.0.2 → bquant-0.0.4}/docs/api/visualization/README.md +11 -7
  23. {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/zone_analyzer_deep_dive.md +2 -2
  24. {bquant-0.0.2 → bquant-0.0.4}/docs/index.rst +28 -6
  25. {bquant-0.0.2 → bquant-0.0.4}/docs/migration/MIGRATION_v2.md +2 -2
  26. {bquant-0.0.2 → bquant-0.0.4}/docs/migration/global_swings_migration.md +1 -1
  27. {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/README.md +1 -1
  28. {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/quick_start.md +1 -1
  29. bquant-0.0.4/docs/user_guide/swing_strategies.md +146 -0
  30. {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/zone_analysis.md +2 -2
  31. {bquant-0.0.2 → bquant-0.0.4}/pyproject.toml +1 -1
  32. bquant-0.0.4/tests/fixtures/swing_coverage.py +85 -0
  33. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_pipeline_global_swings.py +1 -1
  34. bquant-0.0.4/tests/unit/test_docs_parity.py +131 -0
  35. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_pandas_ta_dynamic_loader.py +9 -2
  36. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_swing_global_calculation.py +53 -3
  37. bquant-0.0.4/tests/unit/test_swing_replay_causal.py +185 -0
  38. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zigzag_swing_strategy.py +33 -0
  39. bquant-0.0.2/CHANGELOG.md +0 -122
  40. bquant-0.0.2/docs/BUILD_ISSUES.md +0 -260
  41. bquant-0.0.2/docs/analytics/zones/layerA_ii_representations_case_study.md +0 -68
  42. bquant-0.0.2/docs/analytics/zones/layerA_zone_structure_case_study.md +0 -73
  43. bquant-0.0.2/docs/analytics/zones/macd_zone_consistency_case_study.md +0 -64
  44. bquant-0.0.2/docs/analytics/zones/s1_swing_anatomy_case_study.md +0 -127
  45. bquant-0.0.2/docs/analytics/zones/swing.md +0 -64
  46. bquant-0.0.2/docs/user_guide/swing_analysis_results.md +0 -340
  47. bquant-0.0.2/docs/user_guide/swing_strategies.md +0 -139
  48. {bquant-0.0.2 → bquant-0.0.4}/LICENSE +0 -0
  49. {bquant-0.0.2 → bquant-0.0.4}/MANIFEST.in +0 -0
  50. {bquant-0.0.2 → bquant-0.0.4}/README.md +0 -0
  51. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/__init__.py +0 -0
  52. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/candlestick/__init__.py +0 -0
  53. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/chart/__init__.py +0 -0
  54. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/statistical/__init__.py +0 -0
  55. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/statistical/hypothesis_testing.py +0 -0
  56. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/statistical/regression.py +0 -0
  57. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/technical/__init__.py +0 -0
  58. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/timeseries/__init__.py +0 -0
  59. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/validation/__init__.py +0 -0
  60. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/validation/suite.py +0 -0
  61. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/__init__.py +0 -0
  62. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/analyzer.py +0 -0
  63. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/__init__.py +0 -0
  64. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/base.py +0 -0
  65. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/combined.py +0 -0
  66. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/line_crossing.py +0 -0
  67. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/preloaded.py +0 -0
  68. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/registry.py +0 -0
  69. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/threshold.py +0 -0
  70. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/detection/zero_crossing.py +0 -0
  71. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/models.py +0 -0
  72. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/presets.py +0 -0
  73. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/sequence_analysis.py +0 -0
  74. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/__init__.py +0 -0
  75. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/base.py +0 -0
  76. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/divergence/__init__.py +0 -0
  77. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/divergence/classic.py +0 -0
  78. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/registry.py +0 -0
  79. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/shape/__init__.py +0 -0
  80. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/shape/statistical.py +0 -0
  81. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/__init__.py +0 -0
  82. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/swing/thresholds.py +0 -0
  83. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/volatility/__init__.py +0 -0
  84. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/volatility/combined.py +0 -0
  85. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/volume/__init__.py +0 -0
  86. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/strategies/volume/standard.py +0 -0
  87. {bquant-0.0.2 → bquant-0.0.4}/bquant/analysis/zones/zone_features.py +0 -0
  88. {bquant-0.0.2 → bquant-0.0.4}/bquant/cli.py +0 -0
  89. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/__init__.py +0 -0
  90. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/cache.py +0 -0
  91. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/config.py +0 -0
  92. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/exceptions.py +0 -0
  93. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/logging_config.py +0 -0
  94. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/nb.py +0 -0
  95. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/numpy_fix.py +0 -0
  96. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/performance.py +0 -0
  97. {bquant-0.0.2 → bquant-0.0.4}/bquant/core/utils.py +0 -0
  98. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/__init__.py +0 -0
  99. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/loader.py +0 -0
  100. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/processor.py +0 -0
  101. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/__init__.py +0 -0
  102. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/datasets.py +0 -0
  103. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/embedded/__init__.py +0 -0
  104. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/embedded/mt_xauusd_m15.py +0 -0
  105. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/embedded/tv_xauusd_1h.py +0 -0
  106. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/generator.py +0 -0
  107. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/samples/utils.py +0 -0
  108. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/schemas.py +0 -0
  109. {bquant-0.0.2 → bquant-0.0.4}/bquant/data/validator.py +0 -0
  110. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/__init__.py +0 -0
  111. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/base.py +0 -0
  112. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/calculators.py +0 -0
  113. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/__init__.py +0 -0
  114. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/bollinger.py +0 -0
  115. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/ema.py +0 -0
  116. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/macd.py +0 -0
  117. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/rsi.py +0 -0
  118. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/custom/sma.py +0 -0
  119. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/library/__init__.py +0 -0
  120. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/library/manager.py +0 -0
  121. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/library/pandas_ta.py +0 -0
  122. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/library/talib.py +0 -0
  123. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/macd.py +0 -0
  124. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/preloaded/__init__.py +0 -0
  125. {bquant-0.0.2 → bquant-0.0.4}/bquant/indicators/preloaded/macd.py +0 -0
  126. {bquant-0.0.2 → bquant-0.0.4}/bquant/ml/__init__.py +0 -0
  127. {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/__init__.py +0 -0
  128. {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/charts.py +0 -0
  129. {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/export.py +0 -0
  130. {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/statistical.py +0 -0
  131. {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/themes.py +0 -0
  132. {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/utils.py +0 -0
  133. {bquant-0.0.2 → bquant-0.0.4}/bquant/visualization/zones.py +0 -0
  134. {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/dependency_links.txt +0 -0
  135. {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/entry_points.txt +0 -0
  136. {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/requires.txt +0 -0
  137. {bquant-0.0.2 → bquant-0.0.4}/bquant.egg-info/top_level.txt +0 -0
  138. {bquant-0.0.2 → bquant-0.0.4}/docs/README.md +0 -0
  139. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/analytics/zones/macd_zone_consistency_case_study.md.txt +0 -0
  140. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/analytics/zones/swing.md.txt +0 -0
  141. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/analytics/zones/swing_strategy_comparison_case_study.md.txt +0 -0
  142. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/README.md.txt +0 -0
  143. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/README.md.txt +0 -0
  144. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/base.md.txt +0 -0
  145. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/pipeline.md.txt +0 -0
  146. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/statistical.md.txt +0 -0
  147. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/strategies.md.txt +0 -0
  148. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/zones/models.md.txt +0 -0
  149. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/zones/pipeline.md.txt +0 -0
  150. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/zones/strategies.md.txt +0 -0
  151. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/analysis/zones.md.txt +0 -0
  152. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/README.md.txt +0 -0
  153. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/config.md.txt +0 -0
  154. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/exceptions.md.txt +0 -0
  155. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/logging.md.txt +0 -0
  156. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/nb.md.txt +0 -0
  157. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/performance.md.txt +0 -0
  158. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/core/utils.md.txt +0 -0
  159. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/README.md.txt +0 -0
  160. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/loader.md.txt +0 -0
  161. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/processor.md.txt +0 -0
  162. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/samples.md.txt +0 -0
  163. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/schemas.md.txt +0 -0
  164. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/data/validator.md.txt +0 -0
  165. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/extension_guide.md.txt +0 -0
  166. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/README.md.txt +0 -0
  167. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/base.md.txt +0 -0
  168. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/factory.md.txt +0 -0
  169. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/library_manager.md.txt +0 -0
  170. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/macd.md.txt +0 -0
  171. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/indicators/preloaded.md.txt +0 -0
  172. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/visualization/README.md.txt +0 -0
  173. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/api/visualization/zones.md.txt +0 -0
  174. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/README.md.txt +0 -0
  175. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/analytical_philosophy.md.txt +0 -0
  176. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/statistical_analysis_workflow.md.txt +0 -0
  177. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/zone_analyzer_deep_dive.md.txt +0 -0
  178. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/developer_guide/zone_detection_strategies.md.txt +0 -0
  179. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/examples/README.md.txt +0 -0
  180. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/index.rst.txt +0 -0
  181. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/migration/MIGRATION_v2.md.txt +0 -0
  182. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/migration/global_swings_migration.md.txt +0 -0
  183. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/README.md.txt +0 -0
  184. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/combined_rules_detection.md.txt +0 -0
  185. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/macd_basic_pipeline.md.txt +0 -0
  186. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/preloaded_zones_workflow.md.txt +0 -0
  187. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/tutorials/rsi_strategy_switching.md.txt +0 -0
  188. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/README.md.txt +0 -0
  189. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/best_practices.md.txt +0 -0
  190. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/caching.md.txt +0 -0
  191. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/core_concepts.md.txt +0 -0
  192. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/quick_start.md.txt +0 -0
  193. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/swing_analysis_results.md.txt +0 -0
  194. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/swing_strategies.md.txt +0 -0
  195. {bquant-0.0.2 → bquant-0.0.4}/docs/_build/html/_sources/user_guide/zone_analysis.md.txt +0 -0
  196. {bquant-0.0.2 → bquant-0.0.4}/docs/analytics/zones/swing_strategy_comparison_case_study.md +0 -0
  197. {bquant-0.0.2 → bquant-0.0.4}/docs/api/README.md +0 -0
  198. {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/base.md +0 -0
  199. {bquant-0.0.2 → bquant-0.0.4}/docs/api/analysis/statistical.md +0 -0
  200. /bquant-0.0.2/docs/api/analysis/zones/models.md → /bquant-0.0.4/docs/api/analysis/zones/global_swings_models.md +0 -0
  201. {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/README.md +0 -0
  202. {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/config.md +0 -0
  203. {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/exceptions.md +0 -0
  204. {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/performance.md +0 -0
  205. {bquant-0.0.2 → bquant-0.0.4}/docs/api/core/utils.md +0 -0
  206. {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/processor.md +0 -0
  207. {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/samples.md +0 -0
  208. {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/schemas.md +0 -0
  209. {bquant-0.0.2 → bquant-0.0.4}/docs/api/data/validator.md +0 -0
  210. {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/README.md +0 -0
  211. {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/base.md +0 -0
  212. {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/factory.md +0 -0
  213. {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/library_manager.md +0 -0
  214. {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/macd.md +0 -0
  215. {bquant-0.0.2 → bquant-0.0.4}/docs/api/indicators/preloaded.md +0 -0
  216. {bquant-0.0.2 → bquant-0.0.4}/docs/api/visualization/zones.md +0 -0
  217. {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/README.md +0 -0
  218. {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/analytical_philosophy.md +0 -0
  219. {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/statistical_analysis_workflow.md +0 -0
  220. {bquant-0.0.2 → bquant-0.0.4}/docs/developer_guide/zone_detection_strategies.md +0 -0
  221. {bquant-0.0.2 → bquant-0.0.4}/docs/examples/README.md +0 -0
  222. {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/README.md +0 -0
  223. {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/combined_rules_detection.md +0 -0
  224. {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/macd_basic_pipeline.md +0 -0
  225. {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/preloaded_zones_workflow.md +0 -0
  226. {bquant-0.0.2 → bquant-0.0.4}/docs/tutorials/rsi_strategy_switching.md +0 -0
  227. {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/best_practices.md +0 -0
  228. {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/caching.md +0 -0
  229. {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/core_concepts.md +0 -0
  230. {bquant-0.0.2 → bquant-0.0.4}/docs/user_guide/zone_analysis_result.md +0 -0
  231. {bquant-0.0.2 → bquant-0.0.4}/examples/01_basic_indicators.py +0 -0
  232. {bquant-0.0.2 → bquant-0.0.4}/examples/02_macd_zone_analysis.py +0 -0
  233. {bquant-0.0.2 → bquant-0.0.4}/examples/02a_universal_zones.py +0 -0
  234. {bquant-0.0.2 → bquant-0.0.4}/examples/03_data_processing.py +0 -0
  235. {bquant-0.0.2 → bquant-0.0.4}/examples/04_comprehensive_analysis.py +0 -0
  236. {bquant-0.0.2 → bquant-0.0.4}/examples/05_strategies_demo.py +0 -0
  237. {bquant-0.0.2 → bquant-0.0.4}/examples/06_regression_demo.py +0 -0
  238. {bquant-0.0.2 → bquant-0.0.4}/examples/07_validation_demo.py +0 -0
  239. {bquant-0.0.2 → bquant-0.0.4}/examples/08_macd_swing_analysis.py +0 -0
  240. {bquant-0.0.2 → bquant-0.0.4}/examples/09_zones_visualization_demo.py +0 -0
  241. {bquant-0.0.2 → bquant-0.0.4}/examples/README.md +0 -0
  242. {bquant-0.0.2 → bquant-0.0.4}/examples/zone_analysis_global_swings.py +0 -0
  243. {bquant-0.0.2 → bquant-0.0.4}/scripts/README.md +0 -0
  244. {bquant-0.0.2 → bquant-0.0.4}/scripts/analysis/README.md +0 -0
  245. {bquant-0.0.2 → bquant-0.0.4}/scripts/analysis/batch_analysis.py +0 -0
  246. {bquant-0.0.2 → bquant-0.0.4}/scripts/analysis/run_macd_analysis.py +0 -0
  247. {bquant-0.0.2 → bquant-0.0.4}/scripts/analysis/test_hypotheses.py +0 -0
  248. {bquant-0.0.2 → bquant-0.0.4}/scripts/data/data_loader.py +0 -0
  249. {bquant-0.0.2 → bquant-0.0.4}/scripts/data/extract_samples.py +0 -0
  250. {bquant-0.0.2 → bquant-0.0.4}/scripts/data/generate_samples.py +0 -0
  251. {bquant-0.0.2 → bquant-0.0.4}/scripts/data_processing/README.md +0 -0
  252. {bquant-0.0.2 → bquant-0.0.4}/scripts/deployment/README.md +0 -0
  253. {bquant-0.0.2 → bquant-0.0.4}/scripts/publishing/README.md +0 -0
  254. {bquant-0.0.2 → bquant-0.0.4}/setup.cfg +0 -0
  255. {bquant-0.0.2 → bquant-0.0.4}/tests/analysis/zones/test_pipeline_cache.py +0 -0
  256. {bquant-0.0.2 → bquant-0.0.4}/tests/analysis/zones/test_swing_presets.py +0 -0
  257. {bquant-0.0.2 → bquant-0.0.4}/tests/analysis/zones/test_swing_thresholds.py +0 -0
  258. {bquant-0.0.2 → bquant-0.0.4}/tests/conftest.py +0 -0
  259. {bquant-0.0.2 → bquant-0.0.4}/tests/fixtures/__init__.py +0 -0
  260. {bquant-0.0.2 → bquant-0.0.4}/tests/fixtures/swing_mocks.py +0 -0
  261. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/__init__.py +0 -0
  262. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_backward_compatibility.py +0 -0
  263. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_data_pipeline.py +0 -0
  264. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_full_pipeline.py +0 -0
  265. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_scripts_integration.py +0 -0
  266. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_truly_universal_zones.py +0 -0
  267. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_visualization_pipeline.py +0 -0
  268. {bquant-0.0.2 → bquant-0.0.4}/tests/integration/test_zone_analysis_e2e.py +0 -0
  269. {bquant-0.0.2 → bquant-0.0.4}/tests/performance/test_swing_performance.py +0 -0
  270. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/__init__.py +0 -0
  271. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_all_indicator_types.py +0 -0
  272. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_analysis_structure.py +0 -0
  273. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_architecture_validation.py +0 -0
  274. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_builtin_migration.py +0 -0
  275. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_cache_versioning.py +0 -0
  276. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_classic_divergence_strategy.py +0 -0
  277. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_combined_volatility_strategy.py +0 -0
  278. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_compatibility_validation.py +0 -0
  279. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_core_modules.py +0 -0
  280. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_data_modules.py +0 -0
  281. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_divergence_strategy_universal.py +0 -0
  282. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_find_peaks_swing_strategy.py +0 -0
  283. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_imports_migration.py +0 -0
  284. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_indicator_factory.py +0 -0
  285. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_indicators_base.py +0 -0
  286. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_library_indicators.py +0 -0
  287. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_macd_analyzer.py +0 -0
  288. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_macd_backward_compatibility.py +0 -0
  289. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_performance.py +0 -0
  290. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_pivot_points_swing_strategy.py +0 -0
  291. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_preloaded_indicators.py +0 -0
  292. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_sample_data.py +0 -0
  293. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_sample_generator.py +0 -0
  294. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_shape_strategy_universal.py +0 -0
  295. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_standard_volume_strategy.py +0 -0
  296. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_statistical_hypothesis.py +0 -0
  297. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_statistical_shape_strategy.py +0 -0
  298. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_strategy_infrastructure.py +0 -0
  299. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_swing_context_memory.py +0 -0
  300. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_swing_edge_cases.py +0 -0
  301. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_time_metrics.py +0 -0
  302. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_universal_zone_analyzer.py +0 -0
  303. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_validation_suite.py +0 -0
  304. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_visualization.py +0 -0
  305. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_volume_strategy_universal.py +0 -0
  306. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_analysis_builder.py +0 -0
  307. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_detection_strategies.py +0 -0
  308. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_analyzer_context.py +0 -0
  309. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_divergence_integration.py +0 -0
  310. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_shape_integration.py +0 -0
  311. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_swing_integration.py +0 -0
  312. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_volatility_integration.py +0 -0
  313. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_features_volume_integration.py +0 -0
  314. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_models.py +0 -0
  315. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_pipeline.py +0 -0
  316. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_presets.py +0 -0
  317. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zone_regression_analyzer.py +0 -0
  318. {bquant-0.0.2 → bquant-0.0.4}/tests/unit/test_zones_analysis.py +0 -0
  319. {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_infrastructure.py +0 -0
  320. {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_swing_overlay.py +0 -0
  321. {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_zone_metrics_aggregation.py +0 -0
  322. {bquant-0.0.2 → bquant-0.0.4}/tests/visualization/test_zone_metrics_display.py +0 -0
  323. {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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bquant
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Quantitative research toolkit for financial markets
5
5
  Author-email: kogriv <kogriv@gmail.com>
6
6
  License: MIT
@@ -5,7 +5,7 @@ A comprehensive toolkit for quantitative analysis of financial data,
5
5
  starting with MACD analysis and expandable to all aspects of market research.
6
6
  """
7
7
 
8
- __version__ = "0.0.2"
8
+ __version__ = "0.0.4"
9
9
  __author__ = "kogriv"
10
10
  __email__ = "kogriv@gmail.com"
11
11
 
@@ -27,7 +27,12 @@ class ZoneAnalysisCache:
27
27
  entries are automatically invalidated when the schema version increases.
28
28
  """
29
29
 
30
- CACHE_VERSION = 2
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
- CACHE_SCHEMA_VERSION = 2
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 = LibraryManager.create_indicator(
64
- 'pandas_ta',
65
- 'zigzag',
66
- legs=self.legs,
67
- deviation=self.deviation,
68
- )
69
- result = zigzag.calculate(full_data)
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
- return next_position
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
- threshold = price * (1.0 + self.deviation)
450
- seg = high_arr[position + 1:next_position + 1]
451
- hits = np.nonzero(seg >= threshold)[0]
452
- if len(hits):
453
- return position + 1 + int(hits[0])
454
- return next_position
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([], [])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bquant
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Quantitative research toolkit for financial markets
5
5
  Author-email: kogriv <kogriv@gmail.com>
6
6
  License: MIT
@@ -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/models.md
265
- docs/api/analysis/zones/pipeline.md
266
- docs/api/analysis/zones/strategies.md
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/models.md) — `SwingPoint`, `SwingContext`, расширения `ZoneInfo`
60
- - [Пайплайн](zones/pipeline.md) — `_calculate_global_swings`, `_inject_swing_context`, `with_swing_scope()`
61
- - [Стратегии](zones/strategies.md) — протокол `SwingCalculationStrategy`, ZigZag/FindPeaks/PivotPoints
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](../../research/notebooks/03_zones_universal.py)** - Comprehensive analysis
356
- - **[Advanced Features](../../research/notebooks/03_analysis_new_features.py)** - Swing, divergence, regression
357
- - **[Migration Guide](../../examples/02_macd_zone_analysis.py)** - Переход с legacy API
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