English Deutsch 日本語
preview
价格行为分析工具包开发(第 23 部分):货币强弱指标

价格行为分析工具包开发(第 23 部分):货币强弱指标

MetaTrader 5交易系统 |
20 0
Christian Benjamin
Christian Benjamin

内容


引言

想象你在观看一场赛车比赛。每辆车都独一无二,你不能简单地猜测哪辆最快或最慢。相反,你会观察圈速,评估加速性能,测试刹车表现,并对每款车型进行单独评估。只有在彻底分析每辆车的个体表现后,你才会将它们进行比较,以确定整体性能。

货币的运作方式与此类似。该 EA 会检查每一个出现某货币的交易货币对。例如,对于USD,它会检查 USDJPY、EURUSD、GBPUSD、USDCHF 等。它计算每个货币对在不同时间周期内的变动幅度,首先是 M15,然后是 H1,最后是 H4。这些回溯周期由参数Lookback_M15 Lookback_H1Lookback_H4指定。

如果所关注的货币是货币对中的报价货币,该 EA 会将其倒置反转过来,以准确反映其强弱。在计算完所有相关货币对的这些变动后,它会将结果进行平均,得到每种货币的平均强弱值。EA 会按照 Update_Seconds 参数指定的间隔每隔几秒更新一次。然后它会重绘仪表板以显示当前的强弱值,记录哪些货币强劲、疲软或中性,并更新显示账户权益和回撤的图形曲线。 

在本文中,我们将开发一个 MQL5 工具,通过分析每种货币在多个货币对中的表现来衡量货币强弱。这种方法使你能够可靠地识别最强和最弱的货币,从而让你交易起来更有信心。


理解策略

EA 的主要工作是通过查看某种货币在所有出现的货币对中以及跨多个时间周期的表现,来衡量该货币的强弱。为此,我们按照以下步骤来计算每种货币在其货币对和时间周期上的强弱。

选择相关货币对

对于八种主要货币对中的货币,收集其出现的所有货币对(例如,USD 出现在 USDJPY、EURUSD、GBPUSD、USDCHF 中)。

计算百分比变化

在你选择的时间周期(例如 M15、H1、H4)上,计算每个货币对在回溯周期内的波动百分比:

归一化

如果你正在衡量的货币是货币对中的报价(第二个)货币,则计算该百分比的倒数,以便更强的报价货币始终表现为正向的强弱关系。

跨货币对求平均值

取其所有货币对的(带符号的)百分比变化值,并计算简单平均值。这将给出该货币在此时间周期上的一个“强弱评分”。

上图以美元为例说明了我们的处理过程。我们在美元出现的每个货币对中,跨多个时间周期衡量美元的强弱。这使我们能够识别美元在哪个时间周期上最强或最弱。


代码分解

EA 首先定义基本属性:版权信息、链接、版本和编译模式。这些指令有助于识别 EA,并确保其在 MetaTrader 环境中遵守现有标准。然后,它包含 SymbolInfo.mqh 库,该库提供用于管理和查询货币对信息的函数,这对于动态选择、启用和从多个货币对中检索数据至关重要。这种一步很重要,因为 EA 需要访问可能默认未启用的各种货币对的数据,从而确保脚本能够跨多个货币对平稳运行。

#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

#include <Trade\SymbolInfo.mqh>

接下来,代码定义了几个输入参数,如 Lookback_M15、Lookback_H1 和 Lookback_H4,它们指定了在相应时间周期上计算货币强弱时考虑的历史K线数量。Update_Seconds 参数决定了仪表板更新的频率,在实时响应能力和计算效率之间取得平衡。

FontSize, BackgroundColor, PanelWidth, PanelHeight 和初始位置参数允许用户自定义仪表板在图表上的外观和位置,使其能够适应不同的屏幕尺寸和个人偏好。回溯周期会影响货币强弱计算的敏感度或平滑度,较短的周期反应更快但可能有噪音,而较长的周期提供更高的稳定性但响应速度较慢。

input int    Lookback_M15    = 96;
input int    Lookback_H1     = 48;
input int    Lookback_H4     = 30;
input int    Update_Seconds  = 30;
input int    FontSize        = 12;
input color  BackgroundColor = clrBlack;
input int    PanelWidth      = 280;
input int    PanelHeight     = 240;
input int    InitPanelX      = 10;
input int    InitPanelY      = 10;

数组 Currencies 和 Pairs 是静态数据结构,列出了主要货币及其相关的货币对。这种组织方式确保了每种货币的相关货币对被分组在一起,简化了在强度计算过程中循环遍历货币对的操作。例如,Pairs 数组包含每种货币的四个货币对,包括该货币作为基础货币或报价货币的货币对。这种系统性分组使计算函数能同时分析多个货币对,高效地评估每种货币相对于其他货币的表现,从而提供更全面的强弱衡量。

