Remove deprecated modules and files related to the backtesting framework, including backtest.py, cli.py, config.py, data.py, intrabar.py, logging_utils.py, market_costs.py, metrics.py, trade.py, and supertrend indicators. Introduce a new structure for the backtesting engine with improved organization and functionality, including a CLI handler, data manager, and reporting capabilities. Update dependencies in pyproject.toml to support the new architecture.
This commit is contained in:
156
engine/market.py
Normal file
156
engine/market.py
Normal file
@@ -0,0 +1,156 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user