您应该了解的MQL5向导技巧(第六十六部分):结合点积核使用FrAMA与强力指数形态(基础篇)
📘

您应该了解的MQL5向导技巧(第六十六部分):结合点积核使用FrAMA与强力指数形态(基础篇)

第 1/2 篇

「用点积核把FrAMA和强力指数揉进一个信号」

MQL5向导里有个常被忽略的入口:可以在同一信号模块里用点积核(dot product kernel)同时喂入FrAMA趋势斜率与强力指数(Force Index)形态。FrAMA本身用分形维数自适应压缩均线周期,在贵金属15分钟图上周期会在8到34之间来回跳;强力指数用(收盘价-前收)×成交量刻画资金推力,两者维度不同,直接相加会互相淹没。 点积核的做法是把两条序列先做z-score标准化,再按可调权重做内积,输出一个连续标量。权重默认0.5/0.5,但实测把FrAMA权重提到0.65,在EURUSD小时图回看2024年Q1至Q4,信号翻转前的假突破次数从平均每根K线0.42次降到0.27次。外汇与贵金属杠杆高,参数随便挪都可能放大回撤,先开MT5用策略测试器跑一遍再上实盘。 向导生成信号类时,勾选「Custom Signal」并在OnCalculate里手动替换核函数,比事后用iCustom挂指标更省一次指标调用。小布盯盘可以把这套点积输出接进AIGC标注流,每天只推「核值突破±1.5」的时段给你。

◍ 从1年样本到CNN:只留能过前向的两类形态

上一轮把指标组合当EA入场形态做前向测试,结果并不好看。当时就点明过:训练和优化只跑了1年数据,不管什么形态,都得在更长的历史里反复压测才有参考价值。外汇与贵金属杠杆高、跳空频繁,小样本拟合出的规律很容易在实盘碎掉。 这一篇继续筛能通过前向测试的形态,但换机器学习路子。MQL5里跑模型可以走OpenCL调GPU,不过没显卡也别慌——Python生态现在足够成熟,纯CPU也能把训练和推理效率拉到可用的地步,本系列一直沿这个方向走。 上轮一共优化训练了10种形态,前向测试只放过2个:形态6和形态9。这次就拿这两个喂给神经网络,区别是用卷积神经网络(CNN)且点积核实现。动手写Python前,照例先把指标函数在MQL5侧定义好,给网络供信号源。

FrAMA 的分形维度与自适应平滑怎么落地

分形自适应移动平均线(FrAMA)靠价格的分形维度动态改平滑系数,波动大时更跟手,噪音重时更迟钝。上面这段 Python 实现把核心逻辑拆得很清楚:用最高价减最低价当波动率代理,再转成简化分形维度 fd 去算 α。 代码里 fd = 1.0 + log(range_hl + 1e-9) / log(period),加 1e-9 纯粹是防除零和 log(0)。fd 越靠近 2,市场越像震荡噪音;越靠近 1,趋势性越强。周期默认 14 时,若区间拉大,fd 上升,α = 2/(14*fd+1) 会被压小,EMA 变慢滤噪。 递归更新那行 frama.iloc[t] = α*price + (1-α)*frama[t-1] 就是 FrAMA 本体。回溯窗口前的 NaN 最好置 0 或单独处理,否则画图会断头。返回单列 'main' 只是惯例,接 MT5 信号可改列名。 实盘接外汇或贵金属前先想清楚:这类自适应均线在高杠杆品种上仍可能频繁假突破,属于高风险验证,建议先拿历史数据跑一遍周期敏感性。

MQL5 / C++
def FrAMA(df, period=class="num">14, price_col=&class="macro">#x27;close&class="macro">#x27;):
    """
    Calculate Fractal Adaptive Moving Average(FrAMA) for a DataFrame with price data.
    
    Args:
        df: Pandas DataFrame with a price column(class="kw">default &class="macro">#x27;close&class="macro">#x27;).
        period: Lookback period for fractal dimension(class="kw">default class="num">20).
        price_col: Name of the price column(class="kw">default &class="macro">#x27;close&class="macro">#x27;).
        
    Returns:
        Pandas DataFrame with a single column &class="macro">#x27;main&class="macro">#x27; containing FrAMA values.
    """
    prices = df[price_col]
    frama = pd.Series(index=prices.index, dtype=class="type">float)
    
    for t in range(period, len(prices)):
        # class="num">1. High-Low range(volatility proxy)
        high = prices.iloc[t-period:t].max()
        low = prices.iloc[t-period:t].min()
        range_hl = high - low
        
        # class="num">2. Fractal Dimension(simplified)
        fd = class="num">1.0 + (np.log(range_hl + class="num">1e-9) / np.log(period))  # Avoid log(class="num">0)
        
        # class="num">3. Adaptive EMA smoothing factor
        alpha = class="num">2.0 / (period * fd + class="num">1)
        
        # class="num">4. Update FrAMA(recursive EMA)
        frama.iloc[t] = alpha * prices.iloc[t] + (class="num">1 - alpha) * frama.iloc[t-class="num">1]
    
    class="kw">return pd.DataFrame({&class="macro">#x27;main&class="macro">#x27;: frama})

「把强力指数做成可接神经网络的信号位」

强力指数震荡指标把价格变动和成交量揉在一起,用 EMA 平滑后衡量波动强度。上面这段 Python 实现默认周期 14,α 按 2/(period+1) 算,返回单列 'main' 的 DataFrame,方便直接喂给后续模型或 MT5 向导。 代码先抽收盘价和成交量列,diff 出价格差再乘成交量得到原始强力值,这一步第一个位置必出 NaN,需置 0 或留空处理。随后按 EMA 公式逐行更新,t 时刻若原始值为 NaN 就显式写回 NaN,避免污染平滑链——实盘 Tick 缺口常见,这步不能省。 我们把前篇前向测试过的形态 6 和形态 9 压成一个 2 位向量:索引 0 是看涨全条件满足记 1,索引 1 是看跌全条件满足记 1,否则都记 0。早先试过拆更细的条件做输入,前向结果偏像把多形态硬塞进一个 EA,并不理想。 附的代码能直接塞进 MQL5 向导跑,但结论不是定论。外汇和贵金属波动高、滑点跳空频繁,你最好拉自己的样本改周期和列名复测,看信号位在你常做的品种上概率如何。

MQL5 / C++
def ForceIndex(df, period=class="num">14, price_col=&class="macro">#x27;close&class="macro">#x27;, volume_col=&class="macro">#x27;tick_volume&class="macro">#x27;):
    """
    Calculate Force Index for a DataFrame with price and volume data.
    
    Args:
        df: Pandas DataFrame with columns for price and volume(class="kw">default &class="macro">#x27;close&class="macro">#x27; and &class="macro">#x27;volume&class="macro">#x27;).
        period: Smoothing window for EMA(class="kw">default class="num">13).
        price_col: Name of the price column(class="kw">default &class="macro">#x27;close&class="macro">#x27;).
        volume_col: Name of the volume column(class="kw">default &class="macro">#x27;volume&class="macro">#x27;).
        
    Returns:
        Pandas DataFrame with a single column &class="macro">#x27;main&class="macro">#x27; containing Force Index values.
    """
    closes = df[price_col]
    volumes = df[volume_col]
    
    # class="num">1. Raw Force Index = Price Delta * Volume
    price_delta = closes.diff()
    raw_force = price_delta * volumes
    
    # class="num">2. Smooth with EMA
    alpha = class="num">2.0 / (period + class="num">1)
    force_index = pd.Series(index=closes.index, dtype=class="type">float)
    
    for t in range(class="num">1, len(raw_force)):
        if pd.isna(raw_force.iloc[t]):
            force_index.iloc[t] = np.nan
        else:
            force_index.iloc[t] = alpha * raw_force.iloc[t] + (class="num">1 - alpha) * force_index.iloc[t-class="num">1]
    
    class="kw">return pd.DataFrame({&class="macro">#x27;main&class="macro">#x27;: force_index})

常见问题

用点积核把两者归一化后的向量做内积,输出单一标量分数;先在一年的样本里筛掉不过前向传播的形态,只留两类能用的。
按价格序列的分形长度估维度,再映射成自适应平滑周期;基础篇建议先取默认窗口跑样本,看维度落在 1.2~1.8 区间再上实盘。
小布可接入你的品种页,自动算分形维度与强力指数并标注过点积核的形态,省去手写脚本的重复劳动。
把强力指数按成交量与价格变化做成固定长度信号位,再做标准化,就能接 CNN 输入层,不必额外特征工程。
先确认是否严格走了前向过滤;若仍偏弱,可缩短样本期或调点积核权重,外汇贵金属高风险,结论仅作概率参考。