进阶 · 代码逐项

SMAOffset · 代码逐项

对着 SMAOffset4h.py 从上往下走。跌破买均线再乘偏移才买,涨过卖均线再乘偏移才卖。

SMAOffset4h.py 4h 16 / 0.978 49 / 1.006 5m 默认参数

1怎么走

社区 SMAOffsetProtectOptV1 的 4h 对照版。时间改 4h,ROI 焊死,只算用到的 EMA。偏移、EWO、RSI 仍是 5 分钟街上 hyperopt 留下的默认,没有按 4h 重搜。

2逐项

每一项是文件里的原文,不是口诀。先看黑底那几行,再听人话,再答三问。

EWO 函数
def EWO(dataframe, ema_length=50, ema2_length=200):
    ema1 = ta.EMA(dataframe, timeperiod=ema_length)
    ema2 = ta.EMA(dataframe, timeperiod=ema2_length)
    return (ema1 - ema2) / dataframe["close"] * 100

快均线减慢均线,再除以收盘、乘 100。量的是两条均线拉开的距离,不是涨跌口号。类外面的小函数,后面会喂 50 和 200。

它是什么
Elliott Wave Oscillator 在这份文件里的算法。拉伸尺子。
不管它会怎样
不管它,后面 EWO 列没有来源,两道 EWO 门都废。
拧大 / 拧小 / 拧反
快慢拧近:拉伸几乎是 0,两道门很难开。拧远:更钝。分子写成 ema2-ema1:正负对调,高低门会反着放行。
class SMAOffset4h(IStrategy)
class SMAOffset4h(IStrategy):

向引擎登记这份 4 小时 SMAOffset。对照选的是类名。

它是什么
策略类。
不管它会怎样
没有这个类,回测选不中。
拧大 / 拧小 / 拧反
改名以后配置里的策略名要对上。
INTERFACE_VERSION = 3
    INTERFACE_VERSION = 3

按第三版接口读 enter / exit。

它是什么
接口版本号。
不管它会怎样
版本对不上,进出场字段对不齐。
拧大 / 拧小 / 拧反
拧成 2:新字段名会被旧约定忽略。
timeframe = "4h"
    timeframe = "4h"

时钟改成 4 小时。参数还是 5 分钟街上调的,弹性对不上。这正是对照要暴露的错配。

它是什么
采样间隔。逻辑出身 5m。
不管它会怎样
改回 5m:那是原版街道,不是这份 4h 对照。
拧大 / 拧小 / 拧反
只改时钟、不改偏移和 EWO:皮筋还是 5m 那根。不要另编一套 4h 数冒充优化。
startup_candle_count = 220
    startup_candle_count = 220

先丢掉大约 220 根。最慢的是 EWO 的 200 日 EMA,再留一点余量。

它是什么
暖机根数。慢 EMA 算稳之前不交易。
不管它会怎样
暖机短于 200:EWO 是半残的,高低门会乱放行。
拧大 / 拧小 / 拧反
拧到 50:慢线是假的。拧到 2000:白白丢掉很长一段。
process_only_new_candles = True
    process_only_new_candles = True

只在 4h 收盘时看有没有跌破偏移、涨过偏移。

它是什么
只处理收盘。
不管它会怎样
未收盘就判回踩,影线刺一下 2% 就会提前接。
拧大 / 拧小 / 拧反
拧成 False:盘中刺破偏移就会下手。
can_short = False
    can_short = False

只做多。涨过卖均线是平多,不是开空。

它是什么
空仓开关。关着。
不管它会怎样
有人看见跌破就想做空。这份是回踩做多。
拧大 / 拧小 / 拧反
拧成 True:还要自己写空头条件。
use_exit_signal = True
    use_exit_signal = True

涨过卖均线那行 exit_long,引擎会听。主出场是偏移,不是 ROI。

它是什么
出信号门开着。
不管它会怎样
门关着,弹回卖线也不走,只剩 -12% 地板。
拧大 / 拧小 / 拧反
拧成 False:回归派少了松手那一下。
exit_profit_only = False
    exit_profit_only = False

亏着也能按涨过卖线卖。回踩没弹回来,碰到卖线仍走。

它是什么
出信号是否只许盈利时触发。这里不限制。
不管它会怎样
拧成 True:没解套就不许按信号走,回归会拖成死扛。
拧大 / 拧小 / 拧反
拧反 True:和「碰到另一条线就松手」相反。
minimal_roi = {"0": 10}
    minimal_roi = {"0": 10}

