diff --git a/strategies/README.md b/strategies/README.md new file mode 100644 index 0000000..517caf3 --- /dev/null +++ b/strategies/README.md @@ -0,0 +1,49 @@ +# 策略示例集 + +可直接用于 `easy-tdx backtest --strategy-file` 的策略文件。 + +## 用法 + +```bash +# 在项目根目录执行 +easy-tdx backtest SZ 000001 --strategy-file strategies/ma_cross.py --table +easy-tdx backtest SH 600519 --strategy-file strategies/macd_cross.py --cash 50000 --table +``` + +## 策略列表 + +| 文件 | 策略 | 类型 | 适合行情 | +|------|------|------|----------| +| `ma_cross.py` | 双均线交叉(MA5/MA20) | 趋势跟踪 | 单边趋势 | +| `expma_cross.py` | EMA12/EMA50 交叉 | 趋势跟踪 | 单边趋势(比 MA 更灵敏) | +| `macd_cross.py` | MACD 金叉死叉 | 趋势跟踪 | 中长线趋势 | +| `bollinger_breakout.py` | 布林带突破 | 震荡反转 | 横盘震荡 | +| `rsi_reversal.py` | RSI 超买超卖 | 反转 | 震荡市 | +| `kdj_golden.py` | KDJ 低位金叉/高位死叉 | 反转 | 短线震荡 | +| `turtle_breakout.py` | 海龟交易法(唐安奇通道) | 趋势突破 | 牛市启动 | +| `bias_reversal.py` | 乖离率反转 | 反转 | 震荡回归 | +| `volume_price.py` | 量价配合 | 综合判断 | 放量突破 | + +## 编写自定义策略 + +复制任意一个策略文件作为模板,继承 `Strategy` 基类: + +```python +from easy_tdx.backtest import Strategy, crossover +from easy_tdx import MyTT + + +class MyStrategy(Strategy): + def init(self): + # 注册指标 + self.ma = self.I(MyTT.MA, self.data.close, 10) + + def next(self): + # 每根 K 线调用一次 + if self.data.close[0] > self.ma[self._bar_index]: + self.buy(size=0) # size=0 表示全仓 + elif self.position["size"] > 0: + self.sell(size=0) # size=0 表示清仓 +``` + +完整 API 参考:[docs/backtest_usage.md](../docs/backtest_usage.md) diff --git a/strategies/bias_reversal.py b/strategies/bias_reversal.py new file mode 100644 index 0000000..13c36cb --- /dev/null +++ b/strategies/bias_reversal.py @@ -0,0 +1,27 @@ +"""乖离率反转策略。 + +乖离率低于阈值(超跌)买入,乖离率高于阈值(超涨)卖出。 +适合震荡市。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/bias_reversal.py --table +""" + +from easy_tdx.backtest import Strategy +from easy_tdx import MyTT + + +class BIAStrategy(Strategy): + """乖离率反转策略。""" + + def init(self) -> None: + self.bias = self.I(MyTT.BIAS, self.data.close, 6) + + def next(self) -> None: + val = self.bias[self._bar_index] + + if val < -3 and self.position["size"] == 0: + self.buy(size=0) + elif val > 3 and self.position["size"] > 0: + self.sell(size=0) diff --git a/strategies/bollinger_breakout.py b/strategies/bollinger_breakout.py new file mode 100644 index 0000000..697b0b7 --- /dev/null +++ b/strategies/bollinger_breakout.py @@ -0,0 +1,28 @@ +"""布林带突破策略。 + +收盘价跌破下轨买入,突破上轨卖出。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/bollinger_breakout.py --table +""" + +from easy_tdx.backtest import Strategy +from easy_tdx import MyTT + + +class BollingerStrategy(Strategy): + """布林带突破策略。""" + + def init(self) -> None: + self.upper, self.mid, self.lower = self.I(MyTT.BOLL, self.data.close, 20) + + def next(self) -> None: + cur = self.data.close[0] + lower = self.lower[self._bar_index] + upper = self.upper[self._bar_index] + + if cur <= lower and self.position["size"] == 0: + self.buy(size=0) + elif cur >= upper and self.position["size"] > 0: + self.sell(size=0) diff --git a/strategies/expma_cross.py b/strategies/expma_cross.py new file mode 100644 index 0000000..03b2094 --- /dev/null +++ b/strategies/expma_cross.py @@ -0,0 +1,27 @@ +"""EXPMA 均线交叉策略。 + +EMA12 上穿 EMA50 买入,EMA12 下穿 EMA50 卖出。 +与简单均线相比,EMA 对近期价格更敏感。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/expma_cross.py --table +""" + +from easy_tdx.backtest import Strategy, crossover +from easy_tdx import MyTT + + +class EXPMAStrategy(Strategy): + """EXPMA 指数均线交叉策略。""" + + def init(self) -> None: + self.ema12, self.ema50 = self.I(MyTT.EXPMA, self.data.close, 12, 50) + self.golden = crossover(self.ema12, self.ema50) + self.death = crossover(self.ema50, self.ema12) + + def next(self) -> None: + if self.golden[self._bar_index] and self.position["size"] == 0: + self.buy(size=0) + elif self.death[self._bar_index] and self.position["size"] > 0: + self.sell(size=0) diff --git a/strategies/kdj_golden.py b/strategies/kdj_golden.py new file mode 100644 index 0000000..36f9700 --- /dev/null +++ b/strategies/kdj_golden.py @@ -0,0 +1,30 @@ +"""KDJ 金叉策略。 + +K 上穿 D 且 J < 20(低位金叉)买入,K 下穿 D 且 J > 80(高位死叉)卖出。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/kdj_golden.py --table +""" + +from easy_tdx.backtest import Strategy, crossover +from easy_tdx import MyTT + + +class KDJStrategy(Strategy): + """KDJ 金叉策略。""" + + def init(self) -> None: + self.k, self.d, self.j = self.I( + MyTT.KDJ, self.data.close, self.data.high, self.data.low + ) + self.k_cross_up = crossover(self.k, self.d) + self.k_cross_down = crossover(self.d, self.k) + + def next(self) -> None: + j_val = self.j[self._bar_index] + + if self.k_cross_up[self._bar_index] and j_val < 20 and self.position["size"] == 0: + self.buy(size=0) + elif self.k_cross_down[self._bar_index] and j_val > 80 and self.position["size"] > 0: + self.sell(size=0) diff --git a/strategies/ma_cross.py b/strategies/ma_cross.py new file mode 100644 index 0000000..1246bd6 --- /dev/null +++ b/strategies/ma_cross.py @@ -0,0 +1,27 @@ +"""双均线交叉策略。 + +MA5 上穿 MA20(金叉)全仓买入,MA5 下穿 MA20(死叉)全部卖出。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/ma_cross.py --table +""" + +from easy_tdx.backtest import Strategy, crossover +from easy_tdx import MyTT + + +class MACrossStrategy(Strategy): + """双均线交叉策略。""" + + def init(self) -> None: + self.ma5 = self.I(MyTT.MA, self.data.close, 5) + self.ma20 = self.I(MyTT.MA, self.data.close, 20) + self.golden = crossover(self.ma5, self.ma20) + self.death = crossover(self.ma20, self.ma5) + + def next(self) -> None: + if self.golden[self._bar_index] and self.position["size"] == 0: + self.buy(size=0) + elif self.death[self._bar_index] and self.position["size"] > 0: + self.sell(size=0) diff --git a/strategies/macd_cross.py b/strategies/macd_cross.py new file mode 100644 index 0000000..682c0f4 --- /dev/null +++ b/strategies/macd_cross.py @@ -0,0 +1,26 @@ +"""MACD 金叉死叉策略。 + +DIF 上穿 DEA(金叉)买入,DIF 下穿 DEA(死叉)卖出。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/macd_cross.py --table +""" + +from easy_tdx.backtest import Strategy, crossover +from easy_tdx import MyTT + + +class MACDStrategy(Strategy): + """MACD 金叉死叉策略。""" + + def init(self) -> None: + self.dif, self.dea, self.hist = self.I(MyTT.MACD, self.data.close) + self.golden = crossover(self.dif, self.dea) + self.death = crossover(self.dea, self.dif) + + def next(self) -> None: + if self.golden[self._bar_index] and self.position["size"] == 0: + self.buy(size=0) + elif self.death[self._bar_index] and self.position["size"] > 0: + self.sell(size=0) diff --git a/strategies/rsi_reversal.py b/strategies/rsi_reversal.py new file mode 100644 index 0000000..cf0633b --- /dev/null +++ b/strategies/rsi_reversal.py @@ -0,0 +1,26 @@ +"""RSI 超买超卖策略。 + +RSI < 30(超卖)买入,RSI > 70(超买)卖出。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/rsi_reversal.py --table +""" + +from easy_tdx.backtest import Strategy +from easy_tdx import MyTT + + +class RSIStrategy(Strategy): + """RSI 超买超卖反转策略。""" + + def init(self) -> None: + self.rsi = self.I(MyTT.RSI, self.data.close, 14) + + def next(self) -> None: + cur_rsi = self.rsi[self._bar_index] + + if cur_rsi < 30 and self.position["size"] == 0: + self.buy(size=0) + elif cur_rsi > 70 and self.position["size"] > 0: + self.sell(size=0) diff --git a/strategies/turtle_breakout.py b/strategies/turtle_breakout.py new file mode 100644 index 0000000..39766e2 --- /dev/null +++ b/strategies/turtle_breakout.py @@ -0,0 +1,29 @@ +"""海龟交易法(唐安奇通道)策略。 + +价格突破 N 日最高价买入,跌破 N 日最低价卖出。 +经典的趋势跟踪策略。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/turtle_breakout.py --table +""" + +from easy_tdx.backtest import Strategy +from easy_tdx import MyTT + + +class TurtleStrategy(Strategy): + """海龟交易法(唐安奇通道突破)策略。""" + + def init(self) -> None: + self.upper, self.lower = self.I(MyTT.TAQ, self.data.high, self.data.low, 20) + + def next(self) -> None: + cur = self.data.close[0] + upper = self.upper[self._bar_index] + lower = self.lower[self._bar_index] + + if cur >= upper and self.position["size"] == 0: + self.buy(size=0) + elif cur <= lower and self.position["size"] > 0: + self.sell(size=0) diff --git a/strategies/volume_price.py b/strategies/volume_price.py new file mode 100644 index 0000000..3cdfa52 --- /dev/null +++ b/strategies/volume_price.py @@ -0,0 +1,35 @@ +"""量价配合策略。 + +放量上涨(成交量 > MA(vol,5) 且收阳线)买入, +缩量下跌(成交量 < MA(vol,5) 且收阴线)且持仓盈利时卖出。 + +用法:: + + easy-tdx backtest SZ 000001 --strategy-file strategies/volume_price.py --table +""" + +from easy_tdx.backtest import Strategy +from easy_tdx import MyTT + + +class VolumePriceStrategy(Strategy): + """量价配合策略。""" + + def init(self) -> None: + self.vol_ma = self.I(MyTT.MA, self.data.vol, 5) + + def next(self) -> None: + cur_close = self.data.close[0] + cur_open = self.data.open[0] + cur_vol = self.data.vol[0] + avg_vol = self.vol_ma[self._bar_index] + + is_yang = cur_close > cur_open # 阳线 + is_yin = cur_close < cur_open # 阴线 + is_vol_up = cur_vol > avg_vol # 放量 + is_vol_down = cur_vol < avg_vol # 缩量 + + if is_yang and is_vol_up and self.position["size"] == 0: + self.buy(size=0) + elif is_yin and is_vol_down and self.position["size"] > 0: + self.sell(size=0)