在构建交易策略时,我们往往不仅需要知道指标当前的值,还需要了解它相较于过去是如何变化的。例如,判断移动平均线 (MA) 是正在上升还是下降,或者一个震荡指标(如随机指标)是否刚刚穿越了某个关键水平(如超买/超卖线)。这都需要比较当前或最近完成的K线上的指标值与之前某一根K线上的指标值。
利用 Shift
参数获取历史指标值
我们已经知道,MQL4中几乎所有的技术指标函数(如 iMA()
, iStochastic()
等)的最后一个参数都是 Shift
(位移量)。这个参数决定了函数返回的是哪一根K线上的指标计算结果:
Shift = 0
: 表示获取当前K线(即图表上最右侧、正在形成的K线)的指标值。Shift = 1
: 表示获取前一根已完成的K线的指标值。Shift = 2
: 表示获取再往前一根K线的指标值,以此类推。
示例1:判断移动平均线 (MA) 的方向
要判断一条MA线是上升还是下降,我们可以比较它在当前K线(或最近完成的K线)上的值与它在前一根K线上的值。
// 假设外部参数 MAPeriod, MAMethod, MAPrice 已设置
// 获取最近完成K线 (shift=1) 的MA值
double ma_current_bar = iMA(NULL, 0, MAPeriod, 0, MAMethod, MAPrice, 1); // 使用 shift=1 获取的是刚收盘K线的MA值
// 获取再前一根K线 (shift=2) 的MA值
double ma_previous_bar = iMA(NULL, 0, MAPeriod, 0, MAMethod, MAPrice, 2);
if (ma_current_bar > ma_previous_bar)
{
Print("移动平均线正在上升。");
}
else if (ma_current_bar < ma_previous_bar)
{
Print("移动平均线正在下降。");
}
else
{
Print("移动平均线持平。");
}
- 逻辑:如果最近完成K线的MA值大于其前一根K线的MA值,说明MA在上升;反之则在下降。 (注:原文示例中使用
shift=0
代表当前K线,shift=1
代表前一根。为避免歧义并确保信号在新K线形成时稳定,很多实际策略会使用shift=1
代表“当前已确认的信号K线”,shift=2
代表“信号K线的前一根K线”。本译文示例按此逻辑调整,但核心比较思想一致。)
示例2:检测震荡指标穿越特定水平 (以随机指标为例)
假设我们的策略是当随机指标 (%K线) 从下方上穿30水平线时产生买入信号,或从上方下穿70水平线时产生卖出信号。
// 假设外部参数 KPeriod_val, DPeriod_val, Slowing_val, MAMethod_val, PriceField_val 已设置
// 获取最近完成K线 (shift=1) 的随机指标 %K 值
double stochastic_current = iStochastic(NULL, 0, KPeriod_val, DPeriod_val, Slowing_val,
MAMethod_val, PriceField_val, MODE_MAIN, 1);
// 获取再前一根K线 (shift=2) 的随机指标 %K 值
double stochastic_previous = iStochastic(NULL, 0, KPeriod_val, DPeriod_val, Slowing_val,
MAMethod_val, PriceField_val, MODE_MAIN, 2);
// 检测向上穿越30 (超卖区)
if (stochastic_current > 30 && stochastic_previous <= 30) // 注意使用 <= 来捕捉从下方或恰好在30时穿越的情况
{
Print("随机指标刚刚从下方上穿30!买入信号。");
// OpenBuyOrder(...);
}
// 检测向下穿越70 (超买区)
if (stochastic_current < 70 && stochastic_previous >= 70) // 注意使用 >=
{
Print("随机指标刚刚从上方下穿70!卖出信号。");
// OpenSellOrder(...);
}
- 逻辑:如果当前K线的指标值在水平线的一侧,而前一根K线的指标值在另一侧(或恰好在水平线上),则表明在最近一根K线的形成过程中发生了穿越。
示例3:检测移动平均线交叉 (金叉/死叉)
一个非常经典的交易信号是快慢MA线的交叉。我们可以通过比较两条MA线在当前和前一根K线上的相对位置来精确捕捉交叉发生的时刻。
// 假设外部参数 FastMA_Period, SlowMA_Period, MagicNumber_val 等已设置
// 获取最近完成K线 (shift=1) 的快慢MA值
double fastMA_current = iMA(NULL, 0, FastMA_Period, 0, MODE_EMA, PRICE_CLOSE, 1);
double slowMA_current = iMA(NULL, 0, SlowMA_Period, 0, MODE_SMA, PRICE_CLOSE, 1);
// 获取再前一根K线 (shift=2) 的快慢MA值
double fastMA_previous = iMA(NULL, 0, FastMA_Period, 0, MODE_EMA, PRICE_CLOSE, 2);
double slowMA_previous = iMA(NULL, 0, SlowMA_Period, 0, MODE_SMA, PRICE_CLOSE, 2);
// 检测金叉 (快线上穿慢线)
// 条件:前一根K线时,快线 <= 慢线;当前K线时,快线 > 慢线
// 并且,当前没有持有的买单 (通过 BuyMarketCount 判断)
if (fastMA_current > slowMA_current && fastMA_previous <= slowMA_previous
&& BuyMarketCount(Symbol(), MagicNumber_val) == 0) // 假设 BuyMarketCount 已定义
{
Print("MA金叉出现!买入信号。");
// OpenBuyOrder(...);
}
// 检测死叉 (快线下穿慢线)
// 条件:前一根K线时,快线 >= 慢线;当前K线时,快线 < 慢线
// 并且,当前没有持有的卖单
if (fastMA_current < slowMA_current && fastMA_previous >= slowMA_previous
&& SellMarketCount(Symbol(), MagicNumber_val) == 0) // 假设 SellMarketCount 已定义
{
Print("MA死叉出现!卖出信号。");
// OpenSellOrder(...);
}
- 逻辑:通过检查两条MA在前一根K线和当前K线上的相对位置变化,可以精确判断交叉是否“刚刚发生”(即在最近一根K线内完成)。例如,金叉的条件是:
在前一根K线上,快MA <= 慢MA
,并且在当前K线上,快MA > 慢MA
。 - 这种精确的交叉检测方法可以提供更可靠的交易信号,因为它确保了我们只在交叉发生的“那一刻”附近考虑入场,避免了在交叉发生很久之后才迟钝地做出反应。
- 如果您想检测在过去几根K线内(而不仅仅是最近一根)是否发生过交叉,可以调整用于获取
fastMA_previous
和slowMA_previous
的Shift
参数值(例如,用shift=3
和shift=4
来比较更早的K线状态)。
通过采用这种更精确的交叉检测方法(比较当前和前一根K线的指标状态),可以替代之前EA中可能使用的全局变量(如 BuyTicket
, SellTicket
)来防止重复开仓的逻辑。因为这种检测方式本身就确保了只在新信号(刚发生的交叉)出现时才触发条件,从而自然地避免了对同一历史交叉信号的重复响应。这使得EA的入场逻辑更为健壮和精确。