下载MetaTrader 5

初学者快速入门或简明指南

24 十月 2013, 11:48
Dmitriy Parfenovich
0
2 579

简介

亲爱的读者,您好!本文中,我们会试着为您解释并向您呈现可以如何轻松快速地掌握创建“EA 交易”、使用指标等等原则的要领。本文面向初学者,所以不会包含任何难懂或晦涩的示例。因此,对于那些已经清楚如何编写“EA 交易”程序的人来说,本文可能没有那么多的启示感悟,信息量也不是很充分。

“EA 交易”及其结构

“EA 交易”是一种以 MQL 语言缩写、指定交易执行或搁置情况的程序。

基本上,“EA 交易”的结构可以由超大数量的块构成,但为了方便理解,我想展示的是一个利用 MetaEditor 默认生成的非常简单的示例。

整体的“EA 交易”可以从视觉上划分为 4 个部分,每个部分都负责待执行的某特定部分的工作。

主要的“EA 交易”块 
图 1. 主要的“EA 交易”块

  1. 参数块中包含允许终端以恰当方式处理“EA 交易”的信息。最常见的参数为“EA 交易”版本、生产厂家名称以及一个简要描述。

  2. OnInit() 块会在“EA 交易”被载入终端时获得控制权。其中可能包含与此“EA 交易”初始化相关的各种数据 - 声明变量与数组、获取指标句柄等。也就是说,此块并不包含任何与交易直接关联的函数。

  3. OnDeinit() 块充当的是 OnInit() 块的反方向。会在“EA 交易”完成其操作(“EA 交易”/终端关闭或某“EA 交易”未能成功初始化)时被调用。此块的主要功能之一,即是重新分配“EA 交易”占用且不再需要的内存空间。换而言之,它描述出了删除变量、数组和指标句柄等等的过程。

  4. OnTick() 块每当由服务器接收与交易品种(货币对)相关的新信息时,就会被调用。它会指明交易执行的情况以及交易本身的函数。

MetaEditor 中默认生成的新文档示例
   图 2. MetaEditor 中默认生成的新文档示例

我们利用上例对其进行解释。我们已有一段“空” EA 的代码,一种需要随后填写的“EA 交易”模板。
这里我们可能看到的内容如下:

  • 前五行(第 1 行到第 5 行)为注释,其中包含“EA 交易”的名称(文件名)、生产厂家的名称及其网站。您可以于此写下您想要的任何内容。此文本不会于任何地方显示,甚至可以跳过。其所包含的信息只针对开发人员;

  • 接下来的三行(第 6 至 8 行)为参数块。启动终端中的“EA 交易”时,就会看到此信息;

  • 然后是 OnInit() 函数(第 12 至 19 行)。此为 OnInit() 块。此函数不会获取任何参数,但会返回(也可能不返回)初始化代码;

  • 接下来是 OnDeinit(const int reason) 函数(第 22 至 26 行)。此为 OnDeinit() 块。它拥有一个指定“EA 交易”关闭原因的参数。
    如果“EA 交易”未能成功初始化,则此函数会接收一个相关代码作为参数;

  • 最后一个函数为 OnTick() (第 30 至 34 行)。此为之前谈到过的 OnTick() 块。此块可以说是“EA 交易”的“大脑”,因为其中包含了负责交易的所有函数。

我前面说过,这种结构可以复杂得多,而且可能由大量的块构成,而不像这个易于掌握的示例这么简单。如果您觉得这个已经满足不了您的需求,则可以添加自己的块。
 

指标及其处理方式

指标是在 MQL 中缩写的小型程序,会在价格图表或其下方的一个独立窗口中显示,允许我们对市场执行技术分析。

所有的指标都可以划分为两种类型:顺势指标摆荡指标

顺势指标一般均于价格图表中绘制,用于识别趋势方向;而摆荡指标则通常见于价格图表下方,用于识别进场点。

大多数指标都至少有一个缓冲区(指标缓冲区),其中包含某给定时间点其读数数据。与“EA 交易”相似,指标拥有其借以计算的交易品种和时间表。

可将指标缓冲区视为一个队列,该队列的最后一个元素是一个运行值。

