NOVOSKY uses three configuration files. Never commit .env — it contains secrets.
Environment variables (.env)
Copy from the template:
# MT5 API server
API_URL=http://<YOUR_MT5_SERVER_IP>:6542
API_TOKEN=<your_api_token>
# Cloudflare R2 — model storage (required for both push and pull)
CF_R2_ACCESS_KEY_ID=<your_r2_access_key_id>
CF_R2_SECRET_ACCESS_KEY=<your_r2_secret_access_key>
# Telegram (optional — leave blank to disable notifications)
TELEGRAM_TOKEN=<bot_token>
TELEGRAM_CHAT_ID=<chat_id>
# Supabase (optional — cloud trade dashboard)
SUPABASE_URL=https://...
SUPABASE_KEY=<service_key>
SUPABASE_BOT_NAME=novosky-vt
Getting Cloudflare R2 credentials: Go to dash.cloudflare.com → R2 → Manage R2 API tokens. Create a token with Object Read & Write on bucket novosky-models. Copy the Access Key ID and Secret Access Key into your .env.
Runtime config (config.json)
Controls strategy execution, risk management, and filters. All values are read at startup and at each main loop cycle.
Strategy
| Key | Default | Description |
|---|
strategy | ml_ensemble | Must be ml_ensemble to use the ML brain. |
account_type | standard | "cent" or "standard". See Cent vs standard. |
Dynamic SL/TP
| Key | Default | Description |
|---|
dynamic_sltp.enabled | true | Use ATR-based SL/TP. Must match the labeling method. |
dynamic_sltp.sl_atr_multiplier | 0.8 | SL = ATR × this value. |
dynamic_sltp.tp_atr_multiplier | 0.8 | TP = ATR × this value. |
Keep dynamic_sltp.enabled = true at all times. The models were trained with ATR-aware labels. Disabling this causes live win rate to drop from ~78% to ~49%.
Position sizing
| Key | Default | Description |
|---|
dynamic_position_sizing.risk_percent | 2 | Percent of equity risked per trade. |
dynamic_position_sizing.max_lot | 1.0 | Maximum lot size cap. |
Risk filters
| Key | Default | Description |
|---|
max_consecutive_losses | 5 | Circuit breaker: stops trading after N losses in a row. |
max_daily_loss | 99999 | Stop trading if daily loss exceeds this amount ($). |
max_daily_profit | 99999 | Pause after hitting this daily profit ($). |
trade_cooldown_seconds | 0 | Seconds to wait between trades. 0 = back-to-back OK. |
news_block_minutes | 0 | Block trading N minutes before/after high-impact news. |
Session and trend filters
| Key | Default | Description |
|---|
enable_ema_trend_filter | false | BUY only above EMA200, SELL only below EMA200. |
timezone.offset_hours | 7 | Local UTC offset used for resets, summaries, and notifications. Examples: 7=WIB, 8=MYT/SGT, 5.5=IST. |
The repo examples use WIB because the project started with an Indonesia-based trading schedule, but you can set your own local timezone in config.json.
ML position management
| Key | Default | Description |
|---|
ml_active_management.enabled | true | Phase 8: position model monitors open trades. |
ML config (ml_config.json)
Controls how models are trained and used at inference time. Most values here require a retrain if changed.
Labeling
| Key | Default | Description |
|---|
labeling.method | atr_aware | Label generation method. Always keep atr_aware. |
labeling.atr_tp_mult | 1.5 | TP multiplier for label generation at training time. |
labeling.atr_sl_mult | 0.8 | SL multiplier — must match config.json sl_atr_multiplier. |
labeling.lookahead_candles | 48 | M15 bars to check for TP/SL hit (= 12 hours). |
Signal model inference
| Key | Default | Description |
|---|
prediction.confidence_threshold | 0.60 | Min ensemble confidence to generate a trade signal. |
prediction.min_probability_diff | 0.10 | Required gap between top-2 class probabilities. |
risk_management.min_atr_threshold | 15 | Min ATR in $ — blocks trades in low-volatility markets. |
Position model inference
| Key | Default | Description |
|---|
position_model.prediction.exit_threshold | 0.80 | Min EXIT probability to close early. |
position_model.prediction.min_prob_diff | 0.25 | EXIT must beat HOLD by this margin. |
position_model.prediction.add_threshold | 0.65 | Min ADD probability to pyramid. |
The position model thresholds were tuned on 2026-04-15 via a 13-config sweep. At exit_threshold=0.80 and min_prob_diff=0.25, the model fires ~1 exit per 38 days, preserving TP-bound winners.
ADX gotcha
adx_14 in the feature set is normalized to 0–1, not the traditional 0–100 scale. This affects any ADX-related filters:
"adx_regime_filter": {
"min_adx": 0.20 // This means traditional ADX 20 — NOT the value 20
}
Passing 20 instead of 0.20 would block all trades.