echolon 0.3.0__tar.gz → 0.3.2__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 (336) hide show
  1. echolon-0.3.2/CHANGELOG.md +30 -0
  2. {echolon-0.3.0 → echolon-0.3.2}/PKG-INFO +1 -1
  3. echolon-0.3.2/docs/API_REFERENCE.md +188 -0
  4. echolon-0.3.2/docs/COMPONENT_GUIDE.md +115 -0
  5. echolon-0.3.2/docs/CONFIG_REFERENCE.md +68 -0
  6. echolon-0.3.2/docs/ERROR_CATALOG.md +19 -0
  7. echolon-0.3.2/docs/PATTERNS.md +185 -0
  8. echolon-0.3.2/docs/QUICK_START.md +50 -0
  9. echolon-0.3.2/docs/errors/CFG-001.md +35 -0
  10. echolon-0.3.2/docs/errors/CFG-002.md +40 -0
  11. echolon-0.3.2/docs/errors/DAT-001.md +41 -0
  12. echolon-0.3.2/docs/errors/IND-001.md +31 -0
  13. echolon-0.3.2/docs/errors/IND-002.md +36 -0
  14. echolon-0.3.2/docs/errors/PRM-001.md +44 -0
  15. echolon-0.3.2/docs/errors/PRM-002.md +50 -0
  16. echolon-0.3.2/docs/errors/STR-001.md +35 -0
  17. echolon-0.3.2/docs/errors/STR-002.md +48 -0
  18. echolon-0.3.2/docs/errors/STR-003.md +42 -0
  19. echolon-0.3.2/docs/errors/VAL-001.md +50 -0
  20. echolon-0.3.2/docs/errors/VAL-002.md +34 -0
  21. echolon-0.3.2/docs/errors/VAL-003.md +38 -0
  22. echolon-0.3.2/echolon/__init__.py +20 -0
  23. echolon-0.3.2/echolon/config/__init__.py +0 -0
  24. echolon-0.3.2/echolon/config/backtest_config.py +57 -0
  25. echolon-0.3.2/echolon/config/feature_flags.py +54 -0
  26. echolon-0.3.2/echolon/config/indicator_config.py +32 -0
  27. echolon-0.3.2/echolon/config/markets/__init__.py +0 -0
  28. echolon-0.3.2/echolon/config/markets/core/__init__.py +0 -0
  29. echolon-0.3.2/echolon/config/markets/core/context.py +631 -0
  30. echolon-0.3.2/echolon/config/markets/core/encoding.py +27 -0
  31. echolon-0.3.2/echolon/config/markets/core/registry.py +248 -0
  32. echolon-0.3.2/echolon/config/markets/core/trading_target.py +490 -0
  33. echolon-0.3.2/echolon/config/markets/core/types.py +217 -0
  34. echolon-0.3.2/echolon/config/markets/crypto/__init__.py +0 -0
  35. echolon-0.3.2/echolon/config/markets/crypto/config.py +70 -0
  36. echolon-0.3.2/echolon/config/markets/crypto/perpetuals.py +144 -0
  37. echolon-0.3.2/echolon/config/markets/factory.py +343 -0
  38. echolon-0.3.2/echolon/config/markets/shfe/__init__.py +0 -0
  39. echolon-0.3.2/echolon/config/markets/shfe/config.py +90 -0
  40. echolon-0.3.2/echolon/config/markets/shfe/constants.py +166 -0
  41. echolon-0.3.2/echolon/config/markets/shfe/instruments.py +321 -0
  42. echolon-0.3.2/echolon/config/markets/shfe/phases.py +622 -0
  43. echolon-0.3.2/echolon/config/markets/shfe/sessions.py +79 -0
  44. echolon-0.3.2/echolon/config/optuna_config.py +20 -0
  45. echolon-0.3.2/echolon/config/quant_engine.py +87 -0
  46. echolon-0.3.2/echolon/config/quick_start.py +41 -0
  47. echolon-0.3.2/echolon/config/settings.py +61 -0
  48. echolon-0.3.2/echolon/data_pipeline/__init__.py +6 -0
  49. echolon-0.3.2/echolon/data_pipeline/extractors/base.py +113 -0
  50. echolon-0.3.2/echolon/data_pipeline/extractors/binance/__init__.py +10 -0
  51. echolon-0.3.2/echolon/data_pipeline/extractors/binance/perpetual_extractor.py +587 -0
  52. echolon-0.3.2/echolon/data_pipeline/extractors/shfe/day_extractor.py +164 -0
  53. echolon-0.3.2/echolon/data_pipeline/extractors/shfe/live_day_extractor.py +580 -0
  54. echolon-0.3.2/echolon/data_pipeline/extractors/shfe/minute_extractor.py +277 -0
  55. echolon-0.3.2/echolon/data_pipeline/loaders/calendar_loader.py +180 -0
  56. echolon-0.3.2/echolon/data_pipeline/loaders/ohlcv_loader.py +161 -0
  57. echolon-0.3.2/echolon/data_pipeline/loaders/session_availability_loader.py +477 -0
  58. echolon-0.3.2/echolon/data_pipeline/run_pipeline.py +486 -0
  59. echolon-0.3.2/echolon/data_pipeline/schemas/ohlcv.py +43 -0
  60. echolon-0.3.2/echolon/data_pipeline/schemas/standard_schema.py +536 -0
  61. echolon-0.3.2/echolon/data_pipeline/transformers/calendar_generator.py +211 -0
  62. echolon-0.3.2/echolon/data_pipeline/transformers/contract_splitter.py +113 -0
  63. echolon-0.3.2/echolon/data_pipeline/transformers/ohlcv_resampler.py +218 -0
  64. echolon-0.3.2/echolon/data_pipeline/transformers/ohlcv_standardizer.py +354 -0
  65. echolon-0.3.2/echolon/data_pipeline/transformers/session_filter.py +136 -0
  66. echolon-0.3.2/echolon/data_pipeline/transformers/shfe_session_analyzer.py +320 -0
  67. echolon-0.3.2/echolon/indicators/__init__.py +6 -0
  68. echolon-0.3.2/echolon/indicators/calculators/__init__.py +0 -0
  69. echolon-0.3.2/echolon/indicators/calculators/interday/__init__.py +0 -0
  70. echolon-0.3.2/echolon/indicators/calculators/interday/indicator_dictionary.json +187 -0
  71. echolon-0.3.2/echolon/indicators/calculators/interday/indicator_mapping.py +300 -0
  72. echolon-0.3.2/echolon/indicators/calculators/interday/market_regime.py +425 -0
  73. echolon-0.3.2/echolon/indicators/calculators/interday/price_channel.py +49 -0
  74. echolon-0.3.2/echolon/indicators/calculators/interday/sr_zone.py +150 -0
  75. echolon-0.3.2/echolon/indicators/calculators/interday/ta_lib.py +1157 -0
  76. echolon-0.3.2/echolon/indicators/calculators/intraday/__init__.py +0 -0
  77. echolon-0.3.2/echolon/indicators/calculators/intraday/indicator_dictionary.json +88 -0
  78. echolon-0.3.2/echolon/indicators/calculators/intraday/indicator_mapping.py +337 -0
  79. echolon-0.3.2/echolon/indicators/calculators/intraday/indicators.py +1108 -0
  80. echolon-0.3.2/echolon/indicators/calculators/intraday/market_context.py +398 -0
  81. echolon-0.3.2/echolon/indicators/calculators/intraday/ta_lib.py +1082 -0
  82. echolon-0.3.2/echolon/indicators/config/interday_analysis_indicators.json +147 -0
  83. echolon-0.3.2/echolon/indicators/config/interday_indicators_classification.md +260 -0
  84. echolon-0.3.2/echolon/indicators/config/interday_indicators_documentation.md +255 -0
  85. echolon-0.3.2/echolon/indicators/config/intraday_analysis_indicators.json +356 -0
  86. echolon-0.3.2/echolon/indicators/config/intraday_indicators_classification.md +386 -0
  87. echolon-0.3.2/echolon/indicators/config/intraday_indicators_documentation.md +134 -0
  88. echolon-0.3.2/echolon/indicators/engine/__init__.py +0 -0
  89. echolon-0.3.2/echolon/indicators/engine/processor.py +1285 -0
  90. echolon-0.3.2/echolon/indicators/optimization/__init__.py +0 -0
  91. echolon-0.3.2/echolon/indicators/optimization/interday_regime_optimizer.py +1039 -0
  92. echolon-0.3.2/echolon/indicators/optimization/regime_utils.py +230 -0
  93. echolon-0.3.2/echolon/indicators/registry/__init__.py +0 -0
  94. echolon-0.3.2/echolon/indicators/registry/utils.py +146 -0
  95. echolon-0.3.2/echolon/indicators/run_indicators.py +160 -0
  96. echolon-0.3.2/echolon/indicators/utils/__init__.py +1 -0
  97. echolon-0.3.2/echolon/indicators/utils/indicator_loader.py +67 -0
  98. echolon-0.3.2/echolon/indicators/utils/merge_indicators.py +67 -0
  99. echolon-0.3.2/echolon/lib/__init__.py +0 -0
  100. echolon-0.3.2/echolon/lib/json_utils.py +175 -0
  101. echolon-0.3.2/echolon/lib/regime_utils.py +160 -0
  102. echolon-0.3.2/echolon/lib/stats_utils.py +277 -0
  103. echolon-0.3.2/echolon/lib/strategy_log.py +577 -0
  104. echolon-0.3.2/echolon/native/__init__.py +9 -0
  105. echolon-0.3.2/echolon/native/cli/__init__.py +0 -0
  106. echolon-0.3.2/echolon/native/cli/examples.py +46 -0
  107. echolon-0.3.2/echolon/native/cli/init.py +34 -0
  108. echolon-0.3.2/echolon/native/cli/main.py +31 -0
  109. echolon-0.3.2/echolon/native/cli/run.py +55 -0
  110. echolon-0.3.2/echolon/native/cli/schema.py +37 -0
  111. echolon-0.3.2/echolon/native/cli/validate.py +57 -0
  112. echolon-0.3.2/echolon/native/examples_registry.py +18 -0
  113. echolon-0.3.2/echolon/native/validation/__init__.py +30 -0
  114. echolon-0.3.2/echolon/native/validation/errors.py +227 -0
  115. echolon-0.3.2/echolon/native/validation/indicator_validator.py +75 -0
  116. echolon-0.3.2/echolon/native/validation/strategy_validator.py +126 -0
  117. echolon-0.3.2/echolon/quant_engine/LOGGING_DESIGN.md +725 -0
  118. echolon-0.3.2/echolon/quant_engine/__init__.py +27 -0
  119. echolon-0.3.2/echolon/quant_engine/backtest/__init__.py +0 -0
  120. echolon-0.3.2/echolon/quant_engine/backtest/engine/__init__.py +0 -0
  121. echolon-0.3.2/echolon/quant_engine/backtest/engine/analyzers.py +1106 -0
  122. echolon-0.3.2/echolon/quant_engine/backtest/engine/backtest_runner.py +658 -0
  123. echolon-0.3.2/echolon/quant_engine/backtest/engine/backtrader_engine.py +1444 -0
  124. echolon-0.3.2/echolon/quant_engine/backtest/engine/backtrader_strategy.py +479 -0
  125. echolon-0.3.2/echolon/quant_engine/backtest/engine/enriched_pandas_data.py +245 -0
  126. echolon-0.3.2/echolon/quant_engine/backtest/engine/futures/__init__.py +0 -0
  127. echolon-0.3.2/echolon/quant_engine/backtest/engine/futures/enhanced_position.py +187 -0
  128. echolon-0.3.2/echolon/quant_engine/backtest/engine/hooks/__init__.py +0 -0
  129. echolon-0.3.2/echolon/quant_engine/backtest/engine/hooks/base.py +175 -0
  130. echolon-0.3.2/echolon/quant_engine/backtest/engine/hooks/contract_aware/__init__.py +0 -0
  131. echolon-0.3.2/echolon/quant_engine/backtest/engine/hooks/contract_aware/broker.py +583 -0
  132. echolon-0.3.2/echolon/quant_engine/backtest/engine/hooks/contract_aware/hook.py +197 -0
  133. echolon-0.3.2/echolon/quant_engine/backtest/engine/hooks/contract_aware/observer.py +376 -0
  134. echolon-0.3.2/echolon/quant_engine/backtest/engine/hooks/session_aware.py +184 -0
  135. echolon-0.3.2/echolon/quant_engine/backtest/engine/optimization_runner.py +403 -0
  136. echolon-0.3.2/echolon/quant_engine/backtest/optimization/__init__.py +0 -0
  137. echolon-0.3.2/echolon/quant_engine/backtest/optimization/optuna_study.py +585 -0
  138. echolon-0.3.2/echolon/quant_engine/backtest/optimization/select_best_trial.py +476 -0
  139. echolon-0.3.2/echolon/quant_engine/backtest/portfolio_backtest_runner.py +442 -0
  140. echolon-0.3.2/echolon/quant_engine/backtest/portfolio_metrics.py +261 -0
  141. echolon-0.3.2/echolon/quant_engine/backtest/wfa/__init__.py +11 -0
  142. echolon-0.3.2/echolon/quant_engine/backtest/wfa/analyzer.py +173 -0
  143. echolon-0.3.2/echolon/quant_engine/backtest/wfa/drs_calculator.py +755 -0
  144. echolon-0.3.2/echolon/quant_engine/backtest/wfa/runner.py +361 -0
  145. echolon-0.3.2/echolon/quant_engine/backtest/wfa/window.py +48 -0
  146. echolon-0.3.2/echolon/quant_engine/calculate_mfe_mae.py +551 -0
  147. echolon-0.3.2/echolon/quant_engine/core/__init__.py +0 -0
  148. echolon-0.3.2/echolon/quant_engine/core/base/__init__.py +0 -0
  149. echolon-0.3.2/echolon/quant_engine/core/base/base_component.py +861 -0
  150. echolon-0.3.2/echolon/quant_engine/core/base/base_strategy.py +1332 -0
  151. echolon-0.3.2/echolon/quant_engine/core/base/hooks/__init__.py +0 -0
  152. echolon-0.3.2/echolon/quant_engine/core/base/hooks/component_hook_base.py +90 -0
  153. echolon-0.3.2/echolon/quant_engine/core/base/hooks/forced_exit_strategy_hook.py +324 -0
  154. echolon-0.3.2/echolon/quant_engine/core/base/hooks/session_aware_component_hook.py +277 -0
  155. echolon-0.3.2/echolon/quant_engine/core/base/hooks/session_aware_strategy_hook.py +410 -0
  156. echolon-0.3.2/echolon/quant_engine/core/base/hooks/strategy_hook_base.py +152 -0
  157. echolon-0.3.2/echolon/quant_engine/core/base/parameter_architecture.py +280 -0
  158. echolon-0.3.2/echolon/quant_engine/core/base/state_manager.py +280 -0
  159. echolon-0.3.2/echolon/quant_engine/core/frequency/__init__.py +0 -0
  160. echolon-0.3.2/echolon/quant_engine/core/frequency/interday_context.py +88 -0
  161. echolon-0.3.2/echolon/quant_engine/core/frequency/intraday_context.py +159 -0
  162. echolon-0.3.2/echolon/quant_engine/core/frequency/session_context_provider.py +467 -0
  163. echolon-0.3.2/echolon/quant_engine/core/interfaces/__init__.py +0 -0
  164. echolon-0.3.2/echolon/quant_engine/core/interfaces/frequency_context.py +156 -0
  165. echolon-0.3.2/echolon/quant_engine/core/interfaces/market_adapter.py +413 -0
  166. echolon-0.3.2/echolon/quant_engine/core/interfaces/session_context.py +540 -0
  167. echolon-0.3.2/echolon/quant_engine/core/interfaces/trading_interfaces.py +839 -0
  168. echolon-0.3.2/echolon/quant_engine/core/logging/__init__.py +0 -0
  169. echolon-0.3.2/echolon/quant_engine/core/logging/strategy_logger.py +492 -0
  170. echolon-0.3.2/echolon/quant_engine/data_loader/SHFE_loader.py +175 -0
  171. echolon-0.3.2/echolon/quant_engine/data_loader/__init__.py +0 -0
  172. echolon-0.3.2/echolon/quant_engine/data_loader/contract_data.py +397 -0
  173. echolon-0.3.2/echolon/quant_engine/deploy/__init__.py +1 -0
  174. echolon-0.3.2/echolon/quant_engine/deploy/config/__init__.py +1 -0
  175. echolon-0.3.2/echolon/quant_engine/deploy/config/deploy_config.py +157 -0
  176. echolon-0.3.2/echolon/quant_engine/deploy/config/logging_config.py +159 -0
  177. echolon-0.3.2/echolon/quant_engine/deploy/config/portfolio_deploy_config.py +170 -0
  178. echolon-0.3.2/echolon/quant_engine/deploy/config/trading_calendar.csv +366 -0
  179. echolon-0.3.2/echolon/quant_engine/deploy/data_pipeline/__init__.py +12 -0
  180. echolon-0.3.2/echolon/quant_engine/deploy/data_pipeline/trading_util.py +49 -0
  181. echolon-0.3.2/echolon/quant_engine/deploy/engine/__init__.py +9 -0
  182. echolon-0.3.2/echolon/quant_engine/deploy/engine/capital_slot.py +108 -0
  183. echolon-0.3.2/echolon/quant_engine/deploy/engine/dashboard_aggregator.py +397 -0
  184. echolon-0.3.2/echolon/quant_engine/deploy/engine/dashboard_data_generator.py +393 -0
  185. echolon-0.3.2/echolon/quant_engine/deploy/engine/dashboard_data_sender.py +76 -0
  186. echolon-0.3.2/echolon/quant_engine/deploy/engine/portfolio_risk_overlay.py +343 -0
  187. echolon-0.3.2/echolon/quant_engine/deploy/engine/portfolio_trading_runner.py +1384 -0
  188. echolon-0.3.2/echolon/quant_engine/deploy/engine/slot_aware_portfolio.py +348 -0
  189. echolon-0.3.2/echolon/quant_engine/deploy/engine/trading_data_logger.py +384 -0
  190. echolon-0.3.2/echolon/quant_engine/deploy/engine/trading_runner.py +1194 -0
  191. echolon-0.3.2/echolon/quant_engine/deploy/engine/trading_slot.py +474 -0
  192. echolon-0.3.2/echolon/quant_engine/deploy/platforms/__init__.py +1 -0
  193. echolon-0.3.2/echolon/quant_engine/deploy/platforms/ccxt/__init__.py +45 -0
  194. echolon-0.3.2/echolon/quant_engine/deploy/platforms/ccxt/ccxt_client.py +47 -0
  195. echolon-0.3.2/echolon/quant_engine/deploy/platforms/ccxt/ccxt_engine.py +47 -0
  196. echolon-0.3.2/echolon/quant_engine/deploy/platforms/miniqmt/__init__.py +1 -0
  197. echolon-0.3.2/echolon/quant_engine/deploy/platforms/miniqmt/qmt_client.py +1784 -0
  198. echolon-0.3.2/echolon/quant_engine/deploy/platforms/miniqmt/qmt_engine.py +1132 -0
  199. echolon-0.3.2/echolon/quant_engine/deploy/platforms/miniqmt/xtdc_client.py +357 -0
  200. echolon-0.3.2/echolon/quant_engine/engine_factory.py +383 -0
  201. echolon-0.3.2/echolon/quant_engine/logging_utils.py +392 -0
  202. echolon-0.3.2/echolon/quant_engine/market_adapters/__init__.py +0 -0
  203. echolon-0.3.2/echolon/quant_engine/market_adapters/base_adapter.py +398 -0
  204. echolon-0.3.2/echolon/quant_engine/market_adapters/crypto/__init__.py +0 -0
  205. echolon-0.3.2/echolon/quant_engine/market_adapters/crypto/crypto_adapter.py +500 -0
  206. echolon-0.3.2/echolon/quant_engine/market_adapters/crypto/crypto_session_provider.py +169 -0
  207. echolon-0.3.2/echolon/quant_engine/market_adapters/crypto/perpetual_rules.py +264 -0
  208. echolon-0.3.2/echolon/quant_engine/market_adapters/crypto/session_config.py +73 -0
  209. echolon-0.3.2/echolon/quant_engine/market_adapters/shfe/__init__.py +0 -0
  210. echolon-0.3.2/echolon/quant_engine/market_adapters/shfe/contract_rules.py +484 -0
  211. echolon-0.3.2/echolon/quant_engine/market_adapters/shfe/shfe_adapter.py +581 -0
  212. echolon-0.3.2/echolon/quant_engine/market_adapters/shfe/shfe_session_provider.py +328 -0
  213. echolon-0.3.2/echolon/quant_engine/market_adapters/shfe/trading_calendar.py +315 -0
  214. echolon-0.3.2/echolon/quant_engine/market_adapters/us_futures/__init__.py +0 -0
  215. echolon-0.3.2/echolon/quant_engine/market_adapters/us_futures/cme_adapter.py +33 -0
  216. echolon-0.3.2/echolon/quant_engine/market_adapters/us_futures/session_config.py +33 -0
  217. echolon-0.3.2/echolon/quant_engine/reporting.py +319 -0
  218. echolon-0.3.2/echolon/quant_engine/run_backtest.py +279 -0
  219. echolon-0.3.2/echolon/quant_engine/schemas/README.md +376 -0
  220. echolon-0.3.2/echolon/quant_engine/schemas/__init__.py +0 -0
  221. echolon-0.3.2/echolon/quant_engine/schemas/backtest_results.py +364 -0
  222. echolon-0.3.2/echolon/quant_engine/schemas/selected_trial.py +132 -0
  223. echolon-0.3.2/echolon/quant_engine/schemas/strategy_log.py +283 -0
  224. echolon-0.3.2/echolon/quant_engine/schemas/trade_log.py +370 -0
  225. echolon-0.3.2/echolon/quant_engine/strategy/__init__.py +0 -0
  226. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/__init__.py +0 -0
  227. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/entry.py +277 -0
  228. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/exit.py +390 -0
  229. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/regime_params.json +40 -0
  230. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/risk.py +217 -0
  231. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/selected_robust_trial.json +350 -0
  232. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/sizer.py +300 -0
  233. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/strategy.py +176 -0
  234. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/strategy_code_combined.py +2746 -0
  235. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/strategy_indicator_list.json +17 -0
  236. echolon-0.3.2/echolon/quant_engine/strategy/al_s1/strategy_params.py +622 -0
  237. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/__init__.py +0 -0
  238. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/entry.py +362 -0
  239. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/exit.py +487 -0
  240. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/regime_params.json +40 -0
  241. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/risk.py +213 -0
  242. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/selected_robust_trial.json +388 -0
  243. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/sizer.py +199 -0
  244. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/strategy.py +326 -0
  245. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/strategy_code_combined.py +3018 -0
  246. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/strategy_indicator_list.json +18 -0
  247. echolon-0.3.2/echolon/quant_engine/strategy/cu_s1/strategy_params.py +590 -0
  248. echolon-0.3.2/echolon/quant_engine/strategy/generators/__init__.py +0 -0
  249. echolon-0.3.2/echolon/quant_engine/strategy/generators/strategy_params_generator.py +1171 -0
  250. echolon-0.3.2/echolon/quant_engine/strategy/loader.py +130 -0
  251. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/__init__.py +0 -0
  252. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/entry.py +324 -0
  253. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/exit.py +398 -0
  254. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/regime_params.json +40 -0
  255. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/risk.py +404 -0
  256. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/selected_robust_trial.json +295 -0
  257. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/sizer.py +195 -0
  258. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/strategy.py +210 -0
  259. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/strategy_code_combined.py +2673 -0
  260. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/strategy_indicator_list.json +17 -0
  261. echolon-0.3.2/echolon/quant_engine/strategy/zn_s1/strategy_params.py +488 -0
  262. echolon-0.3.2/echolon/quant_engine/types.py +599 -0
  263. echolon-0.3.2/examples/01_minimal/README.md +30 -0
  264. echolon-0.3.2/examples/01_minimal/entry.py +19 -0
  265. echolon-0.3.2/examples/01_minimal/exit.py +24 -0
  266. echolon-0.3.2/examples/01_minimal/risk.py +12 -0
  267. echolon-0.3.2/examples/01_minimal/sizer.py +16 -0
  268. echolon-0.3.2/examples/01_minimal/strategy.py +24 -0
  269. echolon-0.3.2/examples/01_minimal/strategy_indicator_list.json +1 -0
  270. echolon-0.3.2/examples/01_minimal/strategy_params.py +26 -0
  271. echolon-0.3.2/examples/02_momentum_breakout/README.md +37 -0
  272. echolon-0.3.2/examples/02_momentum_breakout/entry.py +29 -0
  273. echolon-0.3.2/examples/02_momentum_breakout/exit.py +39 -0
  274. echolon-0.3.2/examples/02_momentum_breakout/risk.py +12 -0
  275. echolon-0.3.2/examples/02_momentum_breakout/sizer.py +16 -0
  276. echolon-0.3.2/examples/02_momentum_breakout/strategy.py +24 -0
  277. echolon-0.3.2/examples/02_momentum_breakout/strategy_indicator_list.json +1 -0
  278. echolon-0.3.2/examples/02_momentum_breakout/strategy_params.py +27 -0
  279. echolon-0.3.2/examples/03_rsi_mean_reversion/README.md +37 -0
  280. echolon-0.3.2/examples/03_rsi_mean_reversion/entry.py +29 -0
  281. echolon-0.3.2/examples/03_rsi_mean_reversion/exit.py +39 -0
  282. echolon-0.3.2/examples/03_rsi_mean_reversion/risk.py +12 -0
  283. echolon-0.3.2/examples/03_rsi_mean_reversion/sizer.py +16 -0
  284. echolon-0.3.2/examples/03_rsi_mean_reversion/strategy.py +24 -0
  285. echolon-0.3.2/examples/03_rsi_mean_reversion/strategy_indicator_list.json +1 -0
  286. echolon-0.3.2/examples/03_rsi_mean_reversion/strategy_params.py +30 -0
  287. echolon-0.3.2/llms.txt +37 -0
  288. {echolon-0.3.0 → echolon-0.3.2}/pyproject.toml +2 -5
  289. echolon-0.3.2/tests/__init__.py +0 -0
  290. echolon-0.3.2/tests/native/__init__.py +0 -0
  291. echolon-0.3.2/tests/native/test_ai_native_smoke.py +105 -0
  292. echolon-0.3.2/tests/native/test_cli_examples.py +30 -0
  293. echolon-0.3.2/tests/native/test_cli_init.py +57 -0
  294. echolon-0.3.2/tests/native/test_cli_run.py +41 -0
  295. echolon-0.3.2/tests/native/test_cli_schema.py +37 -0
  296. echolon-0.3.2/tests/native/test_cli_validate.py +113 -0
  297. echolon-0.3.2/tests/native/test_errors.py +140 -0
  298. echolon-0.3.2/tests/native/test_indicator_validator.py +57 -0
  299. echolon-0.3.2/tests/native/test_strategy_validator.py +149 -0
  300. echolon-0.3.2/tests/test_backtest_config.py +92 -0
  301. echolon-0.3.2/tests/test_imports.py +63 -0
  302. echolon-0.3.2/tests/test_indicator_config.py +29 -0
  303. echolon-0.3.2/tests/test_market_adapters.py +251 -0
  304. echolon-0.3.2/tests/test_optuna_config.py +42 -0
  305. echolon-0.3.2/tests/test_optuna_optimizer_config.py +8 -0
  306. echolon-0.3.2/tests/test_quick_start.py +45 -0
  307. echolon-0.3.2/tests/test_strategy_loader.py +88 -0
  308. echolon-0.3.2/tests/test_trading_context.py +16 -0
  309. {echolon-0.3.0 → echolon-0.3.2}/.gitignore +0 -0
  310. {echolon-0.3.0 → echolon-0.3.2}/LICENSE +0 -0
  311. {echolon-0.3.0 → echolon-0.3.2}/README.md +0 -0
  312. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/__init__.py +0 -0
  313. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/minimal/README.md +0 -0
  314. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/minimal/entry.py +0 -0
  315. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/minimal/exit.py +0 -0
  316. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/minimal/risk.py +0 -0
  317. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/minimal/sizer.py +0 -0
  318. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/minimal/strategy.py +0 -0
  319. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/minimal/strategy_indicator_list.json +0 -0
  320. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/minimal/strategy_params.py +0 -0
  321. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/momentum_breakout/README.md +0 -0
  322. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/momentum_breakout/entry.py +0 -0
  323. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/momentum_breakout/exit.py +0 -0
  324. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/momentum_breakout/risk.py +0 -0
  325. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/momentum_breakout/sizer.py +0 -0
  326. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/momentum_breakout/strategy.py +0 -0
  327. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/momentum_breakout/strategy_indicator_list.json +0 -0
  328. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/momentum_breakout/strategy_params.py +0 -0
  329. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/rsi_mean_reversion/README.md +0 -0
  330. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/rsi_mean_reversion/entry.py +0 -0
  331. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/rsi_mean_reversion/exit.py +0 -0
  332. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/rsi_mean_reversion/risk.py +0 -0
  333. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/rsi_mean_reversion/sizer.py +0 -0
  334. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/rsi_mean_reversion/strategy.py +0 -0
  335. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/rsi_mean_reversion/strategy_indicator_list.json +0 -0
  336. {echolon-0.3.0 → echolon-0.3.2}/echolon/native/templates/rsi_mean_reversion/strategy_params.py +0 -0
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 — AI-Native Layer (unreleased)
4
+
5
+ ### Added
6
+ - `echolon.native` subpackage with error system, validators, CLI, and templates
7
+ - `EchelonError` class hierarchy with 13 initial error codes
8
+ - `echolon` CLI with 5 commands: `validate`, `init-strategy`, `run`, `schema`, `examples`
9
+ - 3 strategy templates: `minimal`, `momentum_breakout`, `rsi_mean_reversion`
10
+ - 3 working examples at `examples/`
11
+ - `llms.txt` at repo root (AI agent entry point)
12
+ - `docs/` directory with QUICK_START, API_REFERENCE, COMPONENT_GUIDE, CONFIG_REFERENCE, PATTERNS, ERROR_CATALOG, and per-error docs
13
+
14
+ ### Changed
15
+ - Added `typer>=0.9.0` as a dependency for the CLI
16
+
17
+ ## 0.2.0 — Config Interface
18
+
19
+ ### Breaking Changes
20
+ - BacktestRunner, OptunaOptimizer, WFARunner, and PortfolioBacktestRunner now require explicit configs
21
+ - Removed module-level globals from `echolon.config.quant_engine`
22
+
23
+ ### Added
24
+ - BacktestConfig, OptunaConfig, IndicatorConfig Pydantic models
25
+ - `TradingContext.from_market()` classmethod
26
+ - `echolon.quick_start()` convenience helper
27
+
28
+ ## 0.1.0 — Initial Release
29
+
30
+ Initial extraction from DolphinQuantStrategy monorepo.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: echolon
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: See what others can't. Market-agnostic quantitative trading engine for futures backtesting, optimization, and deployment.
5
5
  Project-URL: Homepage, https://github.com/dolphinquant/echolon
