MQL5 中的交易操作 - 很简单

MetaQuotes | 24 十月, 2013

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

开发某种交易算法的过程中,我们必须要处理大量的技术问题,其中就包括几个最重要的问题:

  1. 交易什么?
  2. 何时交易?
  3. 如何交易?

我们需要回答第一个问题以选择最适合的交易品种。我们的选择可能会受到多种因素的影响,其中包括将我们的市场交易系统自动化的能力。第二个问题涉及对清楚指明交易方向以及进场与出场点的交易规则的详尽阐述。第三个问题看起来相对简单:如何利用某种明确的编程语言买入和卖出?

本文中,我们会研究如何利用采用 MQL5 语言的算法交易实现交易操作。


MQL5 算法交易专用功能

MQL5 是一种交易策略的编程语言,拥有大量操作订单、持仓和交易请求的交易函数。因此,对于开发人员来讲,在 MQL5 中制作算法交易最省时省力了。

MQL5 功能允许您制作一个交易请求,并利用 OrderSend()OrderSendAsync() 函数将其发送到服务器,接收其处理结果,查看交易历史,检查某交易品种的交易一览表,处理某个交易事件,以及接收其它必要数据。

此外,MQL5 亦可用于编写自定义技术指标和应用已经实现的指标,绘制某图表上的符号和对象,设计自定义用户界面等。多篇文章中都能找到实现示例。


交易操作:简单得很!

您的交易机器人中,有下述几种基本的交易操作类型必不可少:

  1. 当前价格买入/卖出,
  2. 根据某种特定情况下买入/卖出的挂单,
  3. 修改/删除某挂单,
  4. 平仓/增持/减持/反向开仓。

上述所有操作均采用 OrderSend() 函数执行。还有一个名为 OrderSendAsync() 的异步版本。所有的交易操作种类均通过 MqlTradeRequest 结构描述,其中包含一个交易请求描述。因此,处理交易操作时,也只有正确填写 MqlTradeRequest 结构和处理请求执行结果有点难度了。

根据您的交易系统,您可以市价买入或卖出(BUY 或SELL),也可与当前市价保持一段距离下买入/卖出挂单:

上述标准的订单类型对应着 ENUM_ORDER_TYPE 枚举。



您可能需要修改或删除某挂单。也可以利用 OrderSend()/OrderSendAsync() 函数来完成。修改某个持仓也是非常简单的一个过程,因为它也采用相同的交易操作来完成。

如果您认为交易操作复杂难懂,现在该改变想法了。我们不仅会讲述如何在 MQL5 中快速轻松地实现买入和卖出编码,还会教给您如何使用交易账户和交易品种的属性。交易类会帮助我们完成这一任务。


利用 CAccountInfo 检查您的交易账户

启动您的交易机器人后,您需要了解的第一件事,就是其操作使用什么交易账户。因为我们在编写一段培训代码,所以我们针对在真实账户上启动“EA 交易”的情况实施一次检验。

CAccountInfo 类用于操作某账户。我们会添加 AccountInfo.mqh 文件包含,并声明此类的变量 - account

#include <Trade\AccountInfo.mqh>
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 处理帐户的对象
   CAccountInfo account;
//--- 接收EA交易系统所运行帐户的账号
   long login=account.Login();
   Print("Login=",login);
//--- 声明帐户类型
   ENUM_ACCOUNT_TRADE_MODE account_type=account.TradeMode();
//--- 如果是实盘账户,立即停止EA交易!
   if(account_type==ACCOUNT_TRADE_MODE_REAL)
     {
      MessageBox("Trading on a real account is forbidden, disabling","The Expert Advisor has been launched on a real account!");
      return(-1);
     
}
//--- 显示帐户类型    
   Print("Account type: ",EnumToString(account_type));
//--- 声明我们可以在此帐户上进行交易
   if(account.TradeAllowed())
      Print("Trading on this account is allowed");
   else
      Print("Trading on this account is forbidden: you may have entered using the Investor password");
//--- 声明我们可以在此帐户上用EA交易
   if(account.TradeExpert())
      Print("Automated trading on this account is allowed");
   else
      Print("Automated trading using Expert Advisors and scripts on this account is forbidden");
//--- 声明已经设置了允许的订单数量
   int orders_limit=account.LimitOrders();
   if(orders_limit!=0)Print("Maximum permissible amount of active pending orders: ",orders_limit);
//--- 显示公司和服务器名称
   Print(account.Company(),": server ",account.Server());
