aether-quant 0.0.1__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.
- aether_quant-0.0.1.dist-info/METADATA +7 -0
- aether_quant-0.0.1.dist-info/RECORD +99 -0
- aether_quant-0.0.1.dist-info/WHEEL +5 -0
- aether_quant-0.0.1.dist-info/entry_points.txt +2 -0
- aether_quant-0.0.1.dist-info/licenses/LICENSE +133 -0
- aether_quant-0.0.1.dist-info/top_level.txt +13 -0
- analyzer/README.md +69 -0
- analyzer/__init__.py +17 -0
- analyzer/market_analyzer.py +521 -0
- aq_cli.py +3633 -0
- audit/README.md +47 -0
- audit/__init__.py +38 -0
- audit/hash_chain.py +52 -0
- audit/postgres_audit.py +61 -0
- audit/postgres_worker.py +402 -0
- audit/redis_queue.py +124 -0
- audit/status_export.py +62 -0
- data_pipeline/README.md +257 -0
- data_pipeline/__init__.py +6 -0
- data_pipeline/bar_synthesis.py +97 -0
- data_pipeline/dividend_backfill.py +243 -0
- data_pipeline/factor_file_backfill.py +276 -0
- data_pipeline/fetch.py +206 -0
- data_pipeline/fred_backfill.py +435 -0
- data_pipeline/ib_backfill.py +287 -0
- data_pipeline/v2_manifest.py +75 -0
- data_pipeline/yfinance_backfill.py +501 -0
- evaluation/README.md +152 -0
- evaluation/__init__.py +73 -0
- evaluation/ablation.py +310 -0
- evaluation/benchmark_comparison.py +195 -0
- evaluation/confidence_threshold_calibration.py +157 -0
- evaluation/factor_neutralization_check.py +94 -0
- evaluation/feature_parity.py +321 -0
- evaluation/feature_reconciliation.py +286 -0
- evaluation/impact_model.py +77 -0
- evaluation/kill_switch_replay.py +186 -0
- evaluation/limit_fill_simulator.py +152 -0
- evaluation/model_predictions.py +192 -0
- evaluation/monte_carlo.py +161 -0
- evaluation/public_benchmarks.py +117 -0
- evaluation/rank_book_simulator.py +494 -0
- evaluation/rank_ic_core.py +204 -0
- evaluation/rank_signal_calibration.py +690 -0
- evaluation/rolling_ic_gate_calibration.py +190 -0
- evaluation/rolling_ic_gate_replay.py +138 -0
- execution/README.md +281 -0
- execution/__init__.py +80 -0
- execution/config_cache.py +48 -0
- execution/cost_model.py +213 -0
- execution/lean_config_render.py +131 -0
- execution/live_credentials.py +38 -0
- execution/live_credentials_io.py +52 -0
- execution/order_gate.py +388 -0
- execution/paper_readiness.py +181 -0
- execution/paper_readiness_io.py +54 -0
- execution/paper_readiness_report.py +103 -0
- execution/paper_readiness_scheduler.py +137 -0
- execution/reconciliation.py +160 -0
- execution/runtime_config_io.py +38 -0
- execution/secret_scan.py +73 -0
- features/README.md +77 -0
- features/__init__.py +137 -0
- features/alt_data_features.py +154 -0
- features/bond_features.py +275 -0
- features/cross_asset_sensitivity.py +79 -0
- features/derivatives_macro_features.py +72 -0
- features/macro_features.py +79 -0
- features/options_greeks.py +329 -0
- features/sector_map.py +53 -0
- features/technical_indicators.py +185 -0
- generate_backtest_report.py +311 -0
- generate_evaluation_report.py +712 -0
- inference/README.md +105 -0
- inference/__init__.py +36 -0
- inference/exported_model.py +929 -0
- inference/parallel_inference.py +160 -0
- inference/strategy_selector_inference.py +75 -0
- json_safety.py +130 -0
- portfolio/README.md +447 -0
- portfolio/__init__.py +41 -0
- portfolio/book_construction.py +786 -0
- portfolio/book_neutrality.py +178 -0
- portfolio/hrp_allocation.py +159 -0
- portfolio/options_arbitrage_detector.py +232 -0
- portfolio/options_assignment_risk.py +119 -0
- portfolio/options_margin_sizing.py +333 -0
- portfolio/options_strategy.py +1999 -0
- portfolio/rank_signal.py +219 -0
- portfolio/rolling_ic_gate.py +183 -0
- risk/README.md +275 -0
- risk/__init__.py +38 -0
- risk/asset_class_router.py +584 -0
- risk/forex_risk.py +158 -0
- risk/futures_risk.py +202 -0
- risk/kill_switch.py +261 -0
- risk/manual_override.py +118 -0
- risk/position_sizing.py +303 -0
- risk/rl_sizing.py +189 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""Interactive Brokers historical-data backfill for futures/options -
|
|
2
|
+
mirrors yfinance_backfill.py's shape (pure helpers + one deferred-import
|
|
3
|
+
boundary + orchestration), using `ib_insync` (add to requirements/dev.txt
|
|
4
|
+
only, never requirements.txt - same "dev-only dependency" convention as
|
|
5
|
+
yfinance).
|
|
6
|
+
|
|
7
|
+
This module is ONLY for the offline historical-bars-to-local-Lean-zip step.
|
|
8
|
+
It does NOT touch live/paper trading, which stays entirely on Lean's own
|
|
9
|
+
InteractiveBrokersBrokerage (lean.json's ib-account/ib-user-name/
|
|
10
|
+
ib-password/ib-trading-mode fields and the environments.live-interactive
|
|
11
|
+
block - both untouched by this module). Lean's backtesting environment
|
|
12
|
+
(environments.backtesting in lean.json) is hardcoded to FileSystemDataFeed +
|
|
13
|
+
SubscriptionDataReaderHistoryProvider - it never talks to IB no matter what
|
|
14
|
+
lean.json's ib-* fields hold - so historical futures/options bars still
|
|
15
|
+
need a separate, offline data-prep step to land as local Lean-format zip
|
|
16
|
+
files before any backtest can use them. That is this module's entire job.
|
|
17
|
+
|
|
18
|
+
Connects to the same local TWS/IB Gateway process using
|
|
19
|
+
config.json's phase_v2.ib.host/port/client_id (a second, independent
|
|
20
|
+
client-id socket connection alongside whatever Lean's own brokerage uses
|
|
21
|
+
when live-deployed - standard IB API pattern, Gateway supports multiple
|
|
22
|
+
simultaneous API clients). "IB ready" requires BOTH:
|
|
23
|
+
1. config.json's phase_v2.ib.enabled == true (Aether's own app-level
|
|
24
|
+
feature flag), AND
|
|
25
|
+
2. lean.json's ib-account/ib-user-name are both non-empty (Lean's own
|
|
26
|
+
credential fields - untouched, read-only from this module's
|
|
27
|
+
perspective).
|
|
28
|
+
Every public function below raises IBNotConfiguredError, never a raw
|
|
29
|
+
traceback, when either check fails - see aq_cli.py::cmd_fetch()/cmd_ib()
|
|
30
|
+
for how that's surfaced to the user.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
import json
|
|
36
|
+
import logging
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
from typing import Any
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
43
|
+
CONFIG_PATH = ROOT / "config.json"
|
|
44
|
+
LEAN_CONFIG_PATH = ROOT / "lean.json"
|
|
45
|
+
CONTRACT_SPECS_PATH = ROOT / "data" / "reference" / "futures_contract_specs.json"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class IBNotConfiguredError(Exception):
|
|
49
|
+
"""Raised by every public function in this module when
|
|
50
|
+
phase_v2.ib.enabled is false in config.json, or lean.json's
|
|
51
|
+
ib-account/ib-user-name are missing - never a raw ConnectionError, so
|
|
52
|
+
callers (fetch.py's ASSET_CLASS_CONFIG dispatch, aq fetch's CLI) can
|
|
53
|
+
catch one specific, documented exception type and print a clear
|
|
54
|
+
message instead of a traceback."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def ib_enabled(config: dict, lean_config: dict) -> bool:
|
|
58
|
+
"""Pure, no I/O. True only when config.json's phase_v2.ib.enabled is
|
|
59
|
+
truthy AND lean.json's ib-account/ib-user-name are both non-empty -
|
|
60
|
+
the toggle and the credentials live in two different, purpose-
|
|
61
|
+
appropriate files, cross-checked here."""
|
|
62
|
+
ib_config = config.get("phase_v2", {}).get("ib", {})
|
|
63
|
+
if not ib_config.get("enabled", False):
|
|
64
|
+
return False
|
|
65
|
+
return bool(lean_config.get("ib-account")) and bool(lean_config.get("ib-user-name"))
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def ib_readiness_status(config: dict, lean_config: dict) -> str:
|
|
69
|
+
"""One of "disabled" / "enabled_but_lean_credentials_missing" /
|
|
70
|
+
"ready" - the three states aq_cli.py::cmd_ib() reports (a real
|
|
71
|
+
connect/disconnect round-trip is a separate, heavier check layered on
|
|
72
|
+
top of this pure classification, see attempt_connection() below)."""
|
|
73
|
+
ib_config = config.get("phase_v2", {}).get("ib", {})
|
|
74
|
+
if not ib_config.get("enabled", False):
|
|
75
|
+
return "disabled"
|
|
76
|
+
if not (lean_config.get("ib-account") and lean_config.get("ib-user-name")):
|
|
77
|
+
return "enabled_but_lean_credentials_missing"
|
|
78
|
+
return "ready"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def load_futures_contract_specs(path: Path = CONTRACT_SPECS_PATH) -> dict:
|
|
82
|
+
try:
|
|
83
|
+
with path.open("r", encoding="utf-8") as handle:
|
|
84
|
+
data = json.load(handle)
|
|
85
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
86
|
+
logger.warning("load_futures_contract_specs(%s): unreadable — %s", path, exc)
|
|
87
|
+
return {}
|
|
88
|
+
return {key: value for key, value in data.items() if not key.startswith("_")}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ---------------------------------------------------------------------------
|
|
92
|
+
# The only functions that import ib_insync - deferred, mirrors
|
|
93
|
+
# yfinance_backfill.fetch_yahoo_ohlcv()'s deferred `import yfinance`.
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def connect_ib(config: dict, lean_config: dict) -> Any:
|
|
98
|
+
"""Raises IBNotConfiguredError if not ib_enabled(config, lean_config).
|
|
99
|
+
Never called at import time - this module must stay importable with
|
|
100
|
+
ib_insync absent when IB is disabled, same convention as
|
|
101
|
+
yfinance_backfill.py."""
|
|
102
|
+
if not ib_enabled(config, lean_config):
|
|
103
|
+
raise IBNotConfiguredError(
|
|
104
|
+
"IB is not configured: run 'aq config set phase_v2.ib.enabled true' and fill in "
|
|
105
|
+
"lean.json's ib-account/ib-user-name first (see 'aq ib status')."
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
from ib_insync import IB # deferred - dev-only dependency, never in requirements.txt
|
|
109
|
+
|
|
110
|
+
ib_config = config["phase_v2"]["ib"]
|
|
111
|
+
ib = IB()
|
|
112
|
+
ib.connect(
|
|
113
|
+
str(ib_config.get("host", "127.0.0.1")),
|
|
114
|
+
int(ib_config.get("port", 7497)),
|
|
115
|
+
clientId=int(ib_config.get("client_id", 7)),
|
|
116
|
+
timeout=float(ib_config.get("connect_timeout_seconds", 10)),
|
|
117
|
+
readonly=True,
|
|
118
|
+
)
|
|
119
|
+
return ib
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def disconnect_ib(ib: Any) -> None:
|
|
123
|
+
ib.disconnect()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def attempt_connection(config: dict, lean_config: dict) -> tuple[bool, str]:
|
|
127
|
+
"""Best-effort connect/disconnect round-trip for aq_cli.py::cmd_ib()'s
|
|
128
|
+
"reachable" tri-state check. Returns (True, "reachable") or
|
|
129
|
+
(False, <reason>) - never raises (any connection failure is caught and
|
|
130
|
+
reported, since this is a diagnostic command, not a data operation)."""
|
|
131
|
+
try:
|
|
132
|
+
ib = connect_ib(config, lean_config)
|
|
133
|
+
except IBNotConfiguredError as exc:
|
|
134
|
+
return False, str(exc)
|
|
135
|
+
except Exception as exc: # pragma: no cover - real-network failure paths, not unit tested
|
|
136
|
+
return False, f"connection failed — {exc}"
|
|
137
|
+
else:
|
|
138
|
+
disconnect_ib(ib)
|
|
139
|
+
return True, "reachable"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _bar_rows_from_ib(bars: list) -> list[dict]:
|
|
143
|
+
"""Normalizes ib_insync's BarData objects (each with .date/.open/.high/
|
|
144
|
+
.low/.close/.volume) into the same row shape fetch_yahoo_ohlcv()
|
|
145
|
+
returns, so they slot into scale_for_lean()/write_lean_zip() unchanged."""
|
|
146
|
+
rows = []
|
|
147
|
+
for bar in bars:
|
|
148
|
+
bar_date = bar.date.date() if hasattr(bar.date, "date") else bar.date
|
|
149
|
+
rows.append(
|
|
150
|
+
{
|
|
151
|
+
"date": bar_date,
|
|
152
|
+
"open": float(bar.open),
|
|
153
|
+
"high": float(bar.high),
|
|
154
|
+
"low": float(bar.low),
|
|
155
|
+
"close": float(bar.close),
|
|
156
|
+
"volume": float(bar.volume),
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
return rows
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def fetch_future_historical_bars(
|
|
163
|
+
ib: Any,
|
|
164
|
+
ticker: str,
|
|
165
|
+
contract_spec: dict,
|
|
166
|
+
start: str,
|
|
167
|
+
end: str,
|
|
168
|
+
contract_month: str | None = None,
|
|
169
|
+
) -> list[dict]:
|
|
170
|
+
"""Historical daily bars for `ticker`'s future via ib_insync +
|
|
171
|
+
reqHistoricalData. contract_month=None (default): the continuous
|
|
172
|
+
front-month contract (ContFuture) - correct for live/current sizing,
|
|
173
|
+
but each call only ever sees "whatever is currently front-month," not
|
|
174
|
+
a stable historical series. contract_month="YYYYMM": a SPECIFIC dated
|
|
175
|
+
Future(...) contract instead - lets a caller fetch e.g. both an
|
|
176
|
+
"ES_FRONT" and "ES_NEXT" ticker (aq_cli.py's --contract-month,
|
|
177
|
+
grouped via --family-ticker) for a real historical front/next-month
|
|
178
|
+
term-structure pair (train.py::build_derivatives_macro_features_by_date()),
|
|
179
|
+
which a single continuous series can't provide on its own.
|
|
180
|
+
|
|
181
|
+
Returns [] (never raises) on any IB-side failure or empty response,
|
|
182
|
+
matching fetch_yahoo_ohlcv()'s "one bad symbol never aborts a multi-
|
|
183
|
+
asset run" convention."""
|
|
184
|
+
from ib_insync import ContFuture, Future, util
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
if contract_month:
|
|
188
|
+
contract = Future(
|
|
189
|
+
ticker, lastTradeDateOrContractMonth=contract_month,
|
|
190
|
+
exchange=contract_spec.get("exchange", "CME"), currency="USD",
|
|
191
|
+
)
|
|
192
|
+
else:
|
|
193
|
+
contract = ContFuture(ticker, exchange=contract_spec.get("exchange", "CME"), currency="USD")
|
|
194
|
+
ib.qualifyContracts(contract)
|
|
195
|
+
duration_days = max((util.parseIBDatetime(end) - util.parseIBDatetime(start)).days, 1)
|
|
196
|
+
bars = ib.reqHistoricalData(
|
|
197
|
+
contract,
|
|
198
|
+
endDateTime=end,
|
|
199
|
+
durationStr=f"{duration_days} D",
|
|
200
|
+
barSizeSetting="1 day",
|
|
201
|
+
whatToShow="TRADES",
|
|
202
|
+
useRTH=True,
|
|
203
|
+
formatDate=1,
|
|
204
|
+
)
|
|
205
|
+
except Exception as exc:
|
|
206
|
+
logger.warning("fetch_future_historical_bars(%s): fetch failed — %s", ticker, exc)
|
|
207
|
+
return []
|
|
208
|
+
|
|
209
|
+
return _bar_rows_from_ib(bars or [])
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def fetch_option_chain_snapshot(ib: Any, underlying_ticker: str, expiry: str) -> list[dict]:
|
|
213
|
+
"""One row per (strike, right) for underlying_ticker's chain at expiry
|
|
214
|
+
- {strike, right, expiry, bid, ask, last, volume, open_interest} -
|
|
215
|
+
the raw chain snapshot features/options_greeks.py's compute_greeks()
|
|
216
|
+
consumes to attach delta/gamma/theta/vega/iv before
|
|
217
|
+
portfolio/options_strategy.py selects a contract. Returns [] on any
|
|
218
|
+
failure - never raises."""
|
|
219
|
+
from ib_insync import Option, Stock
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
underlying = Stock(underlying_ticker, "SMART", "USD")
|
|
223
|
+
ib.qualifyContracts(underlying)
|
|
224
|
+
chain_params = ib.reqSecDefOptParams(underlying.symbol, "", underlying.secType, underlying.conId)
|
|
225
|
+
strikes: set[float] = set()
|
|
226
|
+
for param in chain_params:
|
|
227
|
+
if expiry in param.expirations:
|
|
228
|
+
strikes.update(param.strikes)
|
|
229
|
+
|
|
230
|
+
rows: list[dict] = []
|
|
231
|
+
for strike in sorted(strikes):
|
|
232
|
+
for right in ("C", "P"):
|
|
233
|
+
option = Option(underlying_ticker, expiry, float(strike), right, "SMART")
|
|
234
|
+
ib.qualifyContracts(option)
|
|
235
|
+
ticker_data = ib.reqMktData(option, "", False, False)
|
|
236
|
+
ib.sleep(0.2)
|
|
237
|
+
rows.append(
|
|
238
|
+
{
|
|
239
|
+
"strike": float(strike),
|
|
240
|
+
"right": "call" if right == "C" else "put",
|
|
241
|
+
"expiry": expiry,
|
|
242
|
+
"bid": float(ticker_data.bid) if ticker_data.bid == ticker_data.bid else None,
|
|
243
|
+
"ask": float(ticker_data.ask) if ticker_data.ask == ticker_data.ask else None,
|
|
244
|
+
"last": float(ticker_data.last) if ticker_data.last == ticker_data.last else None,
|
|
245
|
+
"volume": float(ticker_data.volume) if ticker_data.volume == ticker_data.volume else None,
|
|
246
|
+
"open_interest": None,
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
return rows
|
|
250
|
+
except Exception as exc:
|
|
251
|
+
logger.warning("fetch_option_chain_snapshot(%s, %s): fetch failed — %s", underlying_ticker, expiry, exc)
|
|
252
|
+
return []
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def fetch_option_historical_bars(
|
|
256
|
+
ib: Any,
|
|
257
|
+
underlying_ticker: str,
|
|
258
|
+
expiry: str,
|
|
259
|
+
strike: float,
|
|
260
|
+
right: str,
|
|
261
|
+
start: str,
|
|
262
|
+
end: str,
|
|
263
|
+
) -> list[dict]:
|
|
264
|
+
"""Historical daily bars for one specific option contract. Same
|
|
265
|
+
OHLCV row shape as futures/equities. Returns [] on any failure -
|
|
266
|
+
never raises."""
|
|
267
|
+
from ib_insync import Option, util
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
ib_right = "C" if right.lower() == "call" else "P"
|
|
271
|
+
contract = Option(underlying_ticker, expiry, float(strike), ib_right, "SMART")
|
|
272
|
+
ib.qualifyContracts(contract)
|
|
273
|
+
duration_days = max((util.parseIBDatetime(end) - util.parseIBDatetime(start)).days, 1)
|
|
274
|
+
bars = ib.reqHistoricalData(
|
|
275
|
+
contract,
|
|
276
|
+
endDateTime=end,
|
|
277
|
+
durationStr=f"{duration_days} D",
|
|
278
|
+
barSizeSetting="1 day",
|
|
279
|
+
whatToShow="TRADES",
|
|
280
|
+
useRTH=True,
|
|
281
|
+
formatDate=1,
|
|
282
|
+
)
|
|
283
|
+
except Exception as exc:
|
|
284
|
+
logger.warning("fetch_option_historical_bars(%s %s %s%s): fetch failed — %s", underlying_ticker, expiry, strike, right, exc)
|
|
285
|
+
return []
|
|
286
|
+
|
|
287
|
+
return _bar_rows_from_ib(bars or [])
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""V2 metadata contract for the existing Lean-data training pipeline."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _asset_group_counts(assets: list[dict]) -> dict[str, int]:
|
|
13
|
+
counts: dict[str, int] = {}
|
|
14
|
+
for asset in assets:
|
|
15
|
+
security_type = str(asset.get("security_type", "unknown"))
|
|
16
|
+
counts[security_type] = counts.get(security_type, 0) + 1
|
|
17
|
+
return counts
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _pipeline_consumers() -> list[str]:
|
|
21
|
+
return [
|
|
22
|
+
"train.py baseline model training",
|
|
23
|
+
"Lean backtesting via main.py",
|
|
24
|
+
"moe expert datasets",
|
|
25
|
+
"regime detection features",
|
|
26
|
+
"topology snapshots",
|
|
27
|
+
"dynamic risk and volatility dashboard feeds",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def build_v2_pipeline_manifest(config: dict, dataset_manifest: dict | None = None) -> dict:
|
|
32
|
+
phase1 = config["phase1"]
|
|
33
|
+
universe = phase1["universe"]
|
|
34
|
+
assets = list(universe["assets"])
|
|
35
|
+
dataset_manifest = dataset_manifest or {}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
"project": config.get("name", "Aether Quant"),
|
|
39
|
+
"version": "v2",
|
|
40
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
41
|
+
"data_source": {
|
|
42
|
+
"type": "local_lean_data_folder",
|
|
43
|
+
"root": "data",
|
|
44
|
+
"absolute_root": str(ROOT / "data"),
|
|
45
|
+
"training_uses_lean_data_folder": True,
|
|
46
|
+
"backtesting_uses_lean_data_folder": True,
|
|
47
|
+
},
|
|
48
|
+
"universe": {
|
|
49
|
+
"name": universe.get("name"),
|
|
50
|
+
"resolution": universe.get("resolution"),
|
|
51
|
+
"asset_count": len(assets),
|
|
52
|
+
"asset_group_counts": _asset_group_counts(assets),
|
|
53
|
+
"tickers": [asset["ticker"] for asset in assets],
|
|
54
|
+
},
|
|
55
|
+
"windows": phase1["windows"],
|
|
56
|
+
"features": {
|
|
57
|
+
"base_features": phase1["features"]["input_set"],
|
|
58
|
+
"target": phase1["target"],
|
|
59
|
+
"normalization": phase1["features"].get("normalization"),
|
|
60
|
+
},
|
|
61
|
+
"quality": {
|
|
62
|
+
"training_eligible_assets": dataset_manifest.get("training_eligible_assets", []),
|
|
63
|
+
"trading_eligible_assets": dataset_manifest.get("trading_eligible_assets", []),
|
|
64
|
+
"observation_only_assets": dataset_manifest.get("observation_only_assets", []),
|
|
65
|
+
},
|
|
66
|
+
"consumers": _pipeline_consumers(),
|
|
67
|
+
"next_v2_dependencies": [
|
|
68
|
+
"regime vectors",
|
|
69
|
+
"expert-specific training slices",
|
|
70
|
+
"topology snapshots",
|
|
71
|
+
"volatility sizing inputs",
|
|
72
|
+
"experience observations",
|
|
73
|
+
],
|
|
74
|
+
}
|
|
75
|
+
|