static const string Currencies[8] = {"USD","EUR","GBP","JPY","CHF","CAD","AUD","NZD"};
static const string Pairs[8][4] = {
   {"USDJPY","EURUSD","GBPUSD","USDCHF"},
   {"EURUSD","EURJPY","EURGBP","EURCHF"},
   // ... .........
};

声明全局变量来存储在不同时间周期下算得的强弱值,保存在二维数组 Strength[8][3] 中。这些值用于在仪表板上显示和日志记录。像 LastUpdate 这样的变量,跟踪上次刷新数据的时间,防止不必要的重复计算。

变量 dragging、dragOffsetXdragOffsetY 管理用户交互,特别是为了使交易者能够通过鼠标拖动重新定位仪表板。为了可视化账户表现,声明数组 times[] 和 equities[] 来存储带时间戳的账户权益数据,其中 dataCount 跟踪已收集的点数;这些对于绘制账户的权益和回撤趋势随时间的变化至关重要。

double Strength[8][3]; // [currency][timeframe]
datetime LastUpdate;
int dataCount;
double equities[MAX_POINTS];
datetime times[MAX_POINTS];
int PanelX, PanelY;
bool dragging;
int dragOffsetX, dragOffsetY;

在初始化期间 (OnInit()),EA 根据用户输入设置仪表板的起始位置。然后它循环遍历所有货币对,调用 SymbolSelect() 来访问每个货币对的数据。此步骤至关重要,因为如果货币对未启用,后续的数据检索函数(如iClose())将失败,导致计算错误或报错。

然后初始化 LastUpdate 时间戳并重置数据计数器 dataCount。它通过 UpdateStrengths() 执行初始货币的强弱计算,确保仪表板在启动后立即显示当前数据。调用 DrawPanel() 函数创建带有标签、彩色条和标题的视觉仪表板,提供直观且美观的界面。

此外,调用 LogCurrencyStrengths() 在终端中打印货币状态的文本摘要,为交易者提供快速且高水平的概览。最后,EventSetTimer() 按照 Update_Seconds 指定的间隔调度定期更新例程,使仪表板能够自动刷新而无需手动干预。

int OnInit()
{
   PanelX = InitPanelX;
   PanelY = InitPanelY;

   for(int i=0; i<8; i++)
      for(int j=0; j<4; j++)
         SymbolSelect(Pairs[i][j], true);

   LastUpdate = 0;
   dataCount = 0;

   UpdateStrengths();
   DrawPanel();
   LogCurrencyStrengths(1);
   EventSetTimer(Update_Seconds);
   return(INIT_SUCCEEDED);
}

当调用(OnDeinit()) 时, EA 执行反初始化工作:使用 EventKillTimer() 删除计时器事件,删除与仪表板关联的所有图形对象(包括背景、标签、条形、标题),并清除权益和回撤的趋势线。这种清理可以防止遗留对象杂乱图表或消耗资源,确保在移除或重新加载 EA 时运行环境的整洁。

void OnTimer()
{
   if(TimeCurrent() - LastUpdate < Update_Seconds)
      return;

   LastUpdate = TimeCurrent();
   UpdateStrengths();
   DrawPanel();
   LogCurrencyStrengths(1);

   double eq = AccountInfoDouble(ACCOUNT_EQUITY);
   if(dataCount < MAX_POINTS)
   {
      times[dataCount] = TimeCurrent();
      equities[dataCount] = eq;
      dataCount++;
   }
   DrawEquityLines();
   DrawDrawdownLines();
}

核心更新逻辑位于 OnTimer() 函数中,该函数定期执行。它首先通过比较当前时间与 LastUpdate 来检查自上次更新以来是否已过去了足够的时间。如果指定的时间间隔尚未过去,它会提前退出以避免过多的计算。当触发时,它将 LastUpdate 更新为当前时间,并调用 UpdateStrengths() 根据最新的市场数据重新计算货币的强弱。

然后它调用 DrawPanel() 刷新视觉仪表板,更新标签、颜色和条形以反映当前的强弱值。它还通过 LogCurrencyStrengths() 记录当前货币状态,提供文本说明。该函数然后获取当前账户权益 (AccountInfoDouble(ACCOUNT_EQUITY)),当尚未达到最大点数时,其将时间戳和权益值附加到各自的数组中。

