Files
lowkey_backtest/engine/market.py
Simon Moisy 1e4cb87da3 Add check_symbols.py for ETH perpetuals filtering and enhance backtester with size handling
- Introduced `check_symbols.py` to load and filter ETH perpetual markets from the OKX exchange using CCXT.
- Updated the backtester to normalize signals to a 5-tuple format, incorporating size management for trades.
- Enhanced portfolio functions to support variable size and leverage adjustments based on initial capital.
- Added a new method in `CryptoQuantClient` for chunked historical data fetching to avoid API limits.
- Improved market symbol normalization in `market.py` to handle different formats.
- Updated regime strategy parameters based on recent research findings for optimal performance.
2026-01-14 09:46:51 +08:00

169 lines
4.8 KiB
Python

"""
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
if '/' in symbol:
base, quote = symbol.split('/')
return f"{symbol}:{quote}"
elif '-' in symbol:
base, quote = symbol.split('-')
return f"{base}/{quote}:{quote}"
else:
# Assume base is symbol, quote is USDT default
return f"{symbol}/USDT:USDT"
# For spot, normalize dash to slash for CCXT
if '-' in symbol:
return symbol.replace('-', '/')
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