Skip to main content

indicators/
settings.rs

1//! `BotSettings` — typed replacement for Python's `DEFAULT_SETTINGS_*` dicts.
2//!
3//! Every field maps 1-to-1 to a key in the Python `SETTINGS` dict so
4//! Optuna-tuned JSON files can be loaded with zero field renaming.
5
6use serde::{Deserialize, Serialize};
7
8/// Per-symbol bot configuration — mirrors Python `DEFAULT_SETTINGS_BTC`.
9///
10/// Load from JSON with `serde_json::from_str`, or use a `BotSettings::btc()` constructor.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct BotSettings {
13    pub symbol: String,
14
15    // ── Execution ────────────────────────────────────────────────────────────
16    pub leverage: u32,
17    pub contracts: u32,
18    pub use_market_orders: bool,
19    pub taker_fee: f64,
20    pub maker_fee: f64,
21    pub risk_fraction: f64,
22    pub max_contracts: u32,
23    pub sim_balance: f64,
24
25    // ── Kline fetch ──────────────────────────────────────────────────────────
26    pub kline_interval: String,
27    pub rest_kline_type: String,
28    pub history_candles: usize,
29    pub backtest_candles: usize,
30
31    // ── Layer 1-2: VWAP & EMA ────────────────────────────────────────────────
32    pub ema_len: usize,
33
34    // ── Layer 3: ML SuperTrend ───────────────────────────────────────────────
35    pub atr_len: usize,
36    pub st_factor: f64,
37    pub training_period: usize,
38    pub highvol_pct: f64,
39    pub midvol_pct: f64,
40    pub lowvol_pct: f64,
41
42    // ── Layer 4: Trend Speed ─────────────────────────────────────────────────
43    pub ts_max_length: usize,
44    pub ts_accel_mult: f64,
45    pub ts_rma_len: usize,
46    pub ts_hma_len: usize,
47    pub ts_collen: usize,
48    pub ts_lookback: usize,
49    pub ts_speed_exit_threshold: Option<f64>,
50
51    // ── Layer 5: Liquidity Profile ───────────────────────────────────────────
52    pub liq_period: usize,
53    pub liq_bins: usize,
54
55    // ── Layer 6: Confluence ──────────────────────────────────────────────────
56    pub conf_ema_fast: usize,
57    pub conf_ema_slow: usize,
58    pub conf_ema_trend: usize,
59    pub conf_rsi_len: usize,
60    pub conf_adx_len: usize,
61    pub conf_min_score: f64,
62
63    // ── Layer 7: Market Structure + Fibonacci ────────────────────────────────
64    pub struct_swing_len: usize,
65    pub struct_atr_mult: f64,
66    pub fib_zone_enabled: bool,
67
68    // ── Signal mode ──────────────────────────────────────────────────────────
69    /// `"majority"` | `"strict"` | `"any"`
70    pub signal_mode: String,
71    pub signal_confirm_bars: usize,
72
73    // ── Layer 8: CVD ─────────────────────────────────────────────────────────
74    pub cvd_slope_bars: usize,
75    pub cvd_div_lookback: usize,
76
77    // ── Layer 9: AO + Percentile gates ──────────────────────────────────────
78    pub wave_pct_l: f64,
79    pub wave_pct_s: f64,
80    pub mom_pct_min: f64,
81    pub vol_pct_window: usize,
82
83    // ── Layer 10: Hurst ──────────────────────────────────────────────────────
84    pub hurst_threshold: f64,
85    pub hurst_lookback: usize,
86
87    // ── Layer 11: Price Acceleration ─────────────────────────────────────────
88    pub stop_atr_mult: f64,
89
90    // ── Entry gates ──────────────────────────────────────────────────────────
91    pub min_vol_pct: f64,
92    pub min_hold_candles: usize,
93
94    // ── Circuit breaker ──────────────────────────────────────────────────────
95    pub breaker_loss_limit: u32,
96    pub breaker_cooldown_sec: u32,
97
98    // ── Live loop ────────────────────────────────────────────────────────────
99    pub heartbeat_interval_sec: u32,
100    pub param_watch_interval_sec: u32,
101}
102
103impl BotSettings {
104    fn base() -> Self {
105        Self {
106            symbol: String::new(),
107            leverage: 5,
108            contracts: 1,
109            use_market_orders: true,
110            taker_fee: 0.0006,
111            maker_fee: 0.0002,
112            risk_fraction: 0.95,
113            max_contracts: 50,
114            sim_balance: 10_000.0,
115            kline_interval: "1min".into(),
116            rest_kline_type: "1".into(),
117            history_candles: 200,
118            backtest_candles: 8000,
119            ema_len: 9,
120            atr_len: 10,
121            st_factor: 3.0,
122            training_period: 100,
123            highvol_pct: 0.75,
124            midvol_pct: 0.50,
125            lowvol_pct: 0.25,
126            ts_max_length: 50,
127            ts_accel_mult: 5.0,
128            ts_rma_len: 10,
129            ts_hma_len: 5,
130            ts_collen: 100,
131            ts_lookback: 50,
132            ts_speed_exit_threshold: None,
133            liq_period: 100,
134            liq_bins: 31,
135            conf_ema_fast: 9,
136            conf_ema_slow: 21,
137            conf_ema_trend: 55,
138            conf_rsi_len: 13,
139            conf_adx_len: 14,
140            conf_min_score: 5.0,
141            struct_swing_len: 10,
142            struct_atr_mult: 0.5,
143            fib_zone_enabled: true,
144            signal_mode: "majority".into(),
145            signal_confirm_bars: 2,
146            cvd_slope_bars: 10,
147            cvd_div_lookback: 30,
148            wave_pct_l: 0.25,
149            wave_pct_s: 0.75,
150            mom_pct_min: 0.30,
151            vol_pct_window: 200,
152            hurst_threshold: 0.52,
153            hurst_lookback: 20,
154            stop_atr_mult: 1.5,
155            min_vol_pct: 0.20,
156            min_hold_candles: 2,
157            breaker_loss_limit: 3,
158            breaker_cooldown_sec: 900,
159            heartbeat_interval_sec: 30,
160            param_watch_interval_sec: 300,
161        }
162    }
163
164    pub fn btc() -> Self {
165        Self {
166            symbol: "XBTUSDTM".into(),
167            ..Self::base()
168        }
169    }
170
171    pub fn eth() -> Self {
172        Self {
173            symbol: "ETHUSDTM".into(),
174            ..Self::base()
175        }
176    }
177
178    pub fn sol() -> Self {
179        Self {
180            symbol: "SOLUSDTM".into(),
181            ..Self::base()
182        }
183    }
184
185    pub fn by_symbol(symbol: &str) -> Self {
186        match symbol {
187            "XBTUSDTM" => Self::btc(),
188            "ETHUSDTM" => Self::eth(),
189            "SOLUSDTM" => Self::sol(),
190            _ => Self {
191                symbol: symbol.into(),
192                ..Self::base()
193            },
194        }
195    }
196}
197
198/// Contract multiplier (base asset per contract).
199pub fn contract_value(symbol: &str) -> f64 {
200    match symbol {
201        "ETHUSDTM" => 0.01,
202        "SOLUSDTM" => 1.0,
203        _ => 0.001,
204    }
205}