DrawEquityLines()DrawDrawdownLines() 用这些存储的数据点数来更新性能趋势线,直观地表示账户随时间推移的增长和风险。该循环确保整个仪表盘与实时市场状况及账户表现保持同步。

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id==CHARTEVENT_OBJECT_CLICK && sparam=="CS_BG")
   {
      dragging = true;
      dragOffsetX = (int)lparam - PanelX;
      dragOffsetY = (int)dparam - PanelY;
   }
   else if(id==CHARTEVENT_MOUSE_MOVE && dragging)
   {
      PanelX = (int)lparam - dragOffsetX;
      PanelY = (int)dparam - dragOffsetY;
      DrawPanel();
   }
   else if(dragging && id==CHARTEVENT_OBJECT_CLICK)
   {
      dragging = false;
   }
}

用户交互在 OnChartEvent() 中进行管理。当用户点击背景矩形 (“CS_BG”) 时,拖动模式被激活,记录鼠标位置与面板当前位置之间的偏移量。随着鼠标移动 (CHARTEVENT_MOUSE_MOVE),面板的位置会动态更新,允许交易者以交互方式重新定位仪表板以获得更好的可见性。当用户释放鼠标按钮或点击其他地方时,拖动模式停用,将面板锁定在其新位置。此功能增强了可用性,使仪表板可适应不同的工作空间布局。

double CalculateStrength(int ci, ENUM_TIMEFRAMES tf, int lookback)
{
   double sum = 0;
   int cnt = 0;

   for(int j=0; j<4; j++)
   {
      string sym = Pairs[ci][j];
      if(Bars(sym, tf) < lookback+1) continue;
      double now = iClose(sym, tf, 0);
      double prev = iClose(sym, tf, lookback);
      if(prev == 0) continue;

      double pct = (now - prev) / prev * 100.0;

      if(StringFind(sym, Currencies[ci]) > 0)
         pct = -pct;

      sum += pct;
      cnt++;
   }
   return (cnt == 0) ? 0 : sum / cnt;
}

货币强弱值的计算是在 UpdateStrengths()CalculateStrength()中进行的。UpdateStrengths() 遍历每个货币索引,为三个时间周期中的每一个调用 CalculateStrength()

CalculateStrength() 检索每个相关货币对的最新收盘价 (iClose()) ,然后从回溯周期获取历史收盘价。它会检查是否有足够的K线来执行计算;如果没有,它会跳过该货币对以避免错误。计算回溯周期内的百分比变化,如果所讨论的货币是货币对中的报价货币,则将其反转(倒数),以准确衡量基础货币的相对强弱。

这种反转确保报价货币的升值反映为基础货币的贬值,从而在计算中保持一致性。该函数将每种货币在所有四个货币对中的这些百分比变化相加,并取平均值以生成具有代表性的强弱值,该值存储在 Strength 数组中用于显示和日志记录。

void DrawPanel()
{
   RemovePanel();
   ObjectCreate(0, "CS_BG", OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, "CS_BG", OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "CS_BG", OBJPROP_XDISTANCE, PanelX);
   ObjectSetInteger(0, "CS_BG", OBJPROP_YDISTANCE, PanelY);
   ObjectSetInteger(0, "CS_BG", OBJPROP_XSIZE, PanelWidth);
   ObjectSetInteger(0, "CS_BG", OBJPROP_YSIZE, PanelHeight);
   // Add headers, labels, colored bars for each currency
}

这些数据的视觉呈现由 DrawPanel() 处理,它创建一个覆盖指定仪表板区域的矩形。为了清晰起见,顶部添加了每个时间周期的标题。然后函数遍历每种货币,创建货币名称标签、数值强弱值(格式化为两位小数),以及直观指示强弱的彩色条形。

配色方案对较强的货币使用绿色调,中性的使用橙色,较弱的使用红色,允许交易者通过视觉快速评估市场状况。条形的宽度与强弱值成比例,提供直观的视觉提示。这些系统化、一致的图形元素使仪表板信息丰富且一目了然。

void RemovePanel()
{
   for(int i=ObjectsTotal(0)-1; i>=0; i--)
   {
      string name = ObjectName(0, i);
      if(StringFind(name, "CS_") == 0 || StringFind(name, "Lbl_") == 0 || StringFind(name, "Bar_") == 0)
         ObjectDelete(0, name);
   }
}

当仪表板需要更新或删除时,RemovePanel() 会删除所有与仪表板相关的具有特定名称前缀(如 “CS_”、“Hdr_”、“Lbl_”、“Val_” 和 “Bar_”)的对象。这种系统化删除确保图表保持整洁,防止图形混乱,允许仪表板在每次刷新时从头开始重建,而不会随着时间的推移积累残留对象。

