Files
crypto_trader/src/strategies/technical/moving_avg_strategy.py

80 lines
3.1 KiB
Python
Raw Normal View History

"""Moving Average Crossover strategy."""
import pandas as pd
from decimal import Decimal
from typing import Optional, Dict, Any
from src.strategies.base import BaseStrategy, StrategySignal, SignalType
from src.data.indicators import get_indicators
class MovingAverageStrategy(BaseStrategy):
"""Moving average crossover strategy."""
def __init__(self, name: str, parameters: Optional[Dict[str, Any]] = None, timeframes: Optional[list] = None):
"""Initialize moving average strategy.
Parameters:
fast_period: Fast MA period (default 10)
slow_period: Slow MA period (default 30)
ma_type: MA type - 'sma' or 'ema' (default 'ema')
"""
super().__init__(name, parameters, timeframes)
self.fast_period = self.parameters.get('fast_period', 10)
self.slow_period = self.parameters.get('slow_period', 30)
self.ma_type = self.parameters.get('ma_type', 'ema')
self.indicators = get_indicators()
self._price_history = []
async def on_tick(self, symbol: str, price: Decimal, timeframe: str, data: Dict[str, Any]) -> Optional[StrategySignal]:
"""Generate signal based on MA crossover."""
# Add price to history
self._price_history.append(float(price))
if len(self._price_history) < self.slow_period + 1:
return None
# Calculate MAs
prices = pd.Series(self._price_history[-self.slow_period-1:])
if self.ma_type == 'sma':
fast_ma = self.indicators.sma(prices, self.fast_period)
slow_ma = self.indicators.sma(prices, self.slow_period)
else:
fast_ma = self.indicators.ema(prices, self.fast_period)
slow_ma = self.indicators.ema(prices, self.slow_period)
if len(fast_ma) < 2 or len(slow_ma) < 2:
return None
# Check for crossover
fast_current = fast_ma.iloc[-1]
fast_prev = fast_ma.iloc[-2]
slow_current = slow_ma.iloc[-1]
slow_prev = slow_ma.iloc[-2]
# Bullish crossover
if fast_prev <= slow_prev and fast_current > slow_current:
return StrategySignal(
signal_type=SignalType.BUY,
symbol=symbol,
strength=min(1.0, (fast_current - slow_current) / slow_current),
price=price,
metadata={'fast_ma': float(fast_current), 'slow_ma': float(slow_current)}
)
# Bearish crossover
elif fast_prev >= slow_prev and fast_current < slow_current:
return StrategySignal(
signal_type=SignalType.SELL,
symbol=symbol,
strength=min(1.0, (slow_current - fast_current) / slow_current),
price=price,
metadata={'fast_ma': float(fast_current), 'slow_ma': float(slow_current)}
)
return None
def on_signal(self, signal: StrategySignal) -> Optional[StrategySignal]:
"""Process signal."""
return signal if self.should_execute(signal) else None