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