一上车要涨 10 倍才用 ROI。原版 5m 是大约 1% 的短线 ROI,对照把它焊死,让均线偏移自己出场。

它是什么
ROI 表。门槛抬到几乎碰不到。
不管它会怎样
留着 1% ROI:4h 上刚买就会被闹钟平掉,比的就不是偏移了。
拧大 / 拧小 / 拧反
拧小:又变回短线闹钟。不要另编 4h 的 ROI 表。
stoploss = -0.12
    stoploss = -0.12

硬止损 12%。接飞刀时的保命地板,不是主卖点。

它是什么
暴跌地板。
不管它会怎样
没有地板,回踩变成下跌中段,亏没有底。
拧大 / 拧小 / 拧反
拧到 -0.03:地板比偏移更敏,回归还没弹就走。拧到 -0.99:飞刀几乎不防。
trailing_stop = False
    trailing_stop = False

不用跟踪止盈。出门交给卖均线偏移和地板。

它是什么
跟踪止损开关。关着。
不管它会怎样
开着会在回弹中段被剪掉,皮筋还没松完。
拧大 / 拧小 / 拧反
拧成 True:和 high_offset 抢出场。
买均线 16,卖均线 49
    base_nb_candles_buy = 16
    base_nb_candles_sell = 49

买用 16 根 EMA,卖用 49 根 EMA。买和卖不是同一条线。这两个数是 5m 默认,原样搬来。

它是什么
两条均线的长度。
不管它会怎样
写成同一个数:买门槛和卖门槛贴在同一条线上,回归的「另一条线」没了。
拧大 / 拧小 / 拧反
拧大:线更慢,回踩更晚。拧小:更跟价。不要按 4h 另搜一套冒充这份对照。
low_offset / high_offset
    low_offset = 0.978
    high_offset = 1.006

买门槛在买均线下方,乘 0.978,大约再便宜 2.2%。卖门槛在卖均线上方,乘 1.006,大约再贵 0.6%。也是 5m 默认。

它是什么
两条偏移。不是碰到均线就动手。
不管它会怎样
都写成 1.0:回到均线触碰,回归的味淡了。
拧大 / 拧小 / 拧反
low 拧更小:更便宜才买,信号更少。high 拧更大:要弹得更高才卖。高低对调:跌的时候卖、涨的时候买,逻辑反了。
EWO 高低门
    ewo_high = 5.638
    ewo_low = -19.993

拉伸大到 5.638 以上,走「高 EWO + RSI」那一扇。拉伸小到 -19.993 以下,走「低 EWO」那一扇。两道门是 5m hyperopt 留下的小数。

它是什么
EWO 的两道阈值。一正一负,两条入场支路。
不管它会怎样
不管它们:只看跌破 2%,下跌中段也会接,回归会接成接飞刀。
拧大 / 拧小 / 拧反
拧到极宽:几乎从不放行。拧到极窄:过滤形同虚设。正负对调:两扇门认反。
rsi_buy = 61
    rsi_buy = 61

高 EWO 那条支路还要 RSI 小于 61。低 EWO 那条不问 RSI。61 也是 5m 默认。

它是什么
高拉伸支路上的第二道门。
不管它会怎样
不管它:高 EWO 单独放行,惯性上涨里也可能接。
拧大 / 拧小 / 拧反
拧到 20:几乎不放行。拧到 90:RSI 形同虚设。注意:低 EWO 支路本来就没有这道门。
fast_ewo / slow_ewo
    fast_ewo = 50
    slow_ewo = 200

喂给 EWO 函数的快慢 EMA。50 和 200。决定拉伸量的是哪两条线。

它是什么
EWO 的两根均线周期。
不管它会怎样
不管它们,EWO() 会用函数默认 50/200,和这里刚好相同;但改函数默认、不改这里,对不上。
拧大 / 拧小 / 拧反
拧近:拉伸变小。拧远:更钝。对调 200/50:分子反号,高低门会反着放行。
ma_buy / ma_sell
        dataframe["ma_buy"] = ta.EMA(dataframe, timeperiod=self.base_nb_candles_buy)
        dataframe["ma_sell"] = ta.EMA(dataframe, timeperiod=self.base_nb_candles_sell)

按 16 和 49 算出两条 EMA。名字带 SMA,算的是 EMA。只算用到的,不扫 hyperopt 全区间。

