68 lines
1.9 KiB
Python
68 lines
1.9 KiB
Python
"""SMA 交叉 + ATR 动态止损 + 风险回报比止盈"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import numpy as np
|
||
import raptorbt
|
||
|
||
from .base import Strategy, SignalResult
|
||
|
||
|
||
class AtrStopRrStrategy(Strategy):
|
||
"""入场用 SMA 交叉, 出场依赖 ATR 止损 + 风险回报比止盈"""
|
||
|
||
name = "atr_stop_rr"
|
||
|
||
def __init__(
|
||
self,
|
||
fast: int = 10,
|
||
slow: int = 20,
|
||
atr_multiplier: float = 2.0,
|
||
atr_period: int = 14,
|
||
rr_ratio: float = 2.0,
|
||
):
|
||
self.fast = fast
|
||
self.slow = slow
|
||
self.atr_multiplier = atr_multiplier
|
||
self.atr_period = atr_period
|
||
self.rr_ratio = rr_ratio
|
||
|
||
def warmup_bars(self) -> int:
|
||
return self.slow + 1
|
||
|
||
def generate_signals(self, df) -> SignalResult:
|
||
close = df["close"].values.astype(np.float64)
|
||
sma_fast = raptorbt.sma(close, period=self.fast)
|
||
sma_slow = raptorbt.sma(close, period=self.slow)
|
||
|
||
entries = self.cross_above(sma_fast, sma_slow).astype(bool)
|
||
exits = self.cross_below(sma_fast, sma_slow).astype(bool)
|
||
entries, exits = self.apply_warmup(entries, exits)
|
||
|
||
return SignalResult(
|
||
entries=entries,
|
||
exits=exits,
|
||
direction=1,
|
||
extra={"sma_fast": sma_fast, "sma_slow": sma_slow},
|
||
)
|
||
|
||
def build_config(self) -> raptorbt.PyBacktestConfig:
|
||
config = raptorbt.PyBacktestConfig(
|
||
initial_capital=100000.0,
|
||
fees=0.001,
|
||
slippage=0.0005,
|
||
)
|
||
config.set_atr_stop(multiplier=self.atr_multiplier, period=self.atr_period)
|
||
config.set_risk_reward_target(ratio=self.rr_ratio)
|
||
return config
|
||
|
||
def description(self) -> str:
|
||
return (
|
||
f"SMA({self.fast}/{self.slow}) 交叉 + "
|
||
f"{self.atr_multiplier}×ATR({self.atr_period}) 止损 + "
|
||
f"{self.rr_ratio}:1 风险回报止盈"
|
||
)
|
||
|
||
|
||
STRATEGY_CLASS = AtrStopRrStrategy
|