Files
lowkey_backtest/engine/portfolio.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

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,
)