Skip to main content
NOVOSKY runs a second ML model on every open position every cycle. This is the position model — it decides whether to hold, exit early, or add to a position.

How it works

The position model takes 60 features as input:
  • 56 market features (the same as the signal model)
  • 4 position-state features appended after the market features
FeatureDescription
bars_held_normNormalized number of bars the position has been open
pnl_pctUnrealized P/L as a percentage of entry price (signed)
r_multipleUnrealized P/L in units of SL distance
pos_direction+1.0 for BUY, −1.0 for SELL

Three-class output

ClassMeaningWhat happens
HOLDStay in the tradeNothing
EXITClose nowPosition closed early before SL/TP
ADDPyramidLogged only — auto-add is disabled for risk management

Model accuracy

ModelAccuracy
Random Forest72.6%
XGBoost76.9%
LightGBM78.4%
Ensemble77.16%
EXIT precision: 85% — EXIT recall: 82%

Inference thresholds

These are configured in ml_config.json → position_model.prediction:
KeyDefaultDescription
exit_threshold0.80Min EXIT probability to close early.
min_prob_diff0.25EXIT must beat HOLD by this margin.
add_threshold0.65Min ADD probability to pyramid.
These thresholds were tuned on 2026-04-15 via a 13-config sweep (python scripts/sweep.py --target pos --full). At the defaults above, the model fires ~1 exit per 38 days — only on extreme EXIT confidence — which preserves TP-bound winners. Historical short-window validation reached PF 4.71; recent weekly OOS snapshots are lower in different market regimes (for example PF 2.43), but still benefit from conservative EXIT firing.

Kelly lot sizing

At average confidence of 61.5%, the Kelly criterion cuts effective risk from 6% to 2.1%. For growth accounts: Phase 8 Kelly OFF + fixed risk_percent outperforms Phase 8 ON at every tested level. Enable Phase 8 (ml_active_management.enabled = true) only for capital preservation mode.

Trailing stop and partial close

Both features are effectively inactive at the symmetric 1:1 SL/TP ratio (0.8×ATR):
  • Trailing stop activates after the position is already at TP
  • Partial close halves a winner with no added upside
Only re-enable these if tp_atr_multiplier is widened to ≥1.5.

Enabling and disabling

// config.json
{
  "ml_active_management": {
    "enabled": true
  }
}
When disabled, the bot falls back to signal-flip detection for position management (closes on opposite signal).

Training

Developer/operator lane only. Regular users should run onboarding, select profile 1-5, pull approved model revisions from R2, and run trading.
The signal model and position model are always trained together — they share the same StandardScaler. Training one without the other breaks scaler dimensions and causes wrong predictions or crashes at inference.
# Always train both together
python train_ml_model.py --ensemble --position