MQL5 酷客宝典: 读取持有锁仓仓位的属性
简介
在 MetaTrader 5 终端中最近加入的功能可以双向开启订单,这种订单账户系统被称为锁仓。对这种订单系统的支持可以简单地把来自 MetaTrader 4 的交易算法迁移到版本5的平台上,并且享受到 MetaTrader 5 功能上的优势。取得 MetaTrader 5 中锁仓选项的更多信息, 请阅读文章 "MetaTrader 5 已具备锁仓账户系统"。
在本文中,我们将讨论合计仓位的属性,而这样的仓位正是锁仓系统的目标。
1. 锁仓仓位. 类型
锁仓(合计)仓位是一种市场上的仓位,它是由多个市场订单构成的。在狭义上,锁仓仓位包括不同方向(买入和卖出)上的订单,但是,我更倾向于在更广的范围内使用“锁仓”,在这里,锁仓仓位也可以由相同方向的订单组成,这种方法与 MetaTrader 5 终端的功能有关: 我们可以在一个方向上开启订单,也可在不同的方向。
有几种方法可以对合计仓位进行分类,也许最常用的标准是根据组成市场订单的类型进行划分。所以,什么样的订单可以构成这样的仓位呢?下面的表格 1 显示了不同的组合。
编号 | 类型 | 描述 |
---|---|---|
1 | Hedge buy(锁仓买入) | 只进行买入操作 |
2 | Hedge netting buy(锁仓净额买入) | 净额买入 |
3 | Hedge sell(锁仓卖出) | 只进行卖出操作 |
4 | Hedge netting sell(锁仓净额卖出) | 净额卖出 |
5 | Hedge locked(锁仓锁定) | 锁定(全部锁仓) |
表格 1. 锁仓类型
让我们简要解释一下这些类型,如果合计仓位只有买入或者只有卖出订单 (根据 MetaTrader 4 中采用的方式), 这个仓位就当成是锁仓买入或者锁仓卖出仓位。如果仓位中有不同的订单(买入和卖出都有), 我们将会确定哪种订单占优势,如果有更多的买入订单,仓位就会被判断为“锁仓净额买入”,如果由更多的卖出订单,这就是个“锁仓净额卖出”仓位。为了更加清晰,我们需要处理订单的交易量而不是它们的数量。假定,一个仓位有1个1.25手的买入订单和两个分别为0.5和0.6手的卖出订单,合计仓位将是交易量为0.15手的"锁仓净额买入"仓位。
1.25 – (0.5 + 0.6) = 0.15.
一种特殊的混合仓位是锁定,其中买入和卖出的交易量达到了平衡。
让我们把这些描述的锁仓类型使用下面的枚举来表示:
//+------------------------------------------------------------------+ //| 锁仓类型 | //+------------------------------------------------------------------+ enum ENUM_HEDGE_TYPE { HEDGE_BUY=0, // 买入 HEDGE_SELL=1, // 卖出 HEDGE_NETTING_BUY=2, // 净额买入 HEDGE_NETTING_SELL=3, // 净额卖出 HEDGE_LOCKED=4, // 锁定 };
在净额系统中的仓位也是合计的,只能是两种类型之一: 买入或者卖出。类型标识符是 ENUM_POSITION_TYPE 枚举中的数值之一:
1) POSITION_TYPE_BUY;
2) POSITION_TYPE_SELL.
在锁仓系统中,我们有五种类型的合计仓位,
在下一节,我们将创建一个类来处理锁仓仓位的属性。
2. CHedgePositionInfo 类
标准库中提供了 CPositionInfo 类, 它可以用于访问开启的市场仓位中的属性。对于我们的情况,我们会部分使用这个类,因为这个类处理的仓位将表现为一个独立的市场订单(对于 MetaTrader 4 来说)。我们需要一个类,它可以处理合计仓位(锁仓)中的所有仓位。
让我们使用 OOP (面向对象编程) 工具来创建 CHedgePositionInfo 类:
//+------------------------------------------------------------------+ //| Class CHedgePositionInfo | //| 目标: 用于访问锁仓仓位信息的类 | //| 派生于 CObject 类. | //+------------------------------------------------------------------+ class CHedgePositionInfo : public CObject { //--- === 数据成员 === --- private: ENUM_HEDGE_TYPE m_type; double m_volume; double m_price; double m_stop_loss; double m_take_profit; ulong m_magic; //--- 对象 CArrayLong m_tickets; CSymbolInfo m_symbol; CPositionInfo m_pos_info; //--- === 方法 === --- public: //--- 构造函数/析构函数 void CHedgePositionInfo(void){}; void ~CHedgePositionInfo(void){}; //--- 初始化 bool Init(const string _symbol,const ulong _magic=0); //--- get 方法 CSymbolInfo *Symbol(void) {return GetPointer(m_symbol);}; CArrayLong *HedgeTickets(void) {return GetPointer(m_tickets);}; CPositionInfo *PositionInfo(void) {return GetPointer(m_pos_info);}; ulong Magic(void) const {return m_magic;}; //--- 快速访问锁仓的整数属性的方法 datetime Time(void); ulong TimeMsc(void); datetime TimeUpdate(void); ulong TimeUpdateMsc(void); ENUM_HEDGE_TYPE HedgeType(void); //--- 快速访问锁仓的双精度浮点型属性的方法 double Volume(double &_buy_volume,double &_sell_volume); double PriceOpen(const ENUM_TRADE_TYPE_DIR _dir_type=TRADE_TYPE_ALL); double StopLoss(const ENUM_TRADE_TYPE_DIR _dir_type=TRADE_TYPE_ALL); double TakeProfit(const ENUM_TRADE_TYPE_DIR _dir_type=TRADE_TYPE_ALL); double PriceCurrent(const ENUM_TRADE_TYPE_DIR _dir_type=TRADE_TYPE_ALL); double Commission(const bool _full=false); double Swap(void); double Profit(void); double Margin(void); //--- 快速访问锁仓字符串型属性的方法 string TypeDescription(void); //--- 信息方法 string FormatType(string &_str,const uint _type) const; //--- 选择 bool Select(void); //--- 状态 void StoreState(void); bool CheckState(void); private: //--- 计算方法 bool AveragePrice( const SPositionParams &_pos_params, double &_avg_pr, double &_base_volume, double &_quote_volume ); int CheckLoadHistory(ENUM_TIMEFRAMES period,datetime start_date); }; //+------------------------------------------------------------------+
简单介绍一下类的数据成员。
首先,有一个唯一的交易品种名称,也就是说,锁仓仓位可以包含相同交易品种的任意仓位。交易品种是根据 m_symbol 栏位来判断的, 它代表 CSymbolInfo 类的样本。
第二,幻数 (m_magic) 可以用于过滤订单。过滤可以创建由一个EA交易所管理的仓位,这可以创建相同交易品种中的多个锁仓仓位。
还有一个动态数组用于订单的管理 (m_tickets),锁仓仓位订单的单号将会被加到这个数组中。
取得任意选定仓位属性(也就是以 MetaTrader 4 方式) 的功能是由 CPositionInfo 类实例 (m_pos_info) 来进行的,
其它的锁仓属性用于取得它的状态:
- 类型 (m_type);
- 交易量 (m_volume);
- 建仓价格 (m_price);
- 止损价格 (m_stop_loss);
- 获利价格 (m_take_profit).
类的构建是基于 CPositionInfo 类的逻辑的,这很自然。这也是为什么新的类中含有返回整数型属性、双精度型属性的方法等等,当然还会有特殊的方法。
2.1初始化方法
在使用类功能之前,我们需要初始化对应的实例。检查 EA 是否在锁仓系统条件下运行的方法以及所需交易品种是否被选中,还有幻数是否设置的方法。
//+------------------------------------------------------------------+ //| 初始化 | //+------------------------------------------------------------------+ bool CHedgePositionInfo::Init(const string _symbol,const ulong _magic=0) { //--- 账户预付款模式 ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); if(margin_mode!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) { Print(__FUNCTION__+": 不是锁仓模式!"); return false; } if(!m_symbol.Name(_symbol)) { Print(__FUNCTION__+": 交易品种没有被选择!"); return false; } ENUM_SYMBOL_CALC_MODE symbol_calc_mode=(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(_symbol,SYMBOL_TRADE_CALC_MODE); if(symbol_calc_mode!=SYMBOL_CALC_MODE_FOREX) { Print(__FUNCTION__+": 只用于外汇交易模式!"); return false; } m_magic=_magic; //--- return true; } //+------------------------------------------------------------------+
这个方法对于后续锁仓类所使用的功能是必需的,请注意,在方法中检查了预付款计算模式,如果它不是“锁仓”模式,方法就返回 false。还检查了协议计算方法,我们将只会操作外汇交易协议。
2.2整数型属性
整数型属性是使用下面的方法访问的:
- datetime Time(void);
- ulong TimeMsc(void);
- datetime TimeUpdate(void);
- ulong TimeUpdateMsc(void);
- ENUM_HEDGE_TYPE HedgeType(void).
这里是 CHedgePositionInfo::Time() 方法的代码:
//+------------------------------------------------------------------+ //| 取得锁仓开启的时间 | //+------------------------------------------------------------------+ datetime CHedgePositionInfo::Time(void) { datetime hedge_time=WRONG_VALUE; int hedge_pos_num=m_tickets.Total(); //--- 如果有仓位 if(hedge_pos_num>0) { //--- 找到第一个开启的仓位 for(int pos_idx=0;pos_idx<hedge_pos_num;pos_idx++) { ulong curr_pos_ticket=m_tickets.At(pos_idx); if(curr_pos_ticket<LONG_MAX) if(m_pos_info.SelectByTicket(curr_pos_ticket)) { datetime curr_pos_time=m_pos_info.Time(); if(curr_pos_time>0) { if(hedge_time==0) hedge_time=curr_pos_time; else { if(curr_pos_time<hedge_time) hedge_time=curr_pos_time; } } } } } //--- return hedge_time; } //+------------------------------------------------------------------+
为了取得锁仓开启的时间,也就是锁仓中第一个仓位实际开启的时间,我们需要遍历其中所有的仓位并找到最早 的一个。
为了取得锁仓改变的时间,例如最后改变的仓位的时间,我们需要稍微修改一下之前的方法:
//+------------------------------------------------------------------+ //| 取得锁仓更新的时间 | //+------------------------------------------------------------------+ datetime CHedgePositionInfo::TimeUpdate(void) { datetime hedge_time_update=0; int hedge_pos_num=m_tickets.Total(); //--- 如果有仓位 if(hedge_pos_num>0) { //--- 找到第一个开启的仓位 for(int pos_idx=0;pos_idx<hedge_pos_num;pos_idx++) { ulong curr_pos_ticket=m_tickets.At(pos_idx); if(curr_pos_ticket<LONG_MAX) if(m_pos_info.SelectByTicket(curr_pos_ticket)) { //--- 取得当前仓位的更新时间 datetime curr_pos_time_update=m_pos_info.TimeUpdate(); if(curr_pos_time_update>0) if(curr_pos_time_update>hedge_time_update) hedge_time_update=curr_pos_time_update; } } } //--- return hedge_time_update; } //+------------------------------------------------------------------+
这里是判断锁仓类型方法的代码:
//+------------------------------------------------------------------+ //| 取得锁仓类型 | //+------------------------------------------------------------------+ ENUM_HEDGE_TYPE CHedgePositionInfo::HedgeType(void) { ENUM_HEDGE_TYPE curr_hedge_type=WRONG_VALUE; int hedge_pos_num=m_tickets.Total(); //--- 如果有仓位 if(hedge_pos_num>0) { //--- 取得交易量 double total_vol,buy_volume,sell_volume; buy_volume=sell_volume=0.; total_vol=this.Volume(buy_volume,sell_volume); //--- 定义锁仓类型 if(buy_volume>0. && sell_volume>0.) { if(buy_volume>sell_volume) curr_hedge_type=HEDGE_NETTING_BUY; else if(buy_volume<sell_volume) curr_hedge_type=HEDGE_NETTING_SELL; else curr_hedge_type=HEDGE_LOCKED; } else if(buy_volume>0. && sell_volume==0.) curr_hedge_type=HEDGE_BUY; else if(buy_volume==0. && sell_volume>0.) curr_hedge_type=HEDGE_SELL; } //--- return curr_hedge_type; }; //+------------------------------------------------------------------+
锁仓类型依赖于买入和卖出交易量之间的差距。首先我们检查仓位是否是锁仓状态,如果买入和卖出的交易量是相等的,这就是一个完全的锁仓,如果它们不相等,就表示是一个部分锁仓。
然后我们检查仓位是包含不同方向上的交易量,即不仅仅是买入或者仅有卖出。
2.3双精度型属性
双精度型属性是使用下面的方法访问的:
- double Volume(double &_buy_volume,double &_sell_volume);
- double PriceOpen(void);
- double StopLoss(void);
- double TakeProfit(void);
- double PriceCurrent(void);
- double Commission(void);
- double Swap(void);
- double Profit(void);
- double Margin(void).
确定锁仓交易量的方法是使用引用型参数的,这种实现方法可以使我们立即取得锁仓交易量和它的组成部分(买入和卖出订单)的交易量。
//+------------------------------------------------------------------+ //| 取得锁仓交易量 | //+------------------------------------------------------------------+ double CHedgePositionInfo::Volume(double &_buy_volume,double &_sell_volume) { double total_vol=0.; int hedge_pos_num=m_tickets.Total(); //--- 如果有仓位 if(hedge_pos_num>0) { _buy_volume=_sell_volume=0.; //--- 取得买入/卖出交易量 for(int pos_idx=0;pos_idx<hedge_pos_num;pos_idx++) { ulong curr_pos_ticket=m_tickets.At(pos_idx); if(curr_pos_ticket<LONG_MAX) if(m_pos_info.SelectByTicket(curr_pos_ticket)) { ENUM_POSITION_TYPE curr_pos_type=m_pos_info.PositionType(); double curr_pos_vol=m_pos_info.Volume(); if(curr_pos_vol>0.) { //--- 对于一个买入仓位 if(curr_pos_type==POSITION_TYPE_BUY) _buy_volume+=curr_pos_vol; //--- 对于卖出仓位 else if(curr_pos_type==POSITION_TYPE_SELL) _sell_volume+=curr_pos_vol; } } } total_vol=_buy_volume-_sell_volume; } //--- return total_vol; } //+------------------------------------------------------------------+
辅助方法 CHedgePositionInfo::AveragePrice() 方法是创建用于处理价格属性的,这里是根据价格水平的类型来计算平均锁仓价格的代码块。
//--- 如果计算了锁仓交易量 if(hedge_base_volume!=0. && hedge_quote_volume!=0.) { _avg_pr=fabs(hedge_quote_volume/hedge_base_volume); _base_volume=hedge_base_volume; _quote_volume=hedge_quote_volume; return true; }
这里使用的是数值方法: 报价币别的最终锁仓数值与存款币别的最终锁仓数值的比例。
晚些时候我们将会在单独的例子中分析这样的计算。
隔夜息和利润的取得方法就是计算锁仓中每个仓位的对应变量的总和,再返回结果值。取得手续费的方法会分析参与建仓的交易,这里有参数可以选择如何计算手续费大小。使用默认值可以只根据入场交易计算手续费,如果入场和出场手续费都要计算,就把参数设为 true。但是,请注意后一个选项在实际中很少使用,有以下原因,首先,选择的仓位可以使用反向仓位关闭,这样,就会有 DEAL_ENTRY_OUT_BY类型的交易, 这样的交易不会收取手续费。第二,如果 账户币别和基础币别不符,入场和出场的花费在汇率改变的时候可能会不同。
//+------------------------------------------------------------------+ //| 取得锁仓的手续费 | //+------------------------------------------------------------------+ double CHedgePositionInfo::Commission(const bool _full=false) { double hedge_commission=0.; int hedge_pos_num=m_tickets.Total(); //--- 如果有仓位 if(hedge_pos_num>0) for(int pos_idx=0;pos_idx<hedge_pos_num;pos_idx++) { ulong curr_pos_ticket=m_tickets.At(pos_idx); if(curr_pos_ticket<LONG_MAX) if(m_pos_info.SelectByTicket(curr_pos_ticket)) { long curr_pos_id=m_pos_info.Identifier(); if(curr_pos_id>0) //--- 取得与所选仓位相关的交易历史 if(HistorySelectByPosition(curr_pos_id)) { CDealInfo curr_deal; int deals_num=HistoryDealsTotal(); for(int deal_idx=0;deal_idx<deals_num;deal_idx++) if(curr_deal.SelectByIndex(deal_idx)) { ENUM_DEAL_ENTRY curr_deal_entry=curr_deal.Entry(); if(curr_deal_entry==DEAL_ENTRY_IN) { double curr_deal_commission=NormalizeDouble(curr_deal.Commission(),2); if(curr_deal_commission!=0.) { double fac=1.; if(_full) fac=2.; hedge_commission+=(fac*curr_deal_commission); } } } } } } //--- return hedge_commission; } //+------------------------------------------------------------------+
类中包含 CHedgePositionInfo::Margin() 方法,它可以计算锁仓仓位的预付款数量。这个方法实际上很难编程,可以另写一篇独立的文章,来描述如何正确计算有开启仓位和挂单情况的预付款。
2.3.1锁仓仓位预付款
根据开发者的描述,有两种方法来未双向仓位计算保证金,使用的类型是由经纪商决定的。第一种方法使用的是基础计算,而第二种是根据大头计算的。
我从来没有遇到过第二种计算类型,但是,还是在代码中实现了它。但是首先还是让我们探讨第一种方法,它将有更加复杂的算法,包含了预付款的计算:
- 对于未覆盖交易量
- 对于锁仓 (已覆盖) 交易量 (如果制定了锁仓预付款的大小)
- 对于挂单
在本文中,预付款是针对外汇交易和期货模型来计算的,没有考虑挂单的预付款计算。
锁仓仓位预付款的计算需要下面的参数信息才能完成:
- 存款币别. 账户通常有以下存款币别: USD, EUR, GBP, CHF.
- 预付款币别. 通常,它就是基础币别,例如,对于 EURUSD,预付款币别是欧元 (EUR); 而对于 AUDNZD 交叉货币对, 它就是澳元 (AUD)。
- 杠杆.
也请注意,终端的交易页面中,余额那一行中的预付款是以存款币别计算的,所以,计算结果应当是以存款币别为单位的预付款值。
因为预付款币别可能与存款币别不同,有几个计算选项:
- 当锁仓仓位交易品种中存款币别是基础币别的时候,例如您在一个美元账户中交易 USDCHF。
- 当锁仓仓位交易品种中存款币别是报价货币的时候,例如,如果您在一个美元账户中交易 EURUSD。
- 当锁仓仓位交易品种中不包含存款币别时,例如,如果您在一个美元账户中交易 AUDNZD。
第一个选项将是最容易计算的,而最后一种则是最难的。现在,让我们为每个选项探讨计算实例。
变化 1
假定有一个美元账户 (存款),含有五个开启的 USDCHF 仓位 (图1).
图1 市场上的 USDCHF 仓位
基本参数:
账户币别 - USD.
预付款币别 - USD.
杠杆 - 1:100.
其中三个是买入仓位,仓位的总交易量是 5.55 手, 等于 $555,000。另外两个是卖出仓位,这些仓位的总交易量是 7.5 手, 等于 $750,000。
A) 未覆盖交易量的计算
未覆盖交易量等于 1.95 手, 也就是 $195,000,它是卖出的交易量,因为卖出比买入要多。但是,在我们的例子中买入或者卖出都没有关系,因为我们不需要计算加权平均价格,
这个数量的预付款是考虑到杠杆的情况下计算的:
$195,000 / 100 = $1,950.
B) 锁仓交易量的计算
锁仓交易量等于 5.55 手, 也就是 $555,000.
这个数量的预付款是考虑到杠杆的情况下计算的:
$555,000 / 100 = $5,550.
预付款的结果值是以锁仓中未覆盖交易量的预付款总和来计算的。
$1,950 + $5,550 = $7,500.
这就是在交易终端中显示的 "Margin(预付款)"数值。
变化 2
现在,有一个美元账户 (存款),含有五个开启的 EURUSD 仓位 (图2)。
图2 市场上的 EURUSD 仓位
基本参数:
- 账户币别 - USD.
- 预付款币别 - EUR.
- 杠杆 - 1:300.
其中三个是买入仓位,仓位的总交易量是 5.55 手, 等于 €555,000 或者 $645,617.20,买入仓位的加权平均价格是 $1.163274。
还有两个卖出仓位,这些仓位的总交易量是 7.5 手, 等于 €750,000 或者 $872 409。加权平均卖出价格是 $1.163212。
所有仓位都显示于表格2中。
类型 | 交易量 | 价格 | 价值, $ |
---|---|---|---|
买入 | 1.75 | 1.16329 | 203,575.75 |
买入 | 2.55 | 1.16329 | 296,638.95 |
买入 | 1.25 | 1.16322 | 145,402.50 |
卖出 | 3.00 | 1.16323 | 348,969.00 |
卖出 | 4.50 | 1.16320 | 523,440.00 |
总共 | 13.05 | 1.1632385 | 1,518,026.20 |
表格 2. 市场 EURUSD 仓位
一共有5个仓位,仓位的总交易量是 13.05 手, 它等于 €1,305,000 或 $1,518,026.20,加权平均仓位价格为 $1.16324。
A) 未覆盖交易量的计算
未覆盖交易量等于 1.95 手,也就是 €195,000。它是卖出的交易量,因为卖出比买入要多。所以,我们使用加权平均卖出价格来计算交易量的花费。
$1.163212 * €195,000 = $226,826.34.
这个数量的预付款是考虑到杠杆的情况下计算的:
$226,826.34 / 300 = $756.09.
B) 锁仓交易量的计算
锁仓交易量等于 5.55 手, 也就是 €555,000。让我们使用所有仓位的加权平均价格来确定这个交易量的值:
$1.1632385 * €555,000 = $645,597.35.
这个数量的预付款是考虑到杠杆的情况下计算的:
$645,597.35 / 300 = $2,151.99.
这样,从理论上看,整体的全账户总体预付款如下:
$756.09 + $2,151.99 = $2,908.08.
然而,终端中显示的数值是 $1,832.08。
这是因为交易品种规格中的 "Hedged margin" 参数是考虑到了覆盖(锁仓的)交易量。如果它小于合约大小,我们就要做些加倍,这个参数在我们的交易品种规格中等于 50000。然后:
锁仓交易量 = $1.1632385 * €555,000 / (100,000 / 50,000) = $322,798,67.
用于锁仓交易量的预付款 = $322,798.67 / 300 = $1,076.00.
计算总和: $756.09 + $1,076.00 = $1,832.08. 这是终端中显示的数值。
变化 3
这一次我们处理美元账户 (存款), 而有5个开启的 AUDNZD 仓位 (图3).
图3 市场上 AUDNZD 交叉货币对的仓位
基本参数:
- 账户币别 - USD.
- 预付款币别 - AUD.
- 杠杆 - 1:300.
其中三个是买入仓位,仓位的总交易量是 5.55 手, 等于 A$555,000 或者 $400,442.35。买入仓位的加权平均价格是 $0.7215178。
还有两个卖出仓位,仓位的总交易量是 7.5手, 等于 A$750,000 或者 $541,035.00,卖出价格的加权平均为 $0.72138。
所有的仓位都显示在表格3中。
类型 | 交易量 | 价格 | 价值, $ |
---|---|---|---|
买入 | 1.75 | 0.72152 | 126,266.00 |
买入 | 2.55 | 0.72152 | 183,987.60 |
买入 | 1.25 | 0.72151 | 90,188.75 |
卖出 | 3.00 | 0.72144 | 216,432.00 |
卖出 | 4.50 | 0.72134 | 324,603.00 |
总共 | 13.05 | 0.72144 | 941,477.35 |
表格 3. 市场上的 AUDNZD 交叉货币对仓位
价格列中仓位的建仓价格不是对于 AUDNZD, 而是对于 AUDUSD 交易品种的,这可以以存款币别来估算交易量。在此,我需要参考订单单号和货币对的报价历史,它包含存款币别和预付款币别。所以,计算的数值将与实际值有少许偏差。
一共有5个仓位,仓位的总交易量是 13.05 手, 它等于 A$1,305,000 或者 $941,477.35,仓位的加权平均价格是 $0.72144.
A) 未覆盖交易量的计算
未覆盖交易量等于 1.95 手, 也就是. A$195,000. 它是卖出的交易量,因为卖出比买入要多。所以,我们使用加权平均卖出价格来计算交易量的花费。
$0.72138 * A$195,000 = $140,669.10.
这个数量的预付款是考虑到杠杆的情况下计算的:
$140,669.10 / 300 = $468.90.
B) 锁仓交易量的计算
锁仓交易量等于5.55 手,也就是 A$555,000. 让我们使用所有仓位的加权平均价格,考虑到 "Hedged margin" 参数来确定这个交易量的数值:
$0.72144 * A$555,000 / (100,000 / 50,000) = $200,199.21.
这个数量的预付款是考虑到杠杆的情况下计算的:
$200,199.21 / 300 = $667.33.
计算总和 : $468.90 + $667.33 = $1,136.23. 与图3比较结果: 它等于终端中显示的值。
2.4其他属性
类中还包含用于操作锁仓状态的方法: StoreState() 和 CheckState(). 与普通仓位相比,状态包含了类型、交易量、建仓价格、止损和获利价格等。
唯一的文本属性方法 TypeDescription() 以字符串的形式返回锁仓类型。
要特别注意的是 Select() 方法, 这样可以选择一个锁仓仓位。这里是方法的代码:
//+------------------------------------------------------------------+ //| 选择锁仓仓位 | //+------------------------------------------------------------------+ bool CHedgePositionInfo::Select(void) { string hedge_symbol=m_symbol.Name(); //--- 清除所有仓位 m_tickets.Shutdown(); //--- 收集仓位 positions int pos_num=PositionsTotal(); for(int pos_idx=0;pos_idx<pos_num;pos_idx++) if(m_pos_info.SelectByIndex(pos_idx)) { string curr_pos_symbol=m_pos_info.Symbol(); //--- 选择交易品种 if(!StringCompare(hedge_symbol,curr_pos_symbol)) { //--- 如果根据幻数选择 bool is_the_same_magic=true; if(m_magic>0) { long curr_pos_magic=m_pos_info.Magic(); if(m_magic!=curr_pos_magic) is_the_same_magic=false; } if(is_the_same_magic) { ulong curr_pos_ticket=m_pos_info.Ticket(); if(curr_pos_ticket>0) if(!m_tickets.Add(curr_pos_ticket)) { PrintFormat(__FUNCTION__+": 增加 #%d 订单失败!",curr_pos_ticket); return false; } } } } //--- return m_tickets.Total()>0; } //+------------------------------------------------------------------+
这个方法的主要目的是更新构成锁仓的仓位的订单号,它处理市场上的交易品种名称符合锁仓交易品种的仓位,这个部分可以另外通过幻数来过滤。
3. 实例
我们已经创建了一个类,操作锁仓仓位的属性,在这一节中,我们将处理实际的例子,让我们从简单脚本开始。
3.1一个测试脚本
为了教学目的,我创建了 Test_hedge_properties.mq5 脚本, 它在“专家”页面的日志中显示锁仓的属性。
在第一个预付款计算例子中,我们有5个 USDCHF 仓位 (图1). 运行脚本,在日志中将会出现以下信息:
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) ---== 锁仓属性==--- 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) Symbol: USDCHF 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 总仓位 = 5 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 1) #293972991 买入 1.75 USDCHF 0.97160000 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 2) #293974150 买入 2.55 USDCHF 0.97142000 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 3) #293974889 卖出 3.00 USDCHF 0.97157000 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 4) #293975329 卖出 4.50 USDCHF 0.97164000 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 5) #293976289 买入 1.25 USDCHF 0.97205000 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 幻数: 0 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 时间: 2018.08.29 17:15:44 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 时间 毫秒数: 1535562944628 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 更新时间: 2018.08.29 17:20:35 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 更新时间毫秒数: 1535563235034 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 类型: HEDGE_NETTING_SELL 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 类型 描述: 锁仓净额卖出 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 交易量: -1.95 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 买入交易量: 5.55 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 卖出交易量: 7.50 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 开仓价格: 0.97159 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 止损价格: -1.00000 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 获利价格: -1.00000 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 当前价格: 0.96956 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 手续费: 0.00 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 隔夜息: -35.79 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 利润: 409.77 2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1) 预付款: 7500.00
在第二种变化中,我们处理 EURUSD 仓位的属性 (图2). 在运行脚本之后,取得了以下信息:
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) ---== 锁仓属性==--- 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 交易品种: EURUSD 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 仓位总数 = 5 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 1) #119213986 买入 1.75 EURUSD 1.16329000 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 2) #119214003 买入 2.55 EURUSD 1.16329000 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 3) #119214004 买入 1.25 EURUSD 1.16322000 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 4) #119214011 卖出 3.00 EURUSD 1.16323000 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 5) #119214021 卖出 4.50 EURUSD 1.16320000 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 幻数: 0 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 时间: 2018.08.31 16:38:10 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 时间毫秒数: 1535733490531 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 更新时间: 2018.08.31 16:38:49 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 更新时间毫秒数: 1535733529678 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 类型: HEDGE_NETTING_SELL 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 类型 描述: hedge netting sell 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 交易量: -1.95 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 买入交易量: 5.55 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 卖出交易量: 7.50 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 建仓价格: 1.16303 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 止损价格: -1.00000 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 获利价格: -1.00000 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 当前价格: 1.16198 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 手续费: 0.00 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 隔夜息: -37.20 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 利润: 206.60 2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1) 预付款: 1832.08
在第一种变化中,我们有 AUDNZD 仓位 (图3). 脚本在日志中打印如下的信息:
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) ---== 锁仓属性==--- 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 交易品种: AUDNZD 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 仓位总数 = 5 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 1) #119214062 买入 1.75 AUDNZD 1.08781000 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 2) #119214068 买入 2.55 AUDNZD 1.08783000 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 3) #119214071 买入 1.25 AUDNZD 1.08785000 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 4) #119214083 卖出 3.00 AUDNZD 1.08773000 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 5) #119214092 卖出 4.50 AUDNZD 1.08757000 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 幻数: 0 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 时间: 2018.08.31 16:39:41 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 时间 毫秒数: 1535733581113 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 更新时间: 2018.08.31 16:40:07 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 更新时间毫秒数: 1535733607241 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 类型: HEDGE_NETTING_SELL 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 类型 描述: 锁仓净额卖出 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 交易量: -1.95 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 买入交易量: 5.55 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 卖出交易量: 7.50 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 建仓 价格: 1.08708 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 止损价格: -1.00000 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 获利价格: -1.00000 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 当前价格: 1.09314 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 手续费: 0.00 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 隔夜息: -21.06 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 利润: -779.45 2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1) 预付款: 1136.23
Test_hedge_properties.mq5脚本的代码可以从 zip 档案中下载到.
3.1锁仓属性面板
现在我们将使任务复杂一些使用标准库,我们将创建HedgePropertiesEA.mq5 EA交易, 它会在图表上画一个面板,显示所选锁仓仓位的属性。
为了这些目的,让我们创建 CHedgeDialog 类,它派生于标准的 CAppDialog 类。这个类将使我们避免对一些程序典型功能的需要,例如最小化和最大化面板窗口,处理面板上元件的变化,等等。
//+------------------------------------------------------------------+ //| Class CHedgeDialog | //| 目的: 用于显示锁仓仓位信息的类. | //| 派生于 CAppDialog 类。 | //+------------------------------------------------------------------+ class CHedgeDialog : private CAppDialog { //--- === 数据成员 === --- private: CArrayString m_symbols_arr; //--- 控件 CLabel m_labels[FIELDS_NUM+1]; CEdit m_edits[FIELDS_NUM]; CComboBox m_combo; bool m_to_refresh; //--- === 方法 === --- public: //--- 构造函数/析构函数 void CHedgeDialog(void) {}; void ~CHedgeDialog(void) {}; //--- 初始化 bool Init(void); void Deinit(const int _reason); //--- 处理 void OnChartEvent(const int _id, const long &_lparam, const double &_dparam, const string &_sparam); void OnTradeEvent(void); //--- private: int HedgeSymbols(void); void RefreshPanel(void); }; //+------------------------------------------------------------------+
这个类的实例将会在 EA 的代码中被调用,处理初始化和终止化事件,图表事件以及与交易相关的事件。
锁仓仓位属性面板显示在图4中。
图4 锁仓仓位属性面板
一个主要方法是 CHedgeDialog::RefreshPanel(). 无论何时需要,他都会更新面板的信息栏位,在编程和测试中的一些困难是因为锁仓数量改变造成的,在这种情况下,需要在下拉列表中改变唯一的交易品种,避免在 OnChartEvent() 处理函数调用时出现无限循环。为此,我对连续调用处理函数做了限制,一秒最多一次。
//--- 检查刷新限制 if(!m_to_refresh) { uint last_cnt=GetTickCount(); static uint prev_cnt=0; uint msc_elapsed=last_cnt-prev_cnt; prev_cnt=last_cnt; if(msc_elapsed>1000) m_to_refresh=true; else return; }
HedgePropertiesEA.mq5 EA 交易的完整代码在附加的 zip 档案中。
结论
除了交易终端中的多种资产,MetaTrader 5 还支持了不同的仓位管理系统。这种功能为实现和创建交易思路提供了更加广泛的选择,
我希望这篇文章会对打算把他们的策略从 MetaTrader 4 迁移到 MetaTrader 5 的人有用。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/4830