//--- 最后显示帐户的结余和当前利润
   Print("Balance=",account.Balance(),"  Profit=",account.Profit(),"   Equity=",account.Equity());
   Print(__FUNCTION__,"  completed"); //---
   return(0);
  
}
//+------------------------------------------------------------------+
//| EA交易去初始化函数                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  
}
//+------------------------------------------------------------------+
//| EAtick函数                                                        |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  
}

通过上面的代码我们可以看出,可以利用 OnInit() 函数中的 account 变量接收大量有用数据。您可以将此代码添加到您的“EA 交易”,以在分析其操作时轻松检查日志。

下面展示的是“2012 自动交易锦标赛”上推出的某“EA 交易”的结果。



利用 CSymbolInfo 接收交易品种设置

现在,我们的账户上已经有数据,但在执行必要的操作之前,我们还需要了解想要交易的交易品种的属性。带有大量方法的 CSymbolInfo专为上述用途而设计。我们仅于下方示例中展示一小部分方法。

#include<Trade\SymbolInfo.mqh>
//+------------------------------------------------------------------+
//| EA初始化函数                                                      |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 接收交易品种设置参数的对象
   CSymbolInfo symbol_info;
//--- 为合适的交易品种设置名称
   symbol_info.Name(_Symbol);
//--- 接受当前价格相关信息并显示
   symbol_info.RefreshRates();
   Print(symbol_info.Name()," (",symbol_info.Description(),")",
         "  Bid=",symbol_info.Bid(),"   Ask=",symbol_info.Ask());
//--- 接收交易操作的最小冻结水平
   Print("StopsLevel=",symbol_info.StopsLevel()," pips, FreezeLevel=",
         symbol_info.FreezeLevel()," pips");
//--- 接收小数位数和点值
   Print("Digits=",symbol_info.Digits(),
         ", Point=",DoubleToString(symbol_info.Point(),symbol_info.Digits()));
//--- 点差信息
   Print("SpreadFloat=",symbol_info.SpreadFloat(),", Spread(current)=",
         symbol_info.Spread()," pips");
//--- 请求限价订单的执行类型
   Print("Limitations for trade operations: ",EnumToString(symbol_info.TradeMode()),
         " (",symbol_info.TradeModeDescription(),")");
//--- 声明交易执行模式
   Print("Trades execution mode: ",EnumToString(symbol_info.TradeExecution()),
         " (",symbol_info.TradeExecutionDescription(),")");
//--- 声明合约价格计算方法
   Print("Contract price calculation: ",EnumToString(symbol_info.TradeCalcMode()),
         " (",symbol_info.TradeCalcModeDescription(),")");
//--- 合约大小
   Print("Standard contract size: ",symbol_info.ContractSize(),
         " (",symbol_info.CurrencyBase(),")");
//--- 交易操作的最小和最大交易量
   Print("Volume info: LotsMin=",symbol_info.LotsMin(),"  LotsMax=",symbol_info.LotsMax(),
         "  LotsStep=",symbol_info.LotsStep());
//--- 
   Print(__FUNCTION__,"  completed");
//---
   return(0);
  
}
//+------------------------------------------------------------------+
//| EA交易去初始化函数                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  
}
//+------------------------------------------------------------------+
//| EA的tick函数                                                      |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  
}

“自动交易锦标赛”的欧元兑美元属性显示如下。现在,我们已经做好交易操作的准备了。



CTrade - 方便交易操作的类

MQL5 中的交易仅通过两个函数执行 - OrderSend() 和 OrderSendAsync()。实际上,是一个函数的两个实现。OrderSend() 会发送一个交易请求并等待其执行结果,而异步的 OrderSendAsync() 则只发送一个请求,允许应用程序在不等待交易服务器回复的情况下继续其操作。因此,MQL5 中的交易真的很简单,因为针对所有交易操作,您只使用一个函数即可。

那么,有什么挑战呢?两个函数都会接收 MqlTradeRequest 结构,而后者包含作为第一个参数的十多个字段。并非所有字段都必须填写。至于哪组必须填写,则取决于交易操作类型。必填项中填入不当值或字段留空,会导致错误,且该请求不被发送到服务器。其中有 5 个字段需要源于预定义枚举的正确值。

对于描述一个交易请求中的大量订单属性而言,如此众多的字段是完全必要的。订单可能会根据执行政策、到期时间及其它某些参数而有所变化。但是您无需掌握其全部的微妙细节。使用即用型 CTrade 类即可。下面是在您的交易机器人中使用此类的方式:

