aether-quant 0.3.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aether_quant-0.3.0 → aether_quant-0.5.0}/.gitignore +5 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/Dockerfile.retraining_worker +3 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/PKG-INFO +1 -1
- {aether_quant-0.3.0 → aether_quant-0.5.0}/README.md +182 -8
- {aether_quant-0.3.0 → aether_quant-0.5.0}/aether_quant.egg-info/PKG-INFO +1 -1
- {aether_quant-0.3.0 → aether_quant-0.5.0}/aether_quant.egg-info/SOURCES.txt +11 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/aether_quant.egg-info/scm_file_list.json +11 -0
- aether_quant-0.5.0/aether_quant.egg-info/scm_version.json +8 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/aether_quant.egg-info/top_level.txt +1 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/analyzer/README.md +11 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/aq_cli.py +99 -5
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data_pipeline/README.md +27 -0
- aether_quant-0.5.0/data_pipeline/fetch.py +134 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/development/Changelog.md +345 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/development/Problems.md +207 -12
- aether_quant-0.5.0/development/backtest_equity_chart.png +0 -0
- aether_quant-0.5.0/development/logo.png +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/development/v2_architecture.md +23 -3
- {aether_quant-0.3.0 → aether_quant-0.5.0}/generate_backtest_report.py +59 -18
- {aether_quant-0.3.0 → aether_quant-0.5.0}/main.py +139 -33
- aether_quant-0.5.0/ml/gating_feature_schema.json +30 -0
- aether_quant-0.5.0/ml/gating_model.json +570 -0
- aether_quant-0.5.0/ml/gating_training_metrics.json +190 -0
- aether_quant-0.5.0/ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_feature_schema.json +30 -0
- aether_quant-0.5.0/ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_model.json +570 -0
- aether_quant-0.5.0/ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_training_metrics.json +190 -0
- aether_quant-0.5.0/moe/README.md +61 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/moe/__init__.py +4 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/moe/gating.py +101 -36
- {aether_quant-0.3.0 → aether_quant-0.5.0}/monitoring/README.md +1 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/monitoring/neural_network_state.py +41 -22
- {aether_quant-0.3.0 → aether_quant-0.5.0}/pyproject.toml +3 -2
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/__init__.py +4 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/artifacts.py +23 -6
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/orchestrator.py +54 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/worker.py +6 -0
- aether_quant-0.5.0/risk/README.md +50 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/risk/position_sizing.py +52 -1
- {aether_quant-0.3.0 → aether_quant-0.5.0}/risk_controls.py +14 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_aq_cli.py +149 -1
- aether_quant-0.5.0/tests/test_fetch.py +231 -0
- aether_quant-0.5.0/tests/test_gating_network.py +235 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_generate_backtest_report.py +70 -5
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_lean_backtest_ml_coverage.py +8 -6
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_neural_network_state.py +34 -5
- aether_quant-0.5.0/tests/test_position_sizing.py +123 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_retraining_artifacts.py +66 -1
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_retraining_orchestrator.py +49 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_retraining_worker.py +20 -12
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_risk_controls.py +19 -0
- aether_quant-0.5.0/tests/test_train_gating.py +179 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_train_pipeline.py +66 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/topology/README.md +7 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/train.py +20 -1
- aether_quant-0.5.0/train_gating.py +436 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/README.md +13 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/neuralnet/NeuralNetworkScene3D.tsx +5 -3
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/types/state.ts +2 -2
- aether_quant-0.3.0/aether_quant.egg-info/scm_version.json +0 -8
- aether_quant-0.3.0/development/backtest_equity_chart.png +0 -0
- aether_quant-0.3.0/moe/README.md +0 -19
- aether_quant-0.3.0/risk/README.md +0 -19
- aether_quant-0.3.0/tests/test_gating_network.py +0 -97
- aether_quant-0.3.0/tests/test_position_sizing.py +0 -55
- {aether_quant-0.3.0 → aether_quant-0.5.0}/.dockerignore +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/.env.compose.example +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/.env.live.example +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/.gitattributes +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/.github/workflows/ci.yml +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/.github/workflows/release.yml +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/Dockerfile +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/Dockerfile.workers +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/aether_quant.egg-info/dependency_links.txt +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/aether_quant.egg-info/entry_points.txt +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/analyzer/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/analyzer/market_analyzer.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/backtests/.gitkeep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data/alternative/estimize/consensus/aapl/.keep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data/alternative/estimize/estimate/.keep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data/alternative/estimize/release/.keep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data/alternative/sec/aapl/.keep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data/alternative/trading-economics/.keep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data/alternative/trading-economics/calendar/.keep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data/alternative/trading-economics/earnings/.keep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data/alternative/trading-economics/indicator/.keep +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data_pipeline/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data_pipeline/v2_manifest.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/data_pipeline/yfinance_backfill.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/development/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/development/infrastructure.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/docker-compose.yml +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/config_cache.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/live_credentials.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/live_credentials_io.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/order_gate.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/paper_readiness.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/paper_readiness_io.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/paper_readiness_report.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/execution/runtime_config_io.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experience/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experience/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experience/observation_metrics.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experience/postgres_worker.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experience/redis_queue.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experience/simulated_portfolio.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experts/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experts/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/experts/expert_datasets.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/inference/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/inference/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/inference/exported_model.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/liquidity/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/liquidity/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/liquidity/market_liquidity.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/ml/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/monitoring/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/monitoring/api_server.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/notifications/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/notifications/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/notifications/postgres_telegram.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/notifications/telegram_alerts.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/notifications/telegram_client.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/notifications/telegram_worker.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/performance/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/performance/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/performance/postgres_triggers.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/performance/trigger_worker.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/performance/triggers.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/regime/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/regime/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/regime/market_regime.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/requirements/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/requirements/requirements-dev.txt +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/requirements/requirements-retraining-worker.txt +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/requirements/requirements-runtime.txt +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/requirements/requirements-workers.txt +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/requirements/requirements.txt +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/backtest_gate.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/lean_backtest.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/planning.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/postgres_registry.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/status_export.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/validation_gate.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/vault_client.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/retraining/vault_commands.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/risk/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/risk/manual_override.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/setup.cfg +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_backtest_gate.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_config_cache.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_experience_queue.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_expert_datasets.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_expert_models.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_exported_model.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_lean_backtest.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_learned_topology.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_live_credentials.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_live_credentials_io.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_manual_override.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_market_analyzer.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_market_liquidity.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_market_regime.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_market_topology.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_observation_metrics.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_order_gate.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_paper_readiness.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_paper_readiness_io.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_paper_readiness_report.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_postgres_telegram.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_postgres_triggers.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_postgres_worker.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_retraining_planning.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_retraining_postgres_registry.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_runtime_config_io.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_simulated_portfolio.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_status_export.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_telegram_alerts.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_telegram_client.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_telegram_worker.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_train_topology.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_trigger_worker.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_triggers.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_v2_pipeline_manifest.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_validation_gate.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_vault_client.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_vault_commands.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/tests/test_yfinance_backfill.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/topology/__init__.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/topology/learned_topology.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/topology/market_topology.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/train_topology.py +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/visualization/README.md +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/.gitignore +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/.oxlintrc.json +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/index.html +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/overview_v2_12.png +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/package-lock.json +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/package.json +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/public/favicon.svg +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/public/icons.svg +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/risk_v2_12.png +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/App.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/api/client.ts +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/api/hooks.ts +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/heatmap/AssetHeatmap.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/layout/AppShell.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/layout/Panel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/monitoring/CountTable.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/monitoring/MonitoringFeeds.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/monitoring/ObservationPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/monitoring/PaperReadinessPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/monitoring/PerformanceTriggersPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/monitoring/RawStateViewer.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/monitoring/RetrainingStatusPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/neuralnet/NeuralNetworkStatsPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/risk/AssetSizingTable.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/risk/LiquidityTable.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/risk/RiskBar.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/risk/RiskCore.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/risk/StrategyRiskCards.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/scene3d/Scene3D.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/scorecards/Scorecards.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/signals/Badge.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/signals/PositionsList.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/signals/SignalBoard.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/topology/ClusterList.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/topology/TopologyLearningPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/topology/TopologyScene3D.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/tracing/AssetPerformancePanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/tracing/BacktestEquityPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/tracing/DivergingBarChart.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/tracing/LineChart.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/tracing/MetricsSnapshotPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/components/tracing/ObservationEquityPanel.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/index.css +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/lib/downsample.ts +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/lib/format.ts +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/main.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/pages/NeuralNetworkPage.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/pages/Overview.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/pages/RiskPage.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/pages/TopologyPage.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/pages/TracingPage.tsx +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/src/types/tracing.ts +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/tsconfig.app.json +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/tsconfig.json +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/tsconfig.node.json +0 -0
- {aether_quant-0.3.0 → aether_quant-0.5.0}/webui/vite.config.ts +0 -0
|
@@ -94,3 +94,8 @@ Aether-quant-Obsidian-Vault/
|
|
|
94
94
|
# Webui (React/Vite) build artifacts and dependencies
|
|
95
95
|
webui/node_modules/
|
|
96
96
|
webui/dist/
|
|
97
|
+
|
|
98
|
+
# Matplotlib font cache, redirected here by main.py so it persists across
|
|
99
|
+
# Lean CLI's ephemeral per-backtest Docker containers instead of rebuilding
|
|
100
|
+
# every run (see Problems.md)
|
|
101
|
+
.matplotlib_cache/
|
|
@@ -8,7 +8,10 @@ COPY performance/ ./performance/
|
|
|
8
8
|
COPY regime/ ./regime/
|
|
9
9
|
COPY experts/ ./experts/
|
|
10
10
|
COPY topology/ ./topology/
|
|
11
|
+
COPY moe/ ./moe/
|
|
12
|
+
COPY inference/ ./inference/
|
|
11
13
|
COPY retraining/ ./retraining/
|
|
12
14
|
COPY train.py .
|
|
13
15
|
COPY train_topology.py .
|
|
16
|
+
COPY train_gating.py .
|
|
14
17
|
CMD ["python", "-m", "retraining.worker"]
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<img src="https://img.shields.io/badge/python-3.10%2B-FF8C00?style=flat-square&labelColor=1A1A1A&logo=python&logoColor=white" alt="Python 3.10+">
|
|
13
|
-
<!-- AQ:TEST_BADGE_START --><img src="https://img.shields.io/badge/tests-
|
|
13
|
+
<!-- AQ:TEST_BADGE_START --><img src="https://img.shields.io/badge/tests-583%2F583%20passing-brightgreen?style=flat-square&labelColor=1A1A1A" alt="583 of 583 tests passing"><!-- AQ:TEST_BADGE_END -->
|
|
14
14
|
<img src="https://img.shields.io/pypi/v/aether-quant?style=flat-square&labelColor=1A1A1A&color=FF8C00" alt="PyPI version">
|
|
15
15
|
<img src="https://img.shields.io/badge/docker-ghcr.io%2Faether--quant-2496ED?style=flat-square&labelColor=1A1A1A&logo=docker&logoColor=white" alt="Docker image on GHCR">
|
|
16
16
|
</p>
|
|
@@ -35,6 +35,7 @@ window and hope it generalizes.
|
|
|
35
35
|
- [Getting Started](#getting-started)
|
|
36
36
|
- [Requirements](#requirements)
|
|
37
37
|
- [Architecture](#architecture)
|
|
38
|
+
- [Universe Size](#universe-size)
|
|
38
39
|
- [Project Structure](#project-structure)
|
|
39
40
|
- [Module Documentation](#module-documentation)
|
|
40
41
|
- [Development Documentation](#development-documentation)
|
|
@@ -202,6 +203,105 @@ and more), the module map, and an honest analysis of what would need to
|
|
|
202
203
|
change for this to become a genuinely low-latency/HFT system — see
|
|
203
204
|
**[`development/v2_architecture.md`](development/v2_architecture.md)**.
|
|
204
205
|
|
|
206
|
+
## Universe Size
|
|
207
|
+
|
|
208
|
+
The trading universe currently spans **20 assets** — 15 equities and 5
|
|
209
|
+
crypto pairs — defined in `config.json`'s `phase1.universe.assets` and
|
|
210
|
+
shared across training, validation, and backtesting
|
|
211
|
+
(`phase1.universe.common_window`: `2014-12-01` to `2021-03-31`).
|
|
212
|
+
|
|
213
|
+
| Ticker | Type | Role |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| AAPL | Equity | Trading |
|
|
216
|
+
| SPY | Equity | Trading |
|
|
217
|
+
| QQQ | Equity | Trading |
|
|
218
|
+
| IWM | Equity | Trading |
|
|
219
|
+
| EEM | Equity | Trading |
|
|
220
|
+
| BAC | Equity | Trading |
|
|
221
|
+
| IBM | Equity | Trading |
|
|
222
|
+
| AIG | Equity | Trading |
|
|
223
|
+
| BNO | Equity | Trading |
|
|
224
|
+
| FB | Equity | Trading |
|
|
225
|
+
| GOOG | Equity | Trading |
|
|
226
|
+
| GOOGL | Equity | Trading |
|
|
227
|
+
| USO | Equity | Trading |
|
|
228
|
+
| WM | Equity | Trading |
|
|
229
|
+
| AAA | Equity | Observation-only (thin history) |
|
|
230
|
+
| BTCUSD | Crypto | Trading |
|
|
231
|
+
| ETHUSD | Crypto | Observation-only (thin history) |
|
|
232
|
+
| LTCUSD | Crypto | Trading |
|
|
233
|
+
| XRPUSD | Crypto | Observation-only (thin history) |
|
|
234
|
+
| ADAUSD | Crypto | Observation-only (thin history) |
|
|
235
|
+
|
|
236
|
+
"Observation-only" assets (Phase 9's `asset_quality` gate) are still fed
|
|
237
|
+
through the full model/expert/topology pipeline every bar and visible on
|
|
238
|
+
the dashboard, but are never sized into real positions — their real
|
|
239
|
+
history is too short relative to the training window to be trusted for
|
|
240
|
+
trading decisions (see [`development/Changelog.md`](development/Changelog.md)
|
|
241
|
+
for the exact row-count thresholds). This is re-evaluated automatically
|
|
242
|
+
every time `train.py` rebuilds the dataset, so an asset can move between
|
|
243
|
+
these two roles as more history accumulates.
|
|
244
|
+
|
|
245
|
+
```mermaid
|
|
246
|
+
flowchart TD
|
|
247
|
+
DNN(("Baseline DNN<br/>+ MoE Experts<br/>bullish / bearish /<br/>sideways / volatility"))
|
|
248
|
+
|
|
249
|
+
subgraph Equities["Equities (15)"]
|
|
250
|
+
AAPL["AAPL"]
|
|
251
|
+
SPY["SPY"]
|
|
252
|
+
QQQ["QQQ"]
|
|
253
|
+
IWM["IWM"]
|
|
254
|
+
EEM["EEM"]
|
|
255
|
+
BAC["BAC"]
|
|
256
|
+
IBM["IBM"]
|
|
257
|
+
AIG["AIG"]
|
|
258
|
+
BNO["BNO"]
|
|
259
|
+
FB["FB"]
|
|
260
|
+
GOOG["GOOG"]
|
|
261
|
+
GOOGL["GOOGL"]
|
|
262
|
+
USO["USO"]
|
|
263
|
+
WM["WM"]
|
|
264
|
+
AAA["AAA"]
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
subgraph Crypto["Crypto (5)"]
|
|
268
|
+
BTCUSD["BTCUSD"]
|
|
269
|
+
ETHUSD["ETHUSD"]
|
|
270
|
+
LTCUSD["LTCUSD"]
|
|
271
|
+
XRPUSD["XRPUSD"]
|
|
272
|
+
ADAUSD["ADAUSD"]
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
AAPL --- DNN
|
|
276
|
+
SPY --- DNN
|
|
277
|
+
QQQ --- DNN
|
|
278
|
+
IWM --- DNN
|
|
279
|
+
EEM --- DNN
|
|
280
|
+
BAC --- DNN
|
|
281
|
+
IBM --- DNN
|
|
282
|
+
AIG --- DNN
|
|
283
|
+
BNO --- DNN
|
|
284
|
+
FB --- DNN
|
|
285
|
+
GOOG --- DNN
|
|
286
|
+
GOOGL --- DNN
|
|
287
|
+
USO --- DNN
|
|
288
|
+
WM --- DNN
|
|
289
|
+
AAA --- DNN
|
|
290
|
+
BTCUSD --- DNN
|
|
291
|
+
ETHUSD --- DNN
|
|
292
|
+
LTCUSD --- DNN
|
|
293
|
+
XRPUSD --- DNN
|
|
294
|
+
ADAUSD --- DNN
|
|
295
|
+
|
|
296
|
+
classDef hub fill:#1A1A1A,stroke:#FF8C00,color:#FF8C00,stroke-width:2px;
|
|
297
|
+
classDef trading fill:#FF8C00,stroke:#1A1A1A,color:#1A1A1A,stroke-width:1px;
|
|
298
|
+
classDef observation fill:#3A3A3A,stroke:#FF8C00,color:#FF8C00,stroke-width:1px,stroke-dasharray: 4 2;
|
|
299
|
+
|
|
300
|
+
class DNN hub;
|
|
301
|
+
class AAPL,SPY,QQQ,IWM,EEM,BAC,IBM,AIG,BNO,FB,GOOG,GOOGL,USO,WM,BTCUSD,LTCUSD trading;
|
|
302
|
+
class AAA,ETHUSD,XRPUSD,ADAUSD observation;
|
|
303
|
+
```
|
|
304
|
+
|
|
205
305
|
## Project Structure
|
|
206
306
|
|
|
207
307
|
```text
|
|
@@ -291,16 +391,88 @@ and how it's wired in — this table is the index.
|
|
|
291
391
|
|
|
292
392
|
| Metric | Value |
|
|
293
393
|
|---|---|
|
|
294
|
-
| Backtest window |
|
|
295
|
-
|
|
|
394
|
+
| Backtest window | 2018-04-01 to 2021-04-02 |
|
|
395
|
+
| Sharpe Ratio | -0.71 |
|
|
396
|
+
| Net Profit | -8.069% |
|
|
397
|
+
| Compounding Annual Return | -2.761% |
|
|
398
|
+
| Drawdown | 12.500% |
|
|
399
|
+
| Total Orders | 27 |
|
|
400
|
+
| Win Rate | 17% |
|
|
401
|
+
| Last updated | 2026-07-06 17:20 UTC (auto-generated by `aq backtest`) |
|
|
296
402
|
<!-- AQ:BACKTEST_END -->
|
|
297
403
|
|
|
404
|
+
<details>
|
|
405
|
+
<summary><strong>Full Lean statistics</strong> (Sharpe, Sortino, Alpha/Beta, fees, capacity, and everything else Lean reports)</summary>
|
|
406
|
+
|
|
407
|
+
<!-- AQ:BACKTEST_FULL_STATS_START -->
|
|
408
|
+
| Metric | Value |
|
|
409
|
+
|---|---|
|
|
410
|
+
| Total Orders | 27 |
|
|
411
|
+
| Average Win | 0.18% |
|
|
412
|
+
| Average Loss | -1.70% |
|
|
413
|
+
| Compounding Annual Return | -2.761% |
|
|
414
|
+
| Drawdown | 12.500% |
|
|
415
|
+
| Expectancy | -0.816 |
|
|
416
|
+
| Start Equity | 100000.00 |
|
|
417
|
+
| End Equity | 91930.60 |
|
|
418
|
+
| Net Profit | -8.069% |
|
|
419
|
+
| Sharpe Ratio | -0.71 |
|
|
420
|
+
| Sortino Ratio | -0.471 |
|
|
421
|
+
| Probabilistic Sharpe Ratio | 0.171% |
|
|
422
|
+
| Loss Rate | 83% |
|
|
423
|
+
| Win Rate | 17% |
|
|
424
|
+
| Profit-Loss Ratio | 0.11 |
|
|
425
|
+
| Alpha | -0.058 |
|
|
426
|
+
| Beta | 0.195 |
|
|
427
|
+
| Annual Standard Deviation | 0.051 |
|
|
428
|
+
| Annual Variance | 0.003 |
|
|
429
|
+
| Information Ratio | -0.972 |
|
|
430
|
+
| Tracking Error | 0.155 |
|
|
431
|
+
| Treynor Ratio | -0.184 |
|
|
432
|
+
| Total Fees | $12.00 |
|
|
433
|
+
| Estimated Strategy Capacity | $210000000.00 |
|
|
434
|
+
| Lowest Capacity Asset | IBM R735QTJ8XC9X |
|
|
435
|
+
| Portfolio Turnover | 0.07% |
|
|
436
|
+
| Drawdown Recovery | 503 |
|
|
437
|
+
<!-- AQ:BACKTEST_FULL_STATS_END -->
|
|
438
|
+
|
|
439
|
+
</details>
|
|
440
|
+
|
|
298
441
|
This section is regenerated automatically every time you run `aq backtest`
|
|
299
442
|
(see [`generate_backtest_report.py`](generate_backtest_report.py)) — it
|
|
300
443
|
always reflects your most recent successful Lean backtest, reading directly
|
|
301
444
|
from Lean's own result JSON (strategy equity curve, its native SPY benchmark
|
|
302
445
|
series, and the full statistics block), so it never goes stale as long as
|
|
303
|
-
you keep backtesting.
|
|
446
|
+
you keep backtesting. Both the chart image and every statistic above are
|
|
447
|
+
overwritten on each run — there is no manual step and nothing here can go
|
|
448
|
+
stale relative to your last `aq backtest`.
|
|
449
|
+
|
|
450
|
+
**What this backtest does *not* prove:** a bare `lean backtest .` run
|
|
451
|
+
exercises the full inference stack (baseline model, all 4 experts, MoE
|
|
452
|
+
gating, regime, topology, liquidity) every bar, but it does **not**
|
|
453
|
+
exercise the controlled retraining loop — the "learning while trading"
|
|
454
|
+
half of this system's thesis. That loop is a decoupled, asynchronous
|
|
455
|
+
pipeline (`main.py` → Redis → experience-worker → Postgres →
|
|
456
|
+
performance-trigger-worker → retraining-worker), and a bare backtest run
|
|
457
|
+
outside the Docker Compose network can't even reach Redis — events are
|
|
458
|
+
dropped with a warning, so nothing reaches Postgres, no performance
|
|
459
|
+
trigger can fire, and no retraining ever runs (see
|
|
460
|
+
`development/infrastructure.md`). Exercising retraining for real requires
|
|
461
|
+
the full Compose stack up (`docker compose up -d redis postgres
|
|
462
|
+
experience-worker performance-trigger-worker retraining-worker`) with the
|
|
463
|
+
backtest run inside that network, plus an actual trigger condition being
|
|
464
|
+
met during the run.
|
|
465
|
+
|
|
466
|
+
**If `phase_v2.backtest.bypass_safety_gates` is `true`:** this backtest
|
|
467
|
+
also does not represent live/paper-deployable behavior. That flag (default
|
|
468
|
+
`false`) disables the sticky total-drawdown lock and the regime detector's
|
|
469
|
+
drawdown-driven `risk_off` override — both real, designed safety behavior
|
|
470
|
+
in live/paper mode — purely to generate enough trade volume for
|
|
471
|
+
statistically meaningful backtest metrics (see `development/Problems.md`
|
|
472
|
+
#18). A backtest run with this flag set shows the underlying model's
|
|
473
|
+
signal quality across more market conditions, not what this system would
|
|
474
|
+
have actually done if deployed — in live/paper mode, both gates would have
|
|
475
|
+
genuinely halted trading exactly as designed.
|
|
304
476
|
|
|
305
477
|
## Test Suite
|
|
306
478
|
|
|
@@ -334,7 +506,7 @@ pip install -e .
|
|
|
334
506
|
Either way, `aq --help` gives the full command list:
|
|
335
507
|
|
|
336
508
|
```text
|
|
337
|
-
aq train [--dataset-only|--init-only|--experts-only]
|
|
509
|
+
aq train [--dataset-only|--init-only|--experts-only|--gating-only]
|
|
338
510
|
aq test
|
|
339
511
|
aq backtest
|
|
340
512
|
aq report <backtest-folder> <result-id>
|
|
@@ -344,13 +516,14 @@ aq docker up [--lean|--all]
|
|
|
344
516
|
aq docker build
|
|
345
517
|
aq retrain <plan|train|validate|backtest|commit|promote|rollback|status> [...]
|
|
346
518
|
aq trade-lock --on|--off|--auto|--status
|
|
519
|
+
aq fetch <crypto|stock> --ticker <TICKER> --start <YYYY-MM-DD> --end <YYYY-MM-DD> [--apply]
|
|
347
520
|
aq status
|
|
348
521
|
```
|
|
349
522
|
|
|
350
|
-
Every command except `aq trade-lock` is a thin `subprocess`
|
|
351
|
-
command already documented elsewhere in this README:
|
|
523
|
+
Every command except `aq trade-lock` and `aq fetch` is a thin `subprocess`
|
|
524
|
+
wrapper around a command already documented elsewhere in this README:
|
|
352
525
|
|
|
353
|
-
- **`aq train`** — runs `train.py`: builds the dataset and trains the baseline + expert models.
|
|
526
|
+
- **`aq train`** — runs `train.py`: builds the dataset and trains the baseline + expert models. `--gating-only` trains just the learned gating blend (`train_gating.py`) and installs it straight into active `ml/`, mirroring what `--experts-only` already does for the expert models — see `moe/README.md`.
|
|
354
527
|
- **`aq test`** — runs the pytest suite and refreshes this README's test badge.
|
|
355
528
|
- **`aq backtest`** — runs `lean backtest .` and refreshes this README's [Backtest Results](#backtest-results) section.
|
|
356
529
|
- **`aq report <backtest-folder> <result-id>`** — generates Lean's own HTML backtest report (trade blotter, standard Lean charts) at `backtests/<backtest-folder>/report.html`.
|
|
@@ -360,6 +533,7 @@ command already documented elsewhere in this README:
|
|
|
360
533
|
- **`aq docker build`** — rebuilds the `aether-quant` app image.
|
|
361
534
|
- **`aq retrain <stage>`** — dispatches to `python -m retraining.orchestrator <stage> ...` for a single manual pipeline stage.
|
|
362
535
|
- **`aq trade-lock --on|--off|--auto|--status`** — manually overrides `main.py`'s sticky total-drawdown trade lock (see `development/v2_architecture.md`'s Manual Trade-Lock Override Contract). `--off` deliberately clears an otherwise-permanent lock; `--auto` returns to fully automatic behavior.
|
|
536
|
+
- **`aq fetch <crypto|stock> --ticker <TICKER> --start <YYYY-MM-DD> --end <YYYY-MM-DD> [--apply]`** — fetches historical OHLCV from Yahoo Finance for a ticker that isn't in `config.json` yet, formats it into Lean's zip/CSV convention, and writes it to the right spot under `data/` (`data/crypto/coinbase/daily/<ticker>_trade.zip` or `data/equity/usa/daily/<ticker>.zip`). On `--apply`, it also appends a new asset block to `config.json`'s `phase1.universe.assets[]` — no manual editing needed. Dry run by default (no `--apply`): reports what would happen, writes nothing. Never runs `train.py` itself — once applied, run `python train.py --dataset-only` (then `python train.py` when ready) yourself to actually train on the new ticker. `crypto`/`stock` today; a `derivative` asset class is planned for V3.
|
|
363
537
|
- **`aq status`** — shows `git status`.
|
|
364
538
|
|
|
365
539
|
## Release Process
|
|
@@ -14,6 +14,7 @@ main.py
|
|
|
14
14
|
pyproject.toml
|
|
15
15
|
risk_controls.py
|
|
16
16
|
train.py
|
|
17
|
+
train_gating.py
|
|
17
18
|
train_topology.py
|
|
18
19
|
.github/workflows/ci.yml
|
|
19
20
|
.github/workflows/release.yml
|
|
@@ -38,6 +39,7 @@ data/alternative/trading-economics/earnings/.keep
|
|
|
38
39
|
data/alternative/trading-economics/indicator/.keep
|
|
39
40
|
data_pipeline/README.md
|
|
40
41
|
data_pipeline/__init__.py
|
|
42
|
+
data_pipeline/fetch.py
|
|
41
43
|
data_pipeline/v2_manifest.py
|
|
42
44
|
data_pipeline/yfinance_backfill.py
|
|
43
45
|
development/Changelog.md
|
|
@@ -45,6 +47,7 @@ development/Problems.md
|
|
|
45
47
|
development/README.md
|
|
46
48
|
development/backtest_equity_chart.png
|
|
47
49
|
development/infrastructure.md
|
|
50
|
+
development/logo.png
|
|
48
51
|
development/v2_architecture.md
|
|
49
52
|
execution/README.md
|
|
50
53
|
execution/__init__.py
|
|
@@ -72,6 +75,12 @@ liquidity/README.md
|
|
|
72
75
|
liquidity/__init__.py
|
|
73
76
|
liquidity/market_liquidity.py
|
|
74
77
|
ml/README.md
|
|
78
|
+
ml/gating_feature_schema.json
|
|
79
|
+
ml/gating_model.json
|
|
80
|
+
ml/gating_training_metrics.json
|
|
81
|
+
ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_feature_schema.json
|
|
82
|
+
ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_model.json
|
|
83
|
+
ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_training_metrics.json
|
|
75
84
|
moe/README.md
|
|
76
85
|
moe/__init__.py
|
|
77
86
|
moe/gating.py
|
|
@@ -124,6 +133,7 @@ tests/test_experience_queue.py
|
|
|
124
133
|
tests/test_expert_datasets.py
|
|
125
134
|
tests/test_expert_models.py
|
|
126
135
|
tests/test_exported_model.py
|
|
136
|
+
tests/test_fetch.py
|
|
127
137
|
tests/test_gating_network.py
|
|
128
138
|
tests/test_generate_backtest_report.py
|
|
129
139
|
tests/test_lean_backtest.py
|
|
@@ -158,6 +168,7 @@ tests/test_status_export.py
|
|
|
158
168
|
tests/test_telegram_alerts.py
|
|
159
169
|
tests/test_telegram_client.py
|
|
160
170
|
tests/test_telegram_worker.py
|
|
171
|
+
tests/test_train_gating.py
|
|
161
172
|
tests/test_train_pipeline.py
|
|
162
173
|
tests/test_train_topology.py
|
|
163
174
|
tests/test_trigger_worker.py
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": [
|
|
3
3
|
"README.md",
|
|
4
|
+
"train_gating.py",
|
|
4
5
|
"Dockerfile.workers",
|
|
5
6
|
"aq_cli.py",
|
|
6
7
|
"Dockerfile",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"data_pipeline/README.md",
|
|
44
45
|
"data_pipeline/__init__.py",
|
|
45
46
|
"data_pipeline/v2_manifest.py",
|
|
47
|
+
"data_pipeline/fetch.py",
|
|
46
48
|
"data_pipeline/yfinance_backfill.py",
|
|
47
49
|
"visualization/README.md",
|
|
48
50
|
"inference/README.md",
|
|
@@ -152,6 +154,7 @@
|
|
|
152
154
|
"webui/src/types/state.ts",
|
|
153
155
|
"webui/public/favicon.svg",
|
|
154
156
|
"webui/public/icons.svg",
|
|
157
|
+
"development/logo.png",
|
|
155
158
|
"development/backtest_equity_chart.png",
|
|
156
159
|
"development/README.md",
|
|
157
160
|
"development/Problems.md",
|
|
@@ -209,6 +212,8 @@
|
|
|
209
212
|
"tests/test_train_pipeline.py",
|
|
210
213
|
"tests/test_experience_queue.py",
|
|
211
214
|
"tests/test_vault_commands.py",
|
|
215
|
+
"tests/test_train_gating.py",
|
|
216
|
+
"tests/test_fetch.py",
|
|
212
217
|
"data/alternative/sec/aapl/.keep",
|
|
213
218
|
"data/alternative/trading-economics/.keep",
|
|
214
219
|
"data/alternative/trading-economics/calendar/.keep",
|
|
@@ -224,6 +229,12 @@
|
|
|
224
229
|
"requirements/requirements-workers.txt",
|
|
225
230
|
"requirements/requirements-retraining-worker.txt",
|
|
226
231
|
"ml/README.md",
|
|
232
|
+
"ml/gating_model.json",
|
|
233
|
+
"ml/gating_feature_schema.json",
|
|
234
|
+
"ml/gating_training_metrics.json",
|
|
235
|
+
"ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_model.json",
|
|
236
|
+
"ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_feature_schema.json",
|
|
237
|
+
"ml/versions/gating-only-26218402-34d9-4a0a-add8-ee5d50dd0459/gating_training_metrics.json",
|
|
227
238
|
".github/workflows/release.yml",
|
|
228
239
|
".github/workflows/ci.yml"
|
|
229
240
|
]
|
|
@@ -38,6 +38,17 @@ risk engine, and before action categorization / Lean order placement.
|
|
|
38
38
|
explicitly ruled out of scope for that phase as a materially riskier
|
|
39
39
|
change than what its safety rule ("confidence/uncertainty only, never a
|
|
40
40
|
randomized decision") allows.
|
|
41
|
+
- **Follow-up:** the learned topology overlay's confidence/disagreement
|
|
42
|
+
scores now *do* reach a real trade — but through position sizing
|
|
43
|
+
(`risk/position_sizing.py::topology_sizing_multiplier()`), not this
|
|
44
|
+
module. That integration point was chosen specifically because sizing
|
|
45
|
+
is already a continuous, shrink-only multiplier applied after this
|
|
46
|
+
analyzer has categorized the action, so it changes only *how large* an
|
|
47
|
+
already-approved trade is, never *whether* one happens — preserving
|
|
48
|
+
exactly the "confidence/uncertainty only, never a randomized decision"
|
|
49
|
+
rule above. This module's own `trade`/`simulate`/`observe`/
|
|
50
|
+
`reduce_risk` categorization remains fully deterministic and
|
|
51
|
+
unaffected. See `risk/README.md` for details.
|
|
41
52
|
- `main.py` only calls `_apply_signal` when `action == "trade"`. All five
|
|
42
53
|
actions are written into the per-asset `signal_payload` for
|
|
43
54
|
dashboard/Grafana visibility regardless of whether a real order is
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
Matches this codebase's existing CLI convention exactly (see
|
|
4
4
|
`retraining/orchestrator.py`'s `argparse` + `subparsers.add_parser(...)`
|
|
5
5
|
shape) - a single-file dispatcher, not a framework. Every subcommand other
|
|
6
|
-
than `trade-lock` is a thin `subprocess.run(...)` wrapper around
|
|
7
|
-
that already exists and is already documented elsewhere
|
|
8
|
-
development/infrastructure.md) - no logic is reimplemented
|
|
9
|
-
only saves typing. `trade-lock`
|
|
10
|
-
`risk/manual_override.py`
|
|
6
|
+
than `trade-lock` and `fetch` is a thin `subprocess.run(...)` wrapper around
|
|
7
|
+
a command that already exists and is already documented elsewhere
|
|
8
|
+
(README.md, development/infrastructure.md) - no logic is reimplemented
|
|
9
|
+
here, this file only saves typing. `trade-lock` and `fetch` are the two
|
|
10
|
+
exceptions: they call `risk/manual_override.py` and
|
|
11
|
+
`data_pipeline/fetch.py` directly, in-process, no subprocess.
|
|
11
12
|
|
|
12
13
|
Deliberately scoped for v1 - wraps the commands already in daily use, not
|
|
13
14
|
every command mentioned anywhere in the project. Designed to be extended
|
|
@@ -31,9 +32,12 @@ import subprocess
|
|
|
31
32
|
import sys
|
|
32
33
|
import time
|
|
33
34
|
import urllib.request
|
|
35
|
+
import uuid
|
|
36
|
+
from datetime import date
|
|
34
37
|
from importlib.metadata import version as installed_version
|
|
35
38
|
from pathlib import Path
|
|
36
39
|
|
|
40
|
+
from data_pipeline.fetch import ASSET_CLASSES, fetch_adhoc_asset
|
|
37
41
|
from risk.manual_override import read_manual_trade_lock_override, write_manual_trade_lock_override
|
|
38
42
|
|
|
39
43
|
ROOT_DIR = Path(__file__).resolve().parent
|
|
@@ -94,6 +98,18 @@ def _parse_simple_version(value: str) -> tuple[int, ...] | None:
|
|
|
94
98
|
return None
|
|
95
99
|
|
|
96
100
|
|
|
101
|
+
def _iso_date(value: str) -> str:
|
|
102
|
+
"""Validates --start/--end as strict ISO 8601 YYYY-MM-DD, matching the
|
|
103
|
+
convention used everywhere else in this repo (config.json,
|
|
104
|
+
yfinance_backfill.py) - rejects other formats (e.g. DD.MM.YYYY) with a
|
|
105
|
+
clear error instead of a confusing downstream yfinance failure."""
|
|
106
|
+
try:
|
|
107
|
+
date.fromisoformat(value)
|
|
108
|
+
except ValueError as exc:
|
|
109
|
+
raise argparse.ArgumentTypeError(f"invalid date {value!r} - expected ISO 8601 YYYY-MM-DD") from exc
|
|
110
|
+
return value
|
|
111
|
+
|
|
112
|
+
|
|
97
113
|
def _read_update_cache() -> dict:
|
|
98
114
|
if not UPDATE_CACHE_PATH.exists():
|
|
99
115
|
return {}
|
|
@@ -161,6 +177,8 @@ def check_for_update() -> None:
|
|
|
161
177
|
|
|
162
178
|
|
|
163
179
|
def cmd_train(args: argparse.Namespace) -> int:
|
|
180
|
+
if args.gating_only:
|
|
181
|
+
return _train_gating_only()
|
|
164
182
|
cmd = [sys.executable, "train.py"]
|
|
165
183
|
if args.dataset_only:
|
|
166
184
|
cmd.append("--dataset-only")
|
|
@@ -171,6 +189,41 @@ def cmd_train(args: argparse.Namespace) -> int:
|
|
|
171
189
|
return _run(cmd)
|
|
172
190
|
|
|
173
191
|
|
|
192
|
+
def _train_gating_only() -> int:
|
|
193
|
+
"""`aq train --gating-only`: trains the learned gating blend
|
|
194
|
+
(train_gating.py) and installs it straight into active ml/, mirroring
|
|
195
|
+
what `train.py --experts-only` already does for the expert models.
|
|
196
|
+
|
|
197
|
+
train_gating.py always writes to ml/versions/<version_id>/ (same
|
|
198
|
+
versioned-candidate convention every other trainer in this project
|
|
199
|
+
uses), so this generates a throwaway version-id, runs the trainer,
|
|
200
|
+
then copies the 3 resulting artifacts into active ml/ - the same
|
|
201
|
+
manual promotion-simulation step already documented for verifying this
|
|
202
|
+
trainer, skipping the full retraining/validate/backtest/commit/promote
|
|
203
|
+
pipeline since this is an ad-hoc, user-triggered run, not a scheduled
|
|
204
|
+
candidate."""
|
|
205
|
+
version_id = f"gating-only-{uuid.uuid4()}"
|
|
206
|
+
returncode = _run([sys.executable, "train_gating.py", "--version-id", version_id])
|
|
207
|
+
if returncode != 0:
|
|
208
|
+
return returncode
|
|
209
|
+
|
|
210
|
+
version_dir = ROOT_DIR / "ml" / "versions" / version_id
|
|
211
|
+
artifact_names = ("gating_model.json", "gating_feature_schema.json", "gating_training_metrics.json")
|
|
212
|
+
if any(not (version_dir / name).exists() for name in artifact_names):
|
|
213
|
+
print(
|
|
214
|
+
"aq train --gating-only: train_gating.py exited 0 but skipped writing artifacts "
|
|
215
|
+
"(likely insufficient validation/backtest rows) - active ml/ left unchanged.",
|
|
216
|
+
file=sys.stderr,
|
|
217
|
+
)
|
|
218
|
+
return 0
|
|
219
|
+
|
|
220
|
+
ml_dir = ROOT_DIR / "ml"
|
|
221
|
+
for name in artifact_names:
|
|
222
|
+
shutil.copy2(version_dir / name, ml_dir / name)
|
|
223
|
+
print(f"aq train --gating-only: copied {', '.join(artifact_names)} into active ml/.")
|
|
224
|
+
return 0
|
|
225
|
+
|
|
226
|
+
|
|
174
227
|
def _update_readme_test_badge(passed: int, failed: int) -> None:
|
|
175
228
|
"""Atomically rewrites the shields.io test-count badge between the
|
|
176
229
|
AQ:TEST_BADGE markers in README.md, so it never drifts from the real
|
|
@@ -340,6 +393,30 @@ def cmd_trade_lock(args: argparse.Namespace) -> int:
|
|
|
340
393
|
return 0
|
|
341
394
|
|
|
342
395
|
|
|
396
|
+
def cmd_fetch(args: argparse.Namespace) -> int:
|
|
397
|
+
report = fetch_adhoc_asset(args.asset_class, args.ticker, args.start, args.end, apply=args.apply)
|
|
398
|
+
label = "APPLY" if args.apply else "DRY RUN"
|
|
399
|
+
print(f"{label} — {report['ticker']} ({report['yahoo_symbol']}): {report['action']}, rows_fetched={report['rows_fetched']}")
|
|
400
|
+
if report["suggested_available_from"]:
|
|
401
|
+
print(f" date range fetched: {report['suggested_available_from']} .. {report['suggested_available_to']}")
|
|
402
|
+
print(f" data_path: {report['data_path']}")
|
|
403
|
+
|
|
404
|
+
if report["config_status"] == "added":
|
|
405
|
+
print(f" config.json: added a new {report['ticker']} asset block to phase1.universe.assets[]")
|
|
406
|
+
elif report["config_status"] == "already_exists":
|
|
407
|
+
print(
|
|
408
|
+
f" config.json: {report['ticker']} is already configured - left untouched. "
|
|
409
|
+
"Use data_pipeline/yfinance_backfill.py to extend an existing asset's date range instead."
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
if not args.apply:
|
|
413
|
+
print("\nDry run only — nothing was written. Re-run with --apply to write the zip file and update config.json.")
|
|
414
|
+
elif report["action"] == "written":
|
|
415
|
+
print("\nReady to prepare training: run `python train.py --dataset-only` to confirm this ticker's asset quality, then `python train.py` when ready.")
|
|
416
|
+
|
|
417
|
+
return 1 if report["action"] == "no_data_returned" else 0
|
|
418
|
+
|
|
419
|
+
|
|
343
420
|
def cmd_status(_args: argparse.Namespace) -> int:
|
|
344
421
|
return _run(["git", "status"])
|
|
345
422
|
|
|
@@ -353,6 +430,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
353
430
|
train_group.add_argument("--dataset-only", action="store_true", help="Build dataset/scaler/manifest only")
|
|
354
431
|
train_group.add_argument("--init-only", action="store_true", help="Refresh the data inventory only")
|
|
355
432
|
train_group.add_argument("--experts-only", action="store_true", help="Train the 4 expert models only")
|
|
433
|
+
train_group.add_argument(
|
|
434
|
+
"--gating-only", action="store_true", help="Train the learned gating blend only (wraps python train_gating.py)"
|
|
435
|
+
)
|
|
356
436
|
train_parser.set_defaults(func=cmd_train)
|
|
357
437
|
|
|
358
438
|
test_parser = subparsers.add_parser("test", help="Run the test suite (wraps pytest tests/)")
|
|
@@ -409,6 +489,20 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
409
489
|
trade_lock_group.add_argument("--status", dest="status", action="store_true", help="Print the current override state")
|
|
410
490
|
trade_lock_parser.set_defaults(func=cmd_trade_lock)
|
|
411
491
|
|
|
492
|
+
fetch_parser = subparsers.add_parser(
|
|
493
|
+
"fetch", help="Ad-hoc fetch of historical OHLCV from Yahoo Finance for a ticker not yet in config.json"
|
|
494
|
+
)
|
|
495
|
+
fetch_parser.add_argument(
|
|
496
|
+
"asset_class", choices=list(ASSET_CLASSES), help="Asset class (picks the Lean data_path/market convention)"
|
|
497
|
+
)
|
|
498
|
+
fetch_parser.add_argument("--ticker", required=True, help="Internal ticker, e.g. AAPL or BTCUSD")
|
|
499
|
+
fetch_parser.add_argument("--start", required=True, type=_iso_date, help="Start date, ISO 8601 YYYY-MM-DD")
|
|
500
|
+
fetch_parser.add_argument("--end", required=True, type=_iso_date, help="End date, ISO 8601 YYYY-MM-DD")
|
|
501
|
+
fetch_parser.add_argument(
|
|
502
|
+
"--apply", action="store_true", help="Actually write the zip file and update config.json (default: dry run, report only)"
|
|
503
|
+
)
|
|
504
|
+
fetch_parser.set_defaults(func=cmd_fetch)
|
|
505
|
+
|
|
412
506
|
status_parser = subparsers.add_parser("status", help="Show git status")
|
|
413
507
|
status_parser.set_defaults(func=cmd_status)
|
|
414
508
|
|
|
@@ -35,3 +35,30 @@ Usage: `python -m data_pipeline.yfinance_backfill [--tickers ETHUSD LTCUSD] [--a
|
|
|
35
35
|
`yfinance` is a dev-only dependency (`requirements/requirements-dev.txt`),
|
|
36
36
|
never in `requirements.txt`/`requirements-runtime.txt`.
|
|
37
37
|
|
|
38
|
+
## Ad-hoc ticker fetch (`aq fetch`)
|
|
39
|
+
|
|
40
|
+
`fetch.py` is a narrower sibling to `yfinance_backfill.py` above, with a
|
|
41
|
+
different scope and a deliberately different `config.json` policy:
|
|
42
|
+
|
|
43
|
+
| | `yfinance_backfill.py` | `fetch.py` (backs `aq fetch`) |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Scope | Fills gaps in **already-configured** assets | Fetches **any** ticker, including ones with no `config.json` entry at all |
|
|
46
|
+
| Date range | Auto-detected gap vs. the asset's `"backfill"` block | Explicit `--start`/`--end` |
|
|
47
|
+
| `config.json` | **Never** edited — only prints suggested values | **Writes** a new asset block on `--apply`, for a ticker that isn't already configured |
|
|
48
|
+
|
|
49
|
+
The differing `config.json` policy is deliberate, not an inconsistency:
|
|
50
|
+
`yfinance_backfill.py`'s rule exists to stop it from silently widening an
|
|
51
|
+
*existing*, already-trained asset's date range without a human decision.
|
|
52
|
+
`fetch.py` exists specifically to *add a brand-new ticker* to the universe
|
|
53
|
+
on purpose — auto-writing `config.json` there is the intended effect, not
|
|
54
|
+
an accidental side effect. If a ticker fetched via `aq fetch` already has a
|
|
55
|
+
`config.json` entry, `fetch.py` leaves it untouched and points at
|
|
56
|
+
`yfinance_backfill.py` instead, since extending an existing asset's range
|
|
57
|
+
is that script's job, not this one's.
|
|
58
|
+
|
|
59
|
+
Reuses `yfinance_backfill.py`'s pure functions (`fetch_yahoo_ohlcv`,
|
|
60
|
+
`scale_for_lean`, `write_lean_zip`) unchanged — no duplicated logic. Same
|
|
61
|
+
dry-run-by-default/`--apply` safety convention. Never runs `train.py`
|
|
62
|
+
itself; see the root [`README.md`](../README.md#cli-reference) for the
|
|
63
|
+
full `aq fetch` usage.
|
|
64
|
+
|