166 lines
7 KiB
MQL5
166 lines
7 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| PendingOrderSend.mq5 |
|
||
|
//| Copyright 2022, MetaQuotes Ltd. |
|
||
|
//| https://www.mql5.com |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#property copyright "2022, MetaQuotes Ltd."
|
||
|
#property link "https://www.mql5.com"
|
||
|
#property description "Construct MqlTradeRequest for specified pending order type and call OrderSend with TRADE_ACTION_PENDING."
|
||
|
#property description "Expiration, Stop Loss and Take Profit can be set optionally."
|
||
|
|
||
|
#define SHOW_WARNINGS // output extended info into the log, with changes in data state
|
||
|
#define WARNING Print // use simple Print for warnings (instead of a built-in format with line numbers etc.)
|
||
|
#include "..\..\Include\MqlTradeSync.mqh"
|
||
|
|
||
|
enum ENUM_ORDER_TYPE_PENDING
|
||
|
{ // Captions in UI
|
||
|
PENDING_BUY_STOP = ORDER_TYPE_BUY_STOP, // ORDER_TYPE_BUY_STOP
|
||
|
PENDING_SELL_STOP = ORDER_TYPE_SELL_STOP, // ORDER_TYPE_SELL_STOP
|
||
|
PENDING_BUY_LIMIT = ORDER_TYPE_BUY_LIMIT, // ORDER_TYPE_BUY_LIMIT
|
||
|
PENDING_SELL_LIMIT = ORDER_TYPE_SELL_LIMIT, // ORDER_TYPE_SELL_LIMIT
|
||
|
PENDING_BUY_STOP_LIMIT = ORDER_TYPE_BUY_STOP_LIMIT, // ORDER_TYPE_BUY_STOP_LIMIT
|
||
|
PENDING_SELL_STOP_LIMIT = ORDER_TYPE_SELL_STOP_LIMIT, // ORDER_TYPE_SELL_STOP_LIMIT
|
||
|
};
|
||
|
|
||
|
input string Symbol; // Symbol (empty = current _Symbol)
|
||
|
input double Volume; // Volume (0 = minimal lot)
|
||
|
input ENUM_ORDER_TYPE_PENDING Type = PENDING_BUY_STOP;
|
||
|
input int Distance2SLTP = 0; // Distance to SL/TP in points (0 = no)
|
||
|
input ENUM_ORDER_TYPE_TIME Expiration = ORDER_TIME_GTC;
|
||
|
input datetime Until = 0;
|
||
|
input ulong Magic = 1234567890;
|
||
|
input string Comment;
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Expert initialization function |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int OnInit()
|
||
|
{
|
||
|
if(AccountInfoInteger(ACCOUNT_TRADE_MODE) != ACCOUNT_TRADE_MODE_DEMO)
|
||
|
{
|
||
|
Alert("This is a test EA! Run it on a DEMO account only!");
|
||
|
return INIT_FAILED;
|
||
|
}
|
||
|
|
||
|
// setup timer for postponed execution
|
||
|
EventSetTimer(1);
|
||
|
return INIT_SUCCEEDED;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Prepare MqlTradeRequest struct and call OrderSend with it |
|
||
|
//| to place a pending order of specific type and properties |
|
||
|
//+------------------------------------------------------------------+
|
||
|
ulong PlaceOrder(const ENUM_ORDER_TYPE type,
|
||
|
const string symbol, const double lot,
|
||
|
const int sltp, ENUM_ORDER_TYPE_TIME expiration, datetime until,
|
||
|
const ulong magic = 0, const string comment = NULL)
|
||
|
{
|
||
|
// distance for orders of different types from current market price,
|
||
|
// indices are ENUM_ORDER_TYPE, values to multiply by daily range
|
||
|
static double coefficients[] =
|
||
|
{
|
||
|
0 , // ORDER_TYPE_BUY - not used
|
||
|
0 , // ORDER_TYPE_SELL - not used
|
||
|
-0.5, // ORDER_TYPE_BUY_LIMIT - below price
|
||
|
+0.5, // ORDER_TYPE_SELL_LIMIT - above price
|
||
|
+1.0, // ORDER_TYPE_BUY_STOP - far above price
|
||
|
-1.0, // ORDER_TYPE_SELL_STOP - far below price
|
||
|
+0.7, // ORDER_TYPE_BUY_STOP_LIMIT - middle price above current
|
||
|
-0.7, // ORDER_TYPE_SELL_STOP_LIMIT - middle price below current
|
||
|
0 , // ORDER_TYPE_CLOSE_BY - not used
|
||
|
};
|
||
|
|
||
|
const double range = iHigh(symbol, PERIOD_D1, 1) - iLow(symbol, PERIOD_D1, 1);
|
||
|
Print("Autodetected daily range: ", (float)range);
|
||
|
|
||
|
// default values
|
||
|
const double volume = lot == 0 ? SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN) : lot;
|
||
|
const double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
||
|
|
||
|
// price-related values
|
||
|
const double price = TU::GetCurrentPrice(type, symbol) + range * coefficients[type];
|
||
|
// origin is filled only for *_STOP_LIMIT-orders
|
||
|
const bool stopLimit = type == ORDER_TYPE_BUY_STOP_LIMIT || type == ORDER_TYPE_SELL_STOP_LIMIT;
|
||
|
const double origin = stopLimit ? TU::GetCurrentPrice(type, symbol) : 0;
|
||
|
|
||
|
TU::TradeDirection dir(type);
|
||
|
const double stop = sltp == 0 ? 0 : dir.negative(stopLimit ? origin : price, sltp * point);
|
||
|
const double take = sltp == 0 ? 0 : dir.positive(stopLimit ? origin : price, sltp * point);
|
||
|
|
||
|
MqlTradeRequestSync request(symbol);
|
||
|
|
||
|
// fill optional fields
|
||
|
request.magic = magic;
|
||
|
request.comment = comment;
|
||
|
// you can customize filling mode as well, by default MqlTradeRequestSync will
|
||
|
// automatically select first supported mode
|
||
|
// request.type_filling = SYMBOL_FILLING_FOK;
|
||
|
|
||
|
ResetLastError();
|
||
|
// fill and check relevant fields, send request
|
||
|
ulong order = 0;
|
||
|
switch(type)
|
||
|
{
|
||
|
case ORDER_TYPE_BUY_STOP:
|
||
|
order = request.buyStop(volume, price, stop, take, expiration, until);
|
||
|
break;
|
||
|
case ORDER_TYPE_SELL_STOP:
|
||
|
order = request.sellStop(volume, price, stop, take, expiration, until);
|
||
|
break;
|
||
|
case ORDER_TYPE_BUY_LIMIT:
|
||
|
order = request.buyLimit(volume, price, stop, take, expiration, until);
|
||
|
break;
|
||
|
case ORDER_TYPE_SELL_LIMIT:
|
||
|
order = request.sellLimit(volume, price, stop, take, expiration, until);
|
||
|
break;
|
||
|
case ORDER_TYPE_BUY_STOP_LIMIT:
|
||
|
order = request.buyStopLimit(volume, price, origin, stop, take, expiration, until);
|
||
|
break;
|
||
|
case ORDER_TYPE_SELL_STOP_LIMIT:
|
||
|
order = request.sellStopLimit(volume, price, origin, stop, take, expiration, until);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(order != 0)
|
||
|
{
|
||
|
Print("OK order sent: #=", order);
|
||
|
if(request.completed()) // waiting for acceptance
|
||
|
{
|
||
|
Print("OK order placed");
|
||
|
}
|
||
|
}
|
||
|
Print(TU::StringOf(request));
|
||
|
Print(TU::StringOf(request.result));
|
||
|
return order;
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Timer event handler |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void OnTimer()
|
||
|
{
|
||
|
// once executed, wait for another setup from user
|
||
|
EventKillTimer();
|
||
|
|
||
|
const string symbol = StringLen(Symbol) == 0 ? _Symbol : Symbol;
|
||
|
if(PlaceOrder((ENUM_ORDER_TYPE)Type, symbol, Volume,
|
||
|
Distance2SLTP, Expiration, Until, Magic, Comment))
|
||
|
{
|
||
|
Alert("Pending order placed - remove it manually, please");
|
||
|
}
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
/*
|
||
|
example output (EURUSD, default settings + 1000 points SLTP):
|
||
|
|
||
|
Autodetected daily range: 0.01413
|
||
|
OK order sent: #=1282106395
|
||
|
OK order placed
|
||
|
TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_BUY_STOP, V=0.01, ORDER_FILLING_FOK, @ 1.11248, SL=1.10248, TP=1.12248, ORDER_TIME_GTC, M=1234567890
|
||
|
DONE, #=1282106395, V=0.01, Request executed, Req=91
|
||
|
Alert: Pending order placed - remove it manually, please
|
||
|
|
||
|
*/
|
||
|
//+------------------------------------------------------------------+
|