对着 Turtle4h.py 从上往下走。突破通道买,跌破通道或 2N 卖。
日线海龟搬到 4h:1 天 6 根,所以 20 日是 120 根,10 日是 60 根。通道用 shift(1) 不含当前 K。真正止损是入场那根的 2 个 ATR,-0.25 只是地板。
每一项是文件里的原文,不是口诀。先看黑底那几行,再听人话,再答三问。
class Turtle4h(IStrategy):
向引擎登记这份 4 小时海龟。对照选的是类名 Turtle4h。
INTERFACE_VERSION = 3
按第三版接口读 enter / exit,后面 custom_stoploss 也走这套。
timeframe = "4h"
每根 K 是 4 小时。后面 120 根才等于 20 个日历日,不是 20 根。
startup_candle_count = 130
先丢掉大约 130 根。通道要 120 根,再加 shift(1),前面几根数不满。
process_only_new_candles = True
只在 4h 收盘时判断突破。突破看的是收盘价,不是影线乱晃。
can_short = False
这版只做多。经典海龟有空头系统,这份对照没有。
use_exit_signal = True
跌破 10 日低点那行 exit_long,引擎会听。
exit_profit_only = False
亏着也能按信号卖。假突破可以认赔离场。
use_custom_stoploss = True
打开自定义止损。真正的 2N 在文件最下面那一截。
minimal_roi = {"0": 10}
一上车要涨 10 倍,ROI 才出手。等于关掉按时间止盈,让通道和 2N 负责出场。
stoploss = -0.25
硬地板:亏 25% 必须走。注释写了,真正止损由 custom_stoploss 按 2N 算。
trailing_stop = False
不用跟踪止盈。出场交给通道和 2N。
entry_period = 120 # 20 日
入场通道看过去 120 根最高。4h 上 120 根就是 20 个日历日。
exit_period = 60 # 10 日
出场通道看过去 60 根最低。4h 上 60 根就是 10 个日历日。
atr_period = 120 # 20 日 ATR
N 用 120 根 ATR,和入场窗口同一段路的晃动。
stop_n = 2.0
止损放在入场价下方 2 个 N。这就是 2N。
dataframe["donchian_high"] = dataframe["high"].rolling(self.entry_period).max().shift(1)
过去 120 根的最高价,再往后挪一格。当前这根的高点不算进通道,避免自己跟自己比。
dataframe["donchian_low"] = dataframe["low"].rolling(self.exit_period).min().shift(1)
过去 60 根的最低价,同样挪一格。跌破的是「已经走完的低点」。
dataframe["atr"] = ta.ATR(dataframe, timeperiod=self.atr_period)
用 TA-Lib 算 120 根 ATR,存成一列。后面入场要它大于 0,止损要用入场那一格的值。
(dataframe["close"] > dataframe["donchian_high"])
& (dataframe["volume"] > 0)
& (dataframe["atr"] > 0)
收盘价高于过去 20 日最高,并且这根有量、ATR 已经算出来,才写开多。
(dataframe["close"] < dataframe["donchian_low"])
& (dataframe["volume"] > 0)
收盘价低于过去 10 日最低,并且有量,才写平多。这里不管赚亏。
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
if dataframe is None or dataframe.empty:
return self.stoploss
先把这对币已经算好的表拿来。表是空的,就退回地板 -0.25。
trade_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc)
candle = dataframe.loc[dataframe["date"] == trade_date]
if candle.empty:
candle = dataframe.loc[dataframe["date"] <= trade_date].tail(1)
if candle.empty:
return self.stoploss
把开仓时间对齐到 4h 的那根 K。对不齐就取不晚于开仓的最后一根。还没有,再退回地板。
n = float(candle["atr"].iloc[0])
if n <= 0:
return self.stoploss
入场那根的 ATR 就是 N。N 还没算出来或是 0,不硬算 2N,退回地板。
stop_price = trade.open_rate - self.stop_n * n
从买入价往下量 2 个 N,得到一个固定价格。路晃得大,安全距离也大。
return (stop_price / current_rate) - 1
引擎要的不是价格,是「现在这笔相对现价还要再跌多少才碰到止损价」。止损价固定,现价在变,这个比例每根都会重算。
对着这份文件讲。口头就行。不要编回测数字。