void DrawEquityLines()
{
   for(int i=1; i< dataCount; i++)
   {
      string id = StringFormat("EQ_%d", i);
      ObjectDelete(0, id);
      ObjectCreate(0, id, OBJ_TREND, 0,
                   times[i-1], equities[i-1],
                   times[i], equities[i]);
      ObjectSetInteger(0, id, OBJPROP_COLOR, clrYellow);
      ObjectSetInteger(0, id, OBJPROP_WIDTH, 2);
   }
}

DrawEquityLines()DrawDrawdownLines() 函数将账户的表现趋势图形化。每次记录新的权益数据时,这些函数都会删除先前的趋势对象(“EQ_” 和 “DD_”)以保持绘图整洁。然后它们创建连接存储的数据点的新趋势对象,并使用不同的颜色进行样式设置——权益用黄色,回撤用红色——以清晰区分两者。

趋势线直观地展示了账户资金的演变历程,以及曾经历的最大回撤。。只有当 EA 主动管理交易时,这些可视化图表才真正具有意义,因为它们依赖于已执行订单所引起的账户权益变化。

void DrawDrawdownLines()
{
   double peak = -DBL_MAX;
   for(int i=1; i< dataCount; i++)
   {
      peak = MathMax(peak, equities[i-1]);
      double dd = equities[i-1] - peak;
      string id = StringFormat("DD_%d", i);
      ObjectDelete(0, id);
      ObjectCreate(0, id, OBJ_TREND, 0,
                   times[i-1], dd,
                   times[i], equities[i] - peak);
      ObjectSetInteger(0, id, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, id, OBJPROP_WIDTH, 2);
   }
}

这一点很重要:虽然绘制权益和回撤的代码已包含在内并且会生成趋势线,它们的实用性在很大程度上取决于 EA 是否执行自动交易操作。如果 EA 仅供信息参考或仅手动使用,账户权益只会在交易者手动交易或入金/出金时发生变化。在这种情况下,权益图可能无法准确反映实时交易表现,趋势线可能是静态的或意义不大。

因此因此,将这些绘图功能集成到一个能持续执行自动交易并不断调整账户余额的EA中,才能发挥其最大价值。当此类自动交易系统运行时,权益曲线能直观地展示账户增长、回撤及整体表现,这对于风险管理和绩效评估极具价值。

void LogCurrencyStrengths(int tfIdx)
{
   string sStrong="", sWeak="", sNeutral="";
   for(int i=0; i<8; i++)
   {
      double v = Strength[i][tfIdx];
      if(v > 0.3) sStrong += Currencies[i] + " ";
      else if(v < -0.3) sWeak += Currencies[i] + " ";
      else sNeutral += Currencies[i] + " ";
   }
   Print("Strong: ", sStrong, "| Weak: ", sWeak, "| Neutral: ", sNeutral);
}

最后,LogCurrencyStrengths() 基于预设阈值(例如大于 +0.3% 或小于 -0.3%)将各货币归类为强势、弱势或中性,从而提供文字形式的摘要。它将每个类别的货币代码连接成字符串,并将这些摘要输出到终端窗口。这一文字概述为各主要货币的市场情绪提供了快照,方便偏好快速了解宏观动态的交易者,是对图形显示的有力补充。


结果

在本节中,我们将回顾我们的 EA 在 MetaTrader 5 上的测试结果。


上图是EA在 MetaTrader 5 图表上运行后的示意图。下面,我们将结果制成表格——每个值代表一个百分比变化。
货币 M15 H1 H4
USD -0.11 +1.12 +2.20
EUR -0.23 -0.38 -0.38
GBP +0.20 +0.49 +0.67
JPY +0.01 -1.44 -2.48
CHF +0.32 -0.25 -0.33
CAD +0.17 +0.34 +0.16
AUD +0.05 +0.71 +0.52
NZD +0.10 +0.76 +0.13

  • 美元在 H1(+1.12%)和 H4(+2.20%)上都是最强的,尽管在 M15 上短暂下跌。
  • 日元和欧元在 H1(-1.44% 和 -0.38%)和 H4(-2.48% 和 -0.38%)上是最弱的。
  • 英镑、加元、澳元、纽元在 H1/H4 上显示出温和到中等的强势,使它们成为次要的“强势”候选者。

现在让我们从强弱评分中得出交易启示。在 H4 时间周期上,美元录得 +2.20%,而日元位于 -2.48%。巨大的差距告诉我们美元显然掌控局势且日元疲软——这是做多 USDJPY 的理想机会。同样,欧元在 H4 上显示 -0.38%,再次证实了美元的主导地位。在这种情况下,你会寻找 EURUSD 的做空机会。



