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.
- echolon/__init__.py +3 -0
- echolon/config/__init__.py +0 -0
- echolon/config/feature_flags.py +54 -0
- echolon/config/markets/__init__.py +0 -0
- echolon/config/markets/core/__init__.py +0 -0
- echolon/config/markets/core/context.py +596 -0
- echolon/config/markets/core/encoding.py +27 -0
- echolon/config/markets/core/registry.py +248 -0
- echolon/config/markets/core/trading_target.py +490 -0
- echolon/config/markets/core/types.py +217 -0
- echolon/config/markets/crypto/__init__.py +0 -0
- echolon/config/markets/crypto/config.py +70 -0
- echolon/config/markets/crypto/perpetuals.py +144 -0
- echolon/config/markets/factory.py +343 -0
- echolon/config/markets/shfe/__init__.py +0 -0
- echolon/config/markets/shfe/config.py +90 -0
- echolon/config/markets/shfe/constants.py +166 -0
- echolon/config/markets/shfe/instruments.py +321 -0
- echolon/config/markets/shfe/phases.py +622 -0
- echolon/config/markets/shfe/sessions.py +79 -0
- echolon/config/quant_engine.py +132 -0
- echolon/config/settings.py +61 -0
- echolon/data_pipeline/__init__.py +6 -0
- echolon/data_pipeline/extractors/base.py +113 -0
- echolon/data_pipeline/extractors/binance/__init__.py +10 -0
- echolon/data_pipeline/extractors/binance/perpetual_extractor.py +587 -0
- echolon/data_pipeline/extractors/shfe/day_extractor.py +164 -0
- echolon/data_pipeline/extractors/shfe/live_day_extractor.py +580 -0
- echolon/data_pipeline/extractors/shfe/minute_extractor.py +277 -0
- echolon/data_pipeline/loaders/calendar_loader.py +180 -0
- echolon/data_pipeline/loaders/ohlcv_loader.py +161 -0
- echolon/data_pipeline/loaders/session_availability_loader.py +477 -0
- echolon/data_pipeline/schemas/ohlcv.py +43 -0
- echolon/data_pipeline/schemas/standard_schema.py +536 -0
- echolon/data_pipeline/transformers/calendar_generator.py +211 -0
- echolon/data_pipeline/transformers/contract_splitter.py +113 -0
- echolon/data_pipeline/transformers/ohlcv_resampler.py +218 -0
- echolon/data_pipeline/transformers/ohlcv_standardizer.py +354 -0
- echolon/data_pipeline/transformers/session_filter.py +136 -0
- echolon/data_pipeline/transformers/shfe_session_analyzer.py +320 -0
- echolon/indicators/__init__.py +6 -0
- echolon/indicators/calculators/__init__.py +0 -0
- echolon/indicators/calculators/interday/__init__.py +0 -0
- echolon/indicators/calculators/interday/indicator_dictionary.json +187 -0
- echolon/indicators/calculators/interday/indicator_mapping.py +300 -0
- echolon/indicators/calculators/interday/market_regime.py +425 -0
- echolon/indicators/calculators/interday/price_channel.py +49 -0
- echolon/indicators/calculators/interday/sr_zone.py +150 -0
- echolon/indicators/calculators/interday/ta_lib.py +1157 -0
- echolon/indicators/calculators/intraday/__init__.py +0 -0
- echolon/indicators/calculators/intraday/indicator_dictionary.json +88 -0
- echolon/indicators/calculators/intraday/indicator_mapping.py +337 -0
- echolon/indicators/calculators/intraday/indicators.py +1108 -0
- echolon/indicators/calculators/intraday/market_context.py +398 -0
- echolon/indicators/calculators/intraday/ta_lib.py +1082 -0
- echolon/indicators/config/interday_analysis_indicators.json +147 -0
- echolon/indicators/config/interday_indicators_classification.md +260 -0
- echolon/indicators/config/interday_indicators_documentation.md +255 -0
- echolon/indicators/config/intraday_analysis_indicators.json +356 -0
- echolon/indicators/config/intraday_indicators_classification.md +386 -0
- echolon/indicators/config/intraday_indicators_documentation.md +134 -0
- echolon/indicators/engine/__init__.py +0 -0
- echolon/indicators/engine/processor.py +1274 -0
- echolon/indicators/optimization/__init__.py +0 -0
- echolon/indicators/optimization/interday_regime_optimizer.py +1032 -0
- echolon/indicators/optimization/regime_utils.py +230 -0
- echolon/indicators/registry/__init__.py +0 -0
- echolon/indicators/registry/utils.py +146 -0
- echolon/indicators/utils/__init__.py +1 -0
- echolon/indicators/utils/indicator_loader.py +67 -0
- echolon/indicators/utils/merge_indicators.py +67 -0
- echolon/lib/__init__.py +0 -0
- echolon/lib/json_utils.py +175 -0
- echolon/lib/regime_utils.py +160 -0
- echolon/lib/stats_utils.py +277 -0
- echolon/lib/strategy_log.py +577 -0
- echolon/quant_engine/LOGGING_DESIGN.md +725 -0
- echolon/quant_engine/__init__.py +27 -0
- echolon/quant_engine/backtest/__init__.py +0 -0
- echolon/quant_engine/backtest/engine/__init__.py +0 -0
- echolon/quant_engine/backtest/engine/analyzers.py +1106 -0
- echolon/quant_engine/backtest/engine/backtest_runner.py +631 -0
- echolon/quant_engine/backtest/engine/backtrader_engine.py +1444 -0
- echolon/quant_engine/backtest/engine/backtrader_strategy.py +495 -0
- echolon/quant_engine/backtest/engine/enriched_pandas_data.py +245 -0
- echolon/quant_engine/backtest/engine/futures/__init__.py +0 -0
- echolon/quant_engine/backtest/engine/futures/enhanced_position.py +187 -0
- echolon/quant_engine/backtest/engine/hooks/__init__.py +0 -0
- echolon/quant_engine/backtest/engine/hooks/base.py +175 -0
- echolon/quant_engine/backtest/engine/hooks/contract_aware/__init__.py +0 -0
- echolon/quant_engine/backtest/engine/hooks/contract_aware/broker.py +583 -0
- echolon/quant_engine/backtest/engine/hooks/contract_aware/hook.py +197 -0
- echolon/quant_engine/backtest/engine/hooks/contract_aware/observer.py +376 -0
- echolon/quant_engine/backtest/engine/hooks/session_aware.py +184 -0
- echolon/quant_engine/backtest/engine/optimization_runner.py +403 -0
- echolon/quant_engine/backtest/optimization/__init__.py +0 -0
- echolon/quant_engine/backtest/optimization/optuna_study.py +572 -0
- echolon/quant_engine/backtest/optimization/select_best_trial.py +476 -0
- echolon/quant_engine/backtest/portfolio_backtest_runner.py +421 -0
- echolon/quant_engine/backtest/portfolio_metrics.py +261 -0
- echolon/quant_engine/backtest/wfa/__init__.py +11 -0
- echolon/quant_engine/backtest/wfa/analyzer.py +173 -0
- echolon/quant_engine/backtest/wfa/drs_calculator.py +755 -0
- echolon/quant_engine/backtest/wfa/runner.py +337 -0
- echolon/quant_engine/backtest/wfa/window.py +48 -0
- echolon/quant_engine/calculate_mfe_mae.py +551 -0
- echolon/quant_engine/core/__init__.py +0 -0
- echolon/quant_engine/core/base/__init__.py +0 -0
- echolon/quant_engine/core/base/base_component.py +861 -0
- echolon/quant_engine/core/base/base_strategy.py +1333 -0
- echolon/quant_engine/core/base/hooks/__init__.py +0 -0
- echolon/quant_engine/core/base/hooks/component_hook_base.py +90 -0
- echolon/quant_engine/core/base/hooks/forced_exit_strategy_hook.py +324 -0
- echolon/quant_engine/core/base/hooks/session_aware_component_hook.py +277 -0
- echolon/quant_engine/core/base/hooks/session_aware_strategy_hook.py +410 -0
- echolon/quant_engine/core/base/hooks/strategy_hook_base.py +152 -0
- echolon/quant_engine/core/base/parameter_architecture.py +280 -0
- echolon/quant_engine/core/base/state_manager.py +280 -0
- echolon/quant_engine/core/frequency/__init__.py +0 -0
- echolon/quant_engine/core/frequency/interday_context.py +88 -0
- echolon/quant_engine/core/frequency/intraday_context.py +159 -0
- echolon/quant_engine/core/frequency/session_context_provider.py +467 -0
- echolon/quant_engine/core/interfaces/__init__.py +0 -0
- echolon/quant_engine/core/interfaces/frequency_context.py +156 -0
- echolon/quant_engine/core/interfaces/market_adapter.py +413 -0
- echolon/quant_engine/core/interfaces/session_context.py +540 -0
- echolon/quant_engine/core/interfaces/trading_interfaces.py +839 -0
- echolon/quant_engine/core/logging/__init__.py +0 -0
- echolon/quant_engine/core/logging/strategy_logger.py +492 -0
- echolon/quant_engine/data/indicators/by_contract/al1801_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al1801_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1802_indicators.csv +247 -0
- echolon/quant_engine/data/indicators/by_contract/al1802_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1803_indicators.csv +246 -0
- echolon/quant_engine/data/indicators/by_contract/al1803_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1804_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al1804_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1805_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al1805_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1806_indicators.csv +247 -0
- echolon/quant_engine/data/indicators/by_contract/al1806_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1807_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al1807_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1808_indicators.csv +246 -0
- echolon/quant_engine/data/indicators/by_contract/al1808_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1809_indicators.csv +246 -0
- echolon/quant_engine/data/indicators/by_contract/al1809_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1810_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al1810_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1811_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al1811_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1812_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al1812_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1901_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al1901_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1902_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al1902_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1903_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al1903_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1904_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al1904_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1905_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al1905_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1906_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al1906_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1907_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al1907_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1908_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al1908_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1909_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al1909_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1910_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al1910_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1911_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al1911_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al1912_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al1912_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2001_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2001_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2002_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2002_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2003_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2003_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2004_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2004_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2005_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2005_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2006_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2006_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2007_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2007_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2008_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2008_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2009_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2009_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2010_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2010_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2011_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2011_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2012_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2012_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2101_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2101_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2102_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2102_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2103_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2103_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2104_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2104_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2105_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2105_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2106_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2106_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2107_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2107_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2108_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2108_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2109_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2109_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2110_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2110_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2111_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2111_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2112_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2112_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2201_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2201_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2202_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2202_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2203_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2203_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2204_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2204_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2205_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2205_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2206_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2206_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2207_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2207_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2208_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2208_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2209_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2209_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2210_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2210_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2211_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2211_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2212_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2212_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2301_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2301_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2302_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2302_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2303_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2303_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2304_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2304_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2305_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2305_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2306_indicators.csv +246 -0
- echolon/quant_engine/data/indicators/by_contract/al2306_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2307_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2307_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2308_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2308_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2309_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2309_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2310_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2310_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2311_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2311_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2312_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2312_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2401_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2401_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2402_indicators.csv +245 -0
- echolon/quant_engine/data/indicators/by_contract/al2402_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2403_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2403_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2404_indicators.csv +241 -0
- echolon/quant_engine/data/indicators/by_contract/al2404_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2405_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2405_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2406_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2406_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2407_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2407_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2408_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2408_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2409_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2409_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2410_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2410_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2411_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2411_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2412_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2412_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2501_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2501_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2502_indicators.csv +241 -0
- echolon/quant_engine/data/indicators/by_contract/al2502_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2503_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2503_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2504_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2504_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2505_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2505_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2506_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2506_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2507_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2507_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2508_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2508_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2509_indicators.csv +242 -0
- echolon/quant_engine/data/indicators/by_contract/al2509_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2510_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2510_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2511_indicators.csv +244 -0
- echolon/quant_engine/data/indicators/by_contract/al2511_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2512_indicators.csv +243 -0
- echolon/quant_engine/data/indicators/by_contract/al2512_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2601_indicators.csv +234 -0
- echolon/quant_engine/data/indicators/by_contract/al2601_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2602_indicators.csv +217 -0
- echolon/quant_engine/data/indicators/by_contract/al2602_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2603_indicators.csv +197 -0
- echolon/quant_engine/data/indicators/by_contract/al2603_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2604_indicators.csv +177 -0
- echolon/quant_engine/data/indicators/by_contract/al2604_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2605_indicators.csv +158 -0
- echolon/quant_engine/data/indicators/by_contract/al2605_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2606_indicators.csv +137 -0
- echolon/quant_engine/data/indicators/by_contract/al2606_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2607_indicators.csv +116 -0
- echolon/quant_engine/data/indicators/by_contract/al2607_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2608_indicators.csv +93 -0
- echolon/quant_engine/data/indicators/by_contract/al2608_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2609_indicators.csv +72 -0
- echolon/quant_engine/data/indicators/by_contract/al2609_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2610_indicators.csv +56 -0
- echolon/quant_engine/data/indicators/by_contract/al2610_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2611_indicators.csv +33 -0
- echolon/quant_engine/data/indicators/by_contract/al2611_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/by_contract/al2612_indicators.csv +13 -0
- echolon/quant_engine/data/indicators/by_contract/al2612_indicators.pkl +0 -0
- echolon/quant_engine/data/indicators/strategy_indicator_metadata.json +44 -0
- echolon/quant_engine/data/indicators/strategy_indicators.csv +1943 -0
- echolon/quant_engine/data/indicators/strategy_indicators.pkl +0 -0
- echolon/quant_engine/data_loader/SHFE_loader.py +175 -0
- echolon/quant_engine/data_loader/__init__.py +0 -0
- echolon/quant_engine/data_loader/contract_data.py +397 -0
- echolon/quant_engine/deploy/__init__.py +1 -0
- echolon/quant_engine/deploy/config/__init__.py +1 -0
- echolon/quant_engine/deploy/config/deploy_config.py +157 -0
- echolon/quant_engine/deploy/config/logging_config.py +159 -0
- echolon/quant_engine/deploy/config/portfolio_deploy_config.py +170 -0
- echolon/quant_engine/deploy/config/trading_calendar.csv +366 -0
- echolon/quant_engine/deploy/data_pipeline/__init__.py +12 -0
- echolon/quant_engine/deploy/data_pipeline/trading_util.py +49 -0
- echolon/quant_engine/deploy/engine/__init__.py +9 -0
- echolon/quant_engine/deploy/engine/capital_slot.py +108 -0
- echolon/quant_engine/deploy/engine/dashboard_aggregator.py +397 -0
- echolon/quant_engine/deploy/engine/dashboard_data_generator.py +393 -0
- echolon/quant_engine/deploy/engine/dashboard_data_sender.py +76 -0
- echolon/quant_engine/deploy/engine/portfolio_risk_overlay.py +343 -0
- echolon/quant_engine/deploy/engine/portfolio_trading_runner.py +1382 -0
- echolon/quant_engine/deploy/engine/slot_aware_portfolio.py +348 -0
- echolon/quant_engine/deploy/engine/trading_data_logger.py +384 -0
- echolon/quant_engine/deploy/engine/trading_runner.py +1181 -0
- echolon/quant_engine/deploy/engine/trading_slot.py +511 -0
- echolon/quant_engine/deploy/platforms/__init__.py +1 -0
- echolon/quant_engine/deploy/platforms/ccxt/__init__.py +45 -0
- echolon/quant_engine/deploy/platforms/ccxt/ccxt_client.py +47 -0
- echolon/quant_engine/deploy/platforms/ccxt/ccxt_engine.py +47 -0
- echolon/quant_engine/deploy/platforms/miniqmt/__init__.py +1 -0
- echolon/quant_engine/deploy/platforms/miniqmt/qmt_client.py +1784 -0
- echolon/quant_engine/deploy/platforms/miniqmt/qmt_engine.py +1132 -0
- echolon/quant_engine/deploy/platforms/miniqmt/xtdc_client.py +357 -0
- echolon/quant_engine/engine_factory.py +383 -0
- echolon/quant_engine/logging_utils.py +392 -0
- echolon/quant_engine/market_adapters/__init__.py +0 -0
- echolon/quant_engine/market_adapters/base_adapter.py +398 -0
- echolon/quant_engine/market_adapters/crypto/__init__.py +0 -0
- echolon/quant_engine/market_adapters/crypto/crypto_adapter.py +500 -0
- echolon/quant_engine/market_adapters/crypto/crypto_session_provider.py +169 -0
- echolon/quant_engine/market_adapters/crypto/perpetual_rules.py +264 -0
- echolon/quant_engine/market_adapters/crypto/session_config.py +73 -0
- echolon/quant_engine/market_adapters/shfe/__init__.py +0 -0
- echolon/quant_engine/market_adapters/shfe/contract_rules.py +484 -0
- echolon/quant_engine/market_adapters/shfe/shfe_adapter.py +581 -0
- echolon/quant_engine/market_adapters/shfe/shfe_session_provider.py +328 -0
- echolon/quant_engine/market_adapters/shfe/trading_calendar.py +315 -0
- echolon/quant_engine/market_adapters/us_futures/__init__.py +0 -0
- echolon/quant_engine/market_adapters/us_futures/cme_adapter.py +33 -0
- echolon/quant_engine/market_adapters/us_futures/session_config.py +33 -0
- echolon/quant_engine/reporting.py +319 -0
- echolon/quant_engine/run_backtest.py +272 -0
- echolon/quant_engine/schemas/README.md +376 -0
- echolon/quant_engine/schemas/__init__.py +0 -0
- echolon/quant_engine/schemas/backtest_results.py +364 -0
- echolon/quant_engine/schemas/selected_trial.py +132 -0
- echolon/quant_engine/schemas/strategy_log.py +283 -0
- echolon/quant_engine/schemas/trade_log.py +370 -0
- echolon/quant_engine/strategy/__init__.py +0 -0
- echolon/quant_engine/strategy/al_s1/__init__.py +0 -0
- echolon/quant_engine/strategy/al_s1/entry.py +277 -0
- echolon/quant_engine/strategy/al_s1/exit.py +390 -0
- echolon/quant_engine/strategy/al_s1/regime_params.json +40 -0
- echolon/quant_engine/strategy/al_s1/risk.py +217 -0
- echolon/quant_engine/strategy/al_s1/selected_robust_trial.json +350 -0
- echolon/quant_engine/strategy/al_s1/sizer.py +300 -0
- echolon/quant_engine/strategy/al_s1/strategy.py +176 -0
- echolon/quant_engine/strategy/al_s1/strategy_code_combined.py +2746 -0
- echolon/quant_engine/strategy/al_s1/strategy_indicator_list.json +17 -0
- echolon/quant_engine/strategy/al_s1/strategy_params.py +622 -0
- echolon/quant_engine/strategy/cu_s1/__init__.py +0 -0
- echolon/quant_engine/strategy/cu_s1/entry.py +362 -0
- echolon/quant_engine/strategy/cu_s1/exit.py +487 -0
- echolon/quant_engine/strategy/cu_s1/regime_params.json +40 -0
- echolon/quant_engine/strategy/cu_s1/risk.py +213 -0
- echolon/quant_engine/strategy/cu_s1/selected_robust_trial.json +388 -0
- echolon/quant_engine/strategy/cu_s1/sizer.py +199 -0
- echolon/quant_engine/strategy/cu_s1/strategy.py +326 -0
- echolon/quant_engine/strategy/cu_s1/strategy_code_combined.py +3018 -0
- echolon/quant_engine/strategy/cu_s1/strategy_indicator_list.json +18 -0
- echolon/quant_engine/strategy/cu_s1/strategy_params.py +590 -0
- echolon/quant_engine/strategy/generators/__init__.py +0 -0
- echolon/quant_engine/strategy/generators/strategy_params_generator.py +1171 -0
- echolon/quant_engine/strategy/zn_s1/__init__.py +0 -0
- echolon/quant_engine/strategy/zn_s1/entry.py +324 -0
- echolon/quant_engine/strategy/zn_s1/exit.py +398 -0
- echolon/quant_engine/strategy/zn_s1/regime_params.json +40 -0
- echolon/quant_engine/strategy/zn_s1/risk.py +404 -0
- echolon/quant_engine/strategy/zn_s1/selected_robust_trial.json +295 -0
- echolon/quant_engine/strategy/zn_s1/sizer.py +195 -0
- echolon/quant_engine/strategy/zn_s1/strategy.py +210 -0
- echolon/quant_engine/strategy/zn_s1/strategy_code_combined.py +2673 -0
- echolon/quant_engine/strategy/zn_s1/strategy_indicator_list.json +17 -0
- echolon/quant_engine/strategy/zn_s1/strategy_params.py +488 -0
- echolon/quant_engine/types.py +599 -0
- echolon-0.1.0.dist-info/METADATA +42 -0
- echolon-0.1.0.dist-info/RECORD +444 -0
- echolon-0.1.0.dist-info/WHEEL +4 -0
- echolon-0.1.0.dist-info/licenses/LICENSE +202 -0
echolon/__init__.py
ADDED
|
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
|
+
|