对着 MultiMa4h.py 从上往下走。TEMA 多头排列买,相邻线扭头或官方 ROI 卖。
官方 MultiMa 会预计算 20×100 条 TEMA,最长 1881 根,4h 上要暖机大半年。这份只算买 4×15、卖 12×68 用到的线。列名就是周期数字。排列用 AND,扭头用 OR。
每一项是文件里的原文,不是口诀。先看黑底那几行,再听人话,再答三问。
class MultiMa4h(IStrategy):
向引擎登记这份 4 小时 MultiMa。对照选的是类名。
INTERFACE_VERSION = 3
按第三版接口读 enter / exit。
timeframe = "4h"
每根 K 是 4 小时。官方 ROI 表的分钟数,要按这根时钟去读。
startup_candle_count = 800
先丢掉大约 800 根。最长卖线是 11×68=748,再留一点余量。
process_only_new_candles = True
只在 4h 收盘时看排列齐没齐、相邻线扭没扭。
can_short = False
只做多。相邻线扭头是平多,不是开空。
use_exit_signal = True
相邻线扭头那行 exit_long,引擎会听。官方 ROI 是另一扇门,不靠这行。
minimal_roi = {
"0": 0.523,
"1553": 0.123,
"2332": 0.076,
"3169": 0,
}
官方 hyperopt 出来的时间止盈,对照时也沿用。0 分钟就要 52.3%;1553 分钟降到 12.3%;2332 分钟 7.6%;3169 分钟降到 0,时间到了即使没赚也开门。单位是分钟,不是 4h 根数。
stoploss = -0.345
硬止损 34.5%。也是官方 hyperopt 留下的,对照沿用。
trailing_stop = False
不用跟踪止盈。出门交给扭头、官方 ROI 和地板。
buy_ma_count = 4
buy_ma_gap = 15
买侧循环 0、1、2、3,乘 15 得到周期 0、15、30、45。0 后面会被跳过,真正用到的买线是 15、30、45。
sell_ma_count = 12
sell_ma_gap = 68
卖侧循环 0 到 11,乘 68 得到 0、68、136,一直到 748。0 跳过。扭头看的是这些相邻对。
periods = set()
for ma_count in range(self.buy_ma_count):
periods.add(ma_count * self.buy_ma_gap)
for ma_count in range(self.sell_ma_count):
periods.add(ma_count * self.sell_ma_gap)
把买侧和卖侧的周期丢进集合。官方文件会预计算 20×100 全部 TEMA;这里只收集默认参数用到的那些数。
for period in periods:
if period > 1:
dataframe[period] = ta.TEMA(dataframe, timeperiod=int(period))
周期大于 1 才算。算完以后,列名是整数 15、30、45、68……748,不是 ma_15 这种字符串。0 被跳过。
conditions = []
for ma_count in range(self.buy_ma_count):
key = ma_count * self.buy_ma_gap
past_key = (ma_count - 1) * self.buy_ma_gap
if past_key > 1 and key in dataframe.keys() and past_key in dataframe.keys():
conditions.append(dataframe[key] < dataframe[past_key])
if conditions:
dataframe.loc[reduce(lambda x, y: x & y, conditions), "enter_long"] = 1
买侧相邻两条,慢的 key 低于快的 past_key,才算这一对排齐。ma_count=0、1 时 past_key 是 -15 或 0,被 past_key>1 跳过。真正比的是 30<15 和 45<30。所有对 AND 在一起,全齐才买。
conditions = []
for ma_count in range(self.sell_ma_count):
key = ma_count * self.sell_ma_gap
past_key = (ma_count - 1) * self.sell_ma_gap
if past_key > 1 and key in dataframe.keys() and past_key in dataframe.keys():
conditions.append(dataframe[key] > dataframe[past_key])
if conditions:
dataframe.loc[reduce(lambda x, y: x | y, conditions), "exit_long"] = 1
卖侧相邻两条,慢的 key 高于快的 past_key,就算这一对扭头。从 136>68 一直比到 748>680。任意一对成立就卖,是 OR,不是 AND。
对着这份文件讲。口头就行。不要编回测数字。