结论

货币强弱指标帮助你识别货币对在多个时间周期上的变化。它提供了潜在市场方向的清晰快照。这并不意味着你应该立即交易;相反,利用它来找到最佳入场位,并应用你的风险管理和确认策略。该工具是检测货币强弱的起点,在完善分析并改进结果的呈现方式方面还有改进空间。敬请关注后续项目,获取更多最新进展。

日期 工具名称  说明 版本  更新  提示
01/10/24 图表投影仪 用于叠加前一天价格走势(带“幽灵”效果)的脚本。 1.0 首次发布 工具1
18/11/24 分析评论 它以表格形式提供前一日的市场信息,并预测市场的未来走向。 1.0 首次发布 工具2
27/11/24 分析大师 市场指标每两小时定期更新  1.01 第二版 工具3
02/12/24 分析预测器  每两小时定期更新市场指标,并集成Telegram推送功能。 1.1 第三版 工具4
09/12/24 波动性导航工具 该EA使用布林带、RSI和ATR指标分析市场状况。 1.0 首次发布 工具5
19/12/24 均值回归信号收割器  使用均值回归策略分析市场并提供信号  1.0  首次发布  工具6 
9/01/25  信号脉冲  多时间框架分析器 1.0  首次发布  工具7 
17/01/25  指标看板  带按钮的分析面板  1.0  首次发布 工具8 
21/01/25 外部资金流 通过外部库进行分析 1.0  首次发布 工具9 
27/01/25 VWAP 成交量加权平均价格   1.3  首次发布  工具10 
02/02/25  Heikin Ashi  势平滑与反转信号识别  1.0  首次发布  工具11
04/02/25  FibVWAP  通过 Python 分析生成信号  1.0  首次发布  工具12
14/02/25  RSI 背离  价格走势与 RSI 背离的对比  1.0  首次发布  工具13 
17/02/25  抛物线转向与反转 (PSAR)  自动化PSAR策略 1.0 首次发布  工具14
20/02/25  四分位绘制脚本  在图表上绘制四分位水平线  1.0  首次发布  工具15 
27/02/25  侵入检测器 当价格触及四分位水平时进行检测和警报 1.0   首次发布 工具16 
27/02/25  TrendLoom工具 多时间周期分析面板 1.0 首次发布 工具17
11/03/25  四分位看板  带有可激活或禁用四分位的面板  1.0  首次发布 工具18
26/03/25  ZigZag 分析器  使用ZigZag指标绘制趋势线  1.0  首次发布  工具19 
10/04/25  相关性检测器 使用Python库绘制货币对的相关性。 1.0 首次发布  工具20 
23/04/25 市场结构反转检测工具 市场结构反转检测 1.0  首次发布  工具21
08/05/25  相关性仪表盘  不同货币对之间的相关性 1.0 首次发布 工具22 
13/05/25 货币强弱指标  衡量货币对中每种货币的强弱 1.0 首次发布 工具22 

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/18108

附加的文件 |
MQL5经济日历交易指南(第九部分):通过动态滚动条与界面优化提升新闻交互体验 MQL5经济日历交易指南(第九部分):通过动态滚动条与界面优化提升新闻交互体验
本文中,我们为MQL5经济日历添加了动态滚动条功能,使用户直观快速浏览新闻事件。确保事件展示界面无卡顿且数据更新高效。并通过测试验证滚动条的响应性与仪表盘的美观度。
MQL5 简介(第 18 部分):沃尔夫波浪形态简介 MQL5 简介(第 18 部分):沃尔夫波浪形态简介
本文详细解释了沃尔夫波浪形态,涵盖了看跌和看涨两种变体。它还分解了用于基于这种高级图表形态识别有效买卖设置的分步逻辑。
新手在交易中的10个基本错误 新手在交易中的10个基本错误
新手在交易中会犯的10个基本错误: 在市场刚开始时交易, 获利时不适当地仓促, 在损失的时候追加投资, 从最好的仓位开始平仓, 翻本心理, 最优越的仓位, 用永远买进的规则进行交易, 在第一天就平掉获利的仓位,当发出建一个相反的仓位警示时平仓, 犹豫。
从基础到中级:事件(一) 从基础到中级:事件(一)
鉴于目前所展示的一切,我认为我们现在可以开始实现某种应用程序,以便直接在图表上运行某些交易品种。然而,首先我们需要讨论一个对初学者来说可能相当困惑的概念。也就是说,在 MQL5 中开发并用于在图表上显示的应用程序的创建方式与我们迄今为止看到的不同。在本文中,我们将开始更好地理解这一点。