ETE/EasyTradeEvent_INCL 02.mqh

1064 lines
83 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 14:53:15 +02:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| EasyTradeEvent_INCL.mqh |
//| Calli |
//| https://www.mql5.com/de/users/gooly |
//+------------------------------------------------------------------+
#property copyright "Calli"
#property link "https://www.mql5.com/de/users/gooly"
//+------------------------------------------------------------------+
//| Enums |
//+------------------------------------------------------------------+
enum <EFBFBD> DeBug
{
<EFBFBD> DebugNon,
<EFBFBD> DebugAll,
<EFBFBD> DebugSend,
<EFBFBD> DebugMatch,
<EFBFBD> DebugETE,
<EFBFBD> DebugConf,
} WhatDebug;
DBG_ENUM_RESOLVER(<EFBFBD> DeBug);
enum <EFBFBD> SetMoveTpSl
{
<EFBFBD> setTpSl,
<EFBFBD> MoveTpSl
};
DBG_ENUM_RESOLVER(<EFBFBD> SetMoveTpSl);
enum <EFBFBD> TrdType
{
<EFBFBD> BUY, // 0
<EFBFBD> SELL, // 1
<EFBFBD> BUYSTOP, // 2
<EFBFBD> SELLSTOP, // 3
<EFBFBD> BUYLIMIT, // 4
<EFBFBD> SELLLIMIT, // 5
<EFBFBD> BUYSTOPLIMIT, // 6
<EFBFBD> SELLSTOPLIMIT, // 7
<EFBFBD> BuyPlanA, // 8 Buys of Strategy 1
<EFBFBD> BuyPlanB, // 9 Buys of Strategy 2
<EFBFBD> SellPlanA, // 10 Sells of Strategy 1
<EFBFBD> SellPlanB, // 11 Sells of Strategy 2
<EFBFBD> CLOSEBY, // 12
<EFBFBD> BALANCE, // 13 Avoid cr/bal forum.mql4.com/32363#325360
<EFBFBD> CREDIT, // 14 Never select canceled orders.
<EFBFBD> NOTyp, // 15
<EFBFBD> NOSignal, // 16
<EFBFBD> Send, // 17 Send Order PendingOrder || Buy
<EFBFBD> OK, // 18
<EFBFBD> Fail, // 19
<EFBFBD> ChgTpSl, // 20
<EFBFBD> Placed, // 21
<EFBFBD> Trigg, // 22
<EFBFBD> Closed, // 23
<EFBFBD> XlsTP, // 24
<EFBFBD> XlsSL, // 25
<EFBFBD> ExpAdv, // 26
<EFBFBD> Manual, // 27
<EFBFBD> StpOut, // 28
<EFBFBD> Roll, // 29
<EFBFBD> Margin, // 30
<EFBFBD> Split, // 31
<EFBFBD> TrDeal, // 32
<EFBFBD> TrPend, // 33
<EFBFBD> TrSlTp, // 34
<EFBFBD> TrModif, // 35
<EFBFBD> TrRmve, // 36
<EFBFBD> TrClsBy, // 37
<EFBFBD> Conf, // 38
<EFBFBD> Open, // 39
<EFBFBD> Close, // 40
<EFBFBD> Reverse, // 41
<EFBFBD> CloseBy, // 42
<EFBFBD> NotFound, // 43
<EFBFBD> NoOp, // 44
}; // %2==0 => BUY; %2==1 => Sell
//*/
DBG_ENUM_RESOLVER(<EFBFBD> TrdType);
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
#define fmax3(a,b,c) fmax(a,fmax(b,c))
#define fmin3(a,b,c) fmin(a,fmin(b,c))
#define _e2s(e) EnumToString(e)
#define _d2D(p) DoubleToString(p,_Digits)
#define _d21(p) DoubleToString(p,1)
#define _d22(p) DoubleToString(p,2)
#define _t2Sec(t) TimeToString(t,TIME_SECONDS)
#define _t2All(t) TimeToString(t,TIME_DATE|TIME_SECONDS)
#define matchPOS 0
#define matchCLS 1
#define matchMAG 2
#define FunLine __FUNCTION__+"["+(string)__LINE__+"] "
//+------------------------------------------------------------------+
//| variables & structs |
//+------------------------------------------------------------------+
/* match[][] is used to match a pending order as ProfitTarget.
As soon as a PenOrd is triggered it can close an open pos
if there is a match of ticket #1 and #2 and mag
*/
ulong match[][3];
//--- 3 Arrays the user need not to know them:
MqlTradeRequest ReqFAIL[], // dealing with request that failed
ReqCHCK[]; // check trading
// to track open positions and orders e.g. to write a csv file after it was closed
struct _opTrd
{
ulong uID, uMag, uDevOrInf;
datetime tDiff, tUpd, tFrc, tOpn, tCls;
double dStLim, dOpn, dUpd, dSL, dTP, dCls, dPrf, dVol;
<EFBFBD> TrdType dir, kind, status;
} oPoBU[], oPoSE[], oOrBU[], oOrSE[],
cLstBU = {}, cLstSE = {};
ulong DeBugORDER = 0;
//+------------------------------------------------------------------+
//| tools |
//+------------------------------------------------------------------+
string err(int e = -1, int fromLine = -1)
{
if ( e == -1 && _LastError == 0 )
{ return(""); }
if ( fromLine > 0 )
{ return( StringFormat("L[%i] err:%i", fromLine, e) ); }
return( StringFormat("err:%i", e) ); //ErrorDescription(e)
}
// for addong a struckt to an array of these structs
template<typename T>
int ArrayAdd(T &arr[], const T &itm)
{
int i = ArraySize(arr),
j = ArrayResize(arr, i + 1);
if(j < i)
{ Print("ArrayAdd() FAILED: ", err()); }
arr[i] = itm;
return(i);
}
// for getting a new empty element of an array to fill it
template<typename T>
int ArrayNew(T &arr[])
{
int i = ArraySize(arr),
j = ArrayResize(arr, i + 1);
if(j < i)
{ Print("ArrayAd() FAILED: ", err()); }
ZeroMemory(arr[i]);
return(i);
}
template<typename T>
int ArrayNew(T &arr[][])
{
int i = ArrayRange(arr, 0),
j = ArrayResize(arr, i + 1);
if(j < i)
{ Print("ArrayNew() FAILED: ", err()); }
j = ArrayRange(arr, 1);
while(j-- > 0)
{ arr[i][j] = 0; }
return(i);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
<EFBFBD> TrdType convOrdTyp(const ENUM_DEAL_ENTRY ot)
{
switch(ot)
{
case DEAL_ENTRY_IN:
return(<EFBFBD> Open);
case DEAL_ENTRY_OUT:
return(<EFBFBD> Close);
case DEAL_ENTRY_INOUT:
return(<EFBFBD> Reverse);
case DEAL_ENTRY_OUT_BY:
return(<EFBFBD> CloseBy);
}
return(<EFBFBD> NOTyp);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
<EFBFBD> TrdType convOrdTyp(const ENUM_DEAL_REASON ot)
{
switch(ot)
{
case DEAL_REASON_CLIENT:
return(<EFBFBD> Manual);
case DEAL_REASON_MOBILE:
return(<EFBFBD> Manual);
case DEAL_REASON_WEB:
return(<EFBFBD> Manual);
case DEAL_REASON_EXPERT:
return(<EFBFBD> ExpAdv);
case DEAL_REASON_SL:
return(<EFBFBD> XlsSL);
case DEAL_REASON_TP:
return(<EFBFBD> XlsTP);
case DEAL_REASON_SO:
return(<EFBFBD> StpOut);
case DEAL_REASON_ROLLOVER:
return(<EFBFBD> Roll);
case DEAL_REASON_VMARGIN:
return(<EFBFBD> Margin);
case DEAL_REASON_SPLIT:
return(<EFBFBD> Split);
}
return(<EFBFBD> NOTyp);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
<EFBFBD> TrdType convOrdTyp(const ENUM_DEAL_TYPE ot)
{
switch(ot)
{
case DEAL_TYPE_BUY:
return(<EFBFBD> BUY);
case DEAL_TYPE_SELL:
return(<EFBFBD> SELL);
case DEAL_TYPE_BUY_CANCELED:
return(<EFBFBD> Fail);
case DEAL_TYPE_SELL_CANCELED:
return(<EFBFBD> Fail);
}
return(<EFBFBD> NOTyp);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
<EFBFBD> TrdType convOrdTyp(const ENUM_ORDER_STATE ot)
{
switch(ot)
{
case ORDER_STATE_STARTED:
return(<EFBFBD> Send);
case ORDER_STATE_PLACED:
return(<EFBFBD> Placed);
case ORDER_STATE_CANCELED:
return(<EFBFBD> Fail);
case ORDER_STATE_PARTIAL:
return(<EFBFBD> OK);
case ORDER_STATE_FILLED:
return(<EFBFBD> OK);
case ORDER_STATE_REJECTED:
return(<EFBFBD> Fail);
case ORDER_STATE_EXPIRED:
return(<EFBFBD> Fail);
case ORDER_STATE_REQUEST_ADD:
return(<EFBFBD> Send);
case ORDER_STATE_REQUEST_MODIFY:
return(<EFBFBD> OK);
case ORDER_STATE_REQUEST_CANCEL:
return(<EFBFBD> Fail);
}
return(<EFBFBD> NOTyp);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
<EFBFBD> TrdType convReqAct(const ENUM_TRADE_REQUEST_ACTIONS at)
{
switch(at)
{
case TRADE_ACTION_DEAL:
return(<EFBFBD> TrDeal);
case TRADE_ACTION_PENDING:
return(<EFBFBD> TrPend);
case TRADE_ACTION_SLTP:
return(<EFBFBD> TrSlTp);
case TRADE_ACTION_MODIFY:
return(<EFBFBD> TrModif);
case TRADE_ACTION_REMOVE:
return(<EFBFBD> TrRmve);
case TRADE_ACTION_CLOSE_BY:
return(<EFBFBD> TrClsBy);
}
return(<EFBFBD> NOTyp);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
<EFBFBD> TrdType convOrdTyp(const ENUM_ORDER_TYPE ot)
{
switch(ot)
{
case ORDER_TYPE_BUY:
return(<EFBFBD> BUY);
case ORDER_TYPE_SELL:
return(<EFBFBD> SELL);
case ORDER_TYPE_BUY_LIMIT:
return(<EFBFBD> BUYLIMIT);
case ORDER_TYPE_SELL_LIMIT:
return(<EFBFBD> SELLLIMIT);
case ORDER_TYPE_BUY_STOP:
return(<EFBFBD> BUYSTOP);
case ORDER_TYPE_SELL_STOP:
return(<EFBFBD> SELLSTOP);
case ORDER_TYPE_BUY_STOP_LIMIT:
return(<EFBFBD> BUYSTOPLIMIT);
case ORDER_TYPE_SELL_STOP_LIMIT:
return(<EFBFBD> SELLSTOPLIMIT);
case ORDER_TYPE_CLOSE_BY:
return(<EFBFBD> CLOSEBY);
}
return(<EFBFBD> NOTyp);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
<EFBFBD> TrdType getPosTyp(const string s)
{
if ( StringFind(s, "Buy") != -1 )
{
if ( StringFind(s, "Stop") != -1 )
{ return(<EFBFBD> BUYSTOP); }
if ( StringFind(s, "Limi") != -1 )
{ return(<EFBFBD> BUYLIMIT); }
return(<EFBFBD> BUY);
}
if ( StringFind(s, "Sell") != -1 )
{
if ( StringFind(s, "Stop") != -1 )
{ return(<EFBFBD> SELLSTOP); }
if ( StringFind(s, "Limi") != -1 )
{ return(<EFBFBD> SELLLIMIT); }
return(<EFBFBD> SELL);
}
return(<EFBFBD> NOTyp);
}
/*+------------------------------------------------------------------+
//| admin function & vars prepared of open position |
//| these function are not meant to be used by the EAs/users |
//| tradeCloseOpnPos() close opposite position
//| tradePrtOpPos() print specif. open position
//+------------------------------------------------------------------*/
/*use: adminRmvOpPos(const ulong id,const double p=0.0)
ulong adminRmvOpPos(MqlTradeResult& result) {*/
//*/
//use: adminRmvOpPos(pID, exPrc)
ulong adminRmvOpPos(const ulong id, const double p = 0.0)
{
// 1st check the buys
int i = ArraySize(oPoBU);
while(i-- > 0)
{
if (oPoBU[i].uID != id) continue;
cLstBU = oPoBU[i];
cLstBU.tCls = TimeCurrent();
cLstBU.dCls = p;
cLstBU.dPrf = (oPoBU[i].dir % 2 == 0 ? 1.0 : -1.0) * (p - oPoBU[i].dOpn) / _Point;
if (WhatDebug == <EFBFBD> DebugConf || WhatDebug == <EFBFBD> DebugAll)
{
Print(__FUNCTION__, "[", __LINE__, "] ", prtOneOpnPos(oPoBU[i].uID, FunLine), "\n CLS: ", _t2Sec(cLstBU.tCls), " (", _t2Sec(cLstBU.tCls - oPoBU[i].tOpn), ") ",
(p < _Point ? "" : _d2D(p) + " => " + _d21( cLstBU.dPrf )), " PIP");
}
ArrayRemove(oPoBU, i, 1);
return(id);
}
// now check the sells
i = ArraySize(oPoSE);
while(i-- > 0)
{
if (oPoSE[i].uID != id) continue;
cLstSE = oPoSE[i];
cLstSE.tCls = TimeCurrent();
cLstSE.dCls = p;
cLstSE.dPrf = (oPoSE[i].dir % 2 == 0 ? 1.0 : -1.0) * (p - oPoSE[i].dOpn) / _Point;
if (WhatDebug == <EFBFBD> DebugConf || WhatDebug == <EFBFBD> DebugAll)
{
Print(__FUNCTION__, "[", __LINE__, "] ", prtOneOpnPos(oPoBU[i].uID, FunLine), "\n CLS: ", _t2Sec(cLstSE.tCls), " (", _t2Sec(cLstSE.tCls - cLstSE.tOpn), ") ",
(p < _Point ? "" : _d2D(p) + " => " + _d21( cLstSE.dPrf )), " PIP");
}
ArrayRemove(oPoSE, i, 1);
return(id);
}
return(0);
}
//+------------------------------------------------------------------+
//| Vars and functions dealing with match[][] to match IDs |
//+------------------------------------------------------------------+
//--- an array to match with the results in OnTradingEvent, items are deleted when confirmed
/* in EasyTradeEvent_INCL.mqh used to match a pending order as ProfitTarget,
as soon as a PenOrd is triggered it can close ajn open pos if they match:
ulong match[][3];
#define matchPOS 0
#define matchCLS 1
#define matchMAG 2
*/
// find the mag number for the identification
int getOpMatch(const ulong m, const ulong pX)
{
int i = ArrayRange(match, 0);
while(i-- > 0)
{
if (match[i][matchMAG] == m && match[i][matchCLS] == pX )
{
if (WhatDebug == <EFBFBD> DebugMatch || WhatDebug == <EFBFBD> DebugAll)
{
Print(__LINE__, " found match[", i, "] p:", match[i][matchPOS], " >c:", match[i][matchCLS], "< >m:", match[i][matchMAG]);
}
return( i );
}
}
return(-1);
}
// list all open = not yet confirmed
void listOpMatch(const string from = "", const string cmt = "")
{
int i = ArrayRange(match, 0);
while(i-- > 0)
{
Print((from != "" ? (string)__LINE__ : from), " list match[", i, "] p:", match[i][matchPOS], " c:", match[i][matchCLS], " m:", match[i][matchMAG], " ", cmt);
}
return;
}
// remove an item as it is confirmd
bool rmvOpMatch(const int i)
{
if (WhatDebug == <EFBFBD> DebugMatch || WhatDebug == <EFBFBD> DebugAll)
{
Print(FunLine, " del match[", i, "] p:", match[i][matchPOS], " c:", match[i][matchCLS], " m:", match[i][matchMAG]);
}
if (ArrayRemove(match, i, 1))
{ return(true); }
return(false);
}
//+------------------------------------------------------------------+
//| confReq (two) to remove item in ReqCHCK as confirmation |
//+------------------------------------------------------------------+
//called in OnTradeTransaction: confReq(sym, m, trans, request);
#ifdef DBG_TRACE_ETE_INCL_CONFREQ
#undef DBG_TRACE_ETE_INCL_CONFREQ
#define DBG_TRACE_ETE_INCL_CONFREQ(x) x
#define DBG_TRACE_ETE_INCL_CONFREQ_RETURN(x) DBG_MSG_TRACE_RETURN_VAR(x)
#else
#define DBG_TRACE_ETE_INCL_CONFREQ(x)
#define DBG_TRACE_ETE_INCL_CONFREQ_RETURN(x) DBG_MSG_NOTRACE_RETURN_VAR(x)
#endif
int confReq(const string sym, const ulong mag, const MqlTradeTransaction &tr, const MqlTradeRequest &rq)
{
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_TRACE_BEGIN;
DBG_MSG_VAR(sym);
DBG_MSG_VAR(mag);
DBG_MSG_VAR(tr);
DBG_MSG_VAR(rq);
);
PERF_COUNTER_BEGIN;
// if ( WhatDebug == <EFBFBD> DebugConf || WhatDebug == <EFBFBD> DebugAll)
// Print(__FUNCTION__, "[", __LINE__, "] Conf rq.a:", _e2s(rq.action), " rq.t:", _e2s(rq.type), " rq.o:", rq.order, " rq.p:", rq.position, " m:", mag);
int i = ArraySize(ReqCHCK);
if (i == 0) // m=mag,
{
// 515 list match[0] p:2 c:3 m:1643853600011
//listOpMatch(); // p==3, o==3, tr.order_type=ORDER_TYPE_SELL_LIMIT (3), tr.order_state=ORDER_STATE_FILLED (4)
//prtListOpnOrdr(); // p==0, o==2, v==2 tr.order_type=ORDER_TYPE_BUY_LIMIT (2), tr.order_state=TRADE_TRANSACTION_ORDER_UPDATE (1) (4)o==2,p==0
//prtListOpnPos(); // p==2, o==2, v==0 tr.order_type=ORDER_TYPE_BUY_LIMIT (2), tr.order_state=ORDER_STATE_FILLED (4)
//ArrayPrint(ReqCHCK); // tradeCloseTcktByPos(const ulong t1, const ulong t2, const ulong m)
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(-1);
}
while(i-- > 0) //if(mag==1673007790 || ReqCHCK[i].magic==1673007790) DebugBreak();
{
if( (mag != ReqCHCK[i].magic)
|| (sym != ReqCHCK[i].symbol) )
{ continue; }
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_VAR(ReqCHCK[i].action);
DBG_MSG_VAR(ReqCHCK[i].type);
);
// if (WhatDebug == <EFBFBD> DebugConf || WhatDebug == <EFBFBD> DebugAll)
// { Print(__FUNCTION__, "[", __LINE__, "] Conf rq.a:", _e2s(rq.action), " rq.t:", _e2s(rq.type), " ", i, "].a:", ReqCHCK[i].action, " ", i, "].t:", ReqCHCK[i].type, " rq.o:", rq.order, " rq.p:", rq.position, " m:", mag); }
if( DBG_MSG_EVAL((ReqCHCK[i].type == rq.type) && (ReqCHCK[i].action == rq.action)) )
{
//Print(__FUNCTION__,"[",__LINE__,"] Conf ",_e2s(ReqCHCK[i].type)," ReqCHCK[",i,"] o:",ReqCHCK[i].deviation," m: ",mag," ",_e2s(ReqCHCK[i].action)," ",_e2s(ReqCHCK[i].type));
ArrayRemove(ReqCHCK, i, 1);
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(i);
}
if( DBG_MSG_EVAL((ReqCHCK[i].action == TRADE_ACTION_DEAL) && (ReqCHCK[i].deviation == tr.order)) ) // tr.type==TRADE_TRANSACTION_HISTORY_ADD (3) tr.order==4,position==2, price>_Point
{
//Print(__FUNCTION__,"[",__LINE__,"] Conf DEAL ReqCHCK[",i,"] o:",ReqCHCK[i].deviation," m: ",mag," ",_e2s(ReqCHCK[i].action)," ",_e2s(ReqCHCK[i].type));
ArrayRemove(ReqCHCK, i, 1);
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(i);
}
if( DBG_MSG_EVAL(ReqCHCK[i].action == TRADE_ACTION_SLTP) ) // && ReqCHCK[i].deviation == rq.position) { // dev==2 rq.position == 2
{
//Print(__FUNCTION__, "[", __LINE__, "] Conf CLOSE BY SL,TP: ReqCHCK[", i, "] o:", ReqCHCK[i].deviation, " m: ", mag, " p:", rq.position, " ", _e2s(ReqCHCK[i].action), " ", _e2s(ReqCHCK[i].type));
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_VAR(ReqCHCK[i].deviation);
DBG_MSG_VAR(ReqCHCK[i].action);
DBG_MSG_VAR(ReqCHCK[i].type);
);
ulong idCls = adminRmvOpPos(ReqCHCK[i].position, fmax(rq.price, tr.price));
ArrayRemove(ReqCHCK, i, 1); // SL/TP changed
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(i);
}
if( DBG_MSG_EVAL((rq.action == TRADE_ACTION_MODIFY) && (rq.order == ReqCHCK[i].order)) )
{
//Print(__FUNCTION__,"[",__LINE__,"] Conf mod.Ord : ReqCHCK[",i,"] o:",ReqCHCK[i].deviation," m: ",mag," rq.o:",rq.order," ",_e2s(ReqCHCK[i].action)," ",_e2s(ReqCHCK[i].type));
ArrayRemove(ReqCHCK, i, 1);
return(i);
}
if( DBG_MSG_EVAL((tr.type == TRADE_TRANSACTION_DEAL_ADD) && (ReqCHCK[i].deviation == tr.order)) )
{
//Print(__FUNCTION__,"[",__LINE__,"] Conf CLS 1by1 ReqCHCK[",i,"] o:",ReqCHCK[i].deviation," m: ",mag," ",_e2s(ReqCHCK[i].action)," ",_e2s(ReqCHCK[i].type));
ArrayRemove(ReqCHCK, i, 1);
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(i);
}
if( DBG_MSG_EVAL(tr.type == TRADE_TRANSACTION_HISTORY_ADD) )
{
listOpMatch();//int i = getOpMatch(mag,
prtListOpnOrdr();
prtListOpnPos();
ArrayPrint(ReqCHCK);
// match[0] p:2 c:3 m:1643853600011 tr.p=2 tr.o=2 ReqCHCK[i].action == TRADE_ACTION_CLOSE_BY && && ReqCHCK[i].deviation == tr.order
// Order[0] oT:2 m:1643853600011 pT:0 Pr:1.12670 SL:1.12370 PT:1.13370=> ORDER_TYPE_BUY_LIMIT @ 00:00:00
// Position[0] o:0 m:1643853600011 t:3 p:3 Pr:1.12985 SL:1.13470 PT:0.00000=> POSITION_TYPE_SELL @ 02:02:22
}
}
if ( WhatDebug == <EFBFBD> DebugConf || WhatDebug == <EFBFBD> DebugAll )
{
i = ArraySize(ReqCHCK);
while(i-- > 0)
{
Print(__FUNCTION__, "[", __LINE__, "] CHECK ReqCHCK[", i, "] o:", ReqCHCK[i].deviation, " ", _e2s(ReqCHCK[i].action), " ", _e2s(ReqCHCK[i].type));
}
}
DBG_TRACE_ETE_INCL_CONFREQ(
i = ArraySize(ReqCHCK);
while(i-- > 0)
{
DBG_MSG_VAR(ReqCHCK[i].deviation);
DBG_MSG_VAR(ReqCHCK[i].action);
DBG_MSG_VAR(ReqCHCK[i].type);
}
);
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(-1);
}
//##
int confReq(const string sym, const ulong mag, const MqlTradeTransaction &tr, const MqlTradeRequest &rq, const MqlTradeResult &rs)
{
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_TRACE_BEGIN;
DBG_MSG_VAR(sym);
DBG_MSG_VAR(mag);
DBG_MSG_VAR(tr);
DBG_MSG_VAR(rq);
DBG_MSG_VAR(rs);
);
PERF_COUNTER_BEGIN;
int i = ArraySize(ReqCHCK);
if (i == 0) // m=mag,
{
// 515 list match[0] p:2 c:3 m:1643853600011
//listOpMatch(); // p==3, o==3, tr.order_type=ORDER_TYPE_SELL_LIMIT (3), tr.order_state=ORDER_STATE_FILLED (4)
//prtListOpnOrdr(); // p==0, o==2, v==2 tr.order_type=ORDER_TYPE_BUY_LIMIT (2), tr.order_state=TRADE_TRANSACTION_ORDER_UPDATE (1) (4)o==2,p==0
//prtListOpnPos(); // p==2, o==2, v==0 tr.order_type=ORDER_TYPE_BUY_LIMIT (2), tr.order_state=ORDER_STATE_FILLED (4)
//ArrayPrint(ReqCHCK); // tradeCloseTcktByPos(const ulong t1, const ulong t2, const ulong m)
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(-1);
}
while(i-- > 0) //if(mag==1673007790 || ReqCHCK[i].magic==1673007790) DebugBreak();
{
if( (mag != ReqCHCK[i].magic)
|| (sym != ReqCHCK[i].symbol) )
{ continue; }
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_VAR(ReqCHCK[i].action);
DBG_MSG_VAR(ReqCHCK[i].type);
);
if( DBG_MSG_EVAL((ReqCHCK[i].action == TRADE_ACTION_PENDING) && (ReqCHCK[i].deviation == rs.order)) )
{
//Print(__FUNCTION__,"[",__LINE__,"] Conf DEAL ReqCHCK[",i,"] o:",ReqCHCK[i].deviation," m: ",mag," ",_e2s(ReqCHCK[i].action)," ",_e2s(ReqCHCK[i].type));
//
if (rq.type%2==0) //## buys
{
int b=ArraySize(oOrBU);
while(b-->0)
{
if (oOrBU[b].uID == rs.order)
{
oOrBU[b].status = <EFBFBD> Placed;
ArrayRemove(ReqCHCK, i, 1);
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(i);
return(i);
}
}
}
}
}
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(-1);
}
//called in OnTradeTRansaction: confReq(sym, m, trans, request);
int confReq(const string sym, const ulong mag, const ulong p, const ENUM_DEAL_ENTRY how)
{
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_TRACE_BEGIN;
DBG_MSG_VAR(sym);
DBG_MSG_VAR(mag);
DBG_MSG_VAR(p);
DBG_MSG_VAR(how);
);
PERF_COUNTER_BEGIN;
int reg_chk_ptr = ArraySize(ReqCHCK);
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_VAR(reg_chk_ptr);
);
while(reg_chk_ptr-- > 0)
{
if (mag != ReqCHCK[reg_chk_ptr].magic)
{ continue; }
// if (sym != ReqCHCK[i].symbol) continue;
if( DBG_MSG_EVAL((ReqCHCK[reg_chk_ptr].action == TRADE_ACTION_CLOSE_BY) && (how == DEAL_ENTRY_OUT_BY) && (p == ReqCHCK[reg_chk_ptr].position_by)) )
{
//Print(__FUNCTION__, "[", __LINE__, "] Conf ", _e2s(ReqCHCK[i].type), " ReqCHCK[", i, "] o:", ReqCHCK[i].deviation, " m: ", mag, " ", _e2s(ReqCHCK[i].action), " ", _e2s(ReqCHCK[i].type));
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_VAR(ReqCHCK[reg_chk_ptr].type);
DBG_MSG_VAR(ReqCHCK[reg_chk_ptr].deviation);
DBG_MSG_VAR(ReqCHCK[reg_chk_ptr].action);
);
ArrayRemove(ReqCHCK, reg_chk_ptr, 1);
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(reg_chk_ptr);
}
if( DBG_MSG_EVAL((ReqCHCK[reg_chk_ptr].action == TRADE_ACTION_DEAL) && (how == DEAL_ENTRY_OUT) && (p == ReqCHCK[reg_chk_ptr].position)) )
{
//Print(__FUNCTION__, "[", __LINE__, "] Conf ", _e2s(ReqCHCK[i].type), " ReqCHCK[", i, "] o:", ReqCHCK[i].deviation, " m: ", mag, " ", _e2s(ReqCHCK[i].action), " ", _e2s(ReqCHCK[i].type));
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_VAR(ReqCHCK[reg_chk_ptr].type);
DBG_MSG_VAR(ReqCHCK[reg_chk_ptr].deviation);
DBG_MSG_VAR(ReqCHCK[reg_chk_ptr].action);
);
ArrayRemove(ReqCHCK, reg_chk_ptr, 1);
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(reg_chk_ptr);
}
}// DEAL_ENTRY_OUT (1) p==2 mag==...
DBG_TRACE_ETE_INCL_CONFREQ(
DBG_MSG_VAR(how);
DBG_MSG_VAR(mag);
DBG_MSG_VAR(p);
);
DBG_TRACE_ETE_INCL_CONFREQ_RETURN(0);
}
/* to be detected:
Order placed, L: 682
Position opened L: 675
Stop of StopLimit triggered => StoLimitOrder => LimitOrder
Pending order triggered => position
Position closed
Order deleted
SL & TP placed
SL & TP modified L:874
SL & TP deleted
SL & TP triggered => position (partly) closed L:842
*/
//10004: error_string = "Ret["+(string)error_code+"] TRADE_RETCODE_REQUOTE: Requote"; break;
//10016: error_string = "Ret["+(string)error_code+"] TRADE_RETCODE_INVALID_STOPS: Invalid stops in the request"; break;
bool chkFail(const string from, MqlTradeRequest &req, MqlTradeResult &res) //10004=requote,
{
if(WhatDebug == <EFBFBD> DebugSend || WhatDebug == <EFBFBD> DebugAll)
Print(from, " tC: ", _t2All(TimeCurrent()), " (long)tC:", (string)(ulong)TimeCurrent(), " => ", (string)req.magic, " ", req.comment, " rq.id: ", res.request_id, " rs.d: ", res.deal, " rs.o: ", res.order, " rs.ret: ", res.retcode);
if (res.retcode == 10004) // requote
{
double d;
if (req.action == TRADE_ACTION_DEAL)
{
if (req.type == ORDER_TYPE_SELL )
{
d = (req.price - req.tp);
if ( res.bid < req.tp - d) return(false);
if ( req.tp > 0 ) req.tp = res.bid - fabs(req.price - req.tp);
if ( req.sl > 0 ) req.sl = res.bid + fabs(req.price - req.sl);
req.price = res.bid;
}
if (req.type == ORDER_TYPE_BUY )
{
d = (req.tp - req.price);
if ( res.ask > req.tp + d) return(false);
if ( req.tp > 0 ) req.tp = res.ask + fabs(req.price - req.tp);
if ( req.sl > 0 ) req.sl = res.ask - fabs(req.price - req.sl);
req.price = res.ask;
}
}
if(!OrderSendAsync(req, res))
{
Print("\n", __FUNCTION__, "[", __LINE__, "] ################ 2nd FAIL: 1st. TRADE_ACTION_DEAL REQUOTE ########\n ORDER_TYPE_CLOSE_BY OrderSendAsync error ", err(_LastError), " rs.order ", res.retcode,
"\ntC ", _t2All(TimeCurrent()), " ask: ", _d2D(SymbolInfoDouble(_Symbol, SYMBOL_ASK)), " bid: ", _d2D(SymbolInfoDouble(_Symbol, SYMBOL_BID))
);
//Print(__FUNCTION__,"[",__LINE__,"] ",prtRequ(req)); Print(__FUNCTION__,"[",__LINE__,"] ",prtResult(res));
return(false);
}
else
{
Print("\n", __FUNCTION__, "[", __LINE__, "] ####################### 2nd TRY 1st. TRADE_ACTION_DEAL REQUOTE tC:", (string)(ulong)TimeCurrent(), " => ", (string)req.magic, "\n ", _Symbol, " ", req.magic, " ", TimeToString(TimeCurrent(), TIME_SECONDS), " ", req.comment, "\n SELL-STOP with SL & TP r.ID: ", res.request_id, " d.O: ", res.deal, " r.O: ", res.order, " r.ret: ", res.retcode);
chkREQ(FunLine, req, res.order);
ResetLastError(); // err: 4756=ERR_TRADE_SEND_FAILED, 10013=TRADE_RETCODE_INVALID,
return(true);
}
}
if (res.retcode == 10016) // Invalid stops
{
Print(__FUNCTION__, "[", __LINE__, "] (", from, ") retcode 10016=Invalid stops in the request: bid:", _d2D(SymbolInfoDouble(_Symbol, SYMBOL_BID)), " ask:", _d2D(SymbolInfoDouble(_Symbol, SYMBOL_ASK)));
prtRequ(req, __LINE__);
prtResult(res, __LINE__);
DebugBreak();
}
if (res.retcode == 10019) // Ret[10019] TRADE_RETCODE_NO_MONEY
{
Print(__FUNCTION__, "[", __LINE__, "] (", from, ") retcode 10019= TRADE_RETCODE_NO_MONEY Free Margin: ", _d22(AccountInfoDouble(ACCOUNT_MARGIN_FREE)), " Bal:", _d22(AccountInfoDouble(ACCOUNT_BALANCE)), " Equ:", _d22(AccountInfoDouble(ACCOUNT_EQUITY)));
prtRequ(req, __LINE__);
prtResult(res, __LINE__);
DebugBreak();
}
req.deviation = (ulong)res.retcode + 1000000 * res.retcode_external; // ret: 10 004 ret_srv:
int i = ArrayAdd(ReqFAIL, req);
int j = ArraySize(ReqFAIL);
while(j-- > 0)
{
Print(__FUNCTION__, "[", __LINE__, "][", j, "] (", from, ") err: ", ReqFAIL[j].deviation, " o:", ReqFAIL[i].deviation, " act:", _e2s(ReqFAIL[j].action), " typ:", _e2s(ReqFAIL[j].type));
}
return(false);
}
//use chkREQ(req);
void chkREQ(const string from, MqlTradeRequest &req, const ulong o)
{
req.deviation = o;
int i = ArrayAdd(ReqCHCK, req);
Print(FunLine, from, " ADD ReqCHCK[", i, "] o:", o, " .dev: ", ReqCHCK[i].deviation, " act:", _e2s(ReqCHCK[i].action), " typ:", _e2s(ReqCHCK[i].type));
return;
int j = ArraySize(ReqCHCK);
while(j-- > 0)
{
Print(FunLine, from, " o:", o, " .dev: ", ReqCHCK[i].deviation, " act:", _e2s(ReqCHCK[j].action), " typ:", _e2s(ReqCHCK[j].type));
}
}
//+------------------------------------------------------------------+
string prtTrans(const MqlTradeTransaction &trans, const int l = 0)
{
//---
//if (TimeCurrent()< D'2022.10.04 03:03:00' || trans.order_state != ORDER_STATE_FILLED ) return("");
string desc = "\nstruct TRANS[" + (string)l + "]:\r\ntype[" + (string)((int)trans.type) + "] " + _e2s(trans.type) + "\r\n";
desc += "Symbol: " + trans.symbol + "\r\n";
desc += "Deal ticket: " + (string)trans.deal + "\r\n";
desc += "Deal type[" + (string)((int)trans.deal_type) + "] " + _e2s(trans.deal_type) + "\r\n";
desc += "Order ticket: " + (string)trans.order + "\r\n";
desc += "Order type[" + (string)((int)trans.order_type) + "]: " + _e2s(trans.order_type) + "\r\n";
desc += "Order state[" + (string)((int)trans.order_state) + "]: " + _e2s(trans.order_state) + "\r\n";
desc += "Order time type: " + _e2s(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";
desc += "Position Ticket: " + (string)trans.position + "\r\n";
desc += "Position by: " + (string)trans.position_by + "\r\n";
//--- den erhaltenen String zur<EFBFBD>ckgeben
//Print(desc);
return(desc);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string prtRequ(const MqlTradeRequest &rq, const int l = 0)
{
//if (TimeCurrent()< D'2022.10.04 03:03:00' ) return("");
string ret = "struct REQUEST[" + (string)l + "]:" + _e2s(rq.type) + "\r\n" + "action[" + (string)((int)rq.action) + "] " + _e2s(rq.action) + "\r\n";
ret += "Mag.Nr. " + (string)rq.magic + "\r\n";
ret += "Order Ticket " + (string)rq.order + "\r\n";
ret += "Symbol " + rq.symbol + "\r\n";
ret += "Vol. " + _d22(rq.volume) + "\r\n";
ret += "Preis " + _d2D(rq.price) + "\r\n";
ret += "StopLimit " + _d2D(rq.stoplimit) + "\r\n";
ret += "SL " + _d2D(rq.sl) + "\r\n";
ret += "TP " + _d2D(rq.tp) + "\r\n";
ret += "Deviat. " + (string)rq.deviation + "\r\n";
ret += "Ordertyp[" + (string)((int)rq.type) + "] " + _e2s(rq.type) + "\r\n";
ret += "Durchf<00>hrung " + _e2s(rq.type_filling) + "\r\n";
ret += "Typ d. Ablauffrist " + _e2s(rq.type_time) + "\r\n";
ret += "Ablauffrist der Pending-Order " + _t2All(rq.expiration) + "\r\n";
ret += "Kommentar " + (rq.comment) + "\r\n";
ret += "Position ticket " + (string)rq.position + "\r\n";
ret += "Ticket of opposite position " + (string)rq.position_by + "\r\n";
Print(ret);
return(ret);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string prtResult(const MqlTradeResult &rs, const int l = 0)
{
//if (TimeCurrent()< D'2022.10.04 03:03:00' ) return("");
string ret = "struct RESULT[" + (string)l + "]\nretCode " + err(rs.retcode) + "\r\n";
ret += "Deal-Ticket " + (string)rs.deal + "\r\n";
ret += "Order-Ticket " + (string)rs.order + "\r\n";
ret += "conf. Vol " + _d22(rs.volume) + "\r\n";
ret += "conf. Preis " + _d2D(rs.price) + "\r\n";
ret += "akt.Bid (Requote Preis) " + _d2D(rs.bid) + "\r\n";
ret += "akt.Ask (Requote Preis) " + _d2D(rs.ask) + "\r\n";
ret += "Kommentar " + rs.comment + "\r\n";
ret += "Term.ID " + (string)rs.request_id + "\r\n";
ret += "exter. RestCode " + (string)rs.retcode_external + "\r\n";
Print(ret);
return(ret);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string prtReqCheck(const MqlTradeCheckResult &rc, const int l = 0)
{
//if (TimeCurrent()< D'2022.10.04 03:03:00' ) return("");
string ret = "struct RESULT[" + (string)l + "]\nretCode " + err(rc.retcode) + "\r\n";
ret += "Balance " + _d22(rc.balance) + "\r\n";
ret += "Equity " + _d22(rc.equity) + "\r\n";
ret += "profit " + _d22(rc.profit) + "\r\n";
ret += "margin " + _d22(rc.margin) + "\r\n";
ret += "margin_free " + _d22(rc.margin_free) + "\r\n";
ret += "margin_level " + _d22(rc.margin_level) + "\r\n";
ret += "Comment " + rc.comment + "\r\n";
Print(ret);
return(ret);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string prtListOpnOrdr(const ulong oID = 0, const ulong mag = 0, const int l = 0, const bool all = true)
{
uint i = OrdersTotal();
while(i-- > 0)
{
ulong t = OrderGetTicket(i);
if (t >= 0)
{
if ( all || (mag != 0 && mag == OrderGetInteger(ORDER_MAGIC)) || (oID != 0 && oID == t))
{
string ret = StringFormat("Order[%i] oT:%s m:%s pT:%s Pr:%s SL:%s PT:%s=> %s @ %s", l,
(string)t, (string)(ulong)fmax(0, OrderGetInteger(ORDER_MAGIC)),
(string)(ulong)OrderGetInteger(ORDER_POSITION_ID),
_d2D(OrderGetDouble(ORDER_PRICE_OPEN)),
_d2D(OrderGetDouble(ORDER_SL)),
_d2D(OrderGetDouble(ORDER_TP)),
_e2s((ENUM_ORDER_TYPE) OrderGetInteger(ORDER_TYPE)),
_t2Sec((datetime)OrderGetInteger(ORDER_TIME_DONE))
);
Print(ret);
//return(ret);
}
}
}
return("" + __FUNCTION__ + "[" + (string)l + "]\nOrder o:" + (string)oID + " m:" + (string)mag + " not found as open pend. order Err:" + err(_LastError) + "\n");
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string prtOpnOrdr(const ulong tckt, const int l = 0)
{
if (OrderSelect(tckt))
{
string ret = StringFormat("Order oT:%s m:%s pT:%s Pr:%s SL:%s PT:%s=> %s @ %s",
(string)tckt, (string)(ulong)fmax(0, OrderGetInteger(ORDER_MAGIC)),
(string)(ulong)OrderGetInteger(ORDER_POSITION_ID),
_d2D(OrderGetDouble(ORDER_PRICE_OPEN)),
_d2D(OrderGetDouble(ORDER_SL)),
_d2D(OrderGetDouble(ORDER_TP)),
_e2s((ENUM_ORDER_TYPE) OrderGetInteger(ORDER_TYPE)),
_t2Sec((datetime)OrderGetInteger(ORDER_TIME_DONE))
);
Print(ret);
//return(ret);
}
return("" + __FUNCTION__ + "[" + (string)l + "]\nOrder o:" + (string)tckt + " not found as open pend. order, Err:" + err(_LastError) + "\n");
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string prtListOpnPos(const ulong oID = 0, const ulong mag = 0, const int l = 0, const bool all = true)
{
uint i = PositionsTotal();
while(i-- > 0)
{
ulong t = PositionGetTicket(i);
if (t >= 0)
{
if ( true || (mag != 0 && mag == PositionGetInteger(POSITION_MAGIC)) || (oID != 0 && oID == t))
{
string ret = StringFormat("Position[%i] o:%s m:%s t:%s p:%s Pr:%s SL:%s PT:%s=> %s @ %s", i,
(string)oID, (string)(ulong)fmax(mag, PositionGetInteger(POSITION_MAGIC)), (string)t,
(string)(ulong)PositionGetInteger(POSITION_IDENTIFIER),
_d2D(PositionGetDouble(POSITION_PRICE_OPEN)),
_d2D(PositionGetDouble(POSITION_SL)),
_d2D(PositionGetDouble(POSITION_TP)),
_e2s((ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE)),
_t2Sec((datetime)PositionGetInteger(POSITION_TIME_UPDATE))
);
Print(ret);
//return(ret);
}
}
}
return("" + __FUNCTION__ + "[" + (string)l + "]\n#########\nPosition p:" + (string)oID + " m:" + (string)mag + " not found as open pend. order Err:" + err(_LastError) + "\n");
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string prtOneOpnPos(const ulong tckt, const string from)
{
if (PositionSelectByTicket(tckt))
{
string ret = StringFormat("Position m:%s o:%s p:%s Pr:%s SL:%s TP:%s => %s @ %s (from:%s)",
(string)(ulong)PositionGetInteger(POSITION_MAGIC), (string)tckt,
(string)(ulong)PositionGetInteger(POSITION_IDENTIFIER),
_d2D(PositionGetDouble(POSITION_PRICE_OPEN)),
_d2D(PositionGetDouble(POSITION_SL)),
_d2D(PositionGetDouble(POSITION_TP)),
_e2s((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)),
_t2Sec((datetime)PositionGetInteger(POSITION_TIME_UPDATE)), from
);
Print(ret);
//return(ret);
}
return(FunLine + "\n#########\nPosition p:" + (string)tckt + " not found as open pend. order Err:" + err(_LastError) + "\n");
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string prtHistDeal(ulong hD, const int l = 0)
{
//if (TimeCurrent()< D'2022.10.04 03:03:00' ) return("");
if (hD <= 0)
{
/*Print(__FUNCTION__,"[",__LINE__,"] Deal[",hD,"] from line: ",(string)l," invalid");*/ return("");
}
HistoryDealSelect(hD);
ulong uMag = HistoryDealGetInteger(hD, DEAL_MAGIC),
//myMag = StringFormat(" myMag:>%I64u< ", uMag),
uPos = HistoryDealGetInteger(hD, DEAL_POSITION_ID),
uOrd = HistoryDealGetInteger(hD, DEAL_ORDER);
double dPrc = HistoryDealGetDouble(hD, DEAL_PRICE);
string ret = StringFormat( "DEAL Info\nM:%s D:%s O:%s P:%s p:%s\nmov: %s\nwhy: %s\n",
(string)uMag, (string)hD, (string)uOrd, (string)uPos, _d2D(dPrc),
_e2s((ENUM_DEAL_ENTRY)HistoryDealGetInteger(hD, DEAL_ENTRY)),
_e2s((ENUM_DEAL_REASON)HistoryDealGetInteger(hD, DEAL_REASON))
);
//Print(ret);
return(ret);
}
//+------------------------------------------------------------------+