Commit Graph

924 Commits

Author SHA1 Message Date
jgrusewski
9495cd39ce fix(web-gateway): use TCP peer address for rate limiting instead of X-Forwarded-For
The rate limiter trusted the client-controlled X-Forwarded-For header
to identify clients. An attacker could rotate this header value on every
request to bypass rate limits entirely.

Now uses ConnectInfo<SocketAddr> (the actual TCP connection address) as
the rate limiting key. Server is configured with
into_make_service_with_connect_info to populate this.

X-Forwarded-For and X-Real-Ip headers are no longer consulted.
Falls back to "unknown" if ConnectInfo is unavailable (tests).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:25:05 +01:00
jgrusewski
434f9fbf7a fix(adaptive-strategy): replace fake Kelly return history with error + fallback
get_historical_returns was returning a hardcoded 20-value vector of fake
returns for ALL symbols, causing Kelly criterion to compute position sizes
based on fabricated data. Now returns an error explaining that no market
data feed is connected.

calculate_position_size catches the Kelly/PPO sizing errors and falls
back to standard fixed-fraction sizing with a warning log, instead of
propagating the error to callers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:22:50 +01:00
jgrusewski
477dd47d3f fix(risk): warn when VaR uses static config volatility instead of market data
The VaR engine's get_symbol_volatility used hardcoded per-asset-class
annual volatility values (e.g. 25% for equities, 80% for crypto) without
any indication to operators that real market data was not being used.

Now emits a tracing::warn on every static volatility lookup so operators
see it in logs. Also adds a volatility_overrides HashMap<String, f64>
field on VarEngine for manual per-symbol overrides until a real market
data feed is integrated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:20:26 +01:00
jgrusewski
8641499a6b fix(broker_gateway): gate reconnect Active state on health check
reconnect() previously slept 500ms then unconditionally set
SessionState::Active, faking a successful reconnection regardless of
whether any broker or infrastructure was actually reachable.

Now performs a DB health check (SELECT 1) after the sleep. If the
check fails, state is set to Disconnected and an error is returned.
Active is only set when the health check passes. The DB ping is the
best available liveness probe until a real FIX/cTrader session is
wired into SessionRecovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:18:06 +01:00
jgrusewski
960e8f9dcc fix(broker_gateway): require confirmation for cTrader live trading mode
A single CTRADER_LIVE=true env var was enough to route real money orders
through the broker. Now requires CTRADER_LIVE_CONFIRMED=I_UNDERSTAND_REAL_MONEY
alongside it, preventing accidental live trading from copy-pasted configs.

Also adds prominent warning log when live mode activates and info log
for demo mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:17:43 +01:00
jgrusewski
f1b5f84c6c fix(broker_gateway): log CRITICAL on DB update failure after broker submission
Both route_order and cancel_order used let _ = to discard DB update
errors after successful broker operations. This means an order could be
live at the broker while the database still shows PENDING_SUBMIT or
CANCEL_PENDING, with no log entry to alert operators.

Replaced with if let Err(db_err) that logs at error level with CRITICAL
prefix, client_order_id, and broker_order_id for manual reconciliation.
The RPC still returns success since the broker operation completed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:16:33 +01:00
jgrusewski
a45aec5605 fix(broker_gateway): safe cTrader volume conversion with overflow checks
The previous (quantity * 100_000.0) as i64 silently truncated
fractional lots and could overflow on extreme values. Added
convert_quantity_to_volume() that validates the result is finite,
non-negative, and within i64 range, using round() instead of
truncation. Includes 7 unit tests covering normal values, fractional
rounding, overflow, negative, NaN, infinity, and zero edge cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:14:37 +01:00
jgrusewski
c71c32fff5 fix(trading_service): TFT/Mamba2 validate checkpoint exists and propagate inference errors
from_checkpoint was creating fresh models with random weights and setting
is_trained=true, allowing trading on noise. Now validates checkpoint exists
and does NOT set is_trained=true when weights are random.

Mamba2 predict errors are now wrapped as MLError::InferenceError so the
fallback manager can degrade model health. Both TFT and Mamba2 predict
refuse to run on untrained models, and is_ready() reflects trained state.

