MQL5源码:智能交易脚本EA结构解读

EA是MQL中的自动交易脚本,可以通过编程控制计算机自动进行交易,节省人工盯盘的精力,以及提高执行效率。
本文以经典的均线交易系统解读MQL5交易脚本EA的结构。

策略

当价格上穿均线时做多并在下穿均线时平仓;当价格下穿均线时做空并在上穿均线时平仓。
真是非常简单的均线交易系统呢。

代码结构精解

版本声明

在一开始,会有一些跟实际功能无关的代码,大致是一个EA的自我介绍的玩意,并没有什么功能上的用途。

//+------------------------------------------------------------------+
//|                                              Moving Averages.mq5 |
//|                   Copyright 2009-2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2009-2016, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

使用 #property 来声明EA的各种属性,这些部分系统可以自动生成,基本没有必要改动,一笔带过。

代码引用

与C/C++以及绝大多数编程语言一样,MQL也有代码包含的指令,它仿照C/C++使用了#include,其机制是一致的——预编译。更多的资料可以自行查阅“预编译 文本包含”。

#include <Trade\Trade.mqh>

Trade.mqh 头文件内包含了很多跟交易有关的函数。如果将EA的买/卖操作比作输入/输出,那么Trade.mqh 头文件就可以比作 stdio.h非常重要

输入参数

MQL中的参数是可以由用户定制的,算是一个由外界输入的接口,Meta Trader还可以在GUI界面对输入参数进行调优。在MQL中,输入参数以input 修饰。

input double MaximumRisk        = 0.02;    // Maximum Risk in percentage
input double DecreaseFactor     = 3;       // Descrease factor
input int    MovingPeriod       = 12;      // Moving Average period
input int    MovingShift        = 6;       // Moving Average shift

这里有4个参数,分别为:

  • 最大风险比率(默认2%)(用于风控)
  • 减小因子(默认为3)(用于风控)
  • 均线周期(默认为12)
  • 均线位移(默认为6)

具体是什么意思,还要结合下面的逻辑看。

全局量

EA脚本通常是可以持续执行的(守护态运行),存一些全局变/常量是相当有必要的。

int    ExtHandle=0;
bool   ExtHedging=false;
CTrade ExtTrade;

#define MA_MAGIC 1234501

Ext是Expert的意思,就是EA的E。

CTrade对象来自于Trade.mqh,封装了很多交易方法。ExtTrade是一个实例。

Handle 是句柄,把手的意思,在MQL中,通常指指标的引用

在这里,EA需要使用一个均线的指标,所以需要存储一个指标的对象,指标在MQL中以句柄的形式存储,与操作系统的PID的机制类似,也类似一个地址(指针)。

Hedging是避险的意思,在这里是风险控制,也就是仓位控制。
ExtHedging就是一个开关,是否进行仓位控制,默认是关闭的,但是它会在程序中随时打开(因为如果它并不能随时打开,那么应该设置为 input 属性,由外界给出)。

可以看到,全局变量管理更像是在管理状态机

初始化状态机

全局变量集合就像状态机一样。那么首先开始的就是状态机的起点——初始状态。

在MQL中,使用OnInit函数来控制初始化,它在其他的事件函数开始之前被执行。

int OnInit(void)
  {
//--- prepare trade class to control positions if hedging mode is active
   ExtHedging=((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
   ExtTrade.SetExpertMagicNumber(MA_MAGIC);
   ExtTrade.SetMarginMode();
//--- Moving Average indicator
   ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
   if(ExtHandle==INVALID_HANDLE)
     {
      printf("Error creating MA indicator");
      return(INIT_FAILED);
     }
//--- ok
   return(INIT_SUCCEEDED);
  }

我不得不吐槽一下这诡异的MQL自带缩进,简直不忍直视,啊这不是重点。

函数的签名 int OnInit()int OnInit(void) 是一样的。

是不是有点像 int main()

在函数的开始,首先对ExtHedging进行了操作。
ExtHedging=((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
AccountInfoInteger函数是用于“获取用户账户信息”的,它会根据传入的枚举常量,多态地返回各种值。在这里,是查询用户的保证金模式(Margin:保证金)。当保证金模式为ACCOUNT_MARGIN_MODE_RETAIL_HEDGING具体到底是什么我也不是很清楚)时,ExtHedging开关会打开。

接下来设置一下 CTrade对象 ExtTrade的一些属性

ExtTrade.SetExpertMagicNumber(MA_MAGIC) // 之前的那个宏定义的1234501,就是一个Hash值,随便写。
ExtTrade.SetMarginMode(); // 设置保证金模式

再是获取一下均线指标的数据,利用iMA函数
ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
iMA函数的参数在官方的手册上都可以查,
这里有很多的常量
_Symbol 代表当前货币,这里也可以用NULL代替;
_Period 代表当前周期,即时间周期,如1小时K线;
MovingPeriod 代表均线的周期,这里由input给出;
MovingShift 代表均线平移量,实际的效果延迟若干根K线处理;

在下也不知道为什么要默认延迟6个K线进行交易

MODE_SMA 是使用Simple Moving Average(简单移动平均线:取算术平均数)
PRICE_CLOSE 是应用于收盘价的意思,其他的还可以应用于开盘价。

当然,这个ExtHandle的赋值是有可能出现失败的,比如当传入的参数不合法的时候(总之就是指标内部出现错误的时候),ExtHandle会被赋值为INVALID_HANDLE(非法句柄),在这个时候要检测一下:

   if(ExtHandle==INVALID_HANDLE)
     {
      printf("Error creating MA indicator");
      return(INIT_FAILED);
     }

这样可以提升代码的健壮性

如果想使用自定义指标,请参考 iCustom函数

在初始化结束的时候,如果一切正常,应该返回INIT_SUCCEEDED 表示成功初始化了;否则返回INIT_FAILED 告诉 Meta Trader 停止脚本运行。

状态机转换

MQL提供了一个时间事件 void OnTick() ,一旦任何的变动发生,无论是接受到新的价格、产生订单等都会调用OnTick,所以这是名副其实的状态转换事件

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
   if(SelectPosition())
      CheckForClose();
   else
      CheckForOpen();
//---
  }

逻辑很简单,但涉及了三个尚未定义的函数,在这里先从语义上理解一下:
SelectPostion 函数返回“目前是否存在仓位”;
CheckForClose 函数检查是否满足平仓的条件,如果满足就平仓;
CheckForOpen 函数检查是否满足开仓的条件,如果满足就开仓。

因此这个逻辑非常清晰:如果现在有仓位就看看能不能平仓了&#

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值