6
6
  Project-URL: Repository, https://github.com/dolphinquant/echolon
@@ -0,0 +1,188 @@
1
+ # API Reference
2
+
3
+ All public Echolon classes and their signatures.
4
+
5
+ ## BacktestConfig
6
+
7
+ **Module:** `echolon.config.backtest_config`
8
+
9
+ **Purpose:** Configuration for a single backtest run — dates, paths, thresholds.
10
+
11
+ **Signature:**
12
+
13
+ ```python
14
+ BacktestConfig(
15
+ start_date: str, # "YYYY-MM-DD"
16
+ end_date: str, # "YYYY-MM-DD"
17
+ strategy_dir: Path,
18
+ market_data_dir: Path,
19
+ indicator_dir: Path,
20
+ results_dir: Path,
21
+ max_drawdown_pct: float = 15.0,
22
+ is_end_date: Optional[str] = None,
23
+ oos_start_date: Optional[str] = None,
24
+ market_research_end_date: Optional[str] = None,
25
+ )
26
+ ```
27
+
28
+ **Example:**
29
+
30
+ ```python
31
+ from echolon import BacktestConfig
32
+ from pathlib import Path
33
+
34
+ cfg = BacktestConfig(
35
+ start_date="2020-01-01",
36
+ end_date="2023-12-31",
37
+ strategy_dir=Path("./my_strategy"),
38
+ market_data_dir=Path("./data/market"),
39
+ indicator_dir=Path("./data/indicators"),
40
+ results_dir=Path("./results"),
41
+ )
42
+ ```
43
+
44
+ **Common errors:** CFG-001, CFG-002.
45
+
46
+ ## OptunaConfig
47
+
48
+ **Module:** `echolon.config.optuna_config`
49
+
50
+ **Purpose:** Optuna hyperparameter optimization settings.
51
+
52
+ **Signature:**
53
+
54
+ ```python
55
+ OptunaConfig(
56
+ n_trials: int = 100,
57
+ n_jobs: int = -1,
58
+ timeout: Optional[int] = None,
59
+ target: Literal["sharpe_ratio", "total_return", "annual_return", "drawdown", "multi_objective"] = "sharpe_ratio",
60
+ n_trials_debug: int = 20,
61
+ aggressive_memory_management: bool = False,
62
+ enhanced_monitoring: bool = True,
63
+ )
64
+ ```
65
+
66
+ ## IndicatorConfig
67
+
68
+ **Module:** `echolon.config.indicator_config`
69
+
70
+ **Purpose:** Technical indicator period caps (most users never override).
71
+
72
+ **Signature:**
73
+
74
+ ```python
75
+ IndicatorConfig(
76
+ interday_caps: dict[str, int],
77
+ intraday_caps: dict[str, int],
78
+ )
79
+ ```
80
+
81
+ ## TradingContext
82
+
83
+ **Module:** `echolon.config.markets.core.context`
84
+
85
+ **Purpose:** Market + instrument + frequency runtime context.
86
+
87
+ **Classmethod:**
88
+
89
+ ```python
90
+ TradingContext.from_market(
91
+ market: str, # e.g., "shfe"
92
+ instrument: str, # e.g., "cu"
93
+ frequency: str = "interday",
94
+ bar_size: str = "1d",
95
+ ) -> TradingContext
96
+ ```
97
+
98
+ ## quick_start()
99
+
100
+ **Module:** `echolon`
101
+
102
+ **Purpose:** Build sensible default configs for common cases.
103
+
104
+ ```python
105
+ from echolon import quick_start
106
+
107
+ ctx, bt, opt = quick_start(
108
+ market="shfe",
109
+ instrument="cu",
110
+ start_date="2020-01-01",
111
+ end_date="2023-12-31",
112
+ )
113
+ ```
114
+
115
+ ## EntrySignalOutput
116
+
117
+ **Module:** `echolon.quant_engine.types`
118
+
119
+ **Returned by:** `entry_rule.generate_signal()`
120
+
121
+ **Required fields:**
122
+ - `signal: Literal['LONG', 'SHORT', 'HOLD']`
123
+ - `strength: float` (0.0 to 1.0)
124
+ - `type: str`
125
+ - `entry_reason: str`
126
+ - `regime: str`
127
+
128
+ **Optional:**
129
+ - `intent: Optional[OrderIntent]` — required for non-HOLD signals
130
+
131
+ **Common errors:** VAL-001, VAL-002.
132
+
133
+ ## ExitSignalOutput
134
+
135
+ **Returned by:** `exit_rule.should_exit()`
136
+
137
+ **Required fields:**
138
+ - `should_exit: bool`
139
+ - `exit_reason: str`
140
+ - `position_size: float` (≥ 0)
141
+ - `bars_since_entry: int` (≥ 0)
142
+
143
+ **Optional:**
144
+ - `intent: Optional[OrderIntent]` — required when `should_exit=True`
145
+
146
+ ## RiskOutput
147
+
148
+ **Returned by:** `risk_manager.can_trade()`
149
+
150
+ **Required fields:**
151
+ - `trading_allowed: bool`
152
+ - `risk_reason: str`
153
+
154
+ ## SizerOutput
155
+
156
+ **Returned by:** `position_sizer.calculate_size(signal_data)`
157
+
158
+ **Required fields:**
159
+ - `calculated_size: int` (≥ 0, whole contracts)
160
+ - `signal_direction: Literal['LONG', 'SHORT', 'HOLD']`
161
+ - `sizing_reason: str`
162
+ - `raw_size: float` (≥ 0)
163
+
164
+ ## OrderIntent (enum)
165
+
166
+ **Module:** `echolon.quant_engine.core.interfaces.trading_interfaces`
167
+
168
+ **Values:**
169
+ - `ENTRY_LONG`, `ENTRY_SHORT`
170
+ - `EXIT_LONG`, `EXIT_SHORT`
171
+ - `FORCED_EXIT`
172
+ - `ROLLOVER_CLOSE`, `ROLLOVER_OPEN`
173
+
174
+ ## EchelonError
175
+
176
+ **Module:** `echolon` (top-level) or `echolon.native.validation.errors`
177
+
178
+ **Base class** for all Echolon validation errors. Every error has `code`, `what`, `why`, `fix`, `context`, `docs_url`.
179
+
180
+ **Subclasses:**
181
+ - `ValidationError` (VAL-xxx)
182
+ - `ConfigError` (CFG-xxx)
183
+ - `StrategyStructureError` (STR-xxx)
184
+ - `IndicatorError` (IND-xxx)
185
+ - `ParameterError` (PRM-xxx)
186
+ - `DataError` (DAT-xxx)
187
+
188
+ See [ERROR_CATALOG.md](ERROR_CATALOG.md).
@@ -0,0 +1,115 @@
1
+ # Component Guide
2
+
3
+ Every Echolon strategy has 4 components. This guide explains each one.
4
+
5
+ ## entry_rule (entry.py)
6
+
7
+ **Class name:** `entry_rule` (exact — required by StrategyLoader)
8
+ **Base:** `BaseComponent`
9
+ **Method:** `generate_signal() -> EntrySignalOutput`
10
+
11
+ Called every bar when there is no open position and no pending orders.
12
+
13
+ **Example:**
14
+
15
+ ```python
16
+ from echolon.quant_engine.core.base.base_component import BaseComponent
17
+ from echolon.quant_engine.core.interfaces.trading_interfaces import OrderIntent
18
+ from echolon.quant_engine.types import EntrySignalOutput
19
+
20
+
21
+ class entry_rule(BaseComponent):
22
+ def __init__(self, trading_engine, **params):
23
+ super().__init__(trading_engine, **params)
24
+ self.rsi_period = self.params["rsi_period"]
25
+
26
+ def generate_signal(self) -> EntrySignalOutput:
27
+ rsi = self.get_indicator(f"rsi_{self.rsi_period}")
28
+ regime = self.get_market_regime()
29
+ if rsi < 30:
30
+ return EntrySignalOutput(
31
+ signal="LONG", strength=1.0,
32
+ type="oversold_entry",
33
+ entry_reason=f"RSI({self.rsi_period})={rsi} < 30",
34
+ intent=OrderIntent.ENTRY_LONG,
35
+ regime=regime,
36
+ )
37
+ return EntrySignalOutput(
38
+ signal="HOLD", strength=0.0, type="hold",
39
+ entry_reason="Not oversold", regime=regime,
40
+ )
41
+ ```
42
+
43
+ **Common errors:**
44
+ - VAL-001: missing required field
45
+ - VAL-003: wrong __init__ signature
46
+ - IND-001: uppercase indicator name
47
+
48
+ ## exit_rule (exit.py)
49
+
50
+ **Class name:** `exit_rule`
51
+ **Base:** `BaseComponent`
52
+ **Method:** `should_exit() -> ExitSignalOutput`
53
+
54
+ Called every bar when there is an open position.
55
+
56
+ Stateful exit rules (trailing stops, bars-held counters) must reset their state when there is no position. See the minimal template's `exit.py`.
57
+
58
+ ## risk_manager (risk.py)
59
+
60
+ **Class name:** `risk_manager`
61
+ **Base:** `BaseComponent`
62
+ **Method:** `can_trade() -> RiskOutput`
63
+
64
+ Called at the start of every bar. Returns `trading_allowed=True` to permit trading, `False` to block all new entries.
65
+
66
+ Use cases: max daily loss, max consecutive losses, trading-hours filter.
67
+
68
+ ## position_sizer (sizer.py)
69
+
70
+ **Class name:** `position_sizer`
71
+ **Base:** `BaseComponent`
72
+ **Method:** `calculate_size(signal_data: EntrySignalOutput) -> SizerOutput`
73
+
74
+ Called after `entry_rule.generate_signal()` produces a non-HOLD signal. Receives the signal (so sizer can branch on regime, strength, etc.).
75
+
76
+ The sizer MUST call `self.validate_and_convert_position_size(raw_float)` before setting `calculated_size` — this rounds to whole contracts and handles edge cases.
77
+
78
+ ## Data access helpers
79
+
80
+ All components inherit these helpers from `BaseComponent`:
81
+
82
+ - `self.get_current_price() -> float` — close of current bar
83
+ - `self.get_indicator(name: str) -> float` — value of pre-computed indicator (use lowercase names!)
84
+ - `self.get_market_regime() -> str` — one of: `ranging`, `trending_up`, `trending_down`, `volatile`
85
+ - `self.params: dict` — parameters from strategy_params.py
86
+ - `self.portfolio: IPortfolio` — access position info
87
+ - `self.validate_and_convert_position_size(float) -> int` — sizer helper
88
+
89
+ ## Strategy coordinator (strategy.py)
90
+
91
+ **Class name:** `strategy_main`
92
+ **Base:** `BaseStrategy`
93
+ **Method:** `_execute_bar() -> None` (not `on_bar`)
94
+
95
+ The canonical pattern:
96
+
97
+ ```python
98
+ def _execute_bar(self) -> None:
99
+ risk_out = self.risk_manager.can_trade()
100
+ if not risk_out.trading_allowed:
101
+ return
102
+ if self.has_position() and not self.has_pending_orders():
103
+ exit_out = self.exit_rule.should_exit()
104
+ if exit_out.should_exit and exit_out.intent is not None:
105
+ self.exit(exit_out.intent)
106
+ return
107
+ if not self.has_position() and not self.has_pending_orders():
108
+ entry_out = self.entry_rule.generate_signal()
109
+ if entry_out.signal != "HOLD" and entry_out.intent is not None:
110
+ sizer_out = self.position_sizer.calculate_size(entry_out)
111
+ if sizer_out.calculated_size > 0:
112
+ self.entry(entry_out.intent, sizer_out.calculated_size)
113
+ ```
114
+
115
+ Every bundled template uses this exact pattern. Only customize if your strategy truly needs a different structure.
@@ -0,0 +1,68 @@
1
+ # Configuration Reference
2
+
3
+ Echolon uses Pydantic v2 models for all configuration. Each config class is a typed object — IDEs and LLMs can introspect it.
4
+
5
+ ## BacktestConfig
6
+
7
+ See [API_REFERENCE.md#backtestconfig](API_REFERENCE.md#backtestconfig).
8
+
9
+ Common mistakes:
10
+ - `end_date` before `start_date` → CFG-001
11
+ - Missing directory path → CFG-002
12
+
13
+ ## OptunaConfig
14
+
15
+ See [API_REFERENCE.md#optunaconfig](API_REFERENCE.md#optunaconfig).
16
+
17
+ The `target` field accepts:
18
+ - `"sharpe_ratio"` — maximize risk-adjusted return (default)
19
+ - `"total_return"` — maximize absolute return
20
+ - `"annual_return"` — maximize annualized return
21
+ - `"drawdown"` — minimize max drawdown
22
+ - `"multi_objective"` — Pareto frontier over Sharpe + drawdown
23
+
24
+ ## TradingContext
25
+
26
+ Runtime context: market, instrument, frequency, bar size.
27
+
28
+ ```python
29
+ from echolon import TradingContext
30
+
31
+ ctx = TradingContext.from_market(
32
+ market="shfe",
33
+ instrument="cu",
34
+ frequency="interday",
35
+ bar_size="1d",
36
+ )
37
+ ```
38
+
39
+ ## Environment Variables
40
+
41
+ | Variable | Default | Purpose |
42
+ |----------|---------|---------|
43
+ | `ECHOLON_WORKSPACE_DIR` | `./workspace` | Workspace root |
44
+ | `ECHOLON_DATA_DIR` | `./data` | Market data + indicators |
45
+ | `ECHOLON_LOG_LEVEL` | `INFO` | Logging verbosity |
46
+ | `ECHOLON_N_JOBS_DEFAULT` | `-1` | Default Optuna parallelism |
47
+
48
+ Set via shell export, `.env` file, or Docker env config.
49
+
50
+ ## quick_start()
51
+
52
+ For common cases, use the convenience helper:
53
+
54
+ ```python
55
+ from echolon import quick_start
56
+
57
+ ctx, bt, opt = quick_start(
58
+ market="shfe",
59
+ instrument="cu",
60
+ start_date="2020-01-01",
61
+ end_date="2023-12-31",
62
+ )
63
+ # Override anything
64
+ opt.n_trials = 500
65
+ bt.max_drawdown_pct = 20.0
66
+ ```
67
+
68
+ `quick_start` uses env vars for paths with fallbacks to `./workspace` and `./data`.
@@ -0,0 +1,19 @@
1
+ # Error Catalog
2
+
3
+ All Echolon errors use stable codes. Click any code for the full fix guide.
4
+
5
+ | Code | Category | What went wrong |
6
+ |------|----------|-----------------|
7
+ | [VAL-001](errors/VAL-001.md) | Validation | Missing required field in component output |
8
+ | [VAL-002](errors/VAL-002.md) | Validation | Invalid enum value in signal field |
9
+ | [VAL-003](errors/VAL-003.md) | Validation | Component class signature mismatch |
10
+ | [CFG-001](errors/CFG-001.md) | Config | end_date before start_date |
11
+ | [CFG-002](errors/CFG-002.md) | Config | Required directory does not exist |
12
+ | [STR-001](errors/STR-001.md) | Structure | Strategy directory missing required file |
13
+ | [STR-002](errors/STR-002.md) | Structure | Required class not found in file |
14
+ | [STR-003](errors/STR-003.md) | Structure | Required method not implemented |
15
+ | [IND-001](errors/IND-001.md) | Indicator | Indicator name casing mismatch |
16
+ | [IND-002](errors/IND-002.md) | Indicator | Indicator not declared in JSON |
17
+ | [PRM-001](errors/PRM-001.md) | Parameter | Missing 'printlog' key in component params |
18
+ | [PRM-002](errors/PRM-002.md) | Parameter | DEFAULT_PARAMS structure mismatch |
19
+ | [DAT-001](errors/DAT-001.md) | Data | Missing OHLCV file |
@@ -0,0 +1,185 @@
1
+ # Patterns
2
+
3
+ Canonical strategy patterns in Echolon. Each pattern includes when to use it, the core idea, files to customize, and common errors.
4
+
5
+ ## Indicator Naming Rules
6
+
7
+ 1. **Column names are always lowercase.** `ATR` in JSON → `atr_14`, `atr_15`, ... in code.
8
+ 2. **Use `self.get_indicator('lowercase_name')`.** Uppercase causes silent `KeyError` or `NaN`.
9
+ 3. **Declare every indicator in `strategy_indicator_list.json`.** Undeclared indicators aren't pre-computed.
10
+ 4. **System indicators** (`market_regime`, `session_phase`) go in `indicators_with_special_params`.
11
+
12
+ See [IND-001](errors/IND-001.md) for the casing-mismatch error.
13
+
14
+ ## 1. Trend Breakout
15
+
16
+ **When to use:** Strong trending markets; instruments with persistent momentum (index futures, commodities in backwardation).
17
+
18
+ **Key idea:** Enter when price breaks above an N-day rolling high (or below an N-day rolling low for shorts). Exit on a trailing-low stop or opposite-direction break.
19
+
20
+ **Files to customize:**
21
+ - `entry.py` — compare `self.get_current_price()` to `self.get_indicator('high_20')` (or similar)
22
+ - `exit.py` — track highest-close-since-entry, exit on pullback
23
+ - `strategy_indicator_list.json` — declare `rolling_high`, `rolling_low`, `atr`
24
+
25
+ **Sketch:**
26
+
27
+ ```python
28
+ def generate_signal(self) -> EntrySignalOutput:
29
+ price = self.get_current_price()
30
+ upper = self.get_indicator(f"rolling_high_{self.lookback}")
31
+ regime = self.get_market_regime()
32
+ if price > upper:
33
+ return EntrySignalOutput(
34
+ signal="LONG", strength=1.0, type="breakout",
35
+ entry_reason=f"Close {price} > {self.lookback}d high {upper}",
36
+ intent=OrderIntent.ENTRY_LONG, regime=regime,
37
+ )
38
+ return EntrySignalOutput(signal="HOLD", strength=0.0, type="hold",
39
+ entry_reason="No breakout", regime=regime)
40
+ ```
41
+
42
+ **Common errors:** IND-001 (uppercase `ROLLING_HIGH`), VAL-001 (missing `regime`).
43
+
44
+ ## 2. Mean Reversion
45
+
46
+ **When to use:** Range-bound markets; instruments that oscillate around a mean (pairs, yield curve spreads, some FX crosses).
47
+
48
+ **Key idea:** Enter when an oscillator crosses an oversold/overbought threshold. Exit when it reverts to neutral.
49
+
50
+ **Files to customize:**
51
+ - `entry.py` — check `self.get_indicator(f"rsi_{period}")` < 30 (oversold)
52
+ - `exit.py` — exit when RSI > 50 or a bars-held cap is reached
53
+ - `strategy_indicator_list.json` — declare `rsi` at your chosen period
54
+
55
+ **Sketch:**
56
+
57
+ ```python
58
+ def generate_signal(self) -> EntrySignalOutput:
59
+ rsi = self.get_indicator(f"rsi_{self.rsi_period}")
60
+ regime = self.get_market_regime()
61
+ if rsi < self.oversold_threshold:
62
+ return EntrySignalOutput(
63
+ signal="LONG", strength=1.0, type="oversold",
64
+ entry_reason=f"RSI={rsi} below {self.oversold_threshold}",
65
+ intent=OrderIntent.ENTRY_LONG, regime=regime,
66
+ )
67
+ return EntrySignalOutput(signal="HOLD", strength=0.0, type="hold",
68
+ entry_reason="Not oversold", regime=regime)
69
+ ```
70
+
71
+ **Common errors:** PRM-001 (missing `printlog` in `entry_params`), VAL-002 (using `BUY` instead of `LONG`).
72
+
73
+ ## 3. Regime-Switching
74
+
75
+ **When to use:** Strategies that must behave differently based on market condition — e.g., momentum in trending regimes, mean reversion in ranging.
76
+
77
+ **Key idea:** Branch the entry/exit logic on `self.get_market_regime()`. The system regime indicator classifies bars as `trending_up`, `trending_down`, `ranging`, or `volatile`.
78
+
79
+ **Files to customize:**
80
+ - `entry.py` — outer `if regime == "trending_up"` branches
81
+ - `strategy_indicator_list.json` — add `market_regime` to `indicators_with_special_params`
82
+ - `strategy_params.py` — define per-regime thresholds (e.g., `trend_threshold`, `range_threshold`)
83
+
84
+ **Sketch:**
85
+
86
+ ```python
87
+ def generate_signal(self) -> EntrySignalOutput:
88
+ regime = self.get_market_regime()
89
+ price = self.get_current_price()
90
+ if regime == "trending_up":
91
+ upper = self.get_indicator(f"rolling_high_{self.trend_lookback}")
92
+ if price > upper:
93
+ return EntrySignalOutput(
94
+ signal="LONG", strength=1.0, type="trend_break",
95
+ entry_reason="Trending regime breakout",
96
+ intent=OrderIntent.ENTRY_LONG, regime=regime,
97
+ )
98
+ elif regime == "ranging":
99
+ rsi = self.get_indicator(f"rsi_{self.rsi_period}")
100
+ if rsi < 30:
101
+ return EntrySignalOutput(
102
+ signal="LONG", strength=1.0, type="range_revert",
103
+ entry_reason="Range oversold",
104
+ intent=OrderIntent.ENTRY_LONG, regime=regime,
105
+ )
106
+ return EntrySignalOutput(signal="HOLD", strength=0.0, type="hold",
107
+ entry_reason=f"No signal in {regime}", regime=regime)
108
+ ```
109
+
110
+ **Common errors:** IND-002 (forgetting to declare `market_regime` in JSON), VAL-001 (missing `regime` in HOLD branch).
111
+
112
+ ## 4. Multi-Timeframe
113
+
114
+ **When to use:** Intraday execution informed by a higher-timeframe bias (e.g., take long signals only when daily EMA is rising).
115
+
116
+ **Key idea:** Pre-compute the higher-timeframe indicator at daily frequency, then expose its last value to each intraday bar via the indicator pipeline. The strategy code sees a single indicator column; resampling is done upstream.
117
+
118
+ **Files to customize:**
119
+ - `strategy_indicator_list.json` — add a daily-resampled indicator like `ema_daily_50`
120
+ - `entry.py` — gate signals on the daily indicator before checking intraday triggers
121
+
122
+ **Sketch:**
123
+
124
+ ```python
125
+ def generate_signal(self) -> EntrySignalOutput:
126
+ daily_ema = self.get_indicator("ema_daily_50")
127
+ intraday_ema = self.get_indicator(f"ema_{self.fast_period}")
128
+ price = self.get_current_price()
129
+ regime = self.get_market_regime()
130
+ long_bias = price > daily_ema
131
+ if long_bias and price > intraday_ema:
132
+ return EntrySignalOutput(
133
+ signal="LONG", strength=1.0, type="mtf_pullback",
134
+ entry_reason="Above daily EMA and intraday EMA",
135
+ intent=OrderIntent.ENTRY_LONG, regime=regime,
136
+ )
137
+ return EntrySignalOutput(signal="HOLD", strength=0.0, type="hold",
138
+ entry_reason="No MTF alignment", regime=regime)
139
+ ```
140
+
141
+ **Common errors:** IND-002 (daily indicator not declared), DAT-001 (daily data file missing).
142
+
143
+ ## 5. ML Signal
144
+
145
+ **When to use:** You have a trained model (scikit-learn, XGBoost, small PyTorch) that outputs a directional score from a fixed feature vector.
146
+
147
+ **Key idea:** Load the pickled model once in `__init__`. In `generate_signal()`, build the feature vector from `self.get_indicator(...)` calls, call `model.predict_proba`, and threshold the output.
148
+
149
+ **Files to customize:**
150
+ - `entry.py` — `__init__` loads the model; `generate_signal` builds features and predicts
151
+ - `strategy_indicator_list.json` — declare every feature the model expects
152
+ - `strategy_params.py` — expose the probability threshold as a tunable parameter
153
+
154
+ **Sketch:**
155
+
156
+ ```python
157
+ import joblib
158
+ import numpy as np
159
+ from pathlib import Path
160
+
161
+ class entry_rule(BaseComponent):
162
+ def __init__(self, trading_engine, **params):
163
+ super().__init__(trading_engine, **params)
164
+ self.model = joblib.load(Path(self.params["model_path"]))
165
+ self.prob_threshold = self.params["prob_threshold"]
166
+
167
+ def generate_signal(self) -> EntrySignalOutput:
168
+ regime = self.get_market_regime()
169
+ features = np.array([[
170
+ self.get_indicator("rsi_14"),
171
+ self.get_indicator("atr_14"),
172
+ self.get_indicator("ema_20"),
173
+ ]])
174
+ prob_long = float(self.model.predict_proba(features)[0, 1])
175
+ if prob_long > self.prob_threshold:
176
+ return EntrySignalOutput(
177
+ signal="LONG", strength=prob_long, type="ml_long",
178
+ entry_reason=f"p(long)={prob_long:.3f}",
179
+ intent=OrderIntent.ENTRY_LONG, regime=regime,
180
+ )
181
+ return EntrySignalOutput(signal="HOLD", strength=0.0, type="hold",
182
+ entry_reason="Below threshold", regime=regime)
183
+ ```
184
+
185
+ **Common errors:** DAT-001 (model file missing), IND-002 (feature indicator not declared), PRM-002 (`model_path` missing from `entry_params`).
@@ -0,0 +1,50 @@
1
+ # Quick Start
2
+
3
+ Install Echolon, create a minimal strategy, run your first backtest.
4
+
5
+ ## 1. Install
6
+
7
+ ```bash
8
+ pip install echolon
9
+ ```
10
+
11
+ ## 2. Create a strategy
12
+
13
+ ```bash
14
+ echolon init-strategy my_first --template minimal
15
+ ```
16
+
17
+ This creates `./my_first/` with 7 files:
18
+ - `strategy.py` — strategy coordinator
19
+ - `entry.py`, `exit.py`, `risk.py`, `sizer.py` — component files
20
+ - `strategy_params.py` — parameter definitions
21
+ - `strategy_indicator_list.json` — which indicators to compute
22
+ - `README.md` — template notes
23
+
24
+ ## 3. Validate it
25
+
26
+ ```bash
27
+ echolon validate my_first/
28
+ ```
29
+
30
+ Should print: `✓ Strategy directory is valid.`
31
+
32
+ ## 4. Customize `entry.py`
33
+
34
+ Open `my_first/entry.py` and replace the HOLD-forever logic with your signal.
35
+
36
+ ## 5. Run backtest
37
+
38
+ ```bash
39
+ echolon run my_first/ --instrument cu --start 2020-01-01 --end 2023-12-31
40
+ ```
41
+
42
+ ## If you hit an error
43
+
44
+ Every error includes a code like `[VAL-001]`. Look it up in [ERROR_CATALOG.md](ERROR_CATALOG.md) or at `https://echolon.dev/docs/errors/{code}`.
45
+
46
+ ## Next Steps
47
+
48
+ - Read [COMPONENT_GUIDE.md](COMPONENT_GUIDE.md) to understand each component
49
+ - Browse [PATTERNS.md](PATTERNS.md) for canonical strategy shapes
50
+ - See [CONFIG_REFERENCE.md](CONFIG_REFERENCE.md) for full configuration options