简介
|
标识符 |
说明 |
属性类型 |
SYMBOL_MARGIN_LONG |
买入持仓预付款收取率 |
双精度 |
SYMBOL_MARGIN_SHORT |
卖出持仓预付款收取率 |
双精度 |
SYMBOL_MARGIN_LIMIT |
限价订单预付款收取率 |
双精度 |
SYMBOL_MARGIN_STOP |
止损订单预付款收取率 |
双精度 |
SYMBOL_MARGIN_STOPLIMIT |
限价止损订单预付款收取率 |
双精度 |
您可以使用下述简单代码获取这些系数的值:
//--- 计算不同类型订单的预付款率 PrintFormat("即时买入订单所需要的预付款率等于 %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_LONG)); PrintFormat("即时卖出订单所需要的预付款率等于 %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_SHORT)); PrintFormat("限价订单所需要的预付款率等于 %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_LIMIT)); PrintFormat("止损订单所需要的预付款率等于 %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_STOP)); PrintFormat("止损限价订单所需要的预付款率等于 %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_STOPLIMIT));
对于 Forex 交易品种,挂单的预付款收取率通常等于 0,即对挂单没有预付款要求。
Check_Money.mq5 脚本执行结果。
取决于预付款收取的方式,如果挂单有预付款要求,资金管理系统以及交易系统自身可能存在某些限制。这就是这些参数同样还是“EA 交易”操作天然限制的原因。
当设置了止损位时,要做好其触发的准备。应将资金潜在损失的风险考虑在内;而 OrderCalcProfit() 正是基于此目的。该函数与我们之前讨论过的 OrderCalcMargin() 函数极为相似,但前者要求开盘价和收盘价均用于计算。
指定 ENUM_ORDER_TYPE 枚举的两个值的其中之一作为首个参数 - ORDER_TYPE_BUY 或 ORDER_TYPE_SELL;其他订单类型将会引发错误。在最后一个参数中,您应通过引用传递一个 OrderCalcProfit() 函数在成功执行后将会将盈利/损失值写入其中的变量。
通过指定的进入和退出位关闭买入持仓时,使用 CalculateProfitOneLot() 函数计算盈利或损失的示例:
//+------------------------------------------------------------------+ //| 计算买入一手的潜在利润/亏损 | //+------------------------------------------------------------------+ double CalculateProfitOneLot(double entry_price,double exit_price) { //--- 取得利润值的变量 double profit=0; if(!OrderCalcProfit(ORDER_TYPE_BUY,Symbol(),1.0,entry_price,exit_price,profit)) { Print(__FUNCTION__," 计算 OrderCalcProfit() 失败. 错误 ",GetLastError()); } //--- return(profit); }
该函数的计算结果如图所示。
使用 OrderCalcProfit() 函数计算和在图表上显示潜在损失的示例。
完整的代码请见随附的“EA 交易”CalculateProfit_EA.mq5。
许多交易系统的开发假设仅在出现新柱时计算交易信号;且所有的交易操作仅执行一次。MetaTrader 5 客户端中策略测试程序的“仅开盘价”模式对检查此类自动交易系统大有裨益。
在“仅开盘价”模式下,测试时“EA 交易”中指标的所有计算和 OnTick() 函数的调用仅执行一次/柱。这是最快的交易模式;并且通常是对轻微的价格波动最具容错性的交易系统创建方式。当然,“EA 交易”中使用的指标也应正确编写,并在新柱出现时不应扭曲指标的值。
“仅开盘价”模式的策略测试程序可消除您对“EA 交易”每柱仅启动一次的担忧;并且该测试程序使用极为方便。然而,如果在模拟或真实帐户上以实时模式工作时,交易人员应控制“EA 交易”的行为,使其针对每个接收到的信号仅执行一次交易操作。实现此目的最简单的方式是追踪当前未形成柱的开启。
要获取最后一个柱的开启时间,您应使用 SeriesInfoInteger() 函数及指定的信号名称、时间表和 SERIES_LASTBAR_DATE 属性。通过将当前柱的开启时间不断地与存储在变量中的柱进行比较,您很容易检测到新柱出现的时间。这允许您创建如下所示的自定义函数 isNewBar():
//+------------------------------------------------------------------+ //| 如果在交易品种/周期中出现新柱 | //+------------------------------------------------------------------+ bool isNewBar() { //--- 在静态变量中记录上一个柱的开启时间 static datetime last_time=0; //--- 当前时间 datetime lastbar_time=SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE); //--- 如果是第一次调用此函数 if(last_time==0) { //--- 设置时间并退出 last_time=lastbar_time; return(false); } //--- 如果时间不同 if(last_time!=lastbar_time) { //--- 记录时间并返回true last_time=lastbar_time; return(true); } //--- 如果我们运行到这一行,说明柱不是新的,返回false return(false); }
函数的使用示例在随附的“EA 交易”CheckLastBar.mq5 中给出。
有关新柱在 M1 时间表中出现的 CheckLastBar“EA 交易”消息。
如果您需要限制在一个帐户中可同时出现的活动挂单的数量,您可以编写您自己的自定义函数来达到目的。我们将此函数命名为 IsNewOrderAllowed();它将检查是否允许下达挂单。编写此函数时请遵从“自动交易锦标赛”的规则。
//+------------------------------------------------------------------+ //| 检查是否允许新开订单 | //+------------------------------------------------------------------+ bool IsNewOrderAllowed() { //--- 得到一个账户允许的最大挂单数 int max_allowed_orders=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); //--- 如果没有限制,返回true,您可以发送一个订单 if(max_allowed_orders==0) return(true); //--- 如果我们运行到这一行,说明有限制,检测已经有多少个活动订单 int orders=OrdersTotal(); //--- 返回比较结果 return(orders<max_allowed_orders); }
函数十分简单:获取允许的订单数量至 max_allowed_orders 变量;并且如果其值不等于零,则与 当前订单数量进行比较。然而,此函数未考虑另一可能的限制 - 具体交易品种允许的开仓和挂单的总量的限制。
要获得具体交易品种的开仓的大小,您应使用 PositionSelect() 函数选择一个持仓。仅在该步骤之后,您才可以使用 PositionGetDouble() 请求开仓的交易量;函数返回具有双精度型的选定持仓的各种属性。现在我们将编写 PostionVolume() 函数以获取指定交易品种的持仓量。
//+------------------------------------------------------------------+ //| 返回指定交易品种的持仓大小 | //+------------------------------------------------------------------+ double PositionVolume(string symbol) { //--- 选择交易品种的一个仓位 bool selected=PositionSelect(symbol); //--- 仓位存在 if(selected) //--- 返回仓位大小 return(PositionGetDouble(POSITION_VOLUME)); else { //--- 报告选择仓位失败的信息 Print(__FUNCTION__," 执行PositionSelect()失败, 交易品种 ", symbol," 错误 ",GetLastError()); return(-1); } }
在为某个交易品种下达挂单 发出交易请求前,应检查该交易品种的开仓和挂单的总量限制 - SYMBOL_VOLUME_LIMIT。如果没有限制,则挂单量不能超出可使用 SymbolInfoDouble() 量接收的最大允许量。
double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT); if(max_volume==0) volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
然而,此方法未考虑指定交易品种的当前挂单量。让我们编写一个计算该值的函数:
//+------------------------------------------------------------------+ //| 返回指定交易品种的持仓大小 | //+------------------------------------------------------------------+ double PositionVolume(string symbol) { //--- 根据交易品种选择仓位 bool selected=PositionSelect(symbol); //--- 仓位存在 if(selected) //--- 返回仓位大小 return(PositionGetDouble(POSITION_VOLUME)); else { //--- 如果没有仓位则返回0 return(0); } }
在将开仓量和挂单量纳入考虑后,最终检查代码如下所示:
//+------------------------------------------------------------------+ //| 返回一个交易品种允许的最大新开订单交易量 | //+------------------------------------------------------------------+ double NewOrderAllowedVolume(string symbol) { double allowed_volume=0; //--- 取得订单最大交易量的限制 double symbol_max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); //--- 取得交易品种最大交易量限制 double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT); //--- 取得交易品种的持仓量 double opened_volume=PositionVolume(symbol); if(opened_volume>=0) { //--- 如果我们已经用完了可用的订单量 if(max_volume-opened_volume<=0) return(0); //--- 持仓量没有超过 max_volume double orders_volume_on_symbol=PendingsVolume(symbol); allowed_volume=max_volume-opened_volume-orders_volume_on_symbol; if(allowed_volume>symbol_max_volume) allowed_volume=symbol_max_volume; } return(allowed_volume); }
包含在本节中述及的该函数的 Check_Order_And_Volume_Limits.mq5“EA 交易”的完整代码随附于本文。
“2010 自动交易锦标赛”某参赛者帐户使用 Check_Order_And_Volume_Limits“EA 交易”的检查示例。
交易机器人的一个重要部分是选择正确的交易量执行交易操作的能力。在这里,我们并非是要探讨资金管理系统和风险管理系统,而是讨论针对相应交易品种属性的正确交易量。
标识符 |
说明 |
属性类型 |
SYMBOL_VOLUME_MIN |
最小交易量 |
双精度 |
SYMBOL_VOLUME_MAX |
最大交易量 |
双精度 |
SYMBOL_VOLUME_STEP |
交易执行的最小量更改步骤 |
双精度 |
要进行该验证,我们可以编写自定义函数 CheckVolumeValue():
//+------------------------------------------------------------------+ //| 检查订单量的正确性 | //+------------------------------------------------------------------+ bool CheckVolumeValue(double volume,string &description) { //--- 交易操作中允许的最小订单量 double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN); if(volume<min_volume) { description=StringFormat("交易量小于允许的最小值 SYMBOL_VOLUME_MIN=%.2f",min_volume); return(false); } //--- 交易操作中允许的最大订单量 double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); if(volume>max_volume) { description=StringFormat("交易量大于允许的最大值 SYMBOL_VOLUME_MAX=%.2f",max_volume); return(false); } //--- 取得交易量允许的最小改变步长 double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP); int ratio=(int)MathRound(volume/volume_step); if(MathAbs(ratio*volume_step-volume)>0.0000001) { description=StringFormat("交易量不是最小步长的倍数 SYMBOL_VOLUME_STEP=%.2f, 最接近的正确交易量是 %.2f", volume_step,ratio*volume_step); return(false); } description="正确的交易量 "; return(true); }
您可以使用本文随附的 CheckVolumeValue.mq5 脚本检查该函数的运行。
检查量是否正确的 CheckVolumeValue.mq5 的消息。
本文论述了对使用“EA 交易”的可能限制的基本验证,这些在创建自己的自动交易系统时可能会碰到。文中的示例并未涵盖在交易帐户上操作“EA 交易”的过程中应检查的所有可能情形。我希望这些示例可以帮助初学者理解如何以 MQL5 语言实施最常用的验证。
|