纯 MQL5 货币对强弱指标·进阶篇
📊

纯 MQL5 货币对强弱指标·进阶篇

(2/3)· 从 SPairStrength 结构到气泡排序,把 28 对货币的混乱波动收敛成可读的强弱序列

含代码示例 第 2/3 篇
看 EURUSD 涨了就以为是欧元强?很可能只是美元在弱。不拆开单币种的相对强弱,你看到的只是半张图。本篇接上篇概念,直接落到存储结构与排序逻辑的代码层。

◍ 给货币对发一张数字护照

做强度分析前,先得把每个货币对的状态装进同一个容器里。SPairStrength 这个结构就是干这个的:pair 存名字(如 EURUSD),strength 存综合强度值,h1_change / h4_change / d1_change 分别记小时、4小时、日线的变动量。 底层逻辑很直白——三个周期像三台不同焦距的摄像头,短期波动看 h1,中期节奏看 h4,全局趋势看 d1,最后揉成一个 strength 指数。外汇和贵金属波动大、杠杆高,这种多周期切片能帮你避开只用单周期导致的误判。 全局侧开了三个变量:g_strength_data[] 是结构数组,g_pairs_count 记货币对数量,g_timer_counter 管计时。InitializeDataArray() 里先用 ArraySize(CURRENCY_PAIRS) 定长度,再逐条把 strength 和三个 change 清零,相当于给每张护照盖了空白章。 开 MT5 把下面代码贴进 EA 或脚本,编译后加个 Print(g_pairs_count) 就能验证数组有没有按你 CURRENCY_PAIRS 列表的条数扩出来。

MQL5 / C++
class=class="str">"cmt">// Structure for storing the strength of a currency pair
class="kw">struct SPairStrength {
    class="type">class="kw">string pair;            class=class="str">"cmt">// Currency pair
    class="type">class="kw">double strength;        class=class="str">"cmt">// Current strength
    class="type">class="kw">double h1_change;       class=class="str">"cmt">// Change per hour
    class="type">class="kw">double h4_change;       class=class="str">"cmt">// Change in class="num">4 hours
    class="type">class="kw">double d1_change;       class=class="str">"cmt">// Daily change
};
class=class="str">"cmt">// Global variables
SPairStrength g_strength_data[];
class="type">int g_pairs_count;
class="type">int g_timer_counter;
class=class="str">"cmt">// Initialize the data array
class="type">void InitializeDataArray() {
    g_pairs_count = ArraySize(CURRENCY_PAIRS);
    ArrayResize(g_strength_data, g_pairs_count);
    
    class=class="str">"cmt">// Fill in basic information
    for(class="type">int i = class="num">0; i < g_pairs_count; i++) {
        g_strength_data[i].pair = CURRENCY_PAIRS[i];
        g_strength_data[i].strength = class="num">0;
        g_strength_data[i].h1_change = class="num">0;
        g_strength_data[i].h4_change = class="num">0;
        g_strength_data[i].d1_change = class="num">0;
    }
}

「面板分区与多周期权重的落地实现」

深色底(RGB 16,20,24)不是审美偏好,而是为了降低盯盘时的视觉疲劳;主面板固定在左上角,距边 20 像素,尺寸 800×400,这个尺度能在不挤占 K 线区的前提下排下强对 / 弱对两栏。 界面逻辑上切成两极:左侧放强势货币对(倾向做多),右侧放弱势货币对(倾向做空),像磁铁两极把注意力吸到最有概率出现的机会上。每栏表头固定打印「PAIR / H1 / H4 / D1 / FORCE」,让读者一眼读完三个周期的强度故事。 强度算法的权重分配是核心:D1 占 50% 反映全局趋势,H4 占 30% 管中期方向,H1 占 20% 捕捉短期扰动。相当于三级滤波,先把小时图噪音压下去,再让日线定调。 CreateGraphics 只搭骨架,真正的「活」要等下一节灌入变动数据才看得到;现在开着 MT5 把下面代码丢进指标,能直接看到空面板和两栏标题。 外汇与贵金属杠杆高、滑点突发,面板只做概率参考,不构成方向保证。

MQL5 / C++
class="type">bool CreateGraphics() {
   class=class="str">"cmt">// Main panel
   if(!ObjectCreate(class="num">0, "SPPanel_Main", OBJ_RECTANGLE_LABEL, class="num">0, class="num">0, class="num">0)) {
      Print("Error creating main panel: ", GetLastError());
      class="kw">return false;
   }
   
