Files
lowkey_backtest/strategies/base.py

80 lines
2.7 KiB
Python

"""
Base strategy class for all trading strategies.
Strategies should inherit from BaseStrategy and implement the run() method.
"""
from abc import ABC, abstractmethod
import pandas as pd
from engine.market import MarketType
class BaseStrategy(ABC):
"""
Abstract base class for trading strategies.
Class Attributes:
default_market_type: Default market type for this strategy
default_leverage: Default leverage (only applies to perpetuals)
default_sl_stop: Default stop-loss percentage
default_tp_stop: Default take-profit percentage
default_sl_trail: Whether stop-loss is trailing by default
"""
# Market configuration defaults
default_market_type: MarketType = MarketType.SPOT
default_leverage: int = 1
# Risk management defaults (can be overridden per strategy)
default_sl_stop: float | None = None
default_tp_stop: float | None = None
default_sl_trail: bool = False
def __init__(self, **kwargs):
self.params = kwargs
@abstractmethod
def run(
self,
close: pd.Series,
**kwargs
) -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame]:
"""
Run the strategy logic.
Args:
close: Price series (can be multiple columns for grid search)
**kwargs: Additional data (high, low, open, volume) and parameters
Returns:
Tuple of 4 DataFrames/Series:
- long_entries: Boolean signals to open long positions
- long_exits: Boolean signals to close long positions
- short_entries: Boolean signals to open short positions
- short_exits: Boolean signals to close short positions
Note:
For spot markets, short signals will be ignored.
For backward compatibility, strategies can return 2-tuple (entries, exits)
which will be interpreted as long-only signals.
"""
pass
def get_indicator(self, ind_cls, *args, **kwargs):
"""Helper to run a vectorbt indicator."""
return ind_cls.run(*args, **kwargs)
@staticmethod
def create_empty_signals(reference: pd.Series | pd.DataFrame) -> pd.DataFrame:
"""
Create an empty (all False) signal DataFrame matching the reference shape.
Args:
reference: Series or DataFrame to match shape/index
Returns:
DataFrame of False values with same shape as reference
"""
if isinstance(reference, pd.DataFrame):
return pd.DataFrame(False, index=reference.index, columns=reference.columns)
return pd.Series(False, index=reference.index)