echolon 0.1.0__py3-none-any.whl

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 (444) hide show
  1. echolon/__init__.py +3 -0
  2. echolon/config/__init__.py +0 -0
  3. echolon/config/feature_flags.py +54 -0
  4. echolon/config/markets/__init__.py +0 -0
  5. echolon/config/markets/core/__init__.py +0 -0
  6. echolon/config/markets/core/context.py +596 -0
  7. echolon/config/markets/core/encoding.py +27 -0
  8. echolon/config/markets/core/registry.py +248 -0
  9. echolon/config/markets/core/trading_target.py +490 -0
  10. echolon/config/markets/core/types.py +217 -0
  11. echolon/config/markets/crypto/__init__.py +0 -0
  12. echolon/config/markets/crypto/config.py +70 -0
  13. echolon/config/markets/crypto/perpetuals.py +144 -0
  14. echolon/config/markets/factory.py +343 -0
  15. echolon/config/markets/shfe/__init__.py +0 -0
  16. echolon/config/markets/shfe/config.py +90 -0
  17. echolon/config/markets/shfe/constants.py +166 -0
  18. echolon/config/markets/shfe/instruments.py +321 -0
  19. echolon/config/markets/shfe/phases.py +622 -0
  20. echolon/config/markets/shfe/sessions.py +79 -0
  21. echolon/config/quant_engine.py +132 -0
  22. echolon/config/settings.py +61 -0
  23. echolon/data_pipeline/__init__.py +6 -0
  24. echolon/data_pipeline/extractors/base.py +113 -0
  25. echolon/data_pipeline/extractors/binance/__init__.py +10 -0
  26. echolon/data_pipeline/extractors/binance/perpetual_extractor.py +587 -0
  27. echolon/data_pipeline/extractors/shfe/day_extractor.py +164 -0
  28. echolon/data_pipeline/extractors/shfe/live_day_extractor.py +580 -0
  29. echolon/data_pipeline/extractors/shfe/minute_extractor.py +277 -0
  30. echolon/data_pipeline/loaders/calendar_loader.py +180 -0
  31. echolon/data_pipeline/loaders/ohlcv_loader.py +161 -0
  32. echolon/data_pipeline/loaders/session_availability_loader.py +477 -0
  33. echolon/data_pipeline/schemas/ohlcv.py +43 -0
  34. echolon/data_pipeline/schemas/standard_schema.py +536 -0
  35. echolon/data_pipeline/transformers/calendar_generator.py +211 -0
  36. echolon/data_pipeline/transformers/contract_splitter.py +113 -0
  37. echolon/data_pipeline/transformers/ohlcv_resampler.py +218 -0
  38. echolon/data_pipeline/transformers/ohlcv_standardizer.py +354 -0
  39. echolon/data_pipeline/transformers/session_filter.py +136 -0
  40. echolon/data_pipeline/transformers/shfe_session_analyzer.py +320 -0
  41. echolon/indicators/__init__.py +6 -0
  42. echolon/indicators/calculators/__init__.py +0 -0
  43. echolon/indicators/calculators/interday/__init__.py +0 -0
  44. echolon/indicators/calculators/interday/indicator_dictionary.json +187 -0
  45. echolon/indicators/calculators/interday/indicator_mapping.py +300 -0
  46. echolon/indicators/calculators/interday/market_regime.py +425 -0
  47. echolon/indicators/calculators/interday/price_channel.py +49 -0
  48. echolon/indicators/calculators/interday/sr_zone.py +150 -0
  49. echolon/indicators/calculators/interday/ta_lib.py +1157 -0
  50. echolon/indicators/calculators/intraday/__init__.py +0 -0
  51. echolon/indicators/calculators/intraday/indicator_dictionary.json +88 -0
  52. echolon/indicators/calculators/intraday/indicator_mapping.py +337 -0
  53. echolon/indicators/calculators/intraday/indicators.py +1108 -0
  54. echolon/indicators/calculators/intraday/market_context.py +398 -0
  55. echolon/indicators/calculators/intraday/ta_lib.py +1082 -0
  56. echolon/indicators/config/interday_analysis_indicators.json +147 -0
  57. echolon/indicators/config/interday_indicators_classification.md +260 -0
  58. echolon/indicators/config/interday_indicators_documentation.md +255 -0
  59. echolon/indicators/config/intraday_analysis_indicators.json +356 -0
  60. echolon/indicators/config/intraday_indicators_classification.md +386 -0
  61. echolon/indicators/config/intraday_indicators_documentation.md +134 -0
  62. echolon/indicators/engine/__init__.py +0 -0
  63. echolon/indicators/engine/processor.py +1274 -0
  64. echolon/indicators/optimization/__init__.py +0 -0
  65. echolon/indicators/optimization/interday_regime_optimizer.py +1032 -0
  66. echolon/indicators/optimization/regime_utils.py +230 -0
  67. echolon/indicators/registry/__init__.py +0 -0
  68. echolon/indicators/registry/utils.py +146 -0
  69. echolon/indicators/utils/__init__.py +1 -0
  70. echolon/indicators/utils/indicator_loader.py +67 -0
  71. echolon/indicators/utils/merge_indicators.py +67 -0
  72. echolon/lib/__init__.py +0 -0
  73. echolon/lib/json_utils.py +175 -0
  74. echolon/lib/regime_utils.py +160 -0
  75. echolon/lib/stats_utils.py +277 -0
  76. echolon/lib/strategy_log.py +577 -0
  77. echolon/quant_engine/LOGGING_DESIGN.md +725 -0
  78. echolon/quant_engine/__init__.py +27 -0
  79. echolon/quant_engine/backtest/__init__.py +0 -0
  80. echolon/quant_engine/backtest/engine/__init__.py +0 -0
  81. echolon/quant_engine/backtest/engine/analyzers.py +1106 -0
  82. echolon/quant_engine/backtest/engine/backtest_runner.py +631 -0
  83. echolon/quant_engine/backtest/engine/backtrader_engine.py +1444 -0
  84. echolon/quant_engine/backtest/engine/backtrader_strategy.py +495 -0
  85. echolon/quant_engine/backtest/engine/enriched_pandas_data.py +245 -0
  86. echolon/quant_engine/backtest/engine/futures/__init__.py +0 -0
  87. echolon/quant_engine/backtest/engine/futures/enhanced_position.py +187 -0
  88. echolon/quant_engine/backtest/engine/hooks/__init__.py +0 -0
  89. echolon/quant_engine/backtest/engine/hooks/base.py +175 -0
  90. echolon/quant_engine/backtest/engine/hooks/contract_aware/__init__.py +0 -0
  91. echolon/quant_engine/backtest/engine/hooks/contract_aware/broker.py +583 -0
  92. echolon/quant_engine/backtest/engine/hooks/contract_aware/hook.py +197 -0
  93. echolon/quant_engine/backtest/engine/hooks/contract_aware/observer.py +376 -0
  94. echolon/quant_engine/backtest/engine/hooks/session_aware.py +184 -0
  95. echolon/quant_engine/backtest/engine/optimization_runner.py +403 -0
  96. echolon/quant_engine/backtest/optimization/__init__.py +0 -0
  97. echolon/quant_engine/backtest/optimization/optuna_study.py +572 -0
  98. echolon/quant_engine/backtest/optimization/select_best_trial.py +476 -0
  99. echolon/quant_engine/backtest/portfolio_backtest_runner.py +421 -0
  100. echolon/quant_engine/backtest/portfolio_metrics.py +261 -0
  101. echolon/quant_engine/backtest/wfa/__init__.py +11 -0
  102. echolon/quant_engine/backtest/wfa/analyzer.py +173 -0
  103. echolon/quant_engine/backtest/wfa/drs_calculator.py +755 -0
  104. echolon/quant_engine/backtest/wfa/runner.py +337 -0
  105. echolon/quant_engine/backtest/wfa/window.py +48 -0
  106. echolon/quant_engine/calculate_mfe_mae.py +551 -0
  107. echolon/quant_engine/core/__init__.py +0 -0
  108. echolon/quant_engine/core/base/__init__.py +0 -0
  109. echolon/quant_engine/core/base/base_component.py +861 -0
  110. echolon/quant_engine/core/base/base_strategy.py +1333 -0
  111. echolon/quant_engine/core/base/hooks/__init__.py +0 -0
  112. echolon/quant_engine/core/base/hooks/component_hook_base.py +90 -0
  113. echolon/quant_engine/core/base/hooks/forced_exit_strategy_hook.py +324 -0
  114. echolon/quant_engine/core/base/hooks/session_aware_component_hook.py +277 -0
  115. echolon/quant_engine/core/base/hooks/session_aware_strategy_hook.py +410 -0
  116. echolon/quant_engine/core/base/hooks/strategy_hook_base.py +152 -0
  117. echolon/quant_engine/core/base/parameter_architecture.py +280 -0
  118. echolon/quant_engine/core/base/state_manager.py +280 -0
  119. echolon/quant_engine/core/frequency/__init__.py +0 -0
  120. echolon/quant_engine/core/frequency/interday_context.py +88 -0
  121. echolon/quant_engine/core/frequency/intraday_context.py +159 -0
  122. echolon/quant_engine/core/frequency/session_context_provider.py +467 -0
  123. echolon/quant_engine/core/interfaces/__init__.py +0 -0
  124. echolon/quant_engine/core/interfaces/frequency_context.py +156 -0
  125. echolon/quant_engine/core/interfaces/market_adapter.py +413 -0
  126. echolon/quant_engine/core/interfaces/session_context.py +540 -0
  127. echolon/quant_engine/core/interfaces/trading_interfaces.py +839 -0
  128. echolon/quant_engine/core/logging/__init__.py +0 -0
  129. echolon/quant_engine/core/logging/strategy_logger.py +492 -0
  130. echolon/quant_engine/data/indicators/by_contract/al1801_indicators.csv +245 -0
  131. echolon/quant_engine/data/indicators/by_contract/al1801_indicators.pkl +0 -0
  132. echolon/quant_engine/data/indicators/by_contract/al1802_indicators.csv +247 -0
  133. echolon/quant_engine/data/indicators/by_contract/al1802_indicators.pkl +0 -0
  134. echolon/quant_engine/data/indicators/by_contract/al1803_indicators.csv +246 -0
  135. echolon/quant_engine/data/indicators/by_contract/al1803_indicators.pkl +0 -0
  136. echolon/quant_engine/data/indicators/by_contract/al1804_indicators.csv +245 -0
  137. echolon/quant_engine/data/indicators/by_contract/al1804_indicators.pkl +0 -0
  138. echolon/quant_engine/data/indicators/by_contract/al1805_indicators.csv +245 -0
  139. echolon/quant_engine/data/indicators/by_contract/al1805_indicators.pkl +0 -0
  140. echolon/quant_engine/data/indicators/by_contract/al1806_indicators.csv +247 -0
  141. echolon/quant_engine/data/indicators/by_contract/al1806_indicators.pkl +0 -0
  142. echolon/quant_engine/data/indicators/by_contract/al1807_indicators.csv +245 -0
  143. echolon/quant_engine/data/indicators/by_contract/al1807_indicators.pkl +0 -0
  144. echolon/quant_engine/data/indicators/by_contract/al1808_indicators.csv +246 -0
  145. echolon/quant_engine/data/indicators/by_contract/al1808_indicators.pkl +0 -0
  146. echolon/quant_engine/data/indicators/by_contract/al1809_indicators.csv +246 -0
  147. echolon/quant_engine/data/indicators/by_contract/al1809_indicators.pkl +0 -0
  148. echolon/quant_engine/data/indicators/by_contract/al1810_indicators.csv +244 -0
  149. echolon/quant_engine/data/indicators/by_contract/al1810_indicators.pkl +0 -0
  150. echolon/quant_engine/data/indicators/by_contract/al1811_indicators.csv +245 -0
  151. echolon/quant_engine/data/indicators/by_contract/al1811_indicators.pkl +0 -0
  152. echolon/quant_engine/data/indicators/by_contract/al1812_indicators.csv +245 -0
  153. echolon/quant_engine/data/indicators/by_contract/al1812_indicators.pkl +0 -0
  154. echolon/quant_engine/data/indicators/by_contract/al1901_indicators.csv +244 -0
  155. echolon/quant_engine/data/indicators/by_contract/al1901_indicators.pkl +0 -0
  156. echolon/quant_engine/data/indicators/by_contract/al1902_indicators.csv +243 -0
  157. echolon/quant_engine/data/indicators/by_contract/al1902_indicators.pkl +0 -0
  158. echolon/quant_engine/data/indicators/by_contract/al1903_indicators.csv +244 -0
  159. echolon/quant_engine/data/indicators/by_contract/al1903_indicators.pkl +0 -0
  160. echolon/quant_engine/data/indicators/by_contract/al1904_indicators.csv +244 -0
  161. echolon/quant_engine/data/indicators/by_contract/al1904_indicators.pkl +0 -0
  162. echolon/quant_engine/data/indicators/by_contract/al1905_indicators.csv +244 -0
  163. echolon/quant_engine/data/indicators/by_contract/al1905_indicators.pkl +0 -0
  164. echolon/quant_engine/data/indicators/by_contract/al1906_indicators.csv +243 -0
  165. echolon/quant_engine/data/indicators/by_contract/al1906_indicators.pkl +0 -0
  166. echolon/quant_engine/data/indicators/by_contract/al1907_indicators.csv +243 -0
  167. echolon/quant_engine/data/indicators/by_contract/al1907_indicators.pkl +0 -0
  168. echolon/quant_engine/data/indicators/by_contract/al1908_indicators.csv +244 -0
  169. echolon/quant_engine/data/indicators/by_contract/al1908_indicators.pkl +0 -0
  170. echolon/quant_engine/data/indicators/by_contract/al1909_indicators.csv +242 -0
  171. echolon/quant_engine/data/indicators/by_contract/al1909_indicators.pkl +0 -0
  172. echolon/quant_engine/data/indicators/by_contract/al1910_indicators.csv +244 -0
  173. echolon/quant_engine/data/indicators/by_contract/al1910_indicators.pkl +0 -0
  174. echolon/quant_engine/data/indicators/by_contract/al1911_indicators.csv +244 -0
  175. echolon/quant_engine/data/indicators/by_contract/al1911_indicators.pkl +0 -0
  176. echolon/quant_engine/data/indicators/by_contract/al1912_indicators.csv +243 -0
  177. echolon/quant_engine/data/indicators/by_contract/al1912_indicators.pkl +0 -0
  178. echolon/quant_engine/data/indicators/by_contract/al2001_indicators.csv +245 -0
  179. echolon/quant_engine/data/indicators/by_contract/al2001_indicators.pkl +0 -0
  180. echolon/quant_engine/data/indicators/by_contract/al2002_indicators.csv +244 -0
  181. echolon/quant_engine/data/indicators/by_contract/al2002_indicators.pkl +0 -0
  182. echolon/quant_engine/data/indicators/by_contract/al2003_indicators.csv +244 -0
  183. echolon/quant_engine/data/indicators/by_contract/al2003_indicators.pkl +0 -0
  184. echolon/quant_engine/data/indicators/by_contract/al2004_indicators.csv +245 -0
  185. echolon/quant_engine/data/indicators/by_contract/al2004_indicators.pkl +0 -0
  186. echolon/quant_engine/data/indicators/by_contract/al2005_indicators.csv +245 -0
  187. echolon/quant_engine/data/indicators/by_contract/al2005_indicators.pkl +0 -0
  188. echolon/quant_engine/data/indicators/by_contract/al2006_indicators.csv +244 -0
  189. echolon/quant_engine/data/indicators/by_contract/al2006_indicators.pkl +0 -0
  190. echolon/quant_engine/data/indicators/by_contract/al2007_indicators.csv +244 -0
  191. echolon/quant_engine/data/indicators/by_contract/al2007_indicators.pkl +0 -0
  192. echolon/quant_engine/data/indicators/by_contract/al2008_indicators.csv +244 -0
  193. echolon/quant_engine/data/indicators/by_contract/al2008_indicators.pkl +0 -0
  194. echolon/quant_engine/data/indicators/by_contract/al2009_indicators.csv +244 -0
  195. echolon/quant_engine/data/indicators/by_contract/al2009_indicators.pkl +0 -0
  196. echolon/quant_engine/data/indicators/by_contract/al2010_indicators.csv +244 -0
  197. echolon/quant_engine/data/indicators/by_contract/al2010_indicators.pkl +0 -0
  198. echolon/quant_engine/data/indicators/by_contract/al2011_indicators.csv +243 -0
  199. echolon/quant_engine/data/indicators/by_contract/al2011_indicators.pkl +0 -0
  200. echolon/quant_engine/data/indicators/by_contract/al2012_indicators.csv +243 -0
  201. echolon/quant_engine/data/indicators/by_contract/al2012_indicators.pkl +0 -0
  202. echolon/quant_engine/data/indicators/by_contract/al2101_indicators.csv +244 -0
  203. echolon/quant_engine/data/indicators/by_contract/al2101_indicators.pkl +0 -0
  204. echolon/quant_engine/data/indicators/by_contract/al2102_indicators.csv +242 -0
  205. echolon/quant_engine/data/indicators/by_contract/al2102_indicators.pkl +0 -0
  206. echolon/quant_engine/data/indicators/by_contract/al2103_indicators.csv +243 -0
  207. echolon/quant_engine/data/indicators/by_contract/al2103_indicators.pkl +0 -0
  208. echolon/quant_engine/data/indicators/by_contract/al2104_indicators.csv +244 -0
  209. echolon/quant_engine/data/indicators/by_contract/al2104_indicators.pkl +0 -0
  210. echolon/quant_engine/data/indicators/by_contract/al2105_indicators.csv +244 -0
  211. echolon/quant_engine/data/indicators/by_contract/al2105_indicators.pkl +0 -0
  212. echolon/quant_engine/data/indicators/by_contract/al2106_indicators.csv +243 -0
  213. echolon/quant_engine/data/indicators/by_contract/al2106_indicators.pkl +0 -0
  214. echolon/quant_engine/data/indicators/by_contract/al2107_indicators.csv +245 -0
  215. echolon/quant_engine/data/indicators/by_contract/al2107_indicators.pkl +0 -0
  216. echolon/quant_engine/data/indicators/by_contract/al2108_indicators.csv +244 -0
  217. echolon/quant_engine/data/indicators/by_contract/al2108_indicators.pkl +0 -0
  218. echolon/quant_engine/data/indicators/by_contract/al2109_indicators.csv +245 -0
  219. echolon/quant_engine/data/indicators/by_contract/al2109_indicators.pkl +0 -0
  220. echolon/quant_engine/data/indicators/by_contract/al2110_indicators.csv +244 -0
  221. echolon/quant_engine/data/indicators/by_contract/al2110_indicators.pkl +0 -0
  222. echolon/quant_engine/data/indicators/by_contract/al2111_indicators.csv +243 -0
  223. echolon/quant_engine/data/indicators/by_contract/al2111_indicators.pkl +0 -0
  224. echolon/quant_engine/data/indicators/by_contract/al2112_indicators.csv +244 -0
  225. echolon/quant_engine/data/indicators/by_contract/al2112_indicators.pkl +0 -0
  226. echolon/quant_engine/data/indicators/by_contract/al2201_indicators.csv +244 -0
  227. echolon/quant_engine/data/indicators/by_contract/al2201_indicators.pkl +0 -0
  228. echolon/quant_engine/data/indicators/by_contract/al2202_indicators.csv +245 -0
  229. echolon/quant_engine/data/indicators/by_contract/al2202_indicators.pkl +0 -0
  230. echolon/quant_engine/data/indicators/by_contract/al2203_indicators.csv +244 -0
  231. echolon/quant_engine/data/indicators/by_contract/al2203_indicators.pkl +0 -0
  232. echolon/quant_engine/data/indicators/by_contract/al2204_indicators.csv +243 -0
  233. echolon/quant_engine/data/indicators/by_contract/al2204_indicators.pkl +0 -0
  234. echolon/quant_engine/data/indicators/by_contract/al2205_indicators.csv +242 -0
  235. echolon/quant_engine/data/indicators/by_contract/al2205_indicators.pkl +0 -0
  236. echolon/quant_engine/data/indicators/by_contract/al2206_indicators.csv +243 -0
  237. echolon/quant_engine/data/indicators/by_contract/al2206_indicators.pkl +0 -0
  238. echolon/quant_engine/data/indicators/by_contract/al2207_indicators.csv +243 -0
  239. echolon/quant_engine/data/indicators/by_contract/al2207_indicators.pkl +0 -0
  240. echolon/quant_engine/data/indicators/by_contract/al2208_indicators.csv +242 -0
  241. echolon/quant_engine/data/indicators/by_contract/al2208_indicators.pkl +0 -0
  242. echolon/quant_engine/data/indicators/by_contract/al2209_indicators.csv +242 -0
  243. echolon/quant_engine/data/indicators/by_contract/al2209_indicators.pkl +0 -0
  244. echolon/quant_engine/data/indicators/by_contract/al2210_indicators.csv +244 -0
  245. echolon/quant_engine/data/indicators/by_contract/al2210_indicators.pkl +0 -0
  246. echolon/quant_engine/data/indicators/by_contract/al2211_indicators.csv +244 -0
  247. echolon/quant_engine/data/indicators/by_contract/al2211_indicators.pkl +0 -0
  248. echolon/quant_engine/data/indicators/by_contract/al2212_indicators.csv +244 -0
  249. echolon/quant_engine/data/indicators/by_contract/al2212_indicators.pkl +0 -0
  250. echolon/quant_engine/data/indicators/by_contract/al2301_indicators.csv +243 -0
  251. echolon/quant_engine/data/indicators/by_contract/al2301_indicators.pkl +0 -0
  252. echolon/quant_engine/data/indicators/by_contract/al2302_indicators.csv +244 -0
  253. echolon/quant_engine/data/indicators/by_contract/al2302_indicators.pkl +0 -0
  254. echolon/quant_engine/data/indicators/by_contract/al2303_indicators.csv +244 -0
  255. echolon/quant_engine/data/indicators/by_contract/al2303_indicators.pkl +0 -0
  256. echolon/quant_engine/data/indicators/by_contract/al2304_indicators.csv +245 -0
  257. echolon/quant_engine/data/indicators/by_contract/al2304_indicators.pkl +0 -0
  258. echolon/quant_engine/data/indicators/by_contract/al2305_indicators.csv +244 -0
  259. echolon/quant_engine/data/indicators/by_contract/al2305_indicators.pkl +0 -0
  260. echolon/quant_engine/data/indicators/by_contract/al2306_indicators.csv +246 -0
  261. echolon/quant_engine/data/indicators/by_contract/al2306_indicators.pkl +0 -0
  262. echolon/quant_engine/data/indicators/by_contract/al2307_indicators.csv +244 -0
  263. echolon/quant_engine/data/indicators/by_contract/al2307_indicators.pkl +0 -0
  264. echolon/quant_engine/data/indicators/by_contract/al2308_indicators.csv +244 -0
  265. echolon/quant_engine/data/indicators/by_contract/al2308_indicators.pkl +0 -0
  266. echolon/quant_engine/data/indicators/by_contract/al2309_indicators.csv +245 -0
  267. echolon/quant_engine/data/indicators/by_contract/al2309_indicators.pkl +0 -0
  268. echolon/quant_engine/data/indicators/by_contract/al2310_indicators.csv +243 -0
  269. echolon/quant_engine/data/indicators/by_contract/al2310_indicators.pkl +0 -0
  270. echolon/quant_engine/data/indicators/by_contract/al2311_indicators.csv +244 -0
  271. echolon/quant_engine/data/indicators/by_contract/al2311_indicators.pkl +0 -0
  272. echolon/quant_engine/data/indicators/by_contract/al2312_indicators.csv +244 -0
  273. echolon/quant_engine/data/indicators/by_contract/al2312_indicators.pkl +0 -0
  274. echolon/quant_engine/data/indicators/by_contract/al2401_indicators.csv +243 -0
  275. echolon/quant_engine/data/indicators/by_contract/al2401_indicators.pkl +0 -0
  276. echolon/quant_engine/data/indicators/by_contract/al2402_indicators.csv +245 -0
  277. echolon/quant_engine/data/indicators/by_contract/al2402_indicators.pkl +0 -0
  278. echolon/quant_engine/data/indicators/by_contract/al2403_indicators.csv +244 -0
  279. echolon/quant_engine/data/indicators/by_contract/al2403_indicators.pkl +0 -0
  280. echolon/quant_engine/data/indicators/by_contract/al2404_indicators.csv +241 -0
  281. echolon/quant_engine/data/indicators/by_contract/al2404_indicators.pkl +0 -0
  282. echolon/quant_engine/data/indicators/by_contract/al2405_indicators.csv +243 -0
  283. echolon/quant_engine/data/indicators/by_contract/al2405_indicators.pkl +0 -0
  284. echolon/quant_engine/data/indicators/by_contract/al2406_indicators.csv +242 -0
  285. echolon/quant_engine/data/indicators/by_contract/al2406_indicators.pkl +0 -0
  286. echolon/quant_engine/data/indicators/by_contract/al2407_indicators.csv +242 -0
  287. echolon/quant_engine/data/indicators/by_contract/al2407_indicators.pkl +0 -0
  288. echolon/quant_engine/data/indicators/by_contract/al2408_indicators.csv +244 -0
  289. echolon/quant_engine/data/indicators/by_contract/al2408_indicators.pkl +0 -0
  290. echolon/quant_engine/data/indicators/by_contract/al2409_indicators.csv +243 -0
  291. echolon/quant_engine/data/indicators/by_contract/al2409_indicators.pkl +0 -0
  292. echolon/quant_engine/data/indicators/by_contract/al2410_indicators.csv +242 -0
  293. echolon/quant_engine/data/indicators/by_contract/al2410_indicators.pkl +0 -0
  294. echolon/quant_engine/data/indicators/by_contract/al2411_indicators.csv +243 -0
  295. echolon/quant_engine/data/indicators/by_contract/al2411_indicators.pkl +0 -0
  296. echolon/quant_engine/data/indicators/by_contract/al2412_indicators.csv +242 -0
  297. echolon/quant_engine/data/indicators/by_contract/al2412_indicators.pkl +0 -0
  298. echolon/quant_engine/data/indicators/by_contract/al2501_indicators.csv +243 -0
  299. echolon/quant_engine/data/indicators/by_contract/al2501_indicators.pkl +0 -0
  300. echolon/quant_engine/data/indicators/by_contract/al2502_indicators.csv +241 -0
  301. echolon/quant_engine/data/indicators/by_contract/al2502_indicators.pkl +0 -0
  302. echolon/quant_engine/data/indicators/by_contract/al2503_indicators.csv +242 -0
  303. echolon/quant_engine/data/indicators/by_contract/al2503_indicators.pkl +0 -0
  304. echolon/quant_engine/data/indicators/by_contract/al2504_indicators.csv +243 -0
  305. echolon/quant_engine/data/indicators/by_contract/al2504_indicators.pkl +0 -0
  306. echolon/quant_engine/data/indicators/by_contract/al2505_indicators.csv +243 -0
  307. echolon/quant_engine/data/indicators/by_contract/al2505_indicators.pkl +0 -0
  308. echolon/quant_engine/data/indicators/by_contract/al2506_indicators.csv +242 -0
  309. echolon/quant_engine/data/indicators/by_contract/al2506_indicators.pkl +0 -0
  310. echolon/quant_engine/data/indicators/by_contract/al2507_indicators.csv +243 -0
  311. echolon/quant_engine/data/indicators/by_contract/al2507_indicators.pkl +0 -0
  312. echolon/quant_engine/data/indicators/by_contract/al2508_indicators.csv +243 -0
  313. echolon/quant_engine/data/indicators/by_contract/al2508_indicators.pkl +0 -0
  314. echolon/quant_engine/data/indicators/by_contract/al2509_indicators.csv +242 -0
  315. echolon/quant_engine/data/indicators/by_contract/al2509_indicators.pkl +0 -0
  316. echolon/quant_engine/data/indicators/by_contract/al2510_indicators.csv +244 -0
  317. echolon/quant_engine/data/indicators/by_contract/al2510_indicators.pkl +0 -0
  318. echolon/quant_engine/data/indicators/by_contract/al2511_indicators.csv +244 -0
  319. echolon/quant_engine/data/indicators/by_contract/al2511_indicators.pkl +0 -0
  320. echolon/quant_engine/data/indicators/by_contract/al2512_indicators.csv +243 -0
  321. echolon/quant_engine/data/indicators/by_contract/al2512_indicators.pkl +0 -0
  322. echolon/quant_engine/data/indicators/by_contract/al2601_indicators.csv +234 -0
  323. echolon/quant_engine/data/indicators/by_contract/al2601_indicators.pkl +0 -0
  324. echolon/quant_engine/data/indicators/by_contract/al2602_indicators.csv +217 -0
  325. echolon/quant_engine/data/indicators/by_contract/al2602_indicators.pkl +0 -0
  326. echolon/quant_engine/data/indicators/by_contract/al2603_indicators.csv +197 -0
  327. echolon/quant_engine/data/indicators/by_contract/al2603_indicators.pkl +0 -0
  328. echolon/quant_engine/data/indicators/by_contract/al2604_indicators.csv +177 -0
  329. echolon/quant_engine/data/indicators/by_contract/al2604_indicators.pkl +0 -0
  330. echolon/quant_engine/data/indicators/by_contract/al2605_indicators.csv +158 -0
  331. echolon/quant_engine/data/indicators/by_contract/al2605_indicators.pkl +0 -0
  332. echolon/quant_engine/data/indicators/by_contract/al2606_indicators.csv +137 -0
  333. echolon/quant_engine/data/indicators/by_contract/al2606_indicators.pkl +0 -0
  334. echolon/quant_engine/data/indicators/by_contract/al2607_indicators.csv +116 -0
  335. echolon/quant_engine/data/indicators/by_contract/al2607_indicators.pkl +0 -0
  336. echolon/quant_engine/data/indicators/by_contract/al2608_indicators.csv +93 -0
  337. echolon/quant_engine/data/indicators/by_contract/al2608_indicators.pkl +0 -0
  338. echolon/quant_engine/data/indicators/by_contract/al2609_indicators.csv +72 -0
  339. echolon/quant_engine/data/indicators/by_contract/al2609_indicators.pkl +0 -0
  340. echolon/quant_engine/data/indicators/by_contract/al2610_indicators.csv +56 -0
  341. echolon/quant_engine/data/indicators/by_contract/al2610_indicators.pkl +0 -0
  342. echolon/quant_engine/data/indicators/by_contract/al2611_indicators.csv +33 -0
  343. echolon/quant_engine/data/indicators/by_contract/al2611_indicators.pkl +0 -0
  344. echolon/quant_engine/data/indicators/by_contract/al2612_indicators.csv +13 -0
  345. echolon/quant_engine/data/indicators/by_contract/al2612_indicators.pkl +0 -0
  346. echolon/quant_engine/data/indicators/strategy_indicator_metadata.json +44 -0
  347. echolon/quant_engine/data/indicators/strategy_indicators.csv +1943 -0
  348. echolon/quant_engine/data/indicators/strategy_indicators.pkl +0 -0
  349. echolon/quant_engine/data_loader/SHFE_loader.py +175 -0
  350. echolon/quant_engine/data_loader/__init__.py +0 -0
  351. echolon/quant_engine/data_loader/contract_data.py +397 -0
  352. echolon/quant_engine/deploy/__init__.py +1 -0
  353. echolon/quant_engine/deploy/config/__init__.py +1 -0
  354. echolon/quant_engine/deploy/config/deploy_config.py +157 -0
  355. echolon/quant_engine/deploy/config/logging_config.py +159 -0
  356. echolon/quant_engine/deploy/config/portfolio_deploy_config.py +170 -0
  357. echolon/quant_engine/deploy/config/trading_calendar.csv +366 -0
  358. echolon/quant_engine/deploy/data_pipeline/__init__.py +12 -0
  359. echolon/quant_engine/deploy/data_pipeline/trading_util.py +49 -0
  360. echolon/quant_engine/deploy/engine/__init__.py +9 -0
  361. echolon/quant_engine/deploy/engine/capital_slot.py +108 -0
  362. echolon/quant_engine/deploy/engine/dashboard_aggregator.py +397 -0
  363. echolon/quant_engine/deploy/engine/dashboard_data_generator.py +393 -0
  364. echolon/quant_engine/deploy/engine/dashboard_data_sender.py +76 -0
  365. echolon/quant_engine/deploy/engine/portfolio_risk_overlay.py +343 -0
  366. echolon/quant_engine/deploy/engine/portfolio_trading_runner.py +1382 -0
  367. echolon/quant_engine/deploy/engine/slot_aware_portfolio.py +348 -0
  368. echolon/quant_engine/deploy/engine/trading_data_logger.py +384 -0
  369. echolon/quant_engine/deploy/engine/trading_runner.py +1181 -0
  370. echolon/quant_engine/deploy/engine/trading_slot.py +511 -0
  371. echolon/quant_engine/deploy/platforms/__init__.py +1 -0
  372. echolon/quant_engine/deploy/platforms/ccxt/__init__.py +45 -0
  373. echolon/quant_engine/deploy/platforms/ccxt/ccxt_client.py +47 -0
  374. echolon/quant_engine/deploy/platforms/ccxt/ccxt_engine.py +47 -0
  375. echolon/quant_engine/deploy/platforms/miniqmt/__init__.py +1 -0
  376. echolon/quant_engine/deploy/platforms/miniqmt/qmt_client.py +1784 -0
  377. echolon/quant_engine/deploy/platforms/miniqmt/qmt_engine.py +1132 -0
  378. echolon/quant_engine/deploy/platforms/miniqmt/xtdc_client.py +357 -0
  379. echolon/quant_engine/engine_factory.py +383 -0
  380. echolon/quant_engine/logging_utils.py +392 -0
  381. echolon/quant_engine/market_adapters/__init__.py +0 -0
  382. echolon/quant_engine/market_adapters/base_adapter.py +398 -0
  383. echolon/quant_engine/market_adapters/crypto/__init__.py +0 -0
  384. echolon/quant_engine/market_adapters/crypto/crypto_adapter.py +500 -0
  385. echolon/quant_engine/market_adapters/crypto/crypto_session_provider.py +169 -0
  386. echolon/quant_engine/market_adapters/crypto/perpetual_rules.py +264 -0
  387. echolon/quant_engine/market_adapters/crypto/session_config.py +73 -0
  388. echolon/quant_engine/market_adapters/shfe/__init__.py +0 -0
  389. echolon/quant_engine/market_adapters/shfe/contract_rules.py +484 -0
  390. echolon/quant_engine/market_adapters/shfe/shfe_adapter.py +581 -0
  391. echolon/quant_engine/market_adapters/shfe/shfe_session_provider.py +328 -0
  392. echolon/quant_engine/market_adapters/shfe/trading_calendar.py +315 -0
  393. echolon/quant_engine/market_adapters/us_futures/__init__.py +0 -0
  394. echolon/quant_engine/market_adapters/us_futures/cme_adapter.py +33 -0
  395. echolon/quant_engine/market_adapters/us_futures/session_config.py +33 -0
  396. echolon/quant_engine/reporting.py +319 -0
  397. echolon/quant_engine/run_backtest.py +272 -0
  398. echolon/quant_engine/schemas/README.md +376 -0
  399. echolon/quant_engine/schemas/__init__.py +0 -0
  400. echolon/quant_engine/schemas/backtest_results.py +364 -0
  401. echolon/quant_engine/schemas/selected_trial.py +132 -0
  402. echolon/quant_engine/schemas/strategy_log.py +283 -0
  403. echolon/quant_engine/schemas/trade_log.py +370 -0
  404. echolon/quant_engine/strategy/__init__.py +0 -0
  405. echolon/quant_engine/strategy/al_s1/__init__.py +0 -0
  406. echolon/quant_engine/strategy/al_s1/entry.py +277 -0
  407. echolon/quant_engine/strategy/al_s1/exit.py +390 -0
  408. echolon/quant_engine/strategy/al_s1/regime_params.json +40 -0
  409. echolon/quant_engine/strategy/al_s1/risk.py +217 -0
  410. echolon/quant_engine/strategy/al_s1/selected_robust_trial.json +350 -0
  411. echolon/quant_engine/strategy/al_s1/sizer.py +300 -0
  412. echolon/quant_engine/strategy/al_s1/strategy.py +176 -0
  413. echolon/quant_engine/strategy/al_s1/strategy_code_combined.py +2746 -0
  414. echolon/quant_engine/strategy/al_s1/strategy_indicator_list.json +17 -0
  415. echolon/quant_engine/strategy/al_s1/strategy_params.py +622 -0
  416. echolon/quant_engine/strategy/cu_s1/__init__.py +0 -0
  417. echolon/quant_engine/strategy/cu_s1/entry.py +362 -0
  418. echolon/quant_engine/strategy/cu_s1/exit.py +487 -0
  419. echolon/quant_engine/strategy/cu_s1/regime_params.json +40 -0
  420. echolon/quant_engine/strategy/cu_s1/risk.py +213 -0
  421. echolon/quant_engine/strategy/cu_s1/selected_robust_trial.json +388 -0
  422. echolon/quant_engine/strategy/cu_s1/sizer.py +199 -0
  423. echolon/quant_engine/strategy/cu_s1/strategy.py +326 -0
  424. echolon/quant_engine/strategy/cu_s1/strategy_code_combined.py +3018 -0
  425. echolon/quant_engine/strategy/cu_s1/strategy_indicator_list.json +18 -0
  426. echolon/quant_engine/strategy/cu_s1/strategy_params.py +590 -0
  427. echolon/quant_engine/strategy/generators/__init__.py +0 -0
  428. echolon/quant_engine/strategy/generators/strategy_params_generator.py +1171 -0
  429. echolon/quant_engine/strategy/zn_s1/__init__.py +0 -0
  430. echolon/quant_engine/strategy/zn_s1/entry.py +324 -0
  431. echolon/quant_engine/strategy/zn_s1/exit.py +398 -0
  432. echolon/quant_engine/strategy/zn_s1/regime_params.json +40 -0
  433. echolon/quant_engine/strategy/zn_s1/risk.py +404 -0
  434. echolon/quant_engine/strategy/zn_s1/selected_robust_trial.json +295 -0
  435. echolon/quant_engine/strategy/zn_s1/sizer.py +195 -0
  436. echolon/quant_engine/strategy/zn_s1/strategy.py +210 -0
  437. echolon/quant_engine/strategy/zn_s1/strategy_code_combined.py +2673 -0
  438. echolon/quant_engine/strategy/zn_s1/strategy_indicator_list.json +17 -0
  439. echolon/quant_engine/strategy/zn_s1/strategy_params.py +488 -0
  440. echolon/quant_engine/types.py +599 -0
  441. echolon-0.1.0.dist-info/METADATA +42 -0
  442. echolon-0.1.0.dist-info/RECORD +444 -0
  443. echolon-0.1.0.dist-info/WHEEL +4 -0
  444. echolon-0.1.0.dist-info/licenses/LICENSE +202 -0
