简单移动平均(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 字(可选)

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