""" Market type definitions and configuration for backtesting. Supports different market types with their specific trading conditions: - SPOT: No leverage, no funding, long-only - PERPETUAL: Leverage, funding rates, long/short """ from dataclasses import dataclass from enum import Enum class MarketType(Enum): """Supported market types for backtesting.""" SPOT = "spot" PERPETUAL = "perpetual" @dataclass(frozen=True) class MarketConfig: """ Configuration for a specific market type. Attributes: market_type: The market type enum value maker_fee: Maker fee as decimal (e.g., 0.0008 = 0.08%) taker_fee: Taker fee as decimal (e.g., 0.001 = 0.1%) max_leverage: Maximum allowed leverage funding_rate: Funding rate per 8 hours as decimal (perpetuals only) funding_interval_hours: Hours between funding payments maintenance_margin_rate: Rate for liquidation calculation supports_short: Whether short-selling is supported """ market_type: MarketType maker_fee: float taker_fee: float max_leverage: int funding_rate: float funding_interval_hours: int maintenance_margin_rate: float supports_short: bool # OKX-based default configurations SPOT_CONFIG = MarketConfig( market_type=MarketType.SPOT, maker_fee=0.0008, # 0.08% taker_fee=0.0010, # 0.10% max_leverage=1, funding_rate=0.0, funding_interval_hours=0, maintenance_margin_rate=0.0, supports_short=False, ) PERPETUAL_CONFIG = MarketConfig( market_type=MarketType.PERPETUAL, maker_fee=0.0002, # 0.02% taker_fee=0.0005, # 0.05% max_leverage=125, funding_rate=0.0001, # 0.01% per 8 hours (simplified average) funding_interval_hours=8, maintenance_margin_rate=0.004, # 0.4% for BTC on OKX supports_short=True, ) def get_market_config(market_type: MarketType) -> MarketConfig: """ Get the configuration for a specific market type. Args: market_type: The market type to get configuration for Returns: MarketConfig with default values for that market type """ configs = { MarketType.SPOT: SPOT_CONFIG, MarketType.PERPETUAL: PERPETUAL_CONFIG, } return configs[market_type] def get_ccxt_symbol(symbol: str, market_type: MarketType) -> str: """ Convert a standard symbol to CCXT format for the given market type. Args: symbol: Standard symbol (e.g., 'BTC/USDT') market_type: The market type Returns: CCXT-formatted symbol (e.g., 'BTC/USDT:USDT' for perpetuals) """ if market_type == MarketType.PERPETUAL: # OKX perpetual format: BTC/USDT:USDT quote = symbol.split('/')[1] if '/' in symbol else 'USDT' return f"{symbol}:{quote}" return symbol def calculate_leverage_stop_loss( leverage: int, maintenance_margin_rate: float = 0.004 ) -> float: """ Calculate the implicit stop-loss percentage from leverage. At a given leverage, liquidation occurs when the position loses approximately (1/leverage - maintenance_margin_rate) of its value. Args: leverage: Position leverage multiplier maintenance_margin_rate: Maintenance margin rate (default OKX BTC: 0.4%) Returns: Stop-loss percentage as decimal (e.g., 0.196 for 19.6%) """ if leverage <= 1: return 1.0 # No forced stop for spot return (1 / leverage) - maintenance_margin_rate def calculate_liquidation_price( entry_price: float, leverage: float, is_long: bool, maintenance_margin_rate: float = 0.004 ) -> float: """ Calculate the liquidation price for a leveraged position. Args: entry_price: Position entry price leverage: Position leverage is_long: True for long positions, False for short maintenance_margin_rate: Maintenance margin rate (default OKX BTC: 0.4%) Returns: Liquidation price """ if leverage <= 1: return 0.0 if is_long else float('inf') # Simplified liquidation formula # Long: liq_price = entry * (1 - 1/leverage + maintenance_margin_rate) # Short: liq_price = entry * (1 + 1/leverage - maintenance_margin_rate) margin_ratio = 1 / leverage if is_long: liq_price = entry_price * (1 - margin_ratio + maintenance_margin_rate) else: liq_price = entry_price * (1 + margin_ratio - maintenance_margin_rate) return liq_price