交易事务结构
交易事务结构 (MqlTradeTransaction)
当在交易账户上执行一些明确活动时,它的状态会发生变化。这种活动包括:
- 使用 OrderSend 和 OrderSendAsync 函数在客户端从任何MQL5应用发送交易请求及其进一步执行:
- 通过程序端图形界面发送交易请求及其进一步执行;
- 在服务器上激活挂单和止损订单;
- 在交易服务器上执行操作。
这些操作的结果会执行以下交易事务:
- 处理交易请求;
- 改变持仓订单;
- 改变订单历史记录;
- 改变交易历史记录;
- 改变持仓。
例如,当发送市场买入订单时,它会被处理,为账户创建相应的买入订单,然后执行订单并从持仓列表中移除,添加到历史订单,而相应的交易也会添加到历史记录并创建新的持仓。所有这些操作都是交易事务。
OnTradeTransaction()的特别句柄在MQL5提供,以获得用于账户的交易。句柄的第一个参数获得描述交易事务的MqlTradeTransaction结构。
struct MqlTradeTransaction { ulong deal; // 交易单 ulong order; // 订单标签 string symbol; // 交易品种 ENUM_TRADE_TRANSACTION_TYPE type; // 交易事务类型 ENUM_ORDER_TYPE order_type; // 订单类型 ENUM_ORDER_STATE order_state; // 订单状态 ENUM_DEAL_TYPE deal_type; // 成交类型 ENUM_ORDER_TYPE_TIME time_type; // 操作期的订单类型 datetime time_expiration; // 订单到期时间 double price; // 价格 double price_trigger; // 限价止损订单激活价格 double price_sl; // 止损水平 double price_tp; // 获利水平 double volume; // 交易量手数 ulong position; // 持仓价格 ulong position_by; // 反向持仓价格 };
字段描述
| 字段 | 描述 |
|---|---|
| deal | 交易单。 |
| order | 订单标签。 |
| symbol | 执行交易事务的交易品种的名称。 |
| type | 交易事务类型。该值可以是一个ENUM_TRADE_TRANSACTION_TYPE 枚举值。 |
| order_type | 交易订单类型。该值可以是一个ENUM_ORDER_TYPE 枚举值。 |
| order_state | 交易订单状态。该值可以是一个 ENUM_ORDER_STATE 枚举值。 |
| deal_type | 成交类型。该值可以是一个 ENUM_DEAL_TYPE 枚举值。 |
| time_type | 接近期限的订单类型。该值可以是一个ENUM_ORDER_TYPE_TIME枚举值。 |
| time_expiration | 挂单到期期限 (用于 ORDER_TIME_SPECIFIED 和 ORDER_TIME_SPECIFIED_DAY订单类型)。 |
| price | 价格。根据交易事务类型,它可能是订单价,成交价或持仓价。 |
| price_trigger | 限价止损订单,止损(激活)价格 (ORDER_TYPE_BUY_STOP_LIMIT 和 ORDER_TYPE_SELL_STOP_LIMIT)。 |
| price_sl | 止损价。根据交易事务类型,它可能涉及订单,交易或持仓。 |
| price_tp | 获利价。根据交易事务类型,它可能涉及订单,交易或持仓。 |
| volume | 交易量手数。根据交易事务类型,它可能表明订单,交易或持仓的当前交易量。 |
收到的交易分析基本参数就是type 字段中指定其类型。例如,如果TRADE_TRANSACTION_REQUEST 类型的交易 (已经收到通过服务器处理交易请求的结果),该结构只有一个字段被完整填写 - type。其他字段不分析。这样,我们可以分析两个额外的 request 和result 参数提交到 OnTradeTransaction() 句柄,显示如下。
拥有交易操作类型的数据,您可以决定在交易账户上分析订单,持仓和交易的当前状态。记住从程序端发送至服务器的交易请求可以生成多个新的交易事务。程序端优先到达不保证。
MqlTradeTransaction 结构根据交易事务类型以不同的方式填写 (ENUM_TRADE_TRANSACTION_TYPE):
TRADE_TRANSACTION_ORDER_* and TRADE_TRANSACTION_HISTORY_*
填充MqlTradeTransaction 结构的以下字段,用于有关持仓的相关订单,处理 (TRADE_TRANSACTION_ORDER_ADD, TRADE_TRANSACTION_ORDER_UPDATE 和 TRADE_TRANSACTION_ORDER_DELETE) 和历史订单 (TRADE_TRANSACTION_HISTORY_ADD, TRADE_TRANSACTION_HISTORY_UPDATE, TRADE_TRANSACTION_HISTORY_DELETE):
- order - 订单;
- symbol - 订单交易品种名称;
- type - 交易事务类型;
- order_type - 订单类型;
- orders_state - 订单当前状态;
- time_type - 订单过期类型;
- time_expiration - 订单过期时间 (用于拥有 ORDER_TIME_SPECIFIED 和 ORDER_TIME_SPECIFIED_DAY 过期类型的订单);
- price - 客户指定的订单价格;
- price_trigger - 限价止损订单止损价格(仅用于 ORDER_TYPE_BUY_STOP_LIMIT 和 ORDER_TYPE_SELL_STOP_LIMIT);
- price_sl - 止损订单价(已执行,如果订单指明);
- price_tp - 获利订单价(已执行,如果订单指明);
- volume - 订单当前交易量(未执行)。初始订单交易量可以使用 HistoryOrders* 函数在历史订单中找到。
TRADE_TRANSACTION_DEAL_*
填充MqlTradeTransaction结构的以下字段用于交易相关的交易事务,处理 (TRADE_TRANSACTION_DEAL_ADD, TRADE_TRANSACTION_DEAL_UPDATE 和 TRADE_TRANSACTION_DEAL_DELETE):
- deal - 交易单;
- order - 订单标签,基于已执行的交易;
- symbol - 交易品种名称;
- type - 交易事务类型;
- deal_type - 交易类型;
- price - 交易价格;
- price_sl - 止损价格(已执行,如果执行交易的订单指明);
- price_tp - 获利价(已执行,如果执行交易的订单指明);
- volume - 交易量手数。
TRADE_TRANSACTION_POSITION
填充 MqlTradeTransaction 结构的以下字段用于改变与执行交易 (TRADE_TRANSACTION_POSITION) 无关联的持仓的相关交易事务:
- symbol - 持仓交易品种名称;
- type - 交易事务类型;
- deal_type - 持仓类型(DEAL_TYPE_BUY 或DEAL_TYPE_SELL);
- price - 加权平均持仓价;
- price_sl - 止损价;
- price_tp - 获利价;
- volume - 持仓交易量手数,如果已经改变。
| 持仓改变(添加,改变或关闭),执行交易的结果,不会导致发生TRADE_TRANSACTION_POSITION 事务。 |
TRADE_TRANSACTION_REQUEST
只填充MqlTradeTransaction结构的一个字段,用于描述已被服务器处理的交易请求的交易事务,并且处理结果已经接收(TRADE_TRANSACTION_REQUEST):
- type - 交易事务类型;
| 只有 type 字段(交易事务类型)必须分析这种事务。 OnTradeTransaction 函数 (请求和结果) 的第二和第三参数必须分析额外的数据。 |
例如:
input int MagicNumber=1234567;
//--- 启用CTrade 交易类并声明这种类的变量
#include <Trade\Trade.mqh>
CTrade trade;
//--- 安装和删除挂单的标识
bool pending_done=false;
bool pending_deleted=false;
//--- 挂单将被存储在这里
ulong order_ticket;
//+------------------------------------------------------------------+
//| 专家初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 设置MagicNumber 标记我们所有订单
trade.SetExpertMagicNumber(MagicNumber);
//--- 交易请求将通过OrderSendAsync() 函数以非同步的模式发送
trade.SetAsyncMode(true);
//--- 初始化变量为零
order_ticket=0;
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 专家订单函数 |
//+------------------------------------------------------------------+
void OnTick()
{
//---安装挂单
if(!pending_done)
{
double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double buy_stop_price=NormalizeDouble(ask+1000*_Point,(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS));
bool res=trade.BuyStop(0.1,buy_stop_price,_Symbol);
//--- 如果BuyStop()函数成功执行
if(res)
{
pending_done=true;
//--- 获取从ctrade发送的请求的结果
MqlTradeResult trade_result;
trade.Result(trade_result);
//--- 获得发送请求的request_id
uint request_id=trade_result.request_id;
Print("Request has been sent to set a pending order. Request_ID=",request_id);
//--- 存储订单 (如果使用非同步模式发送到CTrade,则将为零)
order_ticket=trade_result.order;
//--- 全部完成后,提前从OnTick() 处理程序退出
return;
}
}
//--- 删除挂单
if(!pending_deleted)
//--- 附加检查
if(pending_done && (order_ticket!=0))
{
//--- 尝试删除挂单
bool res=trade.OrderDelete(order_ticket);
Print("OrderDelete=",res);
//--- 删除请求发送成功
if(res)
{
pending_deleted=true;
//--- 得到请求执行结果
MqlTradeResult trade_result;
trade.Result(trade_result);
//--- 获得来自结果的 request ID
uint request_id=trade_result.request_id;
//--- 在日志中显示
Print("The request has been sent to delete a pending order #",order_ticket,
". Request_ID=",request_id,
"\r\n");
//--- 修正来自请求结果的订单
order_ticket=trade_result.order;
}
}
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction 函数 |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
//--- 获取事务类型作为枚举值
ENUM_TRADE_TRANSACTION_TYPE type=(ENUM_TRADE_TRANSACTION_TYPE)trans.type;
//--- 如果事务是请求处理结果,那么只显示它的名称
if(type==TRADE_TRANSACTION_REQUEST)
{
Print(EnumToString(type));
//--- 显示已处理的 request 字符串名称
Print("------------RequestDescription\r\n",RequestDescription(request));
//--- 显示request 结果描述
Print("------------ResultDescription\r\n",TradeResultDescription(result));
//--- 存储用于下一个OnTick()处理的删除的订单
if(result.order!=0)
{
//--- 通过在next OnTick() 调用的标识删除该订单
order_ticket=result.order;
Print(" Pending order ticket ",order_ticket,"\r\n");
}
}
else // 显示另一事务类型的完整描述
//--- 在日志中显示已接收事务的描述
Print("------------TransactionDescription\r\n",TransactionDescription(trans));
//---
}
//+------------------------------------------------------------------+
//| 返回事务文本描述 |
//+------------------------------------------------------------------+
string TransactionDescription(const MqlTradeTransaction &trans)
{
//---
string desc=EnumToString(trans.type)+"\r\n";
desc+="Symbol: "+trans.symbol+"\r\n";
desc+="Deal ticket: "+(string)trans.deal+"\r\n";
desc+="Deal type: "+EnumToString(trans.deal_type)+"\r\n";
desc+="Order ticket: "+(string)trans.order+"\r\n";
desc+="Order type: "+EnumToString(trans.order_type)+"\r\n";
desc+="Order state: "+EnumToString(trans.order_state)+"\r\n";
desc+="Order time type: "+EnumToString(trans.time_type)+"\r\n";
desc+="Order expiration: "+TimeToString(trans.time_expiration)+"\r\n";
desc+="Price: "+StringFormat("%G",trans.price)+"\r\n";
desc+="Price trigger: "+StringFormat("%G",trans.price_trigger)+"\r\n";
desc+="Stop Loss: "+StringFormat("%G",trans.price_sl)+"\r\n";
desc+="Take Profit: "+StringFormat("%G",trans.price_tp)+"\r\n";
desc+="Volume: "+StringFormat("%G",trans.volume)+"\r\n";
//--- 返回获得的字符串
return desc;
}
//+------------------------------------------------------------------+
//| 返回交易请求文本描述 |
//+------------------------------------------------------------------+
string RequestDescription(const MqlTradeRequest &request)
{
//---
string desc=EnumToString(request.action)+"\r\n";
desc+="Symbol: "+request.symbol+"\r\n";
desc+="Magic Number: "+StringFormat("%d",request.magic)+"\r\n";
desc+="Order ticket: "+(string)request.order+"\r\n";
desc+="Order type: "+EnumToString(request.type)+"\r\n";
desc+="Order filling: "+EnumToString(request.type_filling)+"\r\n";
desc+="Order time type: "+EnumToString(request.type_time)+"\r\n";
desc+="Order expiration: "+TimeToString(request.expiration)+"\r\n";
desc+="Price: "+StringFormat("%G",request.price)+"\r\n";
desc+="Deviation points: "+StringFormat("%G",request.deviation)+"\r\n";
desc+="Stop Loss: "+StringFormat("%G",request.sl)+"\r\n";
desc+="Take Profit: "+StringFormat("%G",request.tp)+"\r\n";
desc+="Stop Limit: "+StringFormat("%G",request.stoplimit)+"\r\n";
desc+="Volume: "+StringFormat("%G",request.volume)+"\r\n";
desc+="Comment: "+request.comment+"\r\n";
//--- 返回获得的字符串
return desc;
}
//+------------------------------------------------------------------+
//| 返回请求处理结果的文本描述 |
//+------------------------------------------------------------------+
string TradeResultDescription(const MqlTradeResult &result)
{
//---
string desc="Retcode "+(string)result.retcode+"\r\n";
desc+="Request ID: "+StringFormat("%d",result.request_id)+"\r\n";
desc+="Order ticket: "+(string)result.order+"\r\n";
desc+="Deal ticket: "+(string)result.deal+"\r\n";
desc+="Volume: "+StringFormat("%G",result.volume)+"\r\n";
desc+="Price: "+StringFormat("%G",result.price)+"\r\n";
desc+="Ask: "+StringFormat("%G",result.ask)+"\r\n";
desc+="Bid: "+StringFormat("%G",result.bid)+"\r\n";
desc+="Comment: "+result.comment+"\r\n";
//--- 返回获得的字符串
return desc;
}