平仓操作
市价单:平仓操作是基于当前的市价来结束一个已开立的交易头寸。具体规则是:平掉买单使用当前的买价 (Bid),平掉卖单使用当前的卖价 (Ask)。
挂单:对于尚未被市场价格触发的挂单,结束它的操作不是“平仓”,而是删除 (Delete) 或取消。(删除挂单的函数 OrderDelete()
)。
OrderClose() 函数
此函数用于向交易服务器发送平掉一个已成交的市价单(或已被触发的挂单)的请求。
语法:
bool OrderClose(
int ticket, // 要平仓的市价单的订单号
double lots, // 要平掉的手数 (可以小于等于订单手数,用于部分平仓)
double price, // 提供一个当前的市价作为参考 (买单平仓用 Bid, 卖单平仓用 Ask)
int slippage, // 允许成交价与参考价的最大滑点 (单位: points)
color arrow_color=clrNONE // 在图表标记平仓位置的箭头颜色 (可选)
);
ticket
: 目标市价单的订单号。lots
: 要平掉的手数。若小于订单当前手数,则为部分平仓(需经纪商支持)。price
: 提供平仓时的参考市价(平买单提供Bid
,平卖单提供Ask
)。slippage
: 允许最终成交价与您提供的price
之间存在多少points的差异。。arrow_color
: 可选,标记平仓位置的箭头颜色。
返回值 (bool
类型):
true
: 表示平仓指令已成功发送到服务器。这不保证订单已立即成交,可能因网络延迟或服务器处理需要时间。需要后续检查订单状态确认是否真正平仓。false
: 表示平仓指令未能成功发送(例如,参数错误、无网络连接等)。调用GetLastError()
获取原因。
关于部分平仓:
虽然 OrderClose()
支持,但一般不推荐在EA中进行部分平仓,因为它会显著增加订单跟踪和管理的复杂度。如果策略需要分批离场,通常更简单可靠的做法是最初就将总头寸拆分成多个独立的订单。本书示例将始终完全平掉整个订单。
平仓示例 (平掉一个买单):
int ticketToClose = ...; // 假设这是要平仓的买单订单号
int slippagePoints = ...; // 假设这是计算好的滑点 points 值 (e.g., GetSlippage() 的结果)
// 1. 选中订单
if (OrderSelect(ticketToClose, SELECT_BY_TICKET))
{
// 2. 确认是未平仓的买单 (OrderCloseTime()==0 且 OrderType()==OP_BUY)
if (OrderCloseTime() == 0 && OrderType() == OP_BUY)
{
// 3. 准备平仓参数
double lotsToClose = OrderLots(); // 平掉全部手数
double closePrice = Bid; // 买单平仓用当前 Bid 价
RefreshRates(); // (可选但推荐) 确保使用的是最新的报价
// 4. 发送平仓指令
bool result = OrderClose(ticketToClose, lotsToClose, closePrice, slippagePoints, Red); // 红色箭头标记
// 5. 处理发送结果
if (result)
{
Print("成功发送平仓指令给买单 #", ticketToClose);
// 注意:这里只是指令发送成功,不代表已成交。
// 实际应用中可能需要等待一段时间或在下一 Tick 检查 OrderSelect 是否还可选用来确认。
}
else
{
Print("发送平仓指令失败 for #", ticketToClose, " Error: ", GetLastError());
}
}
else
{
Print("订单 #", ticketToClose, " 不是一个未平仓的买单。");
}
}
else
{
Print("无法选中订单 #", ticketToClose, ",错误代码: ", GetLastError());
}
平掉卖单: 逻辑完全一致,只需:
- 检查
OrderType() == OP_SELL
。 - 使用
Ask
作为closePrice
。
// 假设 ticketToClose 是卖单订单号, slippagePoints 已计算
if (OrderSelect(ticketToClose, SELECT_BY_TICKET))
{
if (OrderCloseTime() == 0 && OrderType() == OP_SELL)
{
double lotsToClose = OrderLots();
double closePrice = Ask; // 卖单平仓用 Ask 价
RefreshRates();
bool result = OrderClose(ticketToClose, lotsToClose, closePrice, slippagePoints, Red);
if (!result) Print("发送平仓指令失败 for #", ticketToClose, " Error: ", GetLastError());
else Print("成功发送平仓指令给卖单 #", ticketToClose);
}
}
—
OrderDelete() 函数 (用于删除挂单) 对于尚未被触发的挂单 (Pending Orders),我们不使用 OrderClose()
来“平仓”,而是使用 OrderDelete()
函数将其从交易服务器上删除或取消。与 OrderClose()
不同,删除挂单不需要提供价格、手数或滑点信息。 语法:
bool OrderDelete(int ticket, color arrow_color=clrNONE);
ticket
(整数): 要删除的挂单的订单号。arrow_color
(颜色, 可选): 在图表上标记删除位置的箭头颜色。如果省略或设为clrNONE
,则不绘制箭头。
返回值 (bool
类型):
true
: 表示删除指令已成功发送到服务器。false
: 表示删除指令发送失败。调用GetLastError()
获取原因。
删除挂单示例 (删除一个买入止损挂单):
int ticketToDelete = ...; // 假设这是要删除的挂单订单号
// 1. 选中订单
if (OrderSelect(ticketToDelete, SELECT_BY_TICKET))
{
// 2. 确认是未成交的挂单 (OrderCloseTime()==0 且 OrderType是挂单类型之一)
int type = OrderType();
if (OrderCloseTime() == 0 && (type == OP_BUYSTOP || type == OP_SELLSTOP || type == OP_BUYLIMIT || type == OP_SELLLIMIT))
{
// 3. 发送删除指令
bool result = OrderDelete(ticketToDelete, Red); // 红色箭头标记
// 4. 处理发送结果
if (result)
{
Print("成功发送删除指令给挂单 #", ticketToDelete);
}
else
{
Print("发送删除指令失败 for #", ticketToDelete, " Error: ", GetLastError());
}
}
else
{
Print("订单 #", ticketToDelete, " 不是一个可以删除的挂单 (可能已被触发或已取消).");
}
}
else
{
Print("无法选中订单 #", ticketToDelete, ", 错误代码: ", GetLastError());
}
与平仓操作类似,删除挂单前也需要先用 OrderSelect()
选中订单,并通过 OrderType()
和 OrderCloseTime()
确认其状态确实是未成交的挂单 (类型为 OP_BUYSTOP
, OP_SELLSTOP
, OP_BUYLIMIT
或 OP_SELLLIMIT
之一)。
提示: 如果一个挂单的价格条件被市场触及并已成功执行,那么它就不再是挂单了,而是转变成了一个已开仓的市价单。在这种情况下,您必须使用 OrderClose()
函数来将其平仓,而不能再用 OrderDelete()
。