文章目录
平仓函数的重写设计与代码实现
- MT4与MT5提供的交易函数只有简单的接口,不能适应快速开发。
- 交易策略需要按仓位类型,按产品符号,按魔术编号,按仓位注释等多功能多条件的平仓。
- 将所有平仓条件抽象成为函数的参数,封装成为一个通用的跨平台的平仓函数
- 代码实现如下:
// 定义常量
#define _Deviation 50
// 定义订单遍历宏,实现跨平台编译
#ifdef __MQL4__
#define ForEachPositionDown(i) for (int i=OrdersTotal()-1; i>=0; i--)
#endif
#ifdef __MQL5__
#define ForEachPositionDown(i) for (int i=PositionsTotal()-1; i>=0; i--)
#endif
// 根据指定魔术编号数组,产品符合数组,订单订单注释数组平仓多头仓位
// 本函数为通用函数,兼容MT4与MT5平台
// 数组为空的时,默认全局,如此便实现了各种条件的组合筛选
bool BuyClose(ulong &magic[], string &symbol[], string &comment[]) export
{
bool ret = true;
// 从最新时间到过去,遍历所有的仓位
ForEachPositionDown(i)
{
// 根据索引选择仓位
if ( CheckPositionSelectedByPos(i) )
{
// 判断是否符合魔术编号匹配,不符合返回继续循环
if ( !CheckPositionSelectedMagic(magic) ) continue;
// 判断是否符合产品符号匹配,不符合返回继续循环
if ( !CheckPositionSelectedSymbol(symbol) ) continue;
// 判断是否符合产品符号匹配,不符合返回继续循环
if ( !CheckPositionSelectedComment(comment) ) continue;
// 判断是否选择了多头仓位
if ( !CheckSelectedBuy() ) continue;
// 以上条件全部符合以后,执行仓位平仓,将执行结果保存ret变量
// 只有所有符合条件的仓位全部平仓,ret的结果为true,否则false
ret = ret && SelectedPositionClose();
}
}
//
return (ret);
}
// 筛选仓位是否符合魔术编号数组
// 通用MT4和MT5函数,可跨平台编译
bool CheckPositionSelectedMagic(ulong &magic[]) export
{
int arr_len = ArraySize(magic);
if (arr_len == 0) return (true);
#ifdef __MQL4__
if (MathQuery(magic, OrderMagicNumber()) == -1) return (false);
#endif
#ifdef __MQL5__
ulong pos_magic = PositionGetInteger(POSITION_MAGIC);
if (MathQuery(magic, pos_magic) == -1) return (false);
#endif
return (true);
}
// 筛选仓位是否符合产品符号数组
// 通用MT4和MT5函数,可跨平台编译
bool CheckPositionSelectedSymbol(string &symbol[]) export
{
int arr_len = ArraySize(symbol);
if (arr_len == 0) return (true);
string sym = "";
#ifdef __MQL4__
sym = ::OrderSymbol();
#endif
#ifdef __MQL5__
sym = ::PositionGetString(POSITION_SYMBOL);
#endif
//
if (!ArrayContains(symbol, sym)) return (false);
return (true);
}
// 筛选仓位是否符合订单注释数组
// 通用MT4和MT5函数,可跨平台编译
bool CheckPositionSelectedComment(string &comment[]) export
{
int arr_len = ArraySize(comment);
if (arr_len == 0) return (true);
// 检查仓位注释是否在筛选的注释数组中
if (!ArrayContains(comment, SelectedPositionComment())) return (false);
return (true);
}
// 判断选择的是不是多单,跨平台编译MT4与MT5函数
bool CheckSelectedBuy(void) export
{
#ifdef __MQL4__
if (OrderType() != OP_BUY) return (false);
#endif
#ifdef __MQL5__
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if (type != POSITION_TYPE_BUY) return (false);
#endif
return (true);
}
// 平仓指定选择的仓位
int SelectedPositionClose(void) export
{
#ifdef __MQL4__
double close_price;
if (OrderType() == OP_BUY)
close_price = SymbolInfoDouble(OrderSymbol(), SYMBOL_BID);
else if (OrderType() == OP_SELL)
close_price = SymbolInfoDouble(OrderSymbol(), SYMBOL_ASK);
else
return (-1);
if ( !OrderClose(OrderTicket(), OrderLots(), close_price, _Deviation, clrNONE) )
{
Print("OrderClose failed with error #", GetLastError());
return (0);
}
#endif
#ifdef __MQL5__
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
string symbol = PositionGetString(POSITION_SYMBOL);
request.action = TRADE_ACTION_DEAL;
request.position = PositionGetInteger(POSITION_TICKET);
request.symbol = symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.deviation = _Deviation;
//
if (type == POSITION_TYPE_BUY)
{
request.price = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL), SYMBOL_BID);
request.type = ORDER_TYPE_SELL;
}
if (type == POSITION_TYPE_SELL)
{
request.price = SymbolInfoDouble(PositionGetString(POSITION_SYMBOL), SYMBOL_ASK);
request.type = ORDER_TYPE_BUY;
}
if ( !FillingCheck(symbol, request, result) ) return (0);
//
if (!OrderSend(request, result))
{
PrintFormat( "OrderSend error %d", GetLastError() );
PrintFormat("retcode=%u deal=%I64u order=%I64u", result.retcode, result.deal, result.order);
return (0);
}
#endif
return (1);
}
SellClose 函数的设计思想与以上相同,这里不再代码演示
注意里面部分被调用的函数在前面的文章中已经展示,这里不再写出