Also fixes TFT input_dim mismatch (16 vs 5+10+16=31).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:14:16 +01:00
jgrusewski
4e5a269353 fix(broker_gateway): use blocking write for set_broker_client
try_write() is non-blocking and silently drops the CTraderClient when
the lock is contended. This means a successfully connected broker
client could be lost without any error. Changed to write().await which
guarantees the client is stored. Made function async and updated the
call site in main.rs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:08:43 +01:00
jgrusewski
2f6b76b8fe fix(trading_service): enforce confidence threshold, EMA latency, honest retrain stub
- Low-confidence ensemble votes now forced to Hold (was letting weak
  signals through to order generation in both vote paths)
- Inference latency tracking uses EMA (alpha=0.1) instead of
  overwriting with the latest sample
- retrain_model returns Status::Unimplemented instead of faking
  success with a random job_id
- get_model_performance returns honest zeroes instead of hardcoded
  fake metrics (accuracy=0.85 etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:03:39 +01:00
jgrusewski
5deb618864 fix(ml): DST-aware sessions, normalize ensemble weights, filter non-finite predictions
- Use chrono-tz America/New_York for correct EST/EDT trading session
  boundaries (was hardcoded UTC-5, off by 1h during daylight saving)
- Normalize effective weights to sum to 1.0 before signal aggregation
  (raw weights could sum to anything, biasing the ensemble)
- Skip adapter predictions that return NaN/Inf direction or confidence
  instead of letting them poison the weighted average

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:03:20 +01:00
jgrusewski
17e60a48de fix(adaptive-strategy): init MarketStateTracker with 0.0 instead of NaN
NaN initial features propagate through the PPO policy network and
produce garbage position sizing on the very first inference call.
Replace with 0.0 so the first prediction is safe (neutral).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:02:11 +01:00
jgrusewski
1da0d3bc31 fix(trading_service): validate_order gRPC uses full pre-trade risk checks
Was only checking quantity limit and VaR. Now runs all 5 risk checks:
1. Kill switch / circuit breaker (via TradingServiceKillSwitch)
2. Max order size + position limits (via RiskRepository.get_risk_limits)
3. Daily loss / drawdown limit (via RiskRepository.get_risk_metrics)
4. Leverage limit (via config + RiskRepository.get_risk_metrics)
5. VaR limit (via RiskEngine.check_var_limit, existing)

Violations accumulate rather than short-circuit so callers see all
failures at once. Added 6 tests verifying violation type coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:25:41 +01:00
jgrusewski
774bbe6506 fix(adaptive-strategy): risk limit breaches return errors instead of warnings
VaR, drawdown, and leverage checks in check_risk_limits() only logged
warnings and returned Ok(()). Now they return errors to block order
generation when limits are breached. Also removes unused warn import.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:25:22 +01:00
jgrusewski
fc95dca6ed fix(risk): replace linear z-score interpolation with Abramowitz-Stegun
Linear extrapolation above 0.99 gave z=2.48 for 99.9% (correct: 3.09).
VaR was understated by ~25% at high confidence levels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:17:51 +01:00
jgrusewski
77f7b1e0dc fix(common): limit HalfOpen circuit breaker to single probe
Unlimited concurrent probes could overwhelm recovering services.
Added probe_in_flight guard to ensure only one request probes the
recovering service at a time in HalfOpen state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:16:17 +01:00
jgrusewski
bfe1b2ce2c fix(risk): add account_id field to OrderInfo for per-account risk tracking
Per-account circuit breaker and daily loss tracking was never applied to
real accounts because check_order() hardcoded "default". Added account_id
field to OrderInfo with backward-compatible None fallback. Updated all
construction sites across risk crate tests and integration tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:07:50 +01:00
jgrusewski
5fe0cf953c fix(risk): fail-safe when broker service not configured
Position and leverage checks returned Approved by default when
broker_account_service was None. Now returns ServiceUnavailable
error to prevent unvalidated orders from passing through.

Added 3 tests verifying the fail-safe behavior for both
check_position_limits and check_leverage_limits, plus the
public check_order integration path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 22:06:11 +01:00
jgrusewski
041e6f3d9a fix(trading_engine): reject overfills and fills on completed orders
Duplicate execution reports could double fill_quantity and corrupt
average price. Added guards in process_execution to reject fills on
already-Filled orders and to reject fills that would exceed order qty.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:52:34 +01:00
jgrusewski
5f47df464b fix(trading_engine): atomic validate-and-add prevents duplicate order race
validate_order and add_order were separate operations. The gap between
them allowed duplicate order IDs to both pass validation because
validate_order only took a read lock. New validate_and_add_order method
holds a single write lock for the entire check-and-insert operation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:25:22 +01:00
jgrusewski
330348e84d fix(trading_service): hold write lock across position update to prevent fill race
The update_position method previously acquired a read lock to get the
Arc<AtomicPosition>, dropped it, then called update_with_execution
outside any lock. Two concurrent fills for the same position could both
load the same old_quantity via Acquire, compute independent new quantities,
and the last Release store would silently discard the other fill — causing
the position to show e.g. 10 shares when it should show 20.

Now holds the positions write lock across the entire get-or-create +
update_with_execution sequence, serializing concurrent fills per position.
The validate_position_update call remains outside the lock to minimize
hold time (it does its own async reads and risk checks).

Also removes excessive per-step RDTSC latency tracking from the critical
path (total latency tracking is preserved) and adds a multi-threaded
regression test that spawns 10 concurrent +1 fills and asserts the final
quantity equals 10.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:56:49 +01:00
jgrusewski
2f83e57826 fix(trading_engine): deduct execution value from account cash balance
The old code computed `_execution_value = quantity * price` but
discarded it (underscore prefix).  Only commission was subtracted,
so the account cash balance never reflected the cost of buying or
the proceeds from selling.

Now `update_from_execution` matches on the new `execution.side` field:
- Buy  → cash -= execution_value + commission
- Sell → cash += execution_value − commission

Test assertions updated to expect the corrected balances.

Addresses audit item H2 (account never deducting trade value).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:47:04 +01:00
jgrusewski
3cbf643b4d fix(trading_engine): add OrderSide to ExecutionResult, fix always-buy direction
ExecutionResult.executed_quantity is always a positive magnitude, so the
old `is_buy = executed_quantity > ZERO` check was always true — every
fill was treated as a buy regardless of order side.

Add an explicit `pub side: OrderSide` field to ExecutionResult and use
`execution.side == OrderSide::Buy` in PositionManager.  All construction
sites (source, tests, benchmarks) updated; sell-side tests now use
positive quantities with `side: OrderSide::Sell` instead of the former
negative-quantity hack.

Addresses audit item H4 (position direction always buy).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:45:59 +01:00
jgrusewski
f7b259cb34 fix(trading_service): share atomic counters via Arc in clone_for_async
clone_for_async() was creating independent AtomicU64 instances for
message_count, drop_count, last_heartbeat, and reconnect_attempts
instead of sharing the originals. This meant spawned tasks incremented
their own counters while get_stats() read the original's (always 0),
and the heartbeat monitor watched a counter never updated by the
connection task.

Also fixes last_heartbeat initializing to 0, which caused the first
heartbeat check to compute a huge elapsed time and immediately trigger
a false "connection appears dead" alert.

Changes:
- Change 4 struct fields from AtomicU64 to Arc<AtomicU64>
- Initialize last_heartbeat to HardwareTimestamp::now() instead of 0
- clone_for_async() now clones the Arcs (shared counters)
- Add test verifying counters are shared between original and clone
- Add test verifying heartbeat initialized to current time

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:10:00 +01:00
jgrusewski
8bfd010af5 fix(trading_service): reject negative/NaN prices in fixed-point conversion
Casting negative f64 to u64 saturates to 0, corrupting avg_price and all
downstream PnL calculations. Add price_to_fixed_checked() that rejects
non-finite, zero, and negative prices with PositionError::InvalidPrice.
The critical update_with_execution path now uses the checked variant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:01:38 +01:00
jgrusewski
7eb5ae0c03 fix(trading_engine): order status filter was irrefutable pattern binding
The get_orders() status filter used `matches!(order.status, _status)` which
creates a new wildcard binding instead of comparing against the captured
`status` variable. This caused every order to match regardless of filter,
meaning get_orders(Some(Filled)) returned ALL orders — inflating exposure
calculations. Replaced with direct equality comparison `order.status == *status`.

Added test_get_orders_status_filter_only_returns_matching to prevent regression.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 19:43:59 +01:00
jgrusewski
d45692934a docs: production safety audit implementation plan (38 tasks, 5 layers)
Layer 0: Data Integrity (7 fixes) — position race, price validation, counters
Layer 1: Risk Enforcement (10 fixes) — order atomicity, overfill, risk bypass
Layer 2: ML Pipeline (10 fixes) — random weights, epsilon-greedy, NaN validation
Layer 3: Broker Safety (5 fixes) — connection drops, volume overflow, DB sync
Layer 4: Auth & Ops (6 fixes) — auth stub gating, live trading confirmation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 19:00:29 +01:00
jgrusewski
7e9a3841f0 docs: production safety audit design — 38 fixes across 5 layers
4-domain code audit found 13 CRITICAL, 14 HIGH, 10 MEDIUM issues.
Organized as layer-by-layer remediation:
- Layer 0: Data integrity (positions, prices, market data)
- Layer 1: Risk enforcement (make checks actually block)
- Layer 2: ML pipeline (real weights, bounded predictions)
- Layer 3: Broker safety (connection handling, volumes)
- Layer 4: Auth & ops (credentials, rate limiting, monitoring)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:51:54 +01:00
jgrusewski
17c49f0788 docs: add real data training pipeline design and implementation plan
Design: Download 730 days Databento OHLCV-1m for 4 CME futures,
train DQN + PPO with hyperopt, walk-forward evaluation.

Implementation: 9 tasks — quarterly download binary, walk-forward
splitter, hyperopt runner, training binary, evaluation binary,
DBN wiring, integration tests, manual execution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:07:03 +01:00
jgrusewski
5af8b0b921 fix(docker): use protoc v25 for ml_training_service CUDA build
Ubuntu 22.04's protobuf-compiler (v3.12) lacks proto3 optional field
support. Install protoc v25.1 from GitHub releases instead, which
matches the protoc version available in Debian bookworm-based images
used by the other 5 services.

Validated: docker build completes successfully, binary starts with
ml_training_service --help.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 17:21:27 +01:00
jgrusewski
d8d51aa2d0 fix(docker): add missing workspace members and SQLX_OFFLINE to all Dockerfiles
All 6 service Dockerfiles were missing newly-added workspace crates
(web-gateway, ctrader-openapi, foxhunt-deploy, broker_gateway_service),
causing cargo workspace resolution failures during Docker builds.

Changes across all Dockerfiles:
- Add COPY directives for web-gateway, ctrader-openapi, foxhunt-deploy,
  broker_gateway_service (new workspace members since Dockerfiles written)
- Add SQLX_OFFLINE=true env and .sqlx cache copy where missing
- Add perl and make system deps (needed for OpenSSL build from source)
- Remove COPY migrations (dir excluded by .dockerignore, not needed)
- Expand broker_gateway_service from 3-crate to full workspace copy

Validated: docker build --check passes all 6, cargo check -p passes all 6.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 16:46:24 +01:00
jgrusewski
fa4c649338 fix(ci): triage workflows — fix 3 essential, delete 6 duplicates
Essential workflow fixes:
- ci.yml: add SQLX_OFFLINE=true, replace fictitious cargo subcommands
  (test-unit, ci-lint, audit-deps, etc.) with real cargo commands,
  remove broken 9-way test matrix, remove instrument-coverage RUSTFLAGS
- test.yml: add SQLX_OFFLINE=true to build-check job, fix conflicting
  clippy flags (-D and -W on clippy::all), update JWT secret to 32+ chars
- compilation-guard.yml: add SQLX_OFFLINE=true, remove references to
  non-existent paths (services/trading-engine, crates/common/types),
  remove dangerous auto-commit-to-main, remove MIRI on missing packages

Deleted duplicates (justification):
- comprehensive_testing.yml: duplicate of comprehensive-testing.yml
  (same purpose, underscore vs hyphen naming)
- production-deploy.yml: duplicate of production-deployment.yml
  (both named "Production Deployment Pipeline", this one has stale paths)
- coverage-fixed.yml: duplicate of coverage.yml
  (uses deprecated actions-rs/toolchain@v1 and actions/cache@v3)
- performance.yml: duplicate of benchmark_regression.yml
  (both "Performance Regression Detection", this one less mature)
- quality-baseline.json: not a workflow, stale fake data (999 warnings)
- quality-metrics.json: not a workflow, stale fake data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 16:39:00 +01:00
jgrusewski
f81bd3fc2e test(trading_service): add E2E pipeline integration test (10 models)
Proves the critical trading pipeline path works end-to-end:
OHLCV -> features -> ensemble -> prediction. Uses all 10 real candle
inference adapters (DQN, PPO, TFT, Mamba2, Liquid-CfC, TGGN, TLOB,
KAN, xLSTM, Diffusion) with random weights, 60 synthetic OHLCV bars,
and asserts confidence/action/model-count invariants. No external
dependencies (no DB, no Docker).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 16:34:06 +01:00
jgrusewski
c8bc3504f0 feat(trading_service): wire market data feed to ensemble coordinator
Spawn a background tokio task that feeds synthetic OHLCV bars into the
ensemble coordinator's per-symbol feature extractors.  The extractors
require ~51 bars of warmup before they can produce real 51-dim feature
vectors; without this feed they remain cold and return zeros.

The task uses a random-walk price generator with realistic base prices
for the four baseline futures symbols (ES, NQ, ZN, 6E) and configurable
interval (MARKET_FEED_INTERVAL_MS, default 1s) and symbol list
(MARKET_FEED_SYMBOLS).  In production this will be replaced by a
Databento or exchange data feed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 16:20:02 +01:00
jgrusewski
2942a043ce Merge branch 'worktree-operational-maturity'
# Conflicts:
#	ml/src/ensemble/mod.rs
2026-02-23 16:02:03 +01:00
jgrusewski
1999e5ddbe feat(trading_service): wire all 10 ML models into ensemble coordinator
Register TGGN, TLOB, KAN, xLSTM, and Diffusion inference adapters
alongside the existing DQN, PPO, TFT, Mamba2, and Liquid-CfC.
Rebalance weights to 0.10 each (equal weighting across 10 models).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:55:11 +01:00
jgrusewski
6d43f8d8d2 feat(ml): add TLOB inference adapter for ensemble
Sequence-buffered adapter with 3-layer MLP projection
(flat_dim -> hidden -> hidden/2 -> 1). Ring buffer collects
seq_len feature vectors, returns neutral prediction until full,
then flattens and projects through the MLP with sigmoid output
mapping to direction [-1,1] and confidence [0,1].

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:51:06 +01:00
jgrusewski
7c4341600d feat(ml): add KAN inference adapter for ensemble
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:51:06 +01:00
jgrusewski
3a403669b7 feat(ml): add TGGN inference adapter for ensemble
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:51:06 +01:00
jgrusewski
bb5286e910 Merge branch 'feat/trading-universe-data-org' 2026-02-23 15:22:05 +01:00
jgrusewski
236e1665cf fix(ml): address code review findings
- Remove panic!() calls from test_futures_baseline_micro_mapping,
  use map()+Some() pattern consistent with rest of test suite
- Make DatasetSpec::from_universe() accept a name parameter instead
  of hardcoding "futures-baseline"
- Add doc comment to UniverseConfigMeta explaining dead_code fields

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:17:58 +01:00
jgrusewski
323b77c820 feat(ml): add manifest generation test — builds cache manifest from on-disk DBN files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:05:10 +01:00
jgrusewski
7e96d6e303 chore: add data/cache/ to .gitignore (downloaded market data)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:00:26 +01:00
jgrusewski
7b870726ab docs: add production pipeline wiring implementation plan (10 tasks)
Detailed TDD implementation plan for wiring all 10 ML models into
the ensemble coordinator. Covers 5 new inference adapters (KAN, TGGN,
xLSTM, TLOB, Diffusion), main.rs registration with equal weights,
market data wiring, E2E integration test, Docker/CI validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:59:18 +01:00
jgrusewski
9d8622f410 feat: add futures-baseline universe config (TOML)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:57:48 +01:00
jgrusewski
6d844c009a feat(ml): add AssetUniverse::from_config() for TOML config loading
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:50:40 +01:00
jgrusewski
d268a9dca8 docs: add production pipeline wiring design (6 tasks)
Wire existing components into end-to-end pipeline: 5 missing inference
adapters, 10-model registration, market data feeding, integration test,
Docker build validation, and CI pipeline triage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:43:22 +01:00
jgrusewski
8ce2d53d21 feat(ml): add trading_symbol field to UniverseAsset for micro contract mapping
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:41:22 +01:00
jgrusewski
3a60f303e3 refactor(ml): unify AssetClass — re-export from asset_selection
Remove duplicate AssetClass enum from data_pipeline module and replace
with a re-export from asset_selection, which is now the canonical
location. This ensures data_pipeline::AssetClass and
asset_selection::AssetClass are the same type, enabling direct
comparison and preventing subtle type mismatch bugs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:36:36 +01:00
jgrusewski
ae225b0e31 docs: add trading universe & data organization implementation plan
10-task plan: unify AssetClass, add trading_symbol field, futures_baseline()
preset, TOML config loading, DatasetSpec::from_universe() wiring, data
reorganization into cache structure, stale data cleanup, manifest generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:21:48 +01:00