在过去的几章中,我们致力于创建一系列用于执行订单处理机制的函数。这些函数是几乎所有EA都通用的基础模块,设计它们的初衷是希望它们能在各种交易场景中被复用,并尽可能保持灵活性。这样做的目的是让我们能够从繁琐的订单操作细节中解放出来,从而更专注于编码实现我们交易系统独特的交易逻辑和入场/出场条件。
接下来的核心工作,也将是您开发 EA 的主要精力所在——即如何让 EA 尽可能精确地执行您的交易系统规则。这包括识别开仓和平仓订单的确切条件,以及如何确定止损和止盈价格。几乎所有的交易系统都会用到价格数据和/或技术指标数据。下面我们就来探讨如何在 EA 中访问和使用这些关键信息。
价格数据
除了我们之前章节已经讨论过的当前即时报价——买价 (Bid) 和 卖价 (Ask) 之外,在构建交易逻辑时,您很可能还需要用到历史 K 线的价格数据,特别是每根 K 线的最高价 (High)、最低价 (Low)、开盘价 (Open) 和 收盘价 (Close)(通常合称为 OHLC 数据)。
1. 访问当前图表的 K 线数据:预定义时间序列数组
对于 EA 当前运行所在图表的历史 K 线数据,MQL4提供了一组非常方便的预定义时间序列数组:High[]
, Low[]
, Open[]
和 Close[]
。
- 数组: 在编程中,数组是一种可以存储多个同类型值的变量。您可以通过索引(一个整数,写在方括号
[]
内)来访问数组中的特定元素。 - 索引规则:
Open[0]
代表当前正在形成的 K 线(第 0 根 K 线)的开盘价。它的值会随着当前 K 线的价格跳动而变化。Open[1]
代表前一根已完成的 K 线(第 1 根 K 线)的开盘价。这是一个固定值。Open[2]
代表再往前一根 K 线的开盘价,依此类推。 这些数组通常用于获取最近几根 K 线的价格信息,例如判断突破、形态等。
2. 访问其他品种或其他周期的 K 线数据:iHigh()
, iLow()
, iOpen()
, iClose()
函数 如果您需要获取:
- 非当前图表交易品种的 OHLC 数据(例如,EA 运行在 EURUSD 图表上,但需要 USDJPY 的数据)。
- 非当前图表时间周期的 OHLC 数据(例如,EA 运行在 H1 图表上,但需要 D1 周期的数据)。 那么,您就需要使用 MQL 内置的
i*()
系列函数,如iHigh()
,iLow()
,iOpen()
和iClose()
。
以 iClose()
函数为例,其语法如下:
double iClose(
string symbol, // 交易品种名称 (例如 "EURUSD", NULL 表示当前品种)
int timeframe, // 图表时间周期 (例如 PERIOD_H1, 0 表示当前周期)
int shift // K线柱的位移量 (0代表当前K线, 1代表前一根, ...)
);
symbol
: 您想获取数据的交易品种名称。如果为NULL
或使用Symbol()
函数,则表示当前 EA 运行的图表品种。timeframe
: 您想获取数据的时间周期。可以是预定义的时间周期常量 (如PERIOD_M1
,PERIOD_H4
,PERIOD_D1
等),也可以是自定义的周期(以分钟为单位的整数,如 60 代表 1 小时)。如果为0
,则表示使用当前 EA 运行的图表周期。shift
: K 线的位移量。0
指的是当前 K 线(对于历史数据函数,通常指正在形成的、其收盘价会随价格跳动而变化的K线,直到该 K 线结束),1
指的是已完成的前一根 K 线,2
指的是再往前一根,以此类推。
iClose()
使用示例:
-
示例 1: EA 运行在 H1 图表上,获取当前品种 H4 图表上前一根 K 线的收盘价。
double H4_Previous_Close = iClose(NULL, PERIOD_H4, 1); // NULL: 当前品种 // PERIOD_H4: H4 时间周期 // 1: 前一根已完成的K线
-
示例 2: 获取 GBPUSD 在与当前图表相同时间周期下,当前 K 线的(最新)收盘价。
double GBPUSD_Current_Close = iClose("GBPUSD", 0, 0); // "GBPUSD": 指定品种为 GBPUSD // 0: 使用当前图表的时间周期 // 0: 当前K线 (正在形成的K线)
3. 使用循环遍历历史K线数据
您可以结合 for
或 while
等循环运算符,通过改变 i*()
函数中的 shift
参数,来系统地访问一段历史 K 线的数据。
例如,以下 for
循环获取并打印当前品种、当前周期下,从当前 K 线(shift=0
)开始往前共 10 根 K 线的收盘价:
Print("最近 10 根 K 线的收盘价 (0=当前K线, 1=前一根, ...):");
for (int bar_shift = 0; bar_shift < 10; bar_shift++) // 遍历 shift 从 0 到 9
{
double historical_close = iClose(NULL, 0, bar_shift);
if (historical_close != EMPTY_VALUE) // 检查数据是否有效 (例如,K线是否存在)
{
Print("Bar[", bar_shift, "] Close: ", DoubleToStr(historical_close, Digits)); // 使用 DoubleToStr 格式化输出
}
else
{
Print("Bar[", bar_shift, "] 数据获取失败!");
}
}