forked from rosh/MQL5Book
205 lines
7.4 KiB
MQL5
205 lines
7.4 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| TradeClose.mq5 |
| |||
//| Copyright 2022, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "2022, MetaQuotes Ltd."
| |||
#property link "https://www.mql5.com"
| |||
#property description "Open and then close positions with current symbol and minimal lot according to a simple trending strategy working on per bar basis."
| |||
| |||
#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"
| |||
| |||
input ulong Deviation;
| |||
input ulong Magic = 1234567890;
| |||
| |||
ulong LastErrorCode = 0;
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| 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;
| |||
}
| |||
| |||
return INIT_SUCCEEDED;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Helper function to find compatible position |
| |||
//+------------------------------------------------------------------+
| |||
bool GetMyPosition(const string s, const ulong m)
| |||
{
| |||
for(int i = 0; i < PositionsTotal(); ++i)
| |||
{
| |||
if(PositionGetSymbol(i) == s && PositionGetInteger(POSITION_MAGIC) == m)
| |||
{
| |||
return true; // one is enough
| |||
}
| |||
}
| |||
return false;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Prepare MqlTradeRequestSync struct and send it to close position |
| |||
//+------------------------------------------------------------------+
| |||
ulong ClosePosition(const ulong ticket)
| |||
{
| |||
// define the struct
| |||
MqlTradeRequestSync request;
| |||
| |||
// fill optional fields of the struct
| |||
request.magic = Magic;
| |||
request.deviation = Deviation;
| |||
| |||
ResetLastError();
| |||
// send request and wait for its completion
| |||
if(request.close(ticket) && request.completed())
| |||
{
| |||
Print("OK Close Order/Deal/Position");
| |||
}
| |||
else
| |||
{
| |||
Print(TU::StringOf(request));
| |||
Print(TU::StringOf(request.result));
| |||
LastErrorCode = request.result.retcode;
| |||
return 0; // error
| |||
}
| |||
| |||
return request.position; // success
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Prepare MqlTradeRequestSync struct and send it to create position|
| |||
//+------------------------------------------------------------------+
| |||
ulong OpenPosition(const ENUM_ORDER_TYPE type)
| |||
{
| |||
// define the struct
| |||
MqlTradeRequestSync request;
| |||
| |||
// default values
| |||
const bool wantToBuy = type == ORDER_TYPE_BUY;
| |||
const double volume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
| |||
| |||
// fill optional fields
| |||
request.magic = Magic;
| |||
request.deviation = Deviation;
| |||
| |||
ResetLastError();
| |||
// format parameters appropriately and send request
| |||
if((bool)(wantToBuy ? request.buy(volume) : request.sell(volume))
| |||
&& request.completed())
| |||
{
| |||
Print("OK New Order/Deal/Position");
| |||
}
| |||
else
| |||
{
| |||
Print(TU::StringOf(request));
| |||
Print(TU::StringOf(request.result));
| |||
LastErrorCode = request.result.retcode;
| |||
}
| |||
| |||
return request.position; // nonzero on success
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Detect trading strategy signals to buy or sell |
| |||
//+------------------------------------------------------------------+
| |||
ENUM_ORDER_TYPE GetTradeDirection()
| |||
{
| |||
if(iClose(_Symbol, _Period, 1) > iClose(_Symbol, _Period, 2)
| |||
&& iClose(_Symbol, _Period, 2) > iClose(_Symbol, _Period, 3))
| |||
{
| |||
return ORDER_TYPE_BUY; // open buy
| |||
}
| |||
| |||
if(iClose(_Symbol, _Period, 1) < iClose(_Symbol, _Period, 2)
| |||
&& iClose(_Symbol, _Period, 2) < iClose(_Symbol, _Period, 3))
| |||
{
| |||
return ORDER_TYPE_SELL; // open sell
| |||
}
| |||
| |||
return (ENUM_ORDER_TYPE)-1; // close all
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Expert tick function |
| |||
//+------------------------------------------------------------------+
| |||
void OnTick()
| |||
{
| |||
static int errors = 0;
| |||
static const int maxtrials = 10; // no more than this number of attempts per bar
| |||
| |||
// wait for a new bar
| |||
static datetime lastBar = 0;
| |||
if(iTime(_Symbol, _Period, 0) == lastBar && errors == 0) return;
| |||
lastBar = iTime(_Symbol, _Period, 0);
| |||
| |||
// get trade signal
| |||
const ENUM_ORDER_TYPE type = GetTradeDirection();
| |||
| |||
if(GetMyPosition(_Symbol, Magic))
| |||
{
| |||
if(type != ORDER_TYPE_BUY && type != ORDER_TYPE_SELL)
| |||
{
| |||
if(!ClosePosition(PositionGetInteger(POSITION_TICKET)))
| |||
{
| |||
++errors;
| |||
}
| |||
else
| |||
{
| |||
errors = 0;
| |||
}
| |||
}
| |||
}
| |||
else if(type == ORDER_TYPE_BUY || type == ORDER_TYPE_SELL)
| |||
{
| |||
if(!OpenPosition(type))
| |||
{
| |||
++errors;
| |||
}
| |||
else
| |||
{
| |||
errors = 0;
| |||
}
| |||
}
| |||
// too many errors per bar
| |||
if(errors >= maxtrials) errors = 0;
| |||
// error require a pause at least
| |||
if(IS_TANGIBLE(LastErrorCode)) errors = 0;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
/*
| |||
tester log example
| |||
| |||
2022.01.03 01:05:00 instant buy 0.01 XAUUSD at 1831.36 (1830.63 / 1831.36)
| |||
2022.01.03 01:05:00 deal #2 buy 0.01 XAUUSD at 1831.36 done (based on order #2)
| |||
2022.01.03 01:05:00 deal performed [#2 buy 0.01 XAUUSD at 1831.36]
| |||
2022.01.03 01:05:00 order performed buy 0.01 at 1831.36 [#2 buy 0.01 XAUUSD at 1831.36]
| |||
2022.01.03 01:05:00 Waiting for position for deal D=2
| |||
2022.01.03 01:05:00 OK New Order/Deal/Position
| |||
2022.01.03 04:00:00 instant sell 0.01 XAUUSD at 1828.86, close #2 (1828.86 / 1829.13)
| |||
2022.01.03 04:00:00 deal #3 sell 0.01 XAUUSD at 1828.86 done (based on order #3)
| |||
2022.01.03 04:00:00 deal performed [#3 sell 0.01 XAUUSD at 1828.86]
| |||
2022.01.03 04:00:00 order performed sell 0.01 at 1828.86 [#3 sell 0.01 XAUUSD at 1828.86]
| |||
2022.01.03 04:00:00 OK Close Order/Deal/Position
| |||
2022.01.03 05:00:01 instant sell 0.01 XAUUSD at 1826.22 (1826.22 / 1826.47)
| |||
2022.01.03 05:00:01 deal #4 sell 0.01 XAUUSD at 1826.22 done (based on order #4)
| |||
2022.01.03 05:00:01 deal performed [#4 sell 0.01 XAUUSD at 1826.22]
| |||
2022.01.03 05:00:01 order performed sell 0.01 at 1826.22 [#4 sell 0.01 XAUUSD at 1826.22]
| |||
2022.01.03 05:00:01 Waiting for position for deal D=4
| |||
2022.01.03 05:00:01 OK New Order/Deal/Position
| |||
2022.01.03 08:00:00 instant buy 0.01 XAUUSD at 1825.66, close #4 (1825.44 / 1825.66)
| |||
2022.01.03 08:00:00 deal #5 buy 0.01 XAUUSD at 1825.66 done (based on order #5)
| |||
2022.01.03 08:00:00 deal performed [#5 buy 0.01 XAUUSD at 1825.66]
| |||
2022.01.03 08:00:00 order performed buy 0.01 at 1825.66 [#5 buy 0.01 XAUUSD at 1825.66]
| |||
2022.01.03 08:00:00 OK Close Order/Deal/Position
| |||
| |||
*/
| |||
//+------------------------------------------------------------------+
|