hyperliquid_backtest/trading_mode.rs
1//! # Trading Mode Management
2//!
3//! This module provides functionality for managing different trading modes (backtest, paper trading, live trading)
4//! and seamlessly transitioning between them while maintaining consistent strategy execution.
5//!
6//! ## Features
7//!
8//! - Unified trading mode interface across backtest, paper trading, and live trading
9//! - Configuration management for different trading modes
10//! - Seamless strategy execution across all modes
11//! - Mode-specific configuration and safety checks
12
13use std::collections::HashMap;
14use serde::{Deserialize, Serialize};
15use thiserror::Error;
16use tracing::{warn, error};
17
18use crate::errors::HyperliquidBacktestError;
19
20/// Represents the different trading modes available in the system.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
22pub enum TradingMode {
23 /// Backtesting mode using historical data
24 Backtest,
25
26 /// Paper trading mode using real-time data but simulated execution
27 PaperTrade,
28
29 /// Live trading mode using real-time data and real order execution
30 LiveTrade,
31}
32
33impl std::fmt::Display for TradingMode {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 TradingMode::Backtest => write!(f, "Backtest"),
37 TradingMode::PaperTrade => write!(f, "Paper Trading"),
38 TradingMode::LiveTrade => write!(f, "Live Trading"),
39 }
40 }
41}
42
43/// Error types specific to trading mode operations
44#[derive(Debug, Error)]
45pub enum TradingModeError {
46 /// Error when switching to an unsupported mode
47 #[error("Unsupported trading mode transition from {from} to {to}")]
48 UnsupportedModeTransition {
49 from: TradingMode,
50 to: TradingMode,
51 },
52
53 /// Error when configuration is missing for a specific mode
54 #[error("Missing configuration for {0} mode")]
55 MissingConfiguration(TradingMode),
56
57 /// Error when executing a strategy
58 #[error("Strategy execution error in {mode} mode: {message}")]
59 StrategyExecutionError {
60 mode: TradingMode,
61 message: String,
62 },
63
64 /// Error when validating configuration
65 #[error("Invalid configuration for {mode} mode: {message}")]
66 InvalidConfiguration {
67 mode: TradingMode,
68 message: String,
69 },
70
71 /// Wrapper for backtesting errors
72 #[error("Backtesting error: {0}")]
73 BacktestError(#[from] HyperliquidBacktestError),
74
75 /// Error when a feature is not yet implemented
76 #[error("Feature not implemented: {0}")]
77 NotImplemented(String),
78}
79
80/// Configuration for trading modes
81#[derive(Debug, Clone)]
82pub struct TradingConfig {
83 /// Initial balance for trading
84 pub initial_balance: f64,
85
86 /// Risk management configuration
87 pub risk_config: Option<RiskConfig>,
88
89 /// Slippage configuration for paper trading
90 pub slippage_config: Option<SlippageConfig>,
91
92 /// API configuration for live trading
93 pub api_config: Option<ApiConfig>,
94
95 /// Additional mode-specific configuration parameters
96 pub parameters: HashMap<String, String>,
97}
98
99impl TradingConfig {
100 /// Create a new trading configuration with the specified initial balance
101 pub fn new(initial_balance: f64) -> Self {
102 Self {
103 initial_balance,
104 risk_config: None,
105 slippage_config: None,
106 api_config: None,
107 parameters: HashMap::new(),
108 }
109 }
110
111 /// Add a risk configuration
112 pub fn with_risk_config(mut self, risk_config: RiskConfig) -> Self {
113 self.risk_config = Some(risk_config);
114 self
115 }
116
117 /// Add a slippage configuration for paper trading
118 pub fn with_slippage_config(mut self, slippage_config: SlippageConfig) -> Self {
119 self.slippage_config = Some(slippage_config);
120 self
121 }
122
123 /// Add an API configuration for live trading
124 pub fn with_api_config(mut self, api_config: ApiConfig) -> Self {
125 self.api_config = Some(api_config);
126 self
127 }
128
129 /// Add a custom parameter
130 pub fn with_parameter(mut self, key: &str, value: &str) -> Self {
131 self.parameters.insert(key.to_string(), value.to_string());
132 self
133 }
134
135 /// Validate the configuration for a specific trading mode
136 pub fn validate_for_mode(&self, mode: TradingMode) -> std::result::Result<(), TradingModeError> {
137 match mode {
138 TradingMode::Backtest => {
139 // Backtesting mode has minimal requirements
140 if self.initial_balance <= 0.0 {
141 return Err(TradingModeError::InvalidConfiguration {
142 mode,
143 message: "Initial balance must be positive".to_string(),
144 });
145 }
146 },
147 TradingMode::PaperTrade => {
148 // Paper trading requires initial balance and should have slippage config
149 if self.initial_balance <= 0.0 {
150 return Err(TradingModeError::InvalidConfiguration {
151 mode,
152 message: "Initial balance must be positive".to_string(),
153 });
154 }
155
156 if self.slippage_config.is_none() {
157 warn!("No slippage configuration provided for paper trading mode. Using default values.");
158 }
159 },
160 TradingMode::LiveTrade => {
161 // Live trading requires initial balance, risk config, and API config
162 if self.initial_balance <= 0.0 {
163 return Err(TradingModeError::InvalidConfiguration {
164 mode,
165 message: "Initial balance must be positive".to_string(),
166 });
167 }
168
169 if self.risk_config.is_none() {
170 return Err(TradingModeError::InvalidConfiguration {
171 mode,
172 message: "Risk configuration is required for live trading".to_string(),
173 });
174 }
175
176 if self.api_config.is_none() {
177 return Err(TradingModeError::InvalidConfiguration {
178 mode,
179 message: "API configuration is required for live trading".to_string(),
180 });
181 }
182 },
183 }
184
185 Ok(())
186 }
187}
188
189/// Risk management configuration
190#[derive(Debug, Clone)]
191pub struct RiskConfig {
192 /// Maximum position size as a percentage of portfolio value
193 pub max_position_size_pct: f64,
194
195 /// Maximum daily loss as a percentage of portfolio value
196 pub max_daily_loss_pct: f64,
197
198 /// Stop loss percentage for positions
199 pub stop_loss_pct: f64,
200
201 /// Take profit percentage for positions
202 pub take_profit_pct: f64,
203
204 /// Maximum leverage allowed
205 pub max_leverage: f64,
206
207 /// Maximum portfolio concentration in a single asset class (percentage)
208 pub max_concentration_pct: f64,
209
210 /// Maximum correlation between positions (0.0 to 1.0)
211 pub max_correlation_pct: f64,
212
213 /// Maximum portfolio volatility (percentage)
214 pub max_portfolio_volatility_pct: f64,
215
216 /// Volatility-based position sizing factor (0.0 to 1.0)
217 pub volatility_sizing_factor: f64,
218
219 /// Maximum drawdown before emergency stop (percentage)
220 pub max_drawdown_pct: f64,
221}
222
223impl Default for RiskConfig {
224 fn default() -> Self {
225 Self {
226 max_position_size_pct: 0.1, // 10% of portfolio
227 max_daily_loss_pct: 0.02, // 2% max daily loss
228 stop_loss_pct: 0.05, // 5% stop loss
229 take_profit_pct: 0.1, // 10% take profit
230 max_leverage: 3.0, // 3x max leverage
231 max_concentration_pct: 0.25, // 25% max concentration in one asset class
232 max_correlation_pct: 0.7, // 0.7 maximum correlation between positions
233 max_portfolio_volatility_pct: 0.2, // 20% maximum portfolio volatility
234 volatility_sizing_factor: 0.5, // 50% volatility-based position sizing
235 max_drawdown_pct: 0.15, // 15% maximum drawdown before emergency stop
236 }
237 }
238}
239
240/// Slippage simulation configuration for paper trading
241#[derive(Debug, Clone)]
242pub struct SlippageConfig {
243 /// Base slippage as a percentage
244 pub base_slippage_pct: f64,
245
246 /// Volume-based slippage factor
247 pub volume_impact_factor: f64,
248
249 /// Volatility-based slippage factor
250 pub volatility_impact_factor: f64,
251
252 /// Random slippage component maximum (percentage)
253 pub random_slippage_max_pct: f64,
254
255 /// Simulated latency in milliseconds
256 pub simulated_latency_ms: u64,
257}
258
259impl Default for SlippageConfig {
260 fn default() -> Self {
261 Self {
262 base_slippage_pct: 0.0005, // 0.05% base slippage
263 volume_impact_factor: 0.1, // Volume impact factor
264 volatility_impact_factor: 0.2, // Volatility impact factor
265 random_slippage_max_pct: 0.001, // 0.1% max random component
266 simulated_latency_ms: 500, // 500ms simulated latency
267 }
268 }
269}
270
271/// API configuration for live trading
272#[derive(Debug, Clone)]
273pub struct ApiConfig {
274 /// API key for authentication
275 pub api_key: String,
276
277 /// API secret for authentication
278 pub api_secret: String,
279
280 /// API endpoint URL
281 pub endpoint: String,
282
283 /// Whether to use testnet
284 pub use_testnet: bool,
285
286 /// Timeout for API requests in milliseconds
287 pub timeout_ms: u64,
288}
289
290// Additional types and implementations will be in trading_mode_impl.rs