jgrusewski 35db310893 fix(sp11): symmetric reward cap — losses were unbounded
experience_kernels.cu:2788:
  float capped_pnl = fminf(base_reward, 10.0f);
                          ^^^^^^^^^^^^^ caps profits, NOT losses

Diagnostic instrumentation in smoke-test-k9drh on commit 774d7552a
captured the asymmetry empirically:
  ep1: r_popart min=-9186, max=+10
  ep2: r_popart min=-79089, max=+10 (growing)

`base_reward = 2.0f * vol_normalized_return` and
`vol_normalized_return = segment_return / vol_norm` where
`segment_return` has no structural lower bound (signed P&L). The
unilateral `fminf(base_reward, 10.0f)` capped the upper tail only,
so a single large adverse segment_return produced an arbitrarily
negative `capped_pnl` → r_popart → r_weighted →
reward_components[+0] → slot 63 (PopArt input EMA), inflating
C51/IQN/Bellman normalization scale and breaking Q-target
consistency across epochs. Empirical fingerprint matched the
within-fold sharpe degradation observed in smoke-test-gwfn8 on
commit fd24b5383 (10→4 within F0, 9→2.5 within F1).

Spec semantic: reward bounded in [-10, +10]. Fix:
  float capped_pnl = fmaxf(-10.0f, fminf(base_reward, 10.0f));

Audit findings (per task §2): all related fminf/fmaxf clamps in
experience_kernels.cu reviewed. Reward modifier chain (3260-3500)
verified bounded once r_popart is bilateral. Other bilateral
clamps already correct (515-517, 2174, 2191, 2227, 3300, 3452,
3729, 3763, 5076, 5210, 5213, 5461, 5535, 6353, 6693, 6694).
Intentional asymmetries verified at 1078, 1082-1085, 2564-2565,
2873, 2949, 4574, 5896 (each documented in the audit doc with
the structural reason the lower side is unbounded).

Latent finding flagged separately (NOT fixed here — feature-side
requires consumer audit per feedback_no_partial_refactor):
plan_isv[PNL_VS_TARGET] at line 850 and plan_isv[PNL_VS_STOP]
at line 853 are upper-clamped at 2.0 but lower-unbounded. These
feed assemble_state as policy features (not reward components),
so out of scope of this reward-chain fix. Mirrored in
backtest_plan_kernel.cu:164,168 (same pattern). Tracking as
follow-up.

Per pearl_bounded_modifier_outputs_require_structural_activation:
spec-bounded values require BILATERAL structural enforcement.
This bug was the asymmetric counterpart to the conviction sigmoid
(which IS correctly bounded structurally).

Diagnostic instrumentation (commit 774d7552a) NOT removed in this
commit — will be removed in a follow-up after the symmetric-cap
smoke validates the fix on L40S.

docs/dqn-wire-up-audit.md updated with Resolution (2026-05-04)
section reflecting root cause, fix, audit follow-through, and the
latent plan_isv finding (per Invariant 7).

Build: SQLX_OFFLINE=true cargo check -p ml --lib — clean.
Test: trainers::dqn::trainer::tests::test_reward_function_price_changes
      passes. (PPO test_reward_computation pre-existing failure on
      HEAD 774d7552a, unrelated — verified via stash+rerun.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 14:42:15 +02:00

Foxhunt

Production HFT trading system in Rust.

Architecture

The workspace contains 32 crates organized as follows:

Core Libraries (16)

Crate Purpose
trading_engine Order processing, FIX 4.4, IB TWS, SIMD, RDTSC timing
risk VaR, Kelly, circuit breakers, kill switches, compliance
risk-data Risk data types and shared structures
trading-data Trading data types
ml DQN Rainbow, PPO, TFT, Mamba2, ensemble inference
ml-data ML data types and feature definitions
data Market data ingestion and storage
backtesting Replay engine, strategy tester
adaptive-strategy Ensemble execution, microstructure analysis
common Shared types, resilience, error handling
storage S3 and local model storage
model_loader Model serialization and loading
market-data Market data feed handlers
database PostgreSQL access layer (SQLx)
config Configuration management
tli CLI commands and tooling

Services (8)

Service Purpose
backtesting_service gRPC backtesting service
broker_gateway_service FIX routing, broker connectivity
trading_service Core trading operations
ml_training_service Model training orchestration
data_acquisition_service Market data acquisition
trading_agent_service Autonomous trading agents
api_gateway gRPC API gateway with auth
web-gateway Axum REST + WebSocket gateway

Frontend

web-dashboard/ -- React 19 + TypeScript + Vite + TradingView charts.

Building

# Check compilation (no PostgreSQL required)
SQLX_OFFLINE=true cargo check --workspace

# Run tests for a specific crate
SQLX_OFFLINE=true cargo test -p <crate> --lib

# Clippy
SQLX_OFFLINE=true cargo clippy --workspace

ML Models

Four production model architectures on Candle v0.9.1 with CUDA:

  • DQN Rainbow -- Deep Q-Network with prioritized replay, dueling heads, noisy nets
  • PPO -- Proximal Policy Optimization with GAE and LSTM policies
  • TFT -- Temporal Fusion Transformer for multi-horizon forecasting
  • Mamba2 -- State space model for sequence prediction

Each model has a standalone trainer and a UnifiedTrainable adapter for the hyperopt pipeline.

Infrastructure

  • Git: Gitea at git.fxhnt.ai (Tailscale-only), Scaleway DEV1-S
  • Observability: OpenTelemetry OTLP (env OTEL_EXPORTER_OTLP_ENDPOINT)
  • Database: PostgreSQL with SQLx offline mode for CI

License

Proprietary. All rights reserved.

Description
No description provided
Readme 849 MiB
Languages
Rust 88.2%
Cuda 7.7%
Python 1.3%
Shell 1.1%
PLpgSQL 0.8%
Other 0.8%