#include<Trade\Trade.mqh>
//--- 执行交易操作的对象
CTrade  trade;
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 设置MagicNumber来识别你的订单
   int MagicNumber=123456;
   trade.SetExpertMagicNumber(MagicNumber);
//--- 当买/卖时,设置可用滑点
   int deviation=10;
   trade.SetDeviationInPoints(deviation);
//--- 订单填充模式,要使用服务器允许的模式
   trade.SetTypeFilling(ORDER_FILLING_RETURN);
//--- 日志模式:最好不要声明这个方法,类会自动选择最佳模式。
   trade.LogLevel(1); 
//--- 哪个函数用来交易:true  - OrderSendAsync(), false - OrderSend()
   trade.SetAsyncMode(true);
//---
   return(0);
  
}

现在,我们来看看交易操作中 CTrade 如何发挥其辅助作用。

当前价格买入/卖出

交易策略通常会提供当下以时价买入或卖出的可能性。这种情况下,CTrade 只要求指定一个必要的交易操作数量。所有其它参数(开盘价与交易品种名称、“止损”与“获利”价位、订单备注)均为可选。

//--- 1. 在当前交易品种上进行买入的例子
   if(!trade.Buy(0.1))
     {
      //--- 报错信息
      Print("Buy() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("Buy() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

默认情况是,如果未指定交易品种名称,则 CTrade 会使用图表的交易品种名称。对于简单的策略来说,这样很方便。至于多货币策略,您始终都应该明确地指明交易品种 - 此交易操作将执行的对象。

//--- 2. 在指定交易品种上进行买入的例子
   if(!trade.Buy(0.1,"GBPUSD"))
     {
      //--- 报错信息
      Print("Buy() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("Buy() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

所有订单参数均可指明:“止损”/“获利”价位、开盘价及备注。

//--- 3. 指定交易品种和指定获利止损的买入例子
   double volume=0.1;         // 指定交易量
   string symbol="GBPUSD";    //指定交易操作的交易品种
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // 小数位数
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // 点值
   double bid=SymbolInfoDouble(symbol,SYMBOL_BID);             // 平买入持仓的当前价格
   double SL=bid-1000*point;                                   // 未标准化的止损值
   SL=NormalizeDouble(SL,digits);                              // 标准化止损
   double TP=bid+1000*point;                                   // 未标准化的获利值
   TP=NormalizeDouble(TP,digits);                              // 标准化获利
//--- 接收买入持仓的当前开仓价
   double open_price=SymbolInfoDouble(symbol,SYMBOL_ASK);
   string comment=StringFormat("Buy %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(open_price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
   if(!trade.Buy(volume,symbol,open_price,SL,TP,comment))
     {
      //--- 报错信息
      Print("Buy() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("Buy() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

我们说过,Magic Number (魔术数字)和允许的变量均在 Ctrade 复本初始化时设置。因此,它们不是必填项。但是如有必要,也要在每个交易操作之前设置。

下一个限价单

相应的 BuyLimit()SellLimit() 类方法用于发送一个限价单。大多数情况下,精简版本(只指定一个开盘价和一个数量)即可。Buy Limit 的开盘价应低于时价,而 Sell Limit 的开盘价则应高于时价。这些订单用于以最优价格进入市场,通常最适用于那些预期价格由支撑线反弹的策略。某“EA 交易”借以启动的交易品种就用于这种情况:

//--- 1. 下买入限价挂单的例子
   string symbol="GBPUSD";    // 指定下单的交易品种
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // 小数位数
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // 点值
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // 当前买入价
   double price=1000*point;                                   // 未标准化的开盘价
   price=NormalizeDouble(price,digits);                       // 标准化开盘价
//--- 一切准备就绪,将买入限价挂单发送到服务器
   if(!trade.BuyLimit(0.1,price))
     {
      //--- 报错信息
      Print("BuyLimit() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("BuyLimit() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

也可以使用指定所有参数的详细版本:SL/TP 价位、到期时间、交易品种名称以及订单备注。

//--- 2. 下指定所有参数的买入限价挂单的例子
   double volume=0.1;
   string symbol="GBPUSD";    // 指定下单的交易品种
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // 小数位数
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // 点值
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // 当前买入价
   double price=1000*point;                                 // 未标准化的开盘价
   price=NormalizeDouble(price,digits);                      // 标准化开盘价
   int SL_pips=300;                                         // 止损点数
   int TP_pips=500;                                         // 获利点数
   double SL=price-SL_pips*point;                           // 未标准化的止损值
   SL=NormalizeDouble(SL,digits);                            // 标准化止损
   double TP=price+TP_pips*point;                           // 未标准化的获利值
   TP=NormalizeDouble(TP,digits);                            // 标准化获利
   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);
   string comment=StringFormat("Buy Limit %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
//--- 一切准备就绪,将买入限价挂单发送到服务器
   if(!trade.BuyLimit(volume,price,symbol,SL,TP,ORDER_TIME_GTC,expiration,comment))
     {
      //--- 报错信息
      Print("BuyLimit() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("BuyLimit() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

在第二个版本中,您的任务是正确指明 SL 和 TP 价位。应注意的是:买入时“获利”价位必须高于开盘价,而“止损”价位则必须低于开盘价。Sell Limit 订单则情况相反。在根据历史数据测试“EA 交易”时,您可以轻松获知您的错误。这种情况下,CTrade 类会自动显示信息(除非您已调用 LogLevel 函数)。

下一个止损单

类似的 BuyStop()SellStop() 方法则被用于发送一个止损单。Buy Stop 的开盘价应高于时价,而 Sell Stop 的开盘价则应低于时价。止损单用于突破阻力价位期间进入市场的策略,以及减少亏损。简单版本:

//--- 1. 下买入停止挂单的例子
   string symbol="USDJPY";    // 指定下单的交易品种
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // 小数位数
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // 点值
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // 当前买入价
   double price=1000*point;                                    // 未标准化的开盘价
   price=NormalizeDouble(price,digits);                        // 标准化开盘价
//--- 一切准备就绪,将买入停止挂单发送到服务器 
   if(!trade.BuyStop(0.1,price))
     {
      //--- 报错信息
      Print("BuyStop() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("BuyStop() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

应为 Buy Stop 挂单指定最大数量参数的详细版本:

//--- 2. 下指定所有参数的买入停止挂单的例子
   double volume=0.1;
   string symbol="USDJPY";    // 指定下单的交易品种
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); // 小数位数
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);         // 点值
   double ask=SymbolInfoDouble(symbol,SYMBOL_ASK);             // 当前买入价
   double price=1000*point;                                   // 未标准化的开盘价
   price=NormalizeDouble(price,digits);                       // 标准化开盘价
   int SL_pips=300;                                          // 止损点数
   int TP_pips=500;                                          // 获利点数
   double SL=price-SL_pips*point;                            // 未标准化的止损值
   SL=NormalizeDouble(SL,digits);                             // 标准化止损
   double TP=price+TP_pips*point;                            // 未标准化的获利值
   TP=NormalizeDouble(TP,digits);                             // 标准化获利
   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);
   string comment=StringFormat("Buy Stop %s %G lots at %s, SL=%s TP=%s",
                               symbol,volume,
                               DoubleToString(price,digits),
                               DoubleToString(SL,digits),
                               DoubleToString(TP,digits));
//--- 一切准备就绪,将买入停止挂单发送到服务器 
   if(!trade.BuyStop(volume,price,symbol,SL,TP,ORDER_TIME_GTC,expiration,comment))
     {
      //--- 报错信息
      Print("BuyStop() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("BuyStop() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

相应的 CTrade 类方法被用于发送 Sell Stop 订单。在这里,至关重要的就是正确地指定价格。

操作持仓

您可以使用开仓方法替代 Buy() 和 Sell() 方法,但这种情况下,您必须得指定更多的详情:

//--- 小数位数
   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
//--- 点值
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
//--- 接收买入价格
   double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
//--- 计算并标准化止损和获利
   double SL=NormalizeDouble(price-1000*point,digits);
   double TP=NormalizeDouble(price+1000*point,digits);
//--- 填充备注
   string comment="Buy "+_Symbol+" 0.1 at "+DoubleToString(price,digits);
//--- 一切就绪,尝试建立买入持仓
   if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,0.1,price,SL,TP,comment))
     {
      //--- 报错信息
      Print("PositionOpen() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("PositionOpen() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

您只需指定一个交易品种名称,剩下的全由 CTrade 类完成。

//--- 当前交易品种平仓
   if(!trade.PositionClose(_Symbol))
     {
      //--- 报错信息
      Print("PositionClose() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("PositionClose() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

而修改持仓则只有“止损”和“获利”价位可用。利用 PositionModify() 方法来完成

//--- 小数位数
   int    digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
//--- 点值
   double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
//--- 获取当前卖价
   double price=SymbolInfoDouble(_Symbol,SYMBOL_BID);
//--- 计算并标准化止损和获利
   double SL=NormalizeDouble(price-1000*point,digits);
   double TP=NormalizeDouble(price+1000*point,digits);
//--- 一切就绪,尝试修改买入持仓
   if(!trade.PositionModify(_Symbol,SL,TP))
     {
      //--- 报错信息
      Print("Метод PositionModify() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("PositionModify() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

修改和删除订单

OrderModify() 方法已于 CTrade 类中实现以更改挂单的参数。所需的所有参数均须提交给此方法。

//--- 这只是一个订单号的例子,它应该获取而得
   ulong ticket=1234556;
//--- 这是一个交易品种的例子,它应该获取而得
   string symbol="EURUSD";
//--- 小数位数
   int    digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
//--- 点值
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
//--- 接收买入价格
   double price=SymbolInfoDouble(symbol,SYMBOL_ASK);
//--- 计算并标准化止损和获利
//--- 它们应该基于订单类型计算而得
   double SL=NormalizeDouble(price-1000*point,digits);
   double TP=NormalizeDouble(price+1000*point,digits);
   //--- 将挂单的生命周期设置为1天
   datetime expiration=TimeTradeServer()+PeriodSeconds(PERIOD_D1);   
//--- 一切就绪,尝试修改持仓 
   if(!trade.OrderModify(ticket,price,SL,TP,ORDER_TIME_GTC,expiration))
     {
      //--- 报错信息
      Print("OrderModify() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("OrderModify() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

您应接收待更改的订单的标签。根据类型指定正确的“止损”和“获利”价位。此外,新的开盘价亦应相对于时价正确。

您应识得某订单的某个标签,以将其删除:

//--- 这只是一个订单号的例子,它应该获取而得
   ulong ticket=1234556;
//--- 一切就绪,尝试修改买入持仓
   if(!trade.OrderDelete(ticket))
     {
      //--- 报错信息
      Print("OrderDelete() method failed. Return code=",trade.ResultRetcode(),
            ". Code description: ",trade.ResultRetcodeDescription());
     
}
   else
     {
      Print("OrderDelete() method executed successfully. Return code=",trade.ResultRetcode(),
            " (",trade.ResultRetcodeDescription(),")");
     
}

此类中还包含多用途的 OrderOpen() 方法,该方法可以设置任何类型的挂单。与 BuyLimitBuyStopSellLimit SellStop 这些专用方法不同,它要求指定更多的基本参数。您可能会觉得它更方便。


还有什么要解决的?

我们已经回答完了三个问题中的两个。您已经为您的策略选择了交易品种,我们也为您讲解了如何为买入和卖出操作、以及于某个交易机器人中的挂单轻松编码。而“交易类”章节中还有一些针对 MQL5 开发人员的有用工具:

有了这些类,您就可以将主要精力放在您策略(实现所有技术问题的最小化)的交易一面。此外,CTrade 类还可用于检查交易请求。经过一些练习之后,您就能用它来创建自己的、带有必要的处理交易请求执行结果逻辑的自定义类。

最后一个问题是如何在 MQL5 中接收交易信号以及如何编码。算法交易的大多数新人都会从学习简单的标准交易系统起步,比如说,基于移动平均线交叉的交易系统。想要如此,您应该先学习使用技术指标,在您的交易机器人中创建和使用它们。

我们建议您从头到尾阅读指标以及示例->指标章节的文章。如此您就能够从最简单过渡到最复杂的内容。如果您想快速得到一个有关如何使用指标的想法,请参阅 给新手的 MQL5: 在“EA 交易”中使用技术指标的指南


让复杂的事情变得简单

在任何领域中,最开始的各种难题都会逐渐变成您熟于应对的最简单的问题。此处提供的交易机器人的开发方法,主要是针对新人,但许多经验丰富的开发人员也可能会从中找到有用的新东西。

MQL5 语言不仅为算法交易提供了无限的机遇,还允许每一个人都能以最简单最快速的方式来实现它们。使用“标准库”的交易类节省时间用于做更重要的事情,比如说,用于搜寻所有交易者永无休止问题的答案 - 趋势是什么,以及如何实时把握住它?

不久您就会发现,在 MQL5 中设计一个交易机器人,要比学习一门外语或追踪一个趋势简单多了!