移动平均线指标示例
   图 3. 移动平均线指标示例

指标缓冲区是一种数组,其中的第一个元素(索引为 0)携带最右侧烛形的相关数据,接下来的元素(索引为 1)则携带右数第二个烛形的相关数据,如此等等。而这种元素布置则被称为时间序列

看一看下方示例:
假设我们的货币对为欧元兑美元,时间表为 1 小时。
首先,我们需要向“EA 交易”添加指标并获取其句柄。

句柄是一种指向指标的独特指针,可以让我们处理程序中任何地方的指标。

int iMA_handle; 
iMA_handle=iMA("EURUSD",PERIOD_H1,10,0,MODE_SMA,PRICE_CLOSE);
我们仔细观察一下。

第一行描述的是一个将用于存储指标句柄的变量。第二行会调用指标(此处为移动平均线指标),指定其参数,并将句柄保存到变量中以备将来使用。
MetaEditor 中键入 "iMA" 后,此行上方就会出现一个工具提示,显示逗号分隔指标调用参数。

“移动平均线”指标参数的工具提示示例
   图 4. “移动平均线”指标参数的工具提示示例

下方我们可以看到从左到右排列的各个参数:

  1. 交易品种名称(工具提示中以粗体字符显示)是一种文本参数,货币对(交易品种);
  2. 时间表
  3. 指标时期(此处为平均时期);
  4. 图表平移向前/向后 N 个柱。正数表示图表向前平移 N 个柱,而负数则表示图表向后平移 N 个柱;
  5. 平均方法
  6. 适用价格或某不同指标的句柄。

有一系列独特的变量以及其针对每一种指标的类型。如果您碰到一个未知指标,其相关信息通常都可以在内置的上下文“帮助”中找到。比如说,一旦您键入 iMA 并按下 F1之后,就会打开一个“帮助”窗口,提供该特定指标的相关信息,以及其所有属性的详尽描述。

通过按下 F1 调用该指标描述“帮助”窗口示例
   图 5. 通过按下 F1 调用该指标描述“帮助”窗口示例

代码编写完成并于终端中启动“EA 交易”后,我们就会发现(一旦价格图表的右上角出现“EA 交易”)图表中的指标不见了。这并非错误 - 完全在意料当中。想令其出现,我们需要再添加一行:

ChartIndicatorAdd(ChartID(),0,iMA_handle);

现在,我们看看结果如何。鼠标指针悬停于 ChartIndicatorAdd 命令上方,按 F1 阅读该命令用途相关的“帮助”信息。它表示此命令:

将一个带有指定句柄的指标添加到某个指定的图表窗口中。

等于零的第二个参数为子窗口编号。子窗口通常包含摆荡指标,位于价格图表下方。记住没有?这种东西可能会有很多。欲于子窗口中显示指数,您只需要按照比现有编号大 1 (即现有最后一个编号的下一个数字)的标准指定子窗口编号。

代码行已如下变更:

ChartIndicatorAdd(ChartID(),1,iMA_handle);

我们的指标会于价格图表下方的子窗口中显示。

现在,到了尝试从指标获取一些数据的时候了。为此目的,我们声明一个动态数组,为方便起见按时间序列排列数组索引,并将指标值复制到该数组当中。

double iMA_buf[];
ArraySetAsSeries(iMA_buf,true);
CopyBuffer(iMA_handle,0,0,3,iMA_buf);

上述示例表明,我们已经将双型动态数组 iMA_buf[] 声明为“移动平均线”指标(基于价格及价格片段)。

下一行则按照较小索引号元素存储较旧值、而较大索引号元素则存储较新值的原则设置数组的索引。如此使用是为了方便以避免混淆,因为所有指标中的指标缓冲区都按时间序列索引。

最后一行用于将指标值复制到 iMA_buf[] 数组中。这些数据已经可以使用了。

 

订单、交易与持仓

我们从订单开始。

  • 订单是被交易服务器接受的交易请求。如果请求无效,则会被拒绝。
    为避免填写交易请求中遇到的困难,稍后我会向您展示如何利用标准库让这一切更简单地实现。
    订单分两种类型:市价单(供即时执行)与挂单。
