EA-Setka-2/Libs/Virtual/Sync.mqh
super.admin a4b861dd93 convert
2025-05-30 14:50:44 +02:00

217 lines
No EOL
5.3 KiB
MQL5

#include "Virtual.mqh"
struct MT4ORDER
{
datetime OpenTime;
double OpenPrice;
double TP;
double Lots;
MT4ORDER( void ) : Lots(0), TP(0)
{
}
void Set( void )
{
this.OpenTime = OrderOpenTime();
this.OpenPrice = OrderOpenPrice();
this.TP = OrderTakeProfit();
this.Lots = OrderLots();
return;
}
bool operator !=( const MT4ORDER &MT4Order ) const
{
return((this.OpenPrice != MT4Order.OpenPrice) || (this.TP != MT4Order.TP));
}
};
class ISTIME
{
public:
static bool IsTime( const datetime time )
{
return(true);
}
};
class SYNC
{
private:
template <typename T>
static double GetNettingPosition( const string &Symb )
{
double Res = 0;
for (int i = OrdersTotal() - 1; i >= 0; i--)
if (OrderSelect(i, SELECT_BY_POS) && T::IsTime(OrderOpenTime())/* && (OrderSymbol() == Symb)*/)
{
if (OrderType() == OP_BUY)
Res += OrderLots();
else if (OrderType() == OP_SELL)
Res -= OrderLots();
}
return(Res);
}
static int OrderScan( const int Type )
{
int Res = -1;
for (int i = OrdersTotal() - 1; i >= 0; i--)
if (OrderSelect(i, SELECT_BY_POS) && (OrderType() == Type)/* && (OrderSymbol() == _Symbol)*/)
{
Res = Type;
break;
}
return(Res);
}
static void CloseBy( void )
{
if (SYNC::OrderScan(OP_SELL) == OP_SELL)
{
const TICKET_TYPE SellTicket = OrderTicket();
if (SYNC::OrderScan(OP_BUY) == OP_BUY)
OrderCloseBy(OrderTicket(), SellTicket);
}
return;
}
static void NewOrderSend( const string &Symb, const int &Type, double dLots,
const double &Price, const int Slip, const double SL, const double TP)
{
while (dLots && (SYNC::OrderScan(1 - Type) == 1 - Type))
{
const double SelectLots = OrderLots();
const bool Flag = (SelectLots >= dLots);
const double CloseLots = Flag ? dLots : SelectLots;
if (OrderClose(OrderTicket(), CloseLots, Price, Slip))
dLots = Flag ? 0 : ::NormalizeDouble(dLots - CloseLots, 2);
}
if (dLots)
OrderSend(Symb, Type, dLots, Price, Slip, SL, TP);
return;
}
public:
template <typename T>
static void Positions( const int Handle = 0, const bool Reverse = false )
{
const int PrevHandle = VIRTUAL::GetHandle();
if (Handle != PrevHandle)
{
const double PrevLots = SYNC::GetNettingPosition<T>(_Symbol);
if (VIRTUAL::SelectByHandle(Handle))
{
const double NewLots = SYNC::GetNettingPosition<ISTIME>(_Symbol);
const double AddLots = ::NormalizeDouble(PrevLots - (Reverse ? -NewLots : NewLots), 2);
if (AddLots)
{
const int TypeBuy = Reverse ? OP_SELL : OP_BUY;
const int Type = (AddLots > 0) ? TypeBuy : 1 - TypeBuy;
const double Price = ::SymbolInfoDouble(_Symbol, Type ? SYMBOL_BID : SYMBOL_ASK);
SYNC::NewOrderSend(_Symbol, Type, ::MathAbs(AddLots), Price, 100, 0, 0);
/* OrderSend(_Symbol, Type, ::MathAbs(AddLots), Price, 100, 0, 0);
// https://www.mql5.com/ru/forum/283611/page3#comment_9038400
if (!VIRTUAL::IsNetting())
SYNC::CloseBy(); */
}
VIRTUAL::SelectByHandle(PrevHandle);
}
}
return;
}
static void NewOrderSend( const int Type, const MT4ORDER &NewLimit )
{
MT4ORDER CurrentLimit;
if ((SYNC::OrderScan(Type) == Type))
CurrentLimit.Set();
if (CurrentLimit.Lots != NewLimit.Lots)
{
if (CurrentLimit.Lots)
OrderDelete(OrderTicket());
if (NewLimit.Lots)
OrderSend(_Symbol, Type, NewLimit.Lots, NewLimit.OpenPrice, 100, 0, NewLimit.TP);
}
else if (CurrentLimit.Lots && (CurrentLimit != NewLimit))
OrderModify(OrderTicket(), NewLimit.OpenPrice, 0, NewLimit.TP, 0);
return;
}
template <typename T>
static void Limits( datetime CurrentTime, const int Handle = 0 )
{
static double PrevMarketLots = 0;
static double PrevLimitLots = 0;
const int PrevHandle = VIRTUAL::GetHandle();
if (Handle != PrevHandle)
{
MT4ORDER BuyLimit;
MT4ORDER SellLimit;
MT4ORDER Buy;
MT4ORDER Sell;
if ((SYNC::OrderScan(OP_BUYLIMIT) == OP_BUYLIMIT))
BuyLimit.Set();
if (SYNC::OrderScan(OP_SELLLIMIT) == OP_SELLLIMIT)
SellLimit.Set();
if ((SYNC::OrderScan(OP_BUY) == OP_BUY))
Buy.Set();
else if (SYNC::OrderScan(OP_SELL) == OP_SELL)
Sell.Set();
if (BuyLimit.Lots && !T::IsTime(CurrentTime))
BuyLimit.Lots = Sell.Lots;
if (BuyLimit.Lots && !T::IsTime(Sell.OpenTime))
BuyLimit.Lots -= Sell.Lots;
if (SellLimit.Lots && !T::IsTime(CurrentTime))
SellLimit.Lots = Buy.Lots;
if (SellLimit.Lots && !T::IsTime(Buy.OpenTime))
SellLimit.Lots -= Buy.Lots;
BuyLimit.Lots = ::NormalizeDouble(BuyLimit.Lots, 2);
SellLimit.Lots = ::NormalizeDouble(SellLimit.Lots, 2);
if (VIRTUAL::SelectByHandle(Handle))
{
SYNC::NewOrderSend(OP_BUYLIMIT, BuyLimit);
SYNC::NewOrderSend(OP_SELLLIMIT, SellLimit);
}
VIRTUAL::SelectByHandle(PrevHandle);
}
return;
}
};