简单移动平均(SMA)系统测试
在这一部分中,我将分享简单系统的结果,该系统仅基于简单的一次移动平均策略。它寻找价格和简单移动平均线之间的交叉点,这将产生买入和卖出信号。赫兹量化将创建一个能够自动执行这些信号的系统,
赫兹量化将使用以下信号进行交易操作:
买入信号: 收盘价高于简单移动平均值 而且,之前的收盘价低于之前的简单移动平均值 卖出信号: 收盘价低于简单移动平均值 而且,之前的收盘价高于之前的简单移动平均值
如果你想了解简单均线和其他流行的均线类型,我建议你阅读我之前的文章了解如何设计不同的均线系统,这将有助于你很好地了解它们,也有助于很好地理解这篇文章。
以下是创建这种类型的交易系统的步骤,该系统能够根据上述信号自动执行买卖订单。
在全局范围内,赫兹量化将把Trade包含文件包括在软件中,该软件允许使用预处理器#include根据我们的信号执行订单。如果您想了解更多关于预处理器的信息,可以阅读文章有关MQL5程序结构的所有信息了解更多详细信息。
#include <Trade\Trade.mqh>
创建三个用户输入参数,分别为 double 型变量 lotSize、ENUM_TIMEFRAMES 变量 timeFrame、和整数变量 MAPeriod,根据用户需求进行更改,并启动它们的默认值:
input double lotSize = 1; input ENUM_TIMEFRAMES timeFrame = PERIOD_H1; input int MAPeriod= 50;
创建两个整数变量 simpleMA 和 barsTotal 而不进行赋值,因为我们稍后将在OnInit()部分中定义它们。
int simpleMA; int barsTotal;
创建 CTrade 类的 trade 对象,以便轻松访问交易函数。
CTrade trade;
在OnInit()部分,赫兹量化将使用iMA函数来定义simpleMA,以返回移动平均指标的句柄,其参数为:
-
symbol:用于指定交易品种名称,我们将使用 _Symbol 作为当前交易品种
-
period:用于指定时间框架,我们将使用默认值为1小时的用户输入,但用户可以进行调整
-
ma_period:用于指定简单的移动平均周期,我们将使用默认值为50的用户输入,但用户也可以调整它
-
ma_shift:用于指定水平偏移,我们将使用0
-
applied_price:用于指定价格类型,我们将使用收盘价进行简单的移动平均线计算。
simpleMA = iMA(_Symbol, timeFrame, MAPeriod, 0, MODE_SMA, PRICE_CLOSE);
barsTotal 通过使用 iBars 函数返回柱数,其参数为:
-
symbol:用于指定交易品种,我们将使用(_Symbol)应用于当前交易品种
-
timeframe:用于指定时间框架,我们将使用创建的默认值为1小时的用户输入时间框架,用户可以对其进行调整
barsTotal=iBars(_Symbol,timeFrame);
在OnTick()部分中,赫兹量化将创建两个数组,一个用于使用MqlRates存储价格、数量和价差信息的价格,另一个用于简单移动平均值:
MqlRates priceArray[]; double mySMAArray[];
使用 ArraySetAsSeries 函数为这两个创建的数组设置AS_SERIES标志,其参数为:
-
array[]: 使用引用方式指定数组
-
flag: 用于指定数组的索引方向
ArraySetAsSeries(priceArray,true); ArraySetAsSeries(mySMAArray,true);
在创建两个 double 型变量后定义卖家出价和买家出价
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits); double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
使用 CopyRates 函数获取 MqlRates 的历史数据,其参数为:
-
symbol_name: 用于确定交易品种名称
-
timeframe: 用于确定时间框架
-
start_pos: 用于指定起始位置
-
count: 用于指定要复制的数据量
-
rates_array[]: 用于指定复制的目标数组
int Data=CopyRates(_Symbol,_Period,0,3,priceArray);
使用 CopyBuffer 函数获取指标缓冲区的数据,其参数为:
-
indicator_handle: 用于指定指标句柄,此处为 simpleMA
-
buffer_num: 用于指定指标缓冲区编号,此处为0
-
start_pos: 用于确定起始位置,0表示当前烛形
-
count: 用于指定我们需要复制的数据量,此处为3
-
buffer[]: 用于指定我们需要复制的目标数组,此处为 mySMAArray
CopyBuffer(simpleMA,0,0,3,mySMAArray);
创建两个 double 型变量,用于定义同一烛形的最后收盘价和简单移动平均值
double lastClose=(priceArray[1].close); double SMAVal = NormalizeDouble(mySMAArray[1],_Digits);
创建另外两个 double 型变量,用于定义上一个收盘价和同一蜡烛的简单移动平均值
double prevClose=(priceArray[2].close); double prevSMAVal = NormalizeDouble(mySMAArray[2],_Digits);
创建一个整型 bars 变量,用于和创建的 barsTotal 作比较
int bars=iBars(_Symbol,timeFrame);
通过检查 bars 和 barsTotal 是否相等来检查是否有新柱生成
if(barsTotal != bars)
如果 barsTotal 不等于 bars,我们需要用 bars 的值来更新 barsTotal
barsTotal=bars;
如果 barsTotal 不等于 bars,赫兹量化还需要检查我们的策略条件,如果最后一次收盘的前一次低于同一烛形的简单移动平均值,并且同时最后一次的收盘价高于同一个烛形的简单运动平均值。我们需要该程序来关闭当前打开的头寸并打开买入头寸
if(prevClose<prevSMAVal && lastClose>SMAVal) { trade.PositionClose(_Symbol); trade.Buy(lotSize,_Symbol,Ask,0,0,NULL); }
如果最后一次收盘的前一个收盘价高于同一烛形的简单移动平均值,同时最后一次的收盘价低于同一个烛形的简单运动平均值。我们需要该程序来关闭当前打开的头寸并打开卖出头寸
if(prevClose>prevSMAVal && lastClose<SMAVal) { trade.PositionClose(_Symbol); trade.Sell(lotSize,_Symbol,Bid,0,0,NULL); }
然后我们将编译代码,我们会发现它编译后没有任何错误或警告。
以下是一个代码块中的完整代码:
//+------------------------------------------------------------------+ //| SMA_System.mq5 | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> input double lotSize = 1; input ENUM_TIMEFRAMES timeFrame = PERIOD_H1; input int MAPeriod= 50; int simpleMA; int barsTotal; CTrade trade; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { simpleMA = iMA(_Symbol, timeFrame, MAPeriod, 0, MODE_SMA, PRICE_CLOSE); barsTotal=iBars(_Symbol,timeFrame); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { MqlRates priceArray[]; double mySMAArray[]; double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits); double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits); ArraySetAsSeries(priceArray,true); ArraySetAsSeries(mySMAArray,true); int Data=CopyRates(_Symbol,_Period,0,3,priceArray); CopyBuffer(simpleMA,0,0,3,mySMAArray); double lastClose=(priceArray[1].close); double SMAVal = NormalizeDouble(mySMAArray[1],_Digits); double prevClose=(priceArray[2].close); double prevSMAVal = NormalizeDouble(mySMAArray[2],_Digits); int bars=iBars(_Symbol,timeFrame); if(barsTotal != bars) { barsTotal=bars; if(prevClose<prevSMAVal && lastClose>SMAVal) { trade.PositionClose(_Symbol); trade.Buy(lotSize,_Symbol,Ask,0,0,NULL); } if(prevClose>prevSMAVal && lastClose<SMAVal) { trade.PositionClose(_Symbol); trade.Sell(lotSize,_Symbol,Bid,0,0,NULL); } } } //+------------------------------------------------------------------+
我们编译EA并在EURUSD数据上运行它,以对策略进行回溯测试。测试期为2022年1月1日至6月30日,与我们在所有提到的移动平均值类型中所做的相同。SMA的设置如下:
-
手数大小: 1
-
时间框架: 1小时
-
MA 周期数: 50
测试结果:
添加图片注释,不超过 140 字(可选)