echolon/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Echolon — See what others can't. Market-agnostic quantitative trading engine."""
2
+
3
+ __version__ = "0.1.0"
File without changes
@@ -0,0 +1,54 @@
1
+ """
2
+ Feature Flags for Skills and Hooks Migration
3
+
4
+ This module provides feature flags to enable/disable Skills and Hooks
5
+ functionality for rollback support during the migration.
6
+
7
+ Usage:
8
+ from echolon.config.feature_flags import FEATURES
9
+
10
+ if FEATURES['USE_SKILLS']:
11
+ options.setting_sources = ["project"]
12
+
13
+ if FEATURES['USE_HOOKS']:
14
+ options.hooks = hook_config
15
+ """
16
+
17
+ # Feature flags for migration rollback support
18
+ FEATURES = {
19
+ # Phase 1: Skills (load from .claude/skills/)
20
+ 'USE_SKILLS': True,
21
+
22
+ # Phase 2: Hooks (PreToolUse and PostToolUse validation)
23
+ 'USE_HOOKS': True,
24
+
25
+ # Phase 4: Agent consolidation (reduce 17 agents to 9)
26
+ # Start False until Phase 4 is implemented
27
+ 'USE_CONSOLIDATED_AGENTS': False,
28
+ }
29
+
30
+
31
+ def is_feature_enabled(feature_name: str) -> bool:
32
+ """
33
+ Check if a feature is enabled.
34
+
35
+ Args:
36
+ feature_name: Name of the feature to check
37
+
38
+ Returns:
39
+ True if enabled, False otherwise
40
+
41
+ Raises:
42
+ KeyError: If feature_name is not a valid feature
43
+ """
44
+ return FEATURES[feature_name]
45
+
46
+
47
+ def enable_feature(feature_name: str) -> None:
48
+ """Enable a feature flag."""
49
+ FEATURES[feature_name] = True
50
+
51
+
52
+ def disable_feature(feature_name: str) -> None:
53
+ """Disable a feature flag."""
54
+ FEATURES[feature_name] = False
File without changes
File without changes
@@ -0,0 +1,596 @@
1
+ """
2
+ Trading Context - Runtime context for market-specific trading operations.
3
+
4
+ TradingContext encapsulates all market, instrument, and frequency information
5
+ needed by trading modules. It's created by MarketFactory from session state
6
+ and passed to modules via dependency injection.
7
+
8
+ Usage:
9
+ from echolon.config.markets.factory import MarketFactory
10
+
11
+ # Create context from session state
12
+ ctx = MarketFactory.from_session()
13
+
14
+ # Use in modules
15
+ commission = ctx.instrument.calculate_commission(price, size)
16
+ phase = ctx.encode_phase("morning")
17
+ bars = ctx.bars_per_day
18
+ """
19
+
20
+ from dataclasses import dataclass, field
21
+ from datetime import time, datetime
22
+ from typing import Dict, List, Optional, Callable
23
+
24
+ # Import types at runtime (required for Pydantic models that use TradingContext)
25
+ from .types import MarketConfig, InstrumentSpec, SessionWindow, SessionPhaseSpec
26
+ from .trading_target import TradingTarget
27
+
28
+
29
+ @dataclass
30
+ class TradingContext:
31
+ """
32
+ Runtime trading context for a specific market/instrument/frequency combination.
33
+
34
+ This is the primary interface for modules to access market configuration.
35
+ Created by MarketFactory and passed to modules that need market info.
36
+
37
+ Attributes:
38
+ market: Market configuration (SHFE, CRYPTO, etc.)
39
+ instrument: Instrument specification (al, btc, etc.)
40
+ frequency: Trading frequency ('intraday' or 'interday')
41
+ bar_size: Bar size string ('5m', '15m', '1d', etc.)
42
+ target: User's trading target (TradingTarget from state.json)
43
+ """
44
+ market: MarketConfig
45
+ instrument: InstrumentSpec
46
+ frequency: str # 'intraday' | 'interday'
47
+ bar_size: str # '1m', '5m', '15m', '30m', '1h', '1d'
48
+
49
+ # User's trading target (TradingTarget from session/state.json)
50
+ target: Optional[TradingTarget] = field(default=None, repr=False)
51
+
52
+ # Encoding functions (set by factory based on market)
53
+ _encode_phase: Callable[[str], int] = field(default=lambda x: 0, repr=False)
54
+ _decode_phase: Callable[[int], str] = field(default=lambda x: 'unknown', repr=False)
55
+
56
+ # =========================================================================
57
+ # Market Properties
58
+ # =========================================================================
59
+
60
+ @property
61
+ def market_code(self) -> str:
62
+ """Market code (e.g., 'SHFE', 'CRYPTO')."""
63
+ return self.market.code
64
+
65
+ @property
66
+ def timezone(self) -> str:
67
+ """Market timezone (e.g., 'Asia/Shanghai', 'UTC')."""
68
+ return self.market.timezone
69
+
70
+ @property
71
+ def currency(self) -> str:
72
+ """Trading currency (e.g., 'CNY', 'USDT')."""
73
+ return self.market.currency
74
+
75
+ @property
76
+ def is_24h(self) -> bool:
77
+ """Whether market trades 24/7 (crypto)."""
78
+ return self.market.is_24h
79
+
80
+ @property
81
+ def has_contract_expiry(self) -> bool:
82
+ """Whether contracts expire (futures vs perpetuals)."""
83
+ return self.market.has_contract_expiry
84
+
85
+ # =========================================================================
86
+ # Instrument Properties
87
+ # =========================================================================
88
+
89
+ @property
90
+ def instrument_code(self) -> str:
91
+ """Instrument code (e.g., 'al', 'btc')."""
92
+ return self.instrument.code
93
+
94
+ @property
95
+ def instrument_name(self) -> str:
96
+ """Instrument name (e.g., 'Aluminum', 'Bitcoin Perpetual')."""
97
+ return self.instrument.name
98
+
99
+ @property
100
+ def multiplier(self) -> float:
101
+ """Contract multiplier."""
102
+ return self.instrument.multiplier
103
+
104
+ @property
105
+ def tick_size(self) -> float:
106
+ """Minimum price movement."""
107
+ return self.instrument.tick_size
108
+
109
+ @property
110
+ def margin_rate(self) -> float:
111
+ """Margin requirement (decimal, e.g., 0.08 = 8%)."""
112
+ return self.instrument.margin_rate
113
+
114
+ @property
115
+ def has_night_session(self) -> bool:
116
+ """Whether instrument trades in night session."""
117
+ return self.instrument.has_night_session
118
+
119
+ @property
120
+ def initial_capital(self) -> float:
121
+ """Initial capital for backtesting and live trading."""
122
+ if self.target:
123
+ return self.target.initial_capital
124
+ return 200000.0
125
+
126
+ # =========================================================================
127
+ # Session Access
128
+ # =========================================================================
129
+
130
+ @property
131
+ def sessions(self) -> Dict[str, SessionWindow]:
132
+ """All session windows for this market."""
133
+ return self.market.sessions
134
+
135
+ @property
136
+ def phases(self) -> Dict[str, SessionPhaseSpec]:
137
+ """All session phases for this market."""
138
+ return self.market.phases
139
+
140
+ @property
141
+ def trading_phases(self) -> List[SessionPhaseSpec]:
142
+ """Only trading phases (excludes breaks)."""
143
+ return [p for p in self.market.phases.values() if p.is_trading]
144
+
145
+ # =========================================================================
146
+ # Frequency Properties
147
+ # =========================================================================
148
+
149
+ @property
150
+ def is_intraday(self) -> bool:
151
+ """Whether trading intraday."""
152
+ return self.frequency == 'intraday'
153
+
154
+ @property
155
+ def is_interday(self) -> bool:
156
+ """Whether trading interday (daily bars)."""
157
+ return self.frequency == 'interday'
158
+
159
+ @property
160
+ def bars_per_day(self) -> int:
161
+ """Expected bars per trading day."""
162
+ if self.is_interday:
163
+ return 1
164
+
165
+ # Get from market-specific constants
166
+ if self.market_code == 'SHFE':
167
+ from echolon.config.markets.shfe.constants import BARS_PER_DAY, BARS_PER_DAY_NO_NIGHT
168
+ bars_map = BARS_PER_DAY if self.has_night_session else BARS_PER_DAY_NO_NIGHT
169
+ return bars_map.get(self.bar_size)
170
+ elif self.market_code == 'CRYPTO':
171
+ from echolon.config.markets.crypto.perpetuals import BARS_PER_DAY
172
+ return BARS_PER_DAY.get(self.bar_size, 288)
173
+
174
+ return 1 # Default for unknown markets
175
+
176
+ @property
177
+ def trading_minutes_per_day(self) -> int:
178
+ """Total trading minutes per day."""
179
+ if self.market_code == 'SHFE':
180
+ from echolon.config.markets.shfe.constants import TOTAL_TRADING_MINUTES, DAY_TRADING_MINUTES
181
+ return TOTAL_TRADING_MINUTES if self.has_night_session else DAY_TRADING_MINUTES
182
+ elif self.market_code == 'CRYPTO':
183
+ return 24 * 60 # 1440 minutes
184
+
185
+ return 24 * 60 # Default
186
+
187
+ # =========================================================================
188
+ # Frequency-Derived Parameters (for Indicators)
189
+ # =========================================================================
190
+
191
+ @property
192
+ def bar_size_minutes(self) -> int:
193
+ """
194
+ Bar size in minutes.
195
+
196
+ Parses bar_size string ('1m', '5m', '15m', '30m', '1h', '4h', '1d')
197
+ and returns the duration in minutes.
198
+ """
199
+ bar_size_lower = self.bar_size.lower()
200
+
201
+ # Handle hour format
202
+ if 'h' in bar_size_lower:
203
+ hours = int(bar_size_lower.replace('h', ''))
204
+ return hours * 60
205
+
206
+ # Handle minute formats (both "5m" and "5min")
207
+ if 'min' in bar_size_lower:
208
+ return int(bar_size_lower.replace('min', ''))
209
+ if 'm' in bar_size_lower:
210
+ return int(bar_size_lower.replace('m', ''))
211
+
212
+ # Handle day format
213
+ if 'd' in bar_size_lower:
214
+ return 1440 # 24 * 60
215
+
216
+
217
+ @property
218
+ def bars_per_hour(self) -> int:
219
+ """Bars per hour for current frequency."""
220
+ if self.bar_size_minutes >= 60:
221
+ return 1
222
+ return 60 // self.bar_size_minutes
223
+
224
+ def hours_to_bars(self, hours: float) -> int:
225
+ """
226
+ Convert hours to bar count for current frequency.
227
+
228
+ Args:
229
+ hours: Duration in hours
230
+
231
+ Returns:
232
+ Number of bars (minimum 1)
233
+ """
234
+ return max(1, int(hours * self.bars_per_hour))
235
+
236
+ def minutes_to_bars(self, minutes: int) -> int:
237
+ """
238
+ Convert minutes to bar count for current frequency.
239
+
240
+ Args:
241
+ minutes: Duration in minutes
242
+
243
+ Returns:
244
+ Number of bars (minimum 1)
245
+ """
246
+ return max(1, minutes // self.bar_size_minutes)
247
+
248
+ def get_indicator_params(self) -> dict:
249
+ """
250
+ Get frequency-appropriate indicator parameters.
251
+
252
+ For INTERDAY (daily bars): Returns standard TA-Lib defaults
253
+ For INTRADAY: Returns time-scaled parameters based on bar_size
254
+
255
+ Returns:
256
+ Dictionary of indicator parameters appropriate for current frequency
257
+ """
258
+ # INTERDAY: Use standard TA-Lib defaults (industry standard for daily bars)
259
+ if self.is_interday:
260
+ return {
261
+ # Momentum indicators (standard daily defaults)
262
+ "rsi_period": 14,
263
+ "cci_period": 20,
264
+ "willr_period": 14,
265
+ "mfi_period": 14,
266
+ "mom_period": 10,
267
+
268
+ # Trend indicators
269
+ "adx_period": 14,
270
+ "aroonosc_period": 25,
271
+
272
+ # Volatility
273
+ "atr_period": 14,
274
+
275
+ # Moving averages
276
+ "ema_fast": 12,
277
+ "ema_slow": 26,
278
+ "sma_short": 20,
279
+ "sma_mid": 50,
280
+
281
+ # MACD (standard 12/26/9)
282
+ "macd_fast": 12,
283
+ "macd_slow": 26,
284
+ "macd_signal": 9,
285
+
286
+ # Bollinger Bands
287
+ "bb_period": 20,
288
+
289
+ # Volume percentile (20 trading days)
290
+ "vol_lookback": 20,
291
+
292
+ # Opening range (not applicable for daily)
293
+ "or_bars": 1,
294
+ "or_minutes": 0,
295
+
296
+ # Channel periods (5, 10, 20 days)
297
+ "channel_periods": [5, 10, 20],
298
+
299
+ # ROC periods (5, 10, 20 days)
300
+ "roc_periods": [5, 10, 20],
301
+
302
+ # Volatility state
303
+ "volatility_atr_period": 14,
304
+ "volatility_lookback": 60,
305
+ "volatility_high_pct": 75.0,
306
+ "volatility_low_pct": 25.0,
307
+ }
308
+
309
+ # INTRADAY: Scale parameters based on bar_size to maintain consistent
310
+ # lookback periods in real time across different bar sizes
311
+ return {
312
+ # Momentum indicators (~2-3 hours lookback)
313
+ "rsi_period": self.hours_to_bars(2.3),
314
+ "cci_period": self.hours_to_bars(3.3),
315
+ "willr_period": self.hours_to_bars(2.3),
316
+ "mfi_period": self.hours_to_bars(2.3),
317
+ "mom_period": self.hours_to_bars(1.0),
318
+
319
+ # Trend indicators (~2-3 hours)
320
+ "adx_period": self.hours_to_bars(2.3),
321
+ "aroonosc_period": self.hours_to_bars(3.3),
322
+
323
+ # Volatility
324
+ "atr_period": self.hours_to_bars(2.3),
325
+
326
+ # Moving averages
327
+ "ema_fast": self.hours_to_bars(1.0),
328
+ "ema_slow": self.hours_to_bars(2.3),
329
+ "sma_short": self.hours_to_bars(1.5),
330
+ "sma_mid": self.hours_to_bars(3.3),
331
+
332
+ # MACD (scaled)
333
+ "macd_fast": max(3, self.minutes_to_bars(25)),
334
+ "macd_slow": max(7, self.minutes_to_bars(65)),
335
+ "macd_signal": max(3, self.minutes_to_bars(25)),
336
+
337
+ # Bollinger Bands
338
+ "bb_period": self.hours_to_bars(1.5),
339
+
340
+ # Volume percentile (1 trading day)
341
+ "vol_lookback": self.bars_per_day,
342
+
343
+ # Opening range (30 minutes)
344
+ "or_bars": self.minutes_to_bars(30),
345
+ "or_minutes": 30,
346
+
347
+ # Channel periods (1h, 2h, 4h)
348
+ "channel_periods": [
349
+ self.hours_to_bars(1),
350
+ self.hours_to_bars(2),
351
+ self.hours_to_bars(4),
352
+ ],
353
+
354
+ # ROC periods (30m, 1h, 2h)
355
+ "roc_periods": [
356
+ self.minutes_to_bars(30),
357
+ self.hours_to_bars(1),
358
+ self.hours_to_bars(2),
359
+ ],
360
+
361
+ # Volatility state
362
+ "volatility_atr_period": self.hours_to_bars(1.2),
363
+ "volatility_lookback": self.bars_per_day,
364
+ "volatility_high_pct": 75.0,
365
+ "volatility_low_pct": 25.0,
366
+ }
367
+
368
+ def get_session_bars(self, session_phase: str) -> int:
369
+ """
370
+ Get expected bars for a session phase.
371
+
372
+ Args:
373
+ session_phase: 'night', 'morning', 'afternoon', 'day1', 'day2'
374
+
375
+ Returns:
376
+ Expected number of bars in that session
377
+ """
378
+ if self.market_code == 'SHFE':
379
+ from echolon.config.markets.shfe.constants import get_session_bars
380
+ return get_session_bars(self.bar_size, session_phase, self.has_night_session)
381
+ elif self.market_code == 'CRYPTO':
382
+ # Crypto has 24h continuous - divide by 3 for "sessions"
383
+ return self.bars_per_day // 3
384
+
385
+ return self.bars_per_day
386
+
387
+ # =========================================================================
388
+ # Phase Encoding (for Backtrader compatibility)
389
+ # =========================================================================
390
+
391
+ def encode_phase(self, phase_str: str) -> int:
392
+ """
393
+ Convert session phase string to numeric encoding.
394
+
395
+ This method is bar_size-aware (bar_size baked in at context creation):
396
+ - Granular (5m/15m): 'night'->1, 'morning'->2, 'afternoon'->5
397
+ - Aggregated (30m/1h): 'night_session'->1, 'day_session'->2
398
+
399
+ Args:
400
+ phase_str: Phase name. For granular bars: 'night', 'morning', 'afternoon'.
401
+ For aggregated bars: 'night_session', 'day_session'.
402
+
403
+ Returns:
404
+ Numeric encoding for Backtrader data feed (0 if unknown)
405
+ """
406
+ return self._encode_phase(phase_str)
407
+
408
+ def decode_phase(self, phase_code: int) -> str:
409
+ """
410
+ Convert numeric phase code to string.
411
+
412
+ This method is bar_size-aware (bar_size baked in at context creation):
413
+ - Granular (5m/15m): 1->'night', 2->'morning', 5->'afternoon'
414
+ - Aggregated (30m/1h): 1->'night_session', 2->'day_session'
415
+
416
+ Args:
417
+ phase_code: Numeric encoding from Backtrader data feed
418
+
419
+ Returns:
420
+ Phase name string ('unknown' if code not recognized)
421
+ """
422
+ return self._decode_phase(phase_code)
423
+
424
+ def get_phase_for_time(self, t: time) -> Optional[str]:
425
+ """
426
+ Get session phase name for a given time.
427
+
428
+ Args:
429
+ t: Time to check
430
+
431
+ Returns:
432
+ Phase name or None if outside trading hours
433
+ """
434
+ for name, phase in self.phases.items():
435
+ if phase.contains_time(t):
436
+ return name
437
+ return None
438
+
439
+ def is_trading_time(self, t: time) -> bool:
440
+ """
441
+ Check if time is during active trading (not in a break).
442
+
443
+ Args:
444
+ t: Time to check
445
+
446
+ Returns:
447
+ True if during trading hours
448
+ """
449
+ phase_name = self.get_phase_for_time(t)
450
+ if phase_name is None:
451
+ return False
452
+ return self.phases[phase_name].is_trading
453
+
454
+ # =========================================================================
455
+ # Calculations
456
+ # =========================================================================
457
+
458
+ def calculate_commission(self, price: float, size: int) -> float:
459
+ """Calculate commission for a trade."""
460
+ return self.instrument.calculate_commission(price, size)
461
+
462
+ def calculate_margin(self, price: float, size: int) -> float:
463
+ """Calculate required margin."""
464
+ return self.instrument.calculate_margin(price, size)
465
+
466
+ def calculate_contract_value(self, price: float, size: int) -> float:
467
+ """Calculate total contract value."""
468
+ return self.instrument.calculate_contract_value(price, size)
469
+
470
+ # =========================================================================
471
+ # Serialization
472
+ # =========================================================================
473
+
474
+ def to_dict(self) -> dict:
475
+ """Convert to dictionary for logging/serialization."""
476
+ return {
477
+ 'market': self.market_code,
478
+ 'instrument': self.instrument_code,
479
+ 'instrument_name': self.instrument_name,
480
+ 'frequency': self.frequency,
481
+ 'bar_size': self.bar_size,
482
+ 'timezone': self.timezone,
483
+ 'currency': self.currency,
484
+ 'multiplier': self.multiplier,
485
+ 'tick_size': self.tick_size,
486
+ 'margin_rate': self.margin_rate,
487
+ 'has_night_session': self.has_night_session,
488
+ 'is_24h': self.is_24h,
489
+ 'bars_per_day': self.bars_per_day,
490
+ 'initial_capital': self.initial_capital,
491
+ }
492
+
493
+ def __repr__(self) -> str:
494
+ return (
495
+ f"TradingContext("
496
+ f"market={self.market_code}, "
497
+ f"instrument={self.instrument_code}, "
498
+ f"frequency={self.frequency}, "
499
+ f"bar_size={self.bar_size})"
500
+ )
501
+
502
+ # =========================================================================
503
+ # Bar-Size-Aware Phase Selection (SHFE-specific)
504
+ # =========================================================================
505
+
506
+ @property
507
+ def is_aggregated_phases(self) -> bool:
508
+ """
509
+ Whether current bar size uses aggregated session phases.
510
+
511
+ Returns:
512
+ True for 30m/1h bars (uses night_session, day_session)
513
+ False for 5m/15m bars (uses night, morning, afternoon)
514
+ """
515
+ if self.market_code == 'SHFE' and self.is_intraday:
516
+ from echolon.config.markets.shfe.phases import is_aggregated_bar_size
517
+ return is_aggregated_bar_size(self.bar_size)
518
+ return False
519
+
520
+ @property
521
+ def tradeable_phases(self) -> List[str]:
522
+ """
523
+ Get list of tradeable phase names appropriate for current bar size.
524
+
525
+ Returns:
526
+ ['night', 'morning', 'afternoon'] for 5m/15m
527
+ ['night_session', 'day_session'] for 30m/1h
528
+ """
529
+ if self.market_code == 'SHFE' and self.is_intraday:
530
+ from echolon.config.markets.shfe.phases import get_tradeable_phases
531
+ return get_tradeable_phases(self.bar_size)
532
+ # Default: return all trading phase names
533
+ return [p.name for p in self.trading_phases]
534
+
535
+ def get_phase_bars(self, phase: str) -> int:
536
+ """
537
+ Get expected bars for a session phase, bar-size-aware.
538
+
539
+ Args:
540
+ phase: Phase name (granular or aggregated)
541
+
542
+ Returns:
543
+ Expected number of bars in that phase
544
+ """
545
+ if self.market_code == 'SHFE':
546
+ from echolon.config.markets.shfe.phases import get_phase_trading_bars
547
+ return get_phase_trading_bars(
548
+ phase, self.bar_size_minutes, bar_size=self.bar_size
549
+ )
550
+ return self.bars_per_day
551
+
552
+ def get_phase_buffer_bars(self, phase: str, buffer_type: str) -> int:
553
+ """
554
+ Get buffer bars for a phase (opening or closing), bar-size-aware.
555
+
556
+ Args:
557
+ phase: Phase name (granular or aggregated)
558
+ buffer_type: 'opening' or 'closing'
559
+
560
+ Returns:
561
+ Number of buffer bars
562
+ """
563
+ if self.market_code == 'SHFE':
564
+ from echolon.config.markets.shfe.phases import get_phase_buffer_bars
565
+ return get_phase_buffer_bars(
566
+ phase, buffer_type, self.bar_size_minutes, bar_size=self.bar_size
567
+ )
568
+ return 0
569
+
570
+ def get_phase_for_time_bar_aware(self, t: time) -> Optional[str]:
571
+ """
572
+ Get session phase name for a given time, bar-size-aware.
573
+
574
+ Args:
575
+ t: Time to check
576
+
577
+ Returns:
578
+ Phase name appropriate for current bar size, or None
579
+ """
580
+ if self.market_code == 'SHFE':
581
+ from echolon.config.markets.shfe.phases import get_phase_for_time
582
+ return get_phase_for_time(t, bar_size=self.bar_size)
583
+ return self.get_phase_for_time(t)
584
+
585
+ @property
586
+ def design_paradigm_description(self) -> str:
587
+ """
588
+ Get human-readable description of the design paradigm.
589
+
590
+ Returns:
591
+ Description of granular vs aggregated session design
592
+ """
593
+ if self.market_code == 'SHFE' and self.is_intraday:
594
+ from echolon.config.markets.shfe.phases import get_design_paradigm_description
595
+ return get_design_paradigm_description(self.bar_size)
596
+ return "Standard session-based design"
@@ -0,0 +1,27 @@
1
+ """
2
+ Session Phase Encoding Utilities.
3
+
4
+ Backtrader data feed lines must be numeric, so we encode session phases.
5
+ This module provides the interface for encoding/decoding session phases.
6
+
7
+ Each market implements its own encoding in its phases module.
8
+ This module provides the dispatch mechanism based on market code.
9
+ """
10
+
11
+ from typing import Dict, Callable, Optional
12
+
13
+
14
+ # Registry of market-specific encoders/decoders
15
+ _encoders: Dict[str, Callable[[str], int]] = {}
16
+ _decoders: Dict[str, Callable[[int], str]] = {}
17
+
18
+
19
+ def register_encoder(market: str, encoder: Callable[[str], int]) -> None:
20
+ """Register a market-specific phase encoder."""
21
+ _encoders[market.upper()] = encoder
22
+
23
+
24
+ def register_decoder(market: str, decoder: Callable[[int], str]) -> None:
25
+ """Register a market-specific phase decoder."""
26
+ _decoders[market.upper()] = decoder
27
+