它是什么
买门槛和卖门槛的均线。
不管它会怎样
只算一条:买或卖缺尺子。改成 SMA:比 EMA 钝,回踩点会挪。
拧大 / 拧小 / 拧反
周期跟上面两个 base_nb。官方全扫一段区间,这份不算。
EWO 列和 RSI 列
        dataframe["EWO"] = EWO(dataframe, self.fast_ewo, self.slow_ewo)
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)

把拉伸和 RSI 写进表。RSI 周期写死 14,没有单独属性。

它是什么
两道过滤器的数据列。
不管它会怎样
不算 EWO:高低门比空列。不算 RSI:高 EWO 支路的 rsi<61 废了。
拧大 / 拧小 / 拧反
RSI 周期拧到 2 或 50:61 这道门的松紧会变,但文件里 14 是写死的。
below:跌破买均线乘偏移
        below = dataframe["close"] < (dataframe["ma_buy"] * self.low_offset)

收盘价低于买均线的 0.978 倍,才算回踩够深。下面两扇门都要先过这个 below。

它是什么
回归的主门槛。不是金叉。
不管它会怎样
不管它:只靠 EWO/RSI,价格还在均线上方也会买,回踩变成追价。
拧大 / 拧小 / 拧反
改成 >:涨过均线才买,回归变成追涨。偏移跟 low_offset。
入场支路一:高 EWO 且 RSI 未热
            (below & (dataframe["EWO"] > self.ewo_high) & (dataframe["rsi"] < self.rsi_buy) & (dataframe["volume"] > 0))

已经跌破偏移,并且拉伸向上大、RSI 还小于 61、有量。皮筋绷紧但不是超买向下砸穿。

它是什么
第一扇门。三问都要过。
不管它会怎样
去掉 RSI:高拉伸时也可能在过热里接。去掉 below:见上一项。
拧大 / 拧小 / 拧反
EWO> 改成 <:和支路二抢同一侧,另一侧空掉。
入场支路二:低 EWO
            (below & (dataframe["EWO"] < self.ewo_low) & (dataframe["volume"] > 0))

已经跌破偏移,并且拉伸向下大到 -19.993 以下、有量。这条不问 RSI。

它是什么
第二扇门。超卖拉伸。
不管它会怎样
不管它:只剩高 EWO 那一扇,向下拉伸的回踩不接。
拧大 / 拧小 / 拧反
加上 rsi<61:两扇门变得一样严。去掉 below:下跌中段也会接。
两扇门 OR 在一起
        dataframe.loc[reduce(lambda x, y: x | y, conditions), "enter_long"] = 1

两扇门任一成立就买。是 OR,不是 AND。所以「高拉伸 + RSI」和「低拉伸」是两条路,不是同时要满足。

它是什么
入场合并。
不管它会怎样
改成 AND:既要 EWO>5.638 又要 EWO<-19.993,永远买不到。
拧大 / 拧小 / 拧反
再 OR 第三扇:过滤更松。只留一扇:另一类回踩不接。
出场:涨过卖均线乘偏移
                (dataframe["close"] > (dataframe["ma_sell"] * self.high_offset))
                & (dataframe["volume"] > 0)

收盘价高于卖均线的 1.006 倍,并且有量,才写平多。买看 16 根那条,卖看 49 根这条。

它是什么
松手门槛。和买不是同一条线、也不是同一个偏移。
不管它会怎样
不管它:只靠地板出门,弹回来也不走。改成 ma_buy:买卖贴在同一条线上。
拧大 / 拧小 / 拧反
改成 <:跌的时候卖,逻辑还说得通,但和「弹回再松」相反,变成破位走。偏移跟 high_offset。

3假懂

人们会说:「这些 0.978、5.638、61 是按 4 小时搜出来的最优参数。」
更短的一句:文件注释写明,16 / 0.978、49 / 1.006、EWO、RSI 保持原默认。原默认来自 5 分钟 hyperopt。对照只改了时钟、焊死了 ROI、少算了没用到的 EMA。不要把错配当成 4h 最优。

4你来讲

对着这份文件讲。口头就行。不要编回测数字。

  1. EWO 的公式是哪一行?它量的是方向口号,还是两条均线拉开的距离?
  2. 两扇入场门为什么是 OR?改成 AND 会怎样?低 EWO 那扇为什么不问 RSI?
  3. low_offset=0.978 和 high_offset=1.006 是 4h 搜出来的吗?文件哪一段告诉你它们是 5m 默认?