市价单是指按当前市价卖出或买入特定数量指定金融工具的指令。
挂单则指根据特定情况执行交易的指令。挂单有一个特定的到期时间,届时即被删除。
  • 交易是指订单(执行某交易的指令)执行的结果。每次交易均基于一个特定的单一订单,而单一订单则可能导致多次交易。比如说,一个欲买入 10 手的订单,可通过一系列连续性交易的部分执行而实现。交易始终保存于交易历史中且不能修改。此终端会于 "History" (历史)选项卡中显示交易。
  • 持仓是指活动订单的成果。每个交易品种只能建一个长仓或短仓。

为了更清楚地表达,我们来看一个例子:我们建一个 1 手的长仓,也就是说,我们(例如)以当前市价下一个手数为 1 的订单。如请求有效,则会被发往服务器进行处理。只要处理完成,此终端的 "Trade" (交易)选项卡中就会出现带订单参数的持仓。假设我们之后决定建另一个同为 1 手的长仓。待此订单处理完成后,我们并不会在 "Trade" 选项卡中看到两个订单,而是一个 2 手的持仓。即,持仓是一系列订单的执行成果。

现在我们继续练习。如欲制作一个请求,需要填充下述结构字段:

struct MqlTradeRequest
{
ENUM_TRADE_REQUEST_ACTIONS action; // 操作类型
ulong magic; // EA交易的ID(幻数)
ulong order; // 订单号
string symbol; // 交易工具
double volume; // 请求的交易手数
double price; // 价格 
double stoplimit; // 订单的StopLimit水平
double sl; // 订单的止损水平
double tp; // 订单的获利水平
ulong deviation; // 请求价格的最大允许点差
ENUM_ORDER_TYPE type; // 订单类型
ENUM_ORDER_TYPE_FILLING type_filling; // 订单的执行类型
ENUM_ORDER_TYPE_TIME type_time; // 订单的持续类型
datetime expiration; // 订单过期时间(订单的ORDER_TIME_SPECIFIED类型)
string comment; // 订单的备注
};

因为订单多种多样,每种订单类型又都有其各自的强制参数集。我可不会长篇大论地讲解这些字段。网站上已就此提供了大量的相关信息。如果某特定订单类型的强制参数连一个都未指定(或未正确指定),则请求会失败。

上述结构在此处的布局,只是为了方便论证填写时产生的困难。

“止损”与“获利”

“止损”与“获利”都是作为“后备措施”下达的特殊订单。即,如有错误或是“EA 交易”建了一个呈现损失的仓位,则“止损”订单可将损失限定于某个特定的预定义价位处。

“获利”与其类似,只是这次是限制利润。不再为平仓担心可能会变得很有必要。一旦达到某特定的价位,它将会平仓。也就是说,如果市场对我们不利或是我们想要获利,这些订单就是我们的“保险方案”。

这种类型的订单不能自行独立下达 - 只能修改现有的持仓。

采用标准库

好,我们终于走到了标准库。此库随本终端一同提供,并由此得名 - 标准库。它由方便“EA 交易”编程及部分承担复杂过程(比如交易请求生成)的各种函数构成。

交易库(亦见交易类)位于下述路径:Include\Trade\ 且可利用 #include 指令添加。
例如:

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>

上述类会被视作基础类,因为只利用这两个类(库),即可实现大多数“EA 交易”的编程。我称其为库:

  • 第一个设计用于下达和修改订单。
  • 第二个则用于根据现有持仓获取相关信息。

有些时候,还有一种库很有用:
#include <Trade\OrderInfo.mqh>
它包含操作订单的相关函数,比如说,我们的策略要求采用挂单。

还记得要求妥善运用知识、含各种参数的交易请求结构吗?
现在,我会向大家展示一个利用此库完成交易请求的示例:
CTrade m_Trade;
m_Trade.Sell(lot,symbol_name,price,sl,tp,comment);

