Skip to main content

Model overview

Training order is strict: Signal β†’ Position β†’ SLTP β†’ Risk. The Risk model depends on a backtest that requires trained SLTP models.

Signal model

File: ml/ensemble_trainer.py / ml/ensemble_predictor.py The signal model answers: should we trade this bar?

Architecture

Three independent classifiers trained on the same 62-feature vector with ATR-aware labeling. Majority vote determines the final prediction. When two or more models agree, confidence is that fraction’s vote strength.
If confidence falls below confidence_threshold (default 0.633), the signal is treated as HOLD.

Training

Hyperparameters are tuned with Optuna (ml/tune/hyperparams.py). The tuner optimizes a custom objective that balances precision, recall, and drawdown on an OOS validation split.

Inference

Inference priority: calibrated pkl β†’ ONNX β†’ raw pkl After training, calibrate_models() wraps each classifier with CalibratedClassifierCV to produce well-calibrated probability estimates. The calibrated model is used at runtime.
ONNX export (ml/model_trainer.py) runs after training but before calibration. ONNX cannot wrap CalibratedClassifierCV, so the ONNX fallback is always the uncalibrated version.

Model paths


Position model

File: ml/position_trainer.py / ml/position_predictor.py The position model answers: should we hold, exit early, or add to this open position?

Architecture

Same three-classifier majority-vote ensemble. Trained on labeled historical positions using the same 62-feature vector, but labeling captures in-trade state rather than entry signals. Output classes:
  • HOLD β€” keep position open
  • EXIT β€” close now (reversal signal)
  • ADD β€” increase size (continuation signal β€” currently conservative)

Training

Position labeling is handled by ml/position_labeling.py. Labels are generated from historical trades where early exit would have improved the outcome.

Tuning

Optuna tuning: ml/tune/position.py

Dynamic SL/TP model

File: ml/sltp_trainer.py / ml/sltp_predictor.py The SL/TP model answers: given current market conditions, what SL and TP distance (in ATR units) maximizes risk-adjusted return?

Architecture

LightGBM regressor. Outputs two values:
  • sl_multiplier β€” SL as a multiple of ATR
  • tp_multiplier β€” TP as a multiple of ATR
Constraint: tp_multiplier > sl_multiplier is enforced at inference time (Phase 16 fix β€” previously a bug allowed tp < sl).

Training

Applied at inference


Risk multiplier model

File: ml/risk_trainer.py / ml/risk_predictor.py The risk model answers: given the current state of the account, how aggressively should we size this trade?

Architecture

LightGBM regressor. Input: 7 equity-state features. Output: a multiplier in [0.10, 1.25].

Features

These features are fixed. They must stay in sync across ml/risk_trainer.py, ml/risk_predictor.py, and ml_config.json β†’ risk_model.features.

Training

The Risk model is trained after SLTP models are saved, because its training uses a backtest that requires SL/TP predictions:

Kelly-inspired design

The risk multiplier is loosely inspired by Kelly criterion: scale up when the edge is high (low drawdown, high recent win rate) and scale down when conditions deteriorate. The model learns this relationship from labeled historical trade data augmented with account-state features.

Model storage

Models are stored differently depending on whether you are using the Python bot or the Go binary.

Python bot

Go binary

All model files are embedded inside the binary at compile time. Customers do not receive a models/ directory or a Hugging Face Hub connection. After every retrain, run:
See Go binary for the full post-retrain workflow.

Compatibility check (Python bot)

Before go-live after any retrain, verify model compatibility:
If features or model paths diverge, the predictor raises a ModelCompatibilityError at startup.