纯 MQL5 货币对强弱指标
想象一下,一个交易者每天都要面对外汇市场的混乱。28 对货币在屏幕上闪烁,每对货币都以自己的节奏波动,创造出市场运动的交响乐。但如何在这个金融乐团中把握主旋律呢?我们如何判断哪种货币目前处于市场领先地位,哪种货币正在步履蹒跚、失势?
今天,我们将创造一些特别的东西 —— 一个将把这种混乱转变为市场力量清晰图景的指标。想象一下,有一个工具可以立即显示欧元在小时图表上如何走强,而日元在每日时间周期上如何走弱。这个指标不仅显示数据,还通过三个关键时间周期的棱镜讲述每种货币的故事。
在本指南中,我们将踏上一条从理念到成熟技术工具的道路。一步一步,我们将复杂的数学计算和编程代码转化为优雅的仪表盘,成为您可靠的交易助手。我们不会只是编写代码 —— 我们将创建一个工具,改变你看待市场分析的方式。
准备好深入 MQL5 编程令人兴奋的世界,创建一个数学精度与直观简单性相结合的指标了吗?然后系好安全带,我们即将开启进入专业交易工具开发世界的征程!
1.货币强度仪表盘:介绍实时分析货币对强弱工具的思路和概念
传奇投资者雷•达里奥(Ray Dalio)在桥水基金创建第一套交易系统时,遵循了一个简单但强大的原则:要理解一项资产的变动,你需要看到与之相关的整个工具组的走势。他最初通过交易趋势起步,然后转向交易组合,之后又将他的想法发展为套利和协整投资组合。
这就是我们货币强度仪表盘背后的原理。我们将遵循同样的流程,通过评估趋势的强度,创建篮子指标、公平价格套利指标和协整篮子指标。
为什么这很重要?想象一下你正在查看 EURUSD 图表。该货币对是上涨还是下跌?图表走势似乎很明显。但真相究竟是什么?是欧元走强还是美元走弱?如果不了解每种货币的整体强弱,就无法回答这个问题。这就是我们的指标显示其潜力的地方。
仪表盘主要功能:
多级别时间和价格分析是指使用不同的时间周期来获得更准确的信息。小时图(H1)显示短期波动,而四小时图(H4)反映长期趋势。日线图(D1)可让您了解全局强弱概况。每个时间周期在最终评估中都有自己的权重,有助于避免短期波动造成的扭曲,关注长期趋势。最终货币强度指标使用所有时间间隔计算,允许进行更全面的分析。
动态评分有助于维持货币对的当前位置。这使我们能够立即确定哪些货币目前最强势,哪些货币最弱势。仪表盘以可视化的方式突出显示极值,使我们能够快速跟踪变化。与分别分析每个货币对的经典指标不同,我们的系统与达利奥的方法类似,将市场视为一个单一、相互关联的系统。例如,欧元走强不仅会影响欧元兑美元,还会影响其与英镑、日元或瑞士法郎等其他货币的关系。
因此,我们的仪表盘汇总了这些关系,创造了市场的整体图景,让我们能够看到每种货币的真实强弱。正如达利欧所说:“要想在市场中赚钱,你必须独立思考并保持谦逊。”我们的货币强度仪表盘帮助我们识别通过传统分析无法获取的隐藏趋势。
2.准备基本要素:设置输入参数、连接货币对、定义配色方案和更新间隔
在深入复杂的计算和算法之前,让我们为我们的指标打下坚实的基础。基本要素配置正确,就占整个项目成功的 50%。
指标标题结构
#property copyright "Copyright 2025" #property version "1.00" #property description "Currency strength analysis dashboard" #property indicator_separate_window #property indicator_plots 0
这些指令定义了有关指标的基本信息。请注意 indicator_separate_window —— 我们的面板将显示在单独的窗口中,不会影响主图表。
交易者输入参数
// Inputs input color InpStrongColor = clrLime; // Color of strong currencies input color InpWeakColor = clrRed; // Color of weak currencies input color InpTextColor = clrWhite; // Text color input int InpUpdateInterval = 60; // Update interval (in seconds)
我们允许用户自定义指标的外观和行为。绿色和红色传统上被用来代表强弱,但交易者可以选择任何适合它们的配色方案。
货币对的定义
// Array of currency pairs const string CURRENCY_PAIRS[] = { "EURUSD", "GBPUSD", "USDJPY", "USDCHF", "AUDUSD", "NZDUSD", "USDCAD", "EURGBP", "EURJPY", "EURCHF", "EURAUD", "EURNZD", "EURCAD", "GBPJPY", "GBPCHF", "GBPAUD", "GBPNZD", "GBPCAD", "AUDJPY", "NZDJPY", "CADJPY", "CHFJPY", "AUDCHF", "NZDCHF", "CADCHF", "AUDNZD", "AUDCAD", "NZDCAD" };
这个数组是我们指标的核心。它包含我们将要分析的所有主要货币对。请注意顺序:首先是与美元结算的货币对,然后是与欧元结算的货币对,再是与英镑结算的货币对,依此类推。这一结构将有助于我们进一步计算单独货币的走强。
用于存储信息的数据结构
// Structure for storing the strength of a currency pair struct SPairStrength { string pair; // Currency pair double strength; // Current strength double h1_change; // Change per hour double h4_change; // Change in 4 hours double d1_change; // Daily change }; // Global variables SPairStrength g_strength_data[]; int g_pairs_count; int g_timer_counter;
SPairStrength 结构是我们用于存储每个货币对所有必要信息的容器。我们不仅会存储最终的强度值,还会存储每个时间段的变化值,让交易者能够看到价格走势的全貌。
指标初始化
int OnInit() { // Initialize the data array g_pairs_count = ArraySize(CURRENCY_PAIRS); ArrayResize(g_strength_data, g_pairs_count); // Fill in the names of pairs for(int i = 0; i < g_pairs_count; i++) { g_strength_data[i].pair = CURRENCY_PAIRS[i]; } // Create graphical objects if(!CreateGraphics()) { return(INIT_FAILED); } // Set the timer EventSetTimer(InpUpdateInterval); g_timer_counter = 0; return(INIT_SUCCEEDED); }
在初始化功能中,定义数据数组的大小,填写基本信息,然后创建图形对象,设置更新定时器。
关闭时的清理工作
void OnDeinit(const int reason) { EventKillTimer(); ObjectsDeleteAll(0, "SPPanel_"); ChartRedraw(); }
永远不要忘记正确清理资源 —— 这是编写优秀代码的标志。
现在我们指标的基础准备好了!在下一节中,我们将致力于创建一个计算货币强度并将结果可视化的系统。
3.创建数据存储结构:设计 SPairStrength 结构以存储关于每个货币对强度的信息
每个程序员都知道,数据结构就像房屋的地基。整个项目的成功取决于我们设计得多么周到。让我们深入剖析我们的 SPairStrength 结构。
// Structure for storing the strength of a currency pair struct SPairStrength { string pair; // Currency pair double strength; // Current strength double h1_change; // Change per hour double h4_change; // Change in 4 hours double d1_change; // Daily change }; // Global variables SPairStrength g_strength_data[]; int g_pairs_count; int g_timer_counter;
我们结构的核心是一个优雅的解决方案,用于存储有关货币对的所有必要信息。想象一个货币对的数字护照,每个领域都讲述自己的市场波动故事。
“pair” 字段是我们金融工具的名称,是其在外汇市场中的唯一 ID。就像人的名字可以识别一个人一样,字符串值 “EURUSD” 或 “GBPJPY” 可以立即让我们知道我们正在处理的是哪个货币对。
“strength” 变量是衡量货币对强度的精髓,是其在市场上的数值评级。正如教师基于多项测试计算最终成绩一样,该值考虑了所有时间间隔的表现,以创建单一的强度指数。
接下来我们来谈谈临时数据结构。我们使用三个关键标记:h1_change、h4_change 和 d1_change。它就像三个监控摄像头,每个摄像头都能在自己的时间尺度上捕捉价格波动。小时图(h1_change)捕捉短期波动,四小时图(h4_change)追踪中期趋势,日线图(d1_change)描绘价格走势的全局图景。
为了配合我们的结构,我们还创建了全局变量:
// Initialize the data array void InitializeDataArray() { g_pairs_count = ArraySize(CURRENCY_PAIRS); ArrayResize(g_strength_data, g_pairs_count); // Fill in basic information for(int i = 0; i < g_pairs_count; i++) { g_strength_data[i].pair = CURRENCY_PAIRS[i]; g_strength_data[i].strength = 0; g_strength_data[i].h1_change = 0; g_strength_data[i].h4_change = 0; g_strength_data[i].d1_change = 0; } }
所有这些元素共同创造了一个强大的分析工具。正如医生使用各种指标来评估患者的健康状况一样,我们的结构收集关键指标来确定货币对的健康状况。在下一节中,我们将看到这种优雅的数据结构如何在图形界面中变得栩栩如生,将枯燥的数字变成市场机会的视觉画面。
4.组织图形界面:创建主面板、放置标题、自定义值的显示
数据可视化是将数字转化为清晰画面的艺术。让我们创建一个直观的界面,让交易者能够即时阅读市场行情。
bool CreateGraphics() { // Main panel if(!ObjectCreate(0, "SPPanel_Main", OBJ_RECTANGLE_LABEL, 0, 0, 0)) { Print("Error creating main panel: ", GetLastError()); return false; } // Customize the panel appearance ObjectSetInteger(0, "SPPanel_Main", OBJPROP_XDISTANCE, 20); ObjectSetInteger(0, "SPPanel_Main", OBJPROP_YDISTANCE, 20); ObjectSetInteger(0, "SPPanel_Main", OBJPROP_XSIZE, 800); ObjectSetInteger(0, "SPPanel_Main", OBJPROP_YSIZE, 400); ObjectSetInteger(0, "SPPanel_Main", OBJPROP_BGCOLOR, C'16,20,24'); ObjectSetInteger(0, "SPPanel_Main", OBJPROP_BORDER_COLOR, C'29,31,34'); ObjectSetInteger(0, "SPPanel_Main", OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, "SPPanel_Main", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, "SPPanel_Main", OBJPROP_BACK, false);
选择深色背景是有原因的:它可以减少长时间使用时的眼睛疲劳。仪表板尺寸经过精心选择,以最佳方式显示所有必要信息,而不会使屏幕过载。
// Create headings and markup CreateLabel("SPPanel_Strong", "STRONG PAIRS - LONG", 30, 30, InpTextColor, 10, true); CreateLabel("SPPanel_Weak", "WEAK PAIRS - SHORT", 420, 30, InpTextColor, 10, true); string header = " PAIR H1 H4 D1 FORCE"; CreateLabel("SPPanel_Header1", header, 30, 60, clrGray, 9); CreateLabel("SPPanel_Header2", header, 420, 60, clrGray, 9);
界面分为两个逻辑区:强对和弱对。这就像磁铁的两极 —— 它们将注意力吸引到最重要的交易机会上。每一列数据都有自己的目的,讲述不同时间段的价格走势故事。
bool CreateLabel(const string name, const string text, const int x, const int y, const color clr, const int size, const bool is_bold=false) { if(!ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0)) { Print("Error creating label ", name, ": ", GetLastError()); return false; } ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetString(0, name, OBJPROP_FONT, is_bold ? "Arial Bold" : "Arial"); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER); return true; }
CreateLabel 函数就像我们的艺术家,能够精确地将文本放置在面板上。每一个界面元素都是像素级的完美,创造出和谐的数据组合。
在下一节中,我们将通过在这个界面中填充有关货币对变动的真实数据,让它变得栩栩如生。我们的面板将成为一个有生命的有机体,随着市场的节奏而跳动。
实现力量计算算法
我们指标的核心是计算货币对强度的强大算法。这不仅仅是一个数学方程式 —— 它是市场数据的交响乐,每个时间周期都在发挥作用。
// Calculate the price change for a given timeframe double CalculateChange(const string symbol, const ENUM_TIMEFRAMES timeframe) { MqlRates rates[]; ArraySetAsSeries(rates, true); if(CopyRates(symbol, timeframe, 0, 2, rates) <= 0) { return 0.0; } if(rates[1].open == 0) return 0.0; return ((rates[0].close - rates[1].open) / rates[1].open) * 100.0; } // Calculate the strength of all currency pairs void CalculateStrengths() { for(int i = 0; i < g_pairs_count; i++) { // 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); // Calculate the total force (weighted value) g_strength_data[i].strength = g_strength_data[i].h1_change * 0.2 + // 20% weight of the hourly chart g_strength_data[i].h4_change * 0.3 + // 30% weight of the 4-hour chart g_strength_data[i].d1_change * 0.5; // 50% weight of the daily chart } }
为什么需要这样的权重因子?日线图权重最高(50%),因为它反映了全局趋势。四小时图(30%)反映中期走势,而小时图(20%)反映短期波动。它就像一个过滤系统,每个级别都会清除市场噪音中的信号。
5.气泡排序系统:建立一种按强弱对货币对进行排序的机制,以识别强势和弱势货币对。
在现代算法交易中,数据排序的速度和准确性起着至关重要的作用。我们开发的排序机制不仅仅是经典算法的实现,而是针对外汇市场的具体任务精心优化的解决方案。
void SortStrengthData() {
for(int i = 0; i < g_pairs_count - 1; i++) {
for(int j = i + 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;
}
}
}
}
在这段代码看似简单的背后,隐藏着一个强大的金融分析工具。算法的每一次迭代,都是对货币对实力的微秒级对比,最强的工具自然上升到数组的顶端,形成一个精英交易机会群。另一方面,弱势对倾向于下跌,为卖空交易者创造了一个理想的场景。
void GetTopPairs(SPairStrength &strong[], SPairStrength &weak[], int count = 10) { ArrayResize(strong, count); for(int i = 0; i < count; i++) { strong[i] = g_strength_data[i]; } ArrayResize(weak, count); for(int i = 0; i < count; i++) { weak[i] = g_strength_data[g_pairs_count - 1 - i]; } }
GetTopPairs 函数体现了我们方法的巧妙之处。我们没有不断地对整个数据数组进行重新排序,而是将其存储在一种有组织的状态中,这使我们能够立即提取关于最强和最弱工具的信息。这在高频交易中尤为重要,在高频交易中,每毫秒都很重要。
void UpdateDisplay() { for(int i = 0; i < 10 && i < g_pairs_count; i++) { 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); } }
在下一节中,我们将研究我们的数据更新系统如何保持这台运转良好的机器持续运转,为交易者实时提供有关货币对强度的最新信息。
6.实现数据更新系统:设置定时器和函数定期更新货币强度值
任何成功交易工具的基础都是传入信息的准确性和及时性。我们的货币强度指标也不例外 —— 其核心是一个精心设计的实时数据更新系统。
void OnTimer() { g_timer_counter++; if(g_timer_counter >= InpUpdateInterval) { CalculateStrengths(); SortStrengthData(); UpdateDisplay(); g_timer_counter = 0; } }
这种优雅的计时器机制就像节拍器,计数着市场变化的节奏。每隔 60 秒(默认值),指标对所有数据进行全面更新,为交易者提供最新的决策信息。
void UpdateDisplay() { // Remove old values ObjectsDeleteAll(0, "SPPanel_Value_"); // Update strong pairs for(int i = 0; i < 10 && i < g_pairs_count; i++) { 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); CreateLabel("SPPanel_Value_Strong_" + IntegerToString(i), text, 30, 90 + i * 25, InpStrongColor); } }
数据更新的过程就像剧院里的舞台布景更换 —— 旧值平滑地让位于新值,从而创造出一幅生动、动态的市场图景。每个值的格式都具有数学精度:小数点后两位表示百分比变化,列对齐便于阅读,颜色编码用于即时理解信息。
void RefreshData() { static datetime last_update = 0; datetime current_time = TimeCurrent(); // Check if an update is needed if(current_time - last_update >= InpUpdateInterval) { CalculateStrengths(); SortStrengthData(); UpdateDisplay(); last_update = current_time; } }
该系统还包括防止过度更新的保护,以及与服务器时间同步的机制,这在处理高负载交易账户时尤为重要。在下一节中,我们将看看所有这些元素如何结合在一起,以优化结果的显示。
7.优化结果显示:格式化数据输出,设置值的颜色高亮显示
在金融数据的世界里,视觉呈现扮演着关键角色。我们的指标将市场数据流转化为直观的画面,每个元素都有自己的目的。
void UpdatePairDisplay(const string label_suffix, const string value, const color clr, const int position) { string text = StringFormat("%s %+6.1f %+6.1f %+6.1f %+6.1f", value.pair, value.h1_change, value.h4_change, value.d1_change, value.strength); color display_color = value.strength > 0 ? InpStrongColor : InpWeakColor; CreateLabel("SPPanel_" + label_suffix, text, position < 10 ? 30 : 420, // X coordinate 90 + (position % 10) * 25, // Y coordinate display_color, 9); }
这里的数字格式不仅仅是一种装饰性的增强,每个值都以固定的宽度和符号输出,创建完全对齐的数据列。正值自动着色为绿色,负值自动着色为红色,允许您立即评估情况。
void ApplyColorCoding() { // Dynamically detecting boundaries for color coding double max_strength = 0; for(int i = 0; i < g_pairs_count; i++) { if(MathAbs(g_strength_data[i].strength) > max_strength) max_strength = MathAbs(g_strength_data[i].strength); } // Apply gradient coloring for(int i = 0; i < g_pairs_count; i++) { double strength_ratio = g_strength_data[i].strength / max_strength; color intensity = GetColorIntensity(strength_ratio); UpdatePairColor(i, intensity); } }
该指标采用动态颜色编码系统,颜色强度反映货币对的相对强度。颜色越鲜艳,波动越大 —— 这使得交易者能够立即识别出最活跃的交易品种。
下一节我们将深入指标测试流程,测试其在各种市场条件下的表现。
8.测试指标:检查不同时间周期内的计算准确性和运行稳定性
我们看到眼前是一个功能齐全的货币强度仪表盘,它已经显示了真实的市场数据。我们来看看该指标在各种市场情况下的表现,以及我们如何确保其正常运行。

在截图中,我们看到了货币对的清晰分离。在左侧的强势货币对中,EURCAD 以多数为正的走势领跑。
在右侧的弱势货币对中,我们看到 CADCF 明显疲软,尤其是在较高时间周期(H4:-0.5,D1:-1.8)上,整体疲软程度为 -1.1。这是该指标如何识别可持续发展趋势的一个很好的例子。
结论
我们已经开发出一款专业的货币强度指标,它可以将混乱的市场数据转化为清晰、结构化的交易机会图景。该仪表盘还有专门的付费版本,能够搜索长期趋势调整结束时的入场点(例如,当长期呈上升趋势,但在小时图上出现下降时,我们可以买入获利) 。
仪表板盘结合了几个关键创新:
- 多级别时间周期分析(H1、H4、D1),让您全面了解市场走势。
- 智能加权系统,其中每个时间周期都对整体强度评分做出贡献
- 优雅的视觉界面和直观的数据呈现方式
- 高效的实时更新系统
- 稳健的货币对排序和排名机制
我们指标的强项不仅在于其技术实施,还在于其背后的理念。遵循瑞·达利欧的原则,我们创建了一个工具,将市场视为一个单一的、相互关联的系统,每种货币的走势都会影响整体情况。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/17303
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
MQL5 简介(第 13 部分):构建自定义指标的初学者指南(二)
交易中的资本管理和带有数据库的交易者家庭会计程序
在 MQL5 中创建交易管理员面板(第十部分):基于外部资源的界面
交易中的神经网络:层次化双塔变换器(Hidformer)
以大量交叉盘的形式使用货币对是考虑不周且效率极低的做法。正确的做法是,只使用相对于一个基数(通常是美元)的货币,并从中得到任何组合。
一切都做得很正确,而且比从单一货币开始要明显得多。
干得漂亮
以大量交叉盘的形式使用货币对是考虑不周且效率极低的做法。正确的做法是只使用相对于一个基数(通常是美元)的货币,并从中得到任何组合。
这是个不好的变体,因为代码会变得很小 :-)) 而且很危险 - 引入的术语 "货币强度 "的意义可能会丢失。
这样做是正确的,而且比回击单一货币要明显得多。
做得好
如果交易者不清楚 EURJPY 就是 EURUSD*USDJPY 的含义,那么他很可能从事了错误的交易。如果我们只考虑外汇 "主力",那么处理 7 个货币对比处理 28 个货币对更容易(从任何意义上来说)。如果经纪商(经常出现这种情况)没有一些交叉货币对,您该怎么办?如果您想把 "次要货币"、当地货币、金属添加到篮子里呢?您是否建议将整个市场观察拖入 MQL 程序,尽管它不需要评估相同的篮子?正是因为这样的顾问,论坛上经常出现这样的问题:哦,我的指标变慢了,我的测试代理占用了所有内存,等等。
我并没有开始讨论一些提取出来的代码,包括那些原则上无法编译的代码,如 UpdatePairDisplay。
不尽人意。