这里共有 6 个参数,其中只有一个为必填(订单数量 - 此为第一参数)。
现在我就分别指定:

  • lot 是待下订单的数量;
  • symbol_name 是该订单所应用的交易品种(货币对)(如未指定,则采用“EA 交易”的当前交易品种);
  • price 为开盘价(因为此函数用于打开某活动的订单,所以其价格可能未被指定,这种情况下,则会自动从价格图表直接获取);
  • sl 是此订单的平仓价格 - 假如价格对我们不利(如果策略并没有使用止损的意思,则可忽略);
  • tp 是此订单的平仓价格 - 假如价格向我们期望的方向发展,即,获利(如果策略并没有使用获利的意思,则可忽略);
  • comment 即订单注释,比如说,指明下此订单的原因。

平仓的方法有许多种:

  1. 完全平仓
    CPositionInfo m_Position;
    m_Position.Select(symbol_name);
    m_Trade.PositionClose(symbol_name);
    
  2. 通过下达一个相同数量的反向订单平仓
    CTrade m_Trade;
    m_Trade.Buy(lot,symbol_name,price,sl,tp,comment);
    
  3. 采用一种更加复杂的方法,借此搜遍所有持仓,挑选出符合待进一步平仓的参数(交易品种、类型、魔术数字、仓位识别等)要求的一种。
    因其对于初学者而言很难,所以我就不给示例了。

把所有内容串起来

现在,到了把新习得的知识串成一个“EA 交易”的时候了。

//+------------------------------------------------------------------+
//|                                           fast-start-example.mq5 |
//|                        Copyright 2012, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| EA初始化函数                                                  |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>                                         //包含执行交易的库
#include <Trade\PositionInfo.mqh>                                  //包含获取持仓信息的库

int               iMA_handle;                              //存储指标句柄的变量
double            iMA_buf[];                               //存储指标值的动态数组
double            Close_buf[];                             //存储每个柱形收盘价格的动态数组

string            my_symbol;                               //存储交易品种的变量
ENUM_TIMEFRAMES   my_timeframe;                             //存储时间框架的变量

CTrade            m_Trade;                                 //执行交易的结构体
CPositionInfo     m_Position;                              //获取持仓信息的结构体
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   my_symbol=Symbol();                                      //保存当前图表的交易品种,用于此EA对其进一步的操作。
   my_timeframe=PERIOD_CURRENT;                              //保存图表的当前时间框架,用于此EA对其的进一步操作。
   iMA_handle=iMA(my_symbol,my_timeframe,40,0,MODE_SMA,PRICE_CLOSE);  //应用此指标并获取指标句柄
   if(iMA_handle==INVALID_HANDLE)                            //检查指标句柄是否可用
   {
      Print("Failed to get the indicator handle");              //如果句柄没有获取到,打印相关报错信息到日志文件中
      return(-1);                                           //完成报错处理
   
}
   ChartIndicatorAdd(ChartID(),0,iMA_handle);                  //将指标添加到价格图表中
   ArraySetAsSeries(iMA_buf,true);                            //将iMA_buf数组的索引设置为时间序列
   ArraySetAsSeries(Close_buf,true);                          //将Close_buf数组的索引设置为时间序列
   return(0);                                               //返回0,初始化结束
  
}
//+------------------------------------------------------------------+
//| EA去初始化函数                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(iMA_handle);                             //删除指标句柄并释放分配给它的存储空间
   ArrayFree(iMA_buf);                                      //释放动态数组iMA_buf的数据
   ArrayFree(Close_buf);                                    //释放动态数组Close_buf的数据
  
}
//+------------------------------------------------------------------+
//| EA的tick函数                                                      |
//+------------------------------------------------------------------+
void OnTick()
  {
   int err1=0;                                             //用于存储指标缓存处理结果的变量
   int err2=0;                                             //用于存储价格图表处理结果的变量
   
   err1=CopyBuffer(iMA_handle,0,1,2,iMA_buf);               //将数据从指标数组中拷贝到动态数组iMA_buf中,用于进一步处理
   err2=CopyClose(my_symbol,my_timeframe,1,2,Close_buf);    //将价格图表数据拷贝到动态数Close_buf中,用于进一步处理
   if(err1<0 || err2<0)                                    //如果出错
   {
      Print("Failed to copy data from the indicator buffer or price chart buffer");  //打印相关错误信息到日志文件
      return;                                                               //并退出函数
   
}

   if(iMA_buf[1]>Close_buf[1] && iMA_buf[0]<Close_buf[0])   //如果指标值大于收盘价并且开始变小
     {
      if(m_Position.Select(my_symbol))                     //如果该交易品种的持仓已经存在
        {
         if(m_Position.PositionType()==POSITION_TYPE_SELL) m_Trade.PositionClose(my_symbol);  //并且这是一个卖出持仓,那么平仓
         if(m_Position.PositionType()==POSITION_TYPE_BUY) return;                              //或者,如果是一个买入持仓,那么退出
        
}
      m_Trade.Buy(0.1,my_symbol);                          //如果到这里,说明没有持仓;那么我们开仓
     
}
   if(iMA_buf[1]<Close_buf[1] && iMA_buf[0]>Close_buf[0])  //如果指标值小于收盘价并且在变大
     {
      if(m_Position.Select(my_symbol))                     //如果该交易品种的持仓已经存在
        {
         if(m_Position.PositionType()==POSITION_TYPE_BUY) m_Trade.PositionClose(my_symbol);   //并且这是一个买入持仓,那么平仓
         if(m_Position.PositionType()==POSITION_TYPE_SELL) return;                             //或者,如果这是一个卖出持仓,那么退出
        
}
      m_Trade.Sell(0.1,my_symbol);                         //如果我们到这里,说明没有持仓;那么我们开仓
     
}
  
}
//+------------------------------------------------------------------+

