#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 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 static void Positions( const int Handle = 0, const bool Reverse = false ) { const int PrevHandle = VIRTUAL::GetHandle(); if (Handle != PrevHandle) { const double PrevLots = SYNC::GetNettingPosition(_Symbol); if (VIRTUAL::SelectByHandle(Handle)) { const double NewLots = SYNC::GetNettingPosition(_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 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; } };