   class=class="str">"cmt">// Customize the panel appearance
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_XDISTANCE, class="num">20);
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_YDISTANCE, class="num">20);
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_XSIZE, class="num">800);
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_YSIZE, class="num">400);
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_BGCOLOR, C&class="macro">#x27;class="num">16,class="num">20,class="num">24&class="macro">#x27;);
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_BORDER_COLOR, C&class="macro">#x27;class="num">29,class="num">31,class="num">34&class="macro">#x27;);
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_BORDER_TYPE, BORDER_FLAT);
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(class="num">0, "SPPanel_Main", OBJPROP_BACK, false);
class=class="str">"cmt">// Create headings and markup
   CreateLabel("SPPanel_Strong", "STRONG PAIRS - LONG", class="num">30, class="num">30, InpTextColor, class="num">10, true);
   CreateLabel("SPPanel_Weak", "WEAK PAIRS - SHORT", class="num">420, class="num">30, InpTextColor, class="num">10, true);
   
   class="type">class="kw">string header = "  PAIR     H1     H4     D1    FORCE";
   CreateLabel("SPPanel_Header1", header, class="num">30, class="num">60, clrGray, class="num">9);
   CreateLabel("SPPanel_Header2", header, class="num">420, class="num">60, clrGray, class="num">9);
class="type">bool CreateLabel(const class="type">class="kw">string name, const class="type">class="kw">string text, const class="type">int x, const class="type">int y,
                const class="type">color clr, const class="type">int size, const class="type">bool is_bold=false) {
   if(!ObjectCreate(class="num">0, name, OBJ_LABEL, class="num">0, class="num">0, class="num">0)) {
      Print("Error creating label ", name, ": ", GetLastError());

用加权涨跌拼出货币对力气值

这段逻辑先把标签和文字样式落到图表左上角,再算各周期涨跌,最后揉成一个综合强度。标签函数里 OBJPROP_CORNER 设成 CORNER_LEFT_UPPER、ANCHOR 用 ANCHOR_LEFT_UPPER,意味着文字锚死在窗口左上,不会随滚动跑偏。 CalculateChange 取最近两根 K 线:rates[1].open 为前一根开盘,rates[0].close 为最新收盘,用 (收盘-前开)/前开*100 得出百分比涨跌。若 CopyRates 拿不到数据或前开为 0,直接返回 0.0,避免除零崩脚本。 真正决定「力气」的是 CalculateStrengths 里的权重分配:H1 占 0.2、H4 占 0.3、D1 占 0.5。也就是日线方向说了大半句话,小时线只当杂音。 把下面代码丢进 MT5 脚本,改 g_pairs_count 和 g_strength_data 里的品种,就能在日志里看到每个对的 strength 数值,外汇和贵金属波动大、杠杆高,这种强度只是概率参考,别当方向保证。

MQL5 / C++
   class="kw">return false;
   }
   
   ObjectSetString(class="num">0, name, OBJPROP_TEXT, text);
   ObjectSetInteger(class="num">0, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(class="num">0, name, OBJPROP_YDISTANCE, y);
   ObjectSetString(class="num">0, name, OBJPROP_FONT, is_bold ? "Arial Bold" : "Arial");
   ObjectSetInteger(class="num">0, name, OBJPROP_FONTSIZE, size);
   ObjectSetInteger(class="num">0, name, OBJPROP_COLOR, clr);
   ObjectSetInteger(class="num">0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(class="num">0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
   
   class="kw">return true;
}
class=class="str">"cmt">// Calculate the price change for a given timeframe
class="type">class="kw">double CalculateChange(const class="type">class="kw">string symbol, const ENUM_TIMEFRAMES timeframe) {
   class="type">MqlRates rates[];
   ArraySetAsSeries(rates, true);
   
   if(CopyRates(symbol, timeframe, class="num">0, class="num">2, rates) <= class="num">0) {
      class="kw">return class="num">0.0;
   }
   
   if(rates[class="num">1].open == class="num">0) class="kw">return class="num">0.0;
   
   class="kw">return ((rates[class="num">0].close - rates[class="num">1].open) / rates[class="num">1].open) * class="num">100.0;
}
class=class="str">"cmt">// Calculate the strength of all currency pairs
class="type">void CalculateStrengths() {
   for(class="type">int i = class="num">0; i < g_pairs_count; i++) {
      class=class="str">"cmt">// Calculate changes across different timeframes
      g_strength_data[i].h1_change = CalculateChange(g_strength_data[i].pair, PERIOD_H1);
      g_strength_data[i].h4_change = CalculateChange(g_strength_data[i].pair, PERIOD_H4);
      g_strength_data[i].d1_change = CalculateChange(g_strength_data[i].pair, PERIOD_D1);
      
      class=class="str">"cmt">// Calculate the total force(weighted value)
      g_strength_data[i].strength =
         g_strength_data[i].h1_change * class="num">0.2 +  class=class="str">"cmt">// class="num">20% weight of the hourly chart
         g_strength_data[i].h4_change * class="num">0.3 +  class=class="str">"cmt">// class="num">30% weight of the class="num">4-hour chart
         g_strength_data[i].d1_change * class="num">0.5;   class=class="str">"cmt">// class="num">50% weight of the daily chart
   }
}

◍ 用冒泡思路给货币对排座次

把几十个外汇或贵金属货币对按强弱排队,核心不是炫算法,而是让 MT5 在每次刷新后立刻知道谁强谁弱。下面这段排序逻辑就是最直白的双层循环比较:内层拿 j 位置和 i 位置比 strength 字段,只要后者更强就交换,跑完外层一轮,数组头部自然堆着强势对,尾部是弱势对。 GetTopPairs 的取数方式很省事:不重排,直接按头部取前 count(默认 10)个进 strong 数组,按尾部倒序取进 weak 数组。这意味着你随时能拿到「前 10 强 / 前 10 弱」而无需再算一遍,对刷 new tick 的高频场景,每少一次全量排序就少耗几毫秒。 UpdateDisplay 把前 10 强打印成带 H1/H4/D1 涨跌幅和综合 strength 的字符串,格式 %+.1f 让正负一目了然。实盘接贵金属或交叉盘时,这种强弱分组只是概率参考,杠杆品种回撤可能极快,别把它当方向保证。 让小布替你跑这套 把 SortStrengthData 和 GetTopPairs 直接塞进 EA 的 OnTick 后段,用 Comment 或面板看前 10 强弱名单;若你盯 EURUSD 和 XAUUSD,可把 count 调到 5 观察头部是否被这两个常驻。外汇与贵金属波动受消息驱动,分组结果仅反映历史强度,不预示下一根 K 线。

MQL5 / C++
class="type">void SortStrengthData() {
    for(class="type">int i = class="num">0; i < g_pairs_count - class="num">1; i++) {
        for(class="type">int j = i + class="num">1; j < g_pairs_count; j++) {
            if(g_strength_data[j].strength > g_strength_data[i].strength) {
                SPairStrength temp = g_strength_data[i];
                g_strength_data[i] = g_strength_data[j];
                g_strength_data[j] = temp;
            }
        }
    }
}
class="type">void GetTopPairs(SPairStrength &strong[], SPairStrength &weak[], class="type">int count = class="num">10) {
    ArrayResize(strong, count);
    for(class="type">int i = class="num">0; i < count; i++) {
        strong[i] = g_strength_data[i];
    }
    
    ArrayResize(weak, count);
    for(class="type">int i = class="num">0; i < count; i++) {
        weak[i] = g_strength_data[g_pairs_count - class="num">1 - i];
    }
}
class="type">void UpdateDisplay() {
    for(class="type">int i = class="num">0; i < class="num">10 && i < g_pairs_count; i++) {
        class="type">class="kw">string text = StringFormat("%s  %+.1f  %+.1f  %+.1f  %+.1f",
            g_strength_data[i].pair,
            g_strength_data[i].h1_change,
            g_strength_data[i].h4_change,
            g_strength_data[i].d1_change,
            g_strength_data[i].strength);
            
        UpdatePairDisplay("Strong_" + IntegerToString(i), text, InpStrongColor, i);
    }
}
把重复劳动交给小布
这些多周期强弱诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到实时篮子强弱,不必自己跑这套 MQL5 面板。

常见问题

单货币对涨跌由两侧币种共同驱动,可能是欧元强也可能是美元弱。需通过篮子指标汇总该币种对所有相关货币对的表现才能分离出真实强弱,外汇贵金属高风险,结论仅具概率性。
至少包含货币对名称、各周期(H1/H4/D1)强度值、综合评分与排序位次。这样后续面板刷新与极值高亮才有数据基底,具体字段见本篇代码小节。
可以,小布盯盘品种页已内置 AIGC 生成的篮子强弱视图,覆盖主要外汇与贵金属,省去自行编译指标的过程,你专注决策即可。
28 个元素规模极小,气泡排序开销可忽略,且逻辑直观易调试;若后续扩展至更多资产再考虑更优算法,当前版本倾向保持代码可读性。