- 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.
109 lines
2.7 KiB
Python
109 lines
2.7 KiB
Python
"""
|
|
Portfolio simulation utilities for backtesting.
|
|
|
|
Handles long-only and long/short portfolio creation using VectorBT.
|
|
"""
|
|
import pandas as pd
|
|
import vectorbt as vbt
|
|
|
|
from engine.logging_config import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
def run_long_only_portfolio(
|
|
close: pd.Series,
|
|
entries: pd.DataFrame,
|
|
exits: pd.DataFrame,
|
|
init_cash: float,
|
|
fees: float,
|
|
slippage: float,
|
|
freq: str,
|
|
sl_stop: float | None,
|
|
tp_stop: float | None,
|
|
sl_trail: bool,
|
|
leverage: int
|
|
) -> vbt.Portfolio:
|
|
"""
|
|
Run a long-only portfolio simulation.
|
|
|
|
Args:
|
|
close: Close price series
|
|
entries: Entry signals
|
|
exits: Exit signals
|
|
init_cash: Initial capital
|
|
fees: Transaction fee percentage
|
|
slippage: Slippage percentage
|
|
freq: Data frequency string
|
|
sl_stop: Stop loss percentage
|
|
tp_stop: Take profit percentage
|
|
sl_trail: Enable trailing stop loss
|
|
leverage: Leverage multiplier
|
|
|
|
Returns:
|
|
VectorBT Portfolio object
|
|
"""
|
|
effective_cash = init_cash * leverage
|
|
|
|
return vbt.Portfolio.from_signals(
|
|
close=close,
|
|
entries=entries,
|
|
exits=exits,
|
|
init_cash=effective_cash,
|
|
fees=fees,
|
|
slippage=slippage,
|
|
freq=freq,
|
|
sl_stop=sl_stop,
|
|
tp_stop=tp_stop,
|
|
sl_trail=sl_trail,
|
|
size=1.0,
|
|
size_type='percent',
|
|
)
|
|
|
|
|
|
def run_long_short_portfolio(
|
|
close: pd.Series,
|
|
long_entries: pd.DataFrame,
|
|
long_exits: pd.DataFrame,
|
|
short_entries: pd.DataFrame,
|
|
short_exits: pd.DataFrame,
|
|
init_cash: float,
|
|
fees: float,
|
|
slippage: float,
|
|
freq: str,
|
|
sl_stop: float | None,
|
|
tp_stop: float | None,
|
|
sl_trail: bool,
|
|
leverage: int,
|
|
size: pd.Series | float = 1.0,
|
|
size_type: str = 'value' # Changed to 'value' to support reversals/sizing
|
|
) -> vbt.Portfolio:
|
|
"""
|
|
Run a portfolio supporting both long and short positions.
|
|
|
|
Uses VectorBT's native support for short_entries/short_exits
|
|
to simulate a single unified portfolio.
|
|
"""
|
|
effective_cash = init_cash * leverage
|
|
|
|
# If size is passed as value (USD), we don't scale it by leverage here
|
|
# The backtester has already scaled it by init_cash.
|
|
# If using 'value', vbt treats it as "Amount of CASH to use for the trade"
|
|
|
|
return vbt.Portfolio.from_signals(
|
|
close=close,
|
|
entries=long_entries,
|
|
exits=long_exits,
|
|
short_entries=short_entries,
|
|
short_exits=short_exits,
|
|
init_cash=effective_cash,
|
|
fees=fees,
|
|
slippage=slippage,
|
|
freq=freq,
|
|
sl_stop=sl_stop,
|
|
tp_stop=tp_stop,
|
|
sl_trail=sl_trail,
|
|
size=size,
|
|
size_type=size_type,
|
|
)
|