80 lines
2.7 KiB
Python
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) |