我们如下利用相关参数对“EA 交易”进行测试:

  • 交易品种 - 欧元兑美元
  • 时间表 - H1
  • 交易模式“仅开盘价”。 

因为我们从第一柱(零柱为当前、活动柱)开始使用指标值与收盘价,所以此图表不会重绘。也就是说,我们可以使用“仅开盘价”交易模式。它不会影响到测试质量,却会令运行加快。

而这里则是采用历史数据的快速测试结果。

我们的“EA 交易”测试结果
   图 6. 我们的“EA 交易”测试结果

赔损当然不能被忽略。但是,本文主旨并不是要编写一个拥有超大利润潜力和极低赔损的“超级‘EA 交易’”,而是要说明一个掌握基础知识的人可以如何轻松地制作一个“EA 交易”。
我们已经完成了由不到一百行代码所构成的“EA 交易”。
 

总结

本文讲到了编制“EA 交易”程序时要考虑到的主要原则。通过学习,我们已经知道了如何使用 MetaEditor 5 中的内置上下文“帮助”来获取各个函数的相关信息,了解了订单和持仓的总体概念,而且掌握了标准库的使用。

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/496

附加的文件 |
MQL5 中的交易操作 - 很简单 MQL5 中的交易操作 - 很简单

几乎所有的交易者都是为了赚钱而进入市场,但也有一些交易者却是享受交易过程的本身。然而,并不是只有手动交易才能给您兴奋的体验。自动化交易系统开发也可以让您欲罢不能。创建一个交易机器人,可以像读一本出色的悬疑小说一样有趣。

MQL5 快速上手 MQL5 快速上手

您已决定学习 MQL5 交易策略的编程语言,但却对其一无所知?我们尝试从新人的视角来看待 MQL5 和 MetaTrader 5 终端,并撰写了此篇简短的介绍性文章。本文中简要地讲述了该语言的多种可能性,还包含有关使用 MetaEditor 5 及此终端的一些小贴士。

MQL5 Cookbook: 交易历史和取得仓位信息的函数库 MQL5 Cookbook: 交易历史和取得仓位信息的函数库

现在是时候简单总结一下之前关于仓位属性文章的内容了,在本文中,我们会额外创建几个函数来取得只能通过访问交易历史才能获得的属性,我们也会对数据结构更加熟悉,这使我们可以用更加方便的方法访问仓位和交易品种属性。

MQL5 Cookbook: 在EA交易中使用指标来设置交易条件 MQL5 Cookbook: 在EA交易中使用指标来设置交易条件

在本文中,我们将继续修改之前在MQL5 Cookbook系列文章中的EA交易,这一次,EA交易将进一步增强,使用指标来检查建仓条件。为了增加点乐趣,我们会在外部参数中创建一个下拉列表,可以从三个交易指标中选择一个。