如何构建并优化基于成交量的交易系统蔡金资金流指标(Chaikin Money Flow - CMF)(基础篇)
📘

如何构建并优化基于成交量的交易系统蔡金资金流指标(Chaikin Money Flow - CMF)(基础篇)

第 1/3 篇

「用 CMF 把成交量翻译成资金方向」

蔡金资金流(CMF)把每日成交量和收盘价在当日振幅里的位置绑定,给出一段时间内资金净流入还是净流出的读数。它在 MT5 里属于内置成交量类指标,默认周期 20,输出在 -1 到 +1 之间摆动,0 轴是多空分水岭。 对黄金和外汇来说,CMF 单独用很容易被震荡市刷掉,但它和价格背离的组合值得盯:当价格创新高而 CMF 未同步抬升,上涨动能可能衰竭;反之价格新低而 CMF 回升,下跌倾向减弱。这类信号在 H1 及以上周期更干净,M1 噪音偏大。 在 MT5 里直接拖入 CMF 后,把周期从 20 改成 14 或 34 是常见调法——14 更灵敏但假信号多,34 滞后但过滤强。外汇与贵金属杠杆高、滑点突发行情多,任何指标信号都只是概率参考,实盘前请用策略测试器跑至少 3 个月 tick 数据验证。

◍ 先认识 CMF 这个成交量指标

本篇要拆的是一个基于成交量的技术指标——蔡金资金流指标(CMF)。我们会从定义、计算方式、自定义代码编写,到把它塞进交易系统做回测优化,一步步过一遍。 这类文章的核心目的很直接:把新工具摊开给你看,既能单独用,也能按它的特性拼进你现有的分析框架里,再跑测试看实不实用。 外汇和贵金属市场高杠杆、高波动,CMF 只是概率层面的辅助信号,任何用它构成的系统都得你在 MT5 上自己验过才作数,盈亏自负。

用 CMF 读穿资金积累与派发

蔡金资金流(CMF)把成交量和收盘价在 K 线中的相对位置揉在一起,用来判断一段周期内资金是在吸筹还是派发。核心逻辑很直白:收盘越贴最高价,越像资金在积累;收盘越贴最低价,越像在分布。配合放大的成交量,这种偏向会被放大成指标的正负值。 计算上分三层。先算资金流乘数:(收盘价-最低价)-(最高价-收盘价) 再除以 (最高价-最低价),这东西天然落在 -1 到 1 之间。乘上当年周期成交量得到资金流成交量,最后取 n 周期的资金流成交量之和除以 n 周期成交量之和,就是 CMF。 出来的曲线绕 0 轴晃,区间锁在 +1 到 -1。上穿 0 可能意味着买盘开始占上风,下穿 0 则倾向卖盘主导;贴着 0 磨往往说明多空没分出明显方向。外汇和贵金属波动大、杠杆高,光看穿越信号容易吃假突破,建议开 MT5 加载默认 CMF 先肉眼校一遍再谈用法。 原文给的下一步是把它改成柱状图或调周期,这其实点出了 MT5 指标可改代码的便利——不用死守折线。

「手搓一个独立窗口的蔡金资金流」

想把蔡金资金流(CMF)塞进自己的交易系统,最干净的做法是在 MT5 里写个自定义指标,而不是依赖内置版本。核心思路不复杂:用 #property 把外观和行为钉死,再用 OnCalculate 跑累加逻辑,编译后就能在独立子窗口里看到蓝柱。 外观层面先定调:indicator_separate_window 让它单独开窗;indicator_buffers 设 4、indicator_plots 设 1,说明我们只画一条图但留了多余缓冲;indicator_type1 用 DRAW_HISTOGRAM,线宽 indicator_width1=3,颜色 clrBlue。水平线放在 0、+0.20、-0.20,样式 STYLE_DOT、黑色、线宽 0——这三条线就是后续判多空惯性的参照。 输入参数只留两个:periods 默认 20,volumeTypeInp 默认 VOLUME_TICK。缓冲区 cmfBuffer 用 SetIndexBuffer(0,cmfBuffer,INDICATOR_DATA) 绑定;IndicatorSetInteger(INDICATOR_DIGITS,5) 控小数位;PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,0) 表示从第 0 根就画;短名拼成 "Chaikin Money Flow(20)" 方便看图识别。 计算部分靠 AccDis 函数吃下 high/low/close/volume,先算资金流乘数再乘量得资金流成交量,循环累加 sumAccDis 与 sumVol,比值写回 cmfBuffer。外汇与贵金属波动受成交量断层影响大,CMF 仅作概率倾向参考,实盘前务必在 MT5 用历史数据验证柱体反应速度。 下面这段是拼好的关键声明与初始化片段,直接丢进 MQ5 文件就能编译出雏形:

MQL5 / C++
class="macro">#class="kw">property description "Chaikin Money Flow"
class="macro">#class="kw">property indicator_separate_window
class="macro">#class="kw">property indicator_buffers class="num">4
class="macro">#class="kw">property indicator_plots  class="num">1
class="macro">#class="kw">property indicator_width1  class="num">3
class="macro">#class="kw">property indicator_level1  class="num">0
class="macro">#class="kw">property indicator_level2  class="num">0.20
class="macro">#class="kw">property indicator_level3  -class="num">0.20
class="macro">#class="kw">property indicator_levelstyle STYLE_DOT
class="macro">#class="kw">property indicator_levelwidth class="num">0
class="macro">#class="kw">property indicator_levelcolor clrBlack
class="macro">#class="kw">property indicator_type1   DRAW_HISTOGRAM
class="macro">#class="kw">property indicator_color1   clrBlue
input class="type">int                periods=class="num">20; class=class="str">"cmt">// Periods
input ENUM_APPLIED_VOLUME volumeTypeInp=VOLUME_TICK;  class=class="str">"cmt">// Volume Type
class="type">class="kw">double                   cmfBuffer[];
SetIndexBuffer(class="num">0,cmfBuffer,INDICATOR_DATA);
IndicatorSetInteger(INDICATOR_DIGITS,class="num">5);
PlotIndexSetInteger(class="num">0,PLOT_DRAW_BEGIN,class="num">0);
IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Money Flow("+class="type">class="kw">string(periods)+")");
class="type">int OnCalculate(const class="type">int rates_total,
                const class="type">int prev_calculated,
                const class="type">class="kw">datetime &time[],
                const class="type">class="kw">double &open[],
                const class="type">class="kw">double &high[],
                const class="type">class="kw">double &low[],

◍ CMF 指标里成交量与累积分布的落地写法

上面这段是 Chaikin Money Flow 自定义指标的核心计算段,区分了 tick 成交量与真实成交量两种数据源,由 volumeTypeInp 开关切换。 当 rates_total 小于 periods 时直接返回 0,避免样本不足算出无意义数值;initPos 从 prev_calculated-1 起步,保证增量刷新时不重算整段历史。 内层循环调用 AccDis 函数,用 (2*close-high-low)/(high-low)*volume 把每根 K 线的价量关系折算成累积分布量,再除以周期总成交量得到 CMF 值,写入 cmfBuffer[pos+periods-1]。 指标属性里划了 0、±0.20 三条虚线水平,CMF 突破 +0.20 可能暗示资金流入偏强,跌破 -0.20 则倾向流出;外汇与贵金属波动受杠杆放大,实盘验证前先用 MT5 策略测试器跑一遍。 return 语句返回 rates_total-periods-10,这个值会影响 OnCalculate 下一轮 prev_calculated 的起始位点,调参时别忽略这 10 根缓冲偏移。

MQL5 / C++
const class="type">class="kw">double &close[],
const class="type">long &tick_volume[],
const class="type">long &volume[],
const class="type">int &spread[])
  if(rates_total<periods)
    class="kw">return(class="num">0);
  class="type">int initPos = prev_calculated -class="num">1;
  if(initPos<class="num">0) initPos = class="num">0;
  if(volumeTypeInp==VOLUME_TICK)
  {
    for(class="type">int pos = initPos;pos<=rates_total-periods;pos++)
    {
      class="type">class="kw">double sumAccDis = class="num">0;
      class="type">long sumVol = class="num">0;
      
      for(class="type">int i = class="num">0; i < periods && !IsStopped(); ++i)
      {
        class="type">long thisTickVolume = tick_volume[pos+i];
        sumVol += thisTickVolume;
        sumAccDis += AccDis(high[pos+i], low[pos+i], close[pos+i], thisTickVolume);
      }
      
      cmfBuffer[pos+periods-class="num">1] = sumAccDis/sumVol;
    }
  }
  else
  {
    for(class="type">int pos = initPos;pos<=rates_total-periods;pos++)
    {
      class="type">class="kw">double sumAccDis = class="num">0;
      class="type">long sumVol = class="num">0;
      
      for(class="type">int i = class="num">0; i < periods && !IsStopped(); ++i)
      {
        class="type">long thisTickVolume = volume[pos+i];
        sumVol += thisTickVolume;
        sumAccDis += AccDis(high[pos+i], low[pos+i], close[pos+i], thisTickVolume);
      }
      
      cmfBuffer[pos+periods-class="num">1] = sumAccDis/sumVol;
    }
  }
  
  class="kw">return (rates_total-periods-class="num">10);
class="type">class="kw">double AccDis(class="type">class="kw">double high,class="type">class="kw">double low,class="type">class="kw">double close,class="type">long volume)
{
  class="type">class="kw">double res=class="num">0;
  
  if(high!=low)
    res=(class="num">2*close-high-low)/(high-low)*volume;
  
  class="kw">return(res);
}
class="macro">#class="kw">property description "Chaikin Money Flow"
class="macro">#class="kw">property indicator_separate_window
class="macro">#class="kw">property indicator_buffers class="num">4
class="macro">#class="kw">property indicator_plots   class="num">1
class="macro">#class="kw">property indicator_width1  class="num">3
class="macro">#class="kw">property indicator_level1  class="num">0
class="macro">#class="kw">property indicator_level2  class="num">0.20
class="macro">#class="kw">property indicator_level3  -class="num">0.20
class="macro">#class="kw">property indicator_levelstyle STYLE_DOT

常见问题

CMF 用收盘价在当日高低区间的位置给成交量加权,收盘偏高位算资金流入、偏低位算流出,再对一段时间累加平均,正数倾向流入、负数倾向流出。
0.12 为正且持续抬升倾向资金积累,但外汇贵金属高风险,单看 CMF 不够,需结合价格结构和止损,不能据此直接做多。
小布可在对应品种页自动标注 CMF 穿越零轴与背离,省去手动切指标,你只需看提醒做决策。
先算 ((收盘-最低)-(最高-收盘))/(最高-最低)*成交量 得单根资金流,再用 iMA 类函数对 N 根做移动平均输出到副图。
可把周期拉长到 20 以上,或要求 CMF 突破 ±0.05 才认信号,并等价格同步破位,能滤掉大部分毛刺。