VirtualLimitAndTP

Author: TheXpert
Profit factor:
0.00
1 Views
1 Downloads
0 Favorites
VirtualLimitAndTP
//+------------------------------------------------------------------+
//|                                            VirtualLimitAndTP.mq4 |
//|                         https://login.mql5.com/ru/users/TheXpert |
//+------------------------------------------------------------------+
#property copyright "TheXpert"
#property link      "https://login.mql5.com/ru/users/TheXpert"

#define OID "_VIRTUAL_C_open_"
int OID_Len;

#define CID "_VIRTUAL_C_close_"
int CID_Len;

extern int           MaxSpread         = 3;
extern int           Magic             = 2875621956;
extern bool          ConfirmActions    = true;
extern bool          AlertComplete     = true;
extern string        AlertSound        = "alert.wav";
extern color         SelectionColor    = Red;
extern color         TextColor         = White;

double OTasks.lot[];
double OTasks.price[];
double OTasks.dir[];

double CTasks.ticket[];
double CTasks.price[];

void Alert_(string s)
{
   Print(s);
   
   PlaySound("AlertSound");
}

///=========================================================================
/// GUI
///=========================================================================
 
void SetLabel(string name, int x, int y, string text, int size = 10, color clr = White, int corner = 0, string font = "")
{
   ObjectCreate(name, OBJ_LABEL, 0, 0, 0);
   
   ObjectSet(name, OBJPROP_CORNER, corner);

   ObjectSet(name, OBJPROP_XDISTANCE, x);
   ObjectSet(name, OBJPROP_YDISTANCE, y);
   
   ObjectSetText(name, text, size, font, clr);
}

#define IDOK 1
#define IDCANCEL 2
 
bool Confirmed(string action)
{
   if (!ConfirmActions) return (true);
   
   int result = MessageBox("Do you really want to\n" + action + "?", "Please confirm", IDOK);
   return (result == IDOK);
}
 
///=========================================================================
/// Misc
///=========================================================================
 
string ID()
{
   static string result;
   if (StringLen(result) == 0) result = "ZZCEA_task";
   result = StringSetChar(result, 0, 255);
   
   return (result);
}
 
int IDLen()
{
   return (StringLen(ID()));
}
 
int x = 50;
int y = 50;
int d = 20;

string items[];

///=========================================================================
/// DND Implementation
///=========================================================================
 
bool CheckDrag(string name)
{
   double x = ObjectGet(name, OBJPROP_PRICE1);
   if (GetLastError() != 0) return (false);
   
   if (ObjectSet(name, OBJPROP_PRICE1, x*1.1))
   {
      ObjectSet(name, OBJPROP_PRICE1, x);
      return (false);
   }
   
   return (true);
}
 
bool CheckDrop(string name)
{
   double x = ObjectGet(name, OBJPROP_PRICE1);
   if (GetLastError() != 0) return (true);
   
   if (ObjectSet(name, OBJPROP_PRICE1, x*1.1))
   {
      ObjectSet(name, OBJPROP_PRICE1, x);
      return (true);
   }
   
   return (false);
}
 
 
bool IsDragging = false;
string DragName = "";
 
double DropPrice;
 
void OnDropped(string name)
{
   IsDragging = false;

   if (name != ID() + " remove") return;
   
   int y = ObjectGet(name, OBJPROP_YDISTANCE);
   int item = GetItem(y);

   if (item >= 0 && item < ArraySize(items))
   {
      if (Confirmed(" remove " + items[item]))
      {
         RemoveListItem(item);
      }
   } 
}
 
void WhileDragging(string name)
{
   if (name != ID() + " remove") return;
   
   int y = ObjectGet(name, OBJPROP_YDISTANCE);
   int item = GetItem(y);
   
   DrawList();
   if (item >= 0 && item < ArraySize(items))
   {
      ObjectSet(ID() + item, OBJPROP_COLOR, SelectionColor);
   }
}
 
///=========================================================================
/// Implementation
///=========================================================================

void DrawList()
{
   string label = StringSetChar(" ", 0, 235);
   
   SetLabel(ID() + " remove", x - 10, y - 10, label, 20, SelectionColor, 0, "Wingdings");
   
   int size = ArraySize(items);
   
   for (int i = 0; i < size; i++)
   {
      SetLabel(ID() + i, x + d, y + d*(i + 1), items[i], 10, TextColor);
   }
   
   int total = ObjectsTotal();
   for (i = total - 1; i >= 0; i--)
   {
      string s = ObjectName(i);
      if (s == ID() + " remove") continue;
      if (StringFind(s, ID()) >= 0)
      {
         int idx = StrToInteger(StringSubstr(s, IDLen()));
         if (idx >= size)
         {
            ObjectDelete(s);
         }
      }
   }
}

string StringIf(bool c, string ifTrue, string ifFalse)
{
   if (c) return (ifTrue);
   return (ifFalse);
}

void MakeList()
{
   int oSize = ArraySize(OTasks.price);
   int cSize = ArraySize(CTasks.price);
   
   ArrayResize(items, oSize + cSize);
   
   for (int i = 0; i < oSize; i++)
   {
      string s = " Open ";
      s = s + StringIf(OTasks.dir[i] == 0, "Buy ", "Sell ");
      s = s + DoubleToStr(OTasks.lot[i], 2) + " at " + DoubleToStr(OTasks.price[i], Digits);
      
      items[i] = s;
   }

   for (i = 0; i < cSize; i++)
   {
      s = " Close #" + DoubleToStr(CTasks.ticket[i], 0);
      
      if (OrderSelect(CTasks.ticket[i], SELECT_BY_TICKET))
      {
         s = s + " ( " + DoubleToStr(OrderLots(), 2) + StringIf(OrderType() == OP_BUY, " Buy ", " Sell ") + " at " + DoubleToStr(OrderOpenPrice(), Digits) + " ) ";
      }
      
      s = s + " at " + DoubleToStr(CTasks.price[i], Digits);
      
      items[oSize + i] = s;
   }
}

int GetItem(int yPos)
{
   return ((yPos - y)/d - 1);
}

void RemoveListItem(int pos)
{
   int oSize = ArraySize(OTasks.price);
   int cSize = ArraySize(CTasks.price);
   
   int iSize = ArraySize(items);
   
   if (iSize != oSize + cSize) return;
   if (pos < 0 || pos >= iSize) return;
   
   if (pos < oSize)  RemoveOpenTask(pos);
   else              RemoveCloseTask(pos - oSize);
}

void WaitForContext()
{
   while (IsTradeContextBusy() && !IsStopped())
   {
      Sleep(10 + (MathRand() % 30));
   }
}

void CheckNewTasks()
{
   bool needSave = false;
   
   int total = GlobalVariablesTotal();
   for (int i = 0; i < total; i++)
   {
      string s = GlobalVariableName(i);
      int pos = StringFind(s, OID);
      
      if (pos != -1)
      {
         string dir = StringSubstr(s, pos + OID_Len, 1);
         string lots = StringSubstr(s, pos + OID_Len + 1);
         double price = NormalizeDouble(GlobalVariableGet(s), Digits);
         
         GlobalVariableDel(s);
         
         OnNewOpenTask(StrToInteger(dir), NormalizeDouble(StrToDouble(lots), 2), price);
         needSave = true;
      }
   }
   
   if (needSave) SaveOpenTasks();
   
   needSave = false;
   
   total = GlobalVariablesTotal();
   for (i = 0; i < total; i++)
   {
      s = GlobalVariableName(i);
      pos = StringFind(s, CID);
      
      if (pos != -1)
      {
         string ticket = StringSubstr(s, pos + CID_Len);
         price = NormalizeDouble(GlobalVariableGet(s), Digits);
         
         GlobalVariableDel(s);

         OnNewCloseTask(StrToInteger(ticket), price);
         needSave = true;
      }
   }
   
   if (needSave) SaveCloseTasks();
}

void OnNewOpenTask(int direction, double lots, double price)
{
   if (lots <= 0) return;
   if (price <= 0) return;
   
   int size = ArraySize(OTasks.price);
   
   ArrayResize(OTasks.lot, size + 1);
   ArrayResize(OTasks.price, size + 1);
   ArrayResize(OTasks.dir, size + 1);
   
   OTasks.lot[size] = lots;
   OTasks.price[size] = price;
   OTasks.dir[size] = direction;
   
   Print("Added new open task");
}

void OnNewCloseTask(int ticket, double price)
{
   if (ticket <= 0) return;
   if (price <= 0) return;
   
   int size = ArraySize(CTasks.price);

   ArrayResize(CTasks.ticket, size + 1);
   ArrayResize(CTasks.price, size + 1);

   CTasks.ticket[size] = ticket;
   CTasks.price[size] = price;

   Print("Added new close task");
}

void SaveOpenTasks()
{
   int size = ArraySize(OTasks.price);

   string path = TerminalCompany() + "\\" + AccountNumber() + "\\" + Symbol() + "\\" + "otasks.csv";

   if (size == 0)
   {
      FileDelete(path);
      return;
   }

   int hFile = FileOpen(path, FILE_WRITE | FILE_CSV);
   if (hFile == -1) return;
   
   for (int i = 0; i < size; i++)
   {
      string s;
      s = StringConcatenate(OTasks.lot[i], ";", OTasks.price[i], ";", OTasks.dir[i]);
      FileWrite(hFile, s);
   }
   
   FileClose(hFile);
}

void SaveCloseTasks()
{
   int size = ArraySize(CTasks.price);

   string path = TerminalCompany() + "\\" + AccountNumber() + "\\" + Symbol() + "\\" + "ctasks.csv";

   if (size == 0)
   {
      FileDelete(path);
      return;
   }

   int hFile = FileOpen(path, FILE_WRITE | FILE_CSV);
   if (hFile == -1) return;
   
   for (int i = 0; i < size; i++)
   {
      string s;
      s = StringConcatenate(DoubleToStr(CTasks.ticket[i], 0), ";", DoubleToStr(CTasks.price[i], Digits));
      FileWrite(hFile, s);
   }
   
   FileClose(hFile);
}

void LoadOpenTasks()
{
   string path = TerminalCompany() + "\\" + AccountNumber() + "\\" + Symbol() + "\\" + "otasks.csv";
   int hFile = FileOpen(path, FILE_READ | FILE_CSV);
   if (hFile == -1) return;
   
   ArrayResize(OTasks.lot, 0);
   ArrayResize(OTasks.price, 0);
   ArrayResize(OTasks.dir, 0);
   
   int lastErr = 0;
   
   while (lastErr == 0)
   {
      double lots = FileReadNumber(hFile);
      lastErr = GetLastError();
      if (lastErr != 0) break;
      
      double price = FileReadNumber(hFile);
      lastErr = GetLastError();
      if (lastErr != 0) break;
      
      double dir = FileReadNumber(hFile);
      lastErr = GetLastError();
      if (lastErr != 0) break;

      int size = ArraySize(OTasks.price);

      ArrayResize(OTasks.lot, size + 1);
      ArrayResize(OTasks.price, size + 1);
      ArrayResize(OTasks.dir, size + 1);
      
      OTasks.lot[size] = lots;
      OTasks.price[size] = price;
      OTasks.dir[size] = dir;
   }
   
   FileClose(hFile);
}

void LoadCloseTasks()
{
   string path = TerminalCompany() + "\\" + AccountNumber() + "\\" + Symbol() + "\\" + "ctasks.csv";
   int hFile = FileOpen(path, FILE_READ | FILE_CSV);
   if (hFile == -1) return;
   
   ArrayResize(CTasks.ticket, 0);
   ArrayResize(CTasks.price, 0);
   
   int lastErr = 0;
   
   while (lastErr == 0)
   {
      double ticket = FileReadNumber(hFile);
      lastErr = GetLastError();
      if (lastErr != 0) break;
      
      double price = FileReadNumber(hFile);
      lastErr = GetLastError();
      if (lastErr != 0) break;
      
      int size = ArraySize(CTasks.price);

      ArrayResize(CTasks.ticket, size + 1);
      ArrayResize(CTasks.price, size + 1);

      CTasks.ticket[size] = ticket;
      CTasks.price[size] = price;
   }
   
   FileClose(hFile);
}

void ProcessOpenTasks()
{
   int size = ArraySize(OTasks.price);
   
   for (int i = size - 1; i >= 0; i--)
   {
      if (OTasks.dir[i] == 0)
      {
         ProcessOpenBuy(i, OTasks.lot[i], OTasks.price[i]);
      }
      else if (OTasks.dir[i] == 1)
      {
         ProcessOpenSell(i, OTasks.lot[i], OTasks.price[i]);
      }
   }
}

void ProcessCloseTasks()
{
   int size = ArraySize(CTasks.price);
   
   for (int i = size - 1; i >= 0; i--)
   {
      if (!OrderSelect(CTasks.ticket[i], SELECT_BY_TICKET))
      {
         RemoveCloseTask(i);
         continue;
      }
      
      if (OrderCloseTime() > 0)
      {
         RemoveCloseTask(i);
         continue;
      }
      
      if (OrderType() == OP_BUY)
      {
         ProcessCloseBuy(i, CTasks.ticket[i], CTasks.price[i]);
      }
      else if (OrderType() == OP_SELL)
      {
         ProcessCloseSell(i, CTasks.ticket[i], CTasks.price[i]);
      }
   }
}

void ProcessOpenBuy(int pos, double lots, double price)
{
   WaitForContext();
   RefreshRates();

   if (Ask < (price + (MaxSpread + 0.5)*Point))
   { // ìîæíî îòêðûâàòüñÿ
      int res = OrderSend(Symbol(), OP_BUY, lots, Ask, 0, 0, 0, NULL, Magic, 0, Blue);
      if (res != -1)
      {
         RemoveOpenTask(pos);
         Alert_("Open buy task processed successfully");
      }
   }
}

void ProcessOpenSell(int pos, double lots, double price)
{
   WaitForContext();
   RefreshRates();

   if (Bid > price - 0.5*Point)
   { // ìîæíî îòêðûâàòüñÿ
      int res = OrderSend(Symbol(), OP_SELL, lots, Bid, 0, 0, 0, NULL, Magic, 0, Red);
      if (res != -1)
      {
         RemoveOpenTask(pos);
         Alert_("Open sell task processed successfully");
      }
   }
}

void ProcessCloseBuy(int pos, int ticket, double price)
{
   if (!OrderSelect(ticket, SELECT_BY_TICKET)) return;

   WaitForContext();
   RefreshRates();

   if (Bid > price - 0.5*Point)
   { // ìîæíî çàêðûâàòüñÿ
      if (OrderClose(ticket, OrderLots(), Bid, 0, Blue))
      {
         RemoveCloseTask(pos);
         Alert_("Close buy task processed successfully");
      }
   }
}

void ProcessCloseSell(int pos, int ticket, double price)
{
   if (!OrderSelect(ticket, SELECT_BY_TICKET)) return;

   WaitForContext();
   RefreshRates();

   if (Ask < (price + (MaxSpread + 0.5)*Point))
   { // ìîæíî çàêðûâàòüñÿ
      if (OrderClose(ticket, OrderLots(), Ask, 0, Red))
      {
         RemoveCloseTask(pos);
         Alert_("Close sell task processed successfully");
      }
   }
}

void RemoveOpenTask(int i)
{
   int size = ArraySize(OTasks.price);
   int pos = size - 1;
   
   OTasks.lot[i] = OTasks.lot[pos];
   OTasks.price[i] = OTasks.price[pos];
   OTasks.dir[i] = OTasks.dir[pos];
   
   ArrayResize(OTasks.lot, pos);
   ArrayResize(OTasks.price, pos);
   ArrayResize(OTasks.dir, pos);
   
   SaveOpenTasks();
}

void RemoveCloseTask(int i)
{
   int size = ArraySize(CTasks.price);
   int pos = size - 1;
   
   CTasks.ticket[i] = CTasks.ticket[pos];
   CTasks.price[i] = CTasks.price[pos];
   
   ArrayResize(CTasks.ticket, pos);
   ArrayResize(CTasks.price, pos);
   
   SaveCloseTasks();
}

bool FirstRun;

int init()
{
   OID_Len = StringLen(OID);
   ArrayResize(OTasks.lot, 0);
   ArrayResize(OTasks.price, 0);
   ArrayResize(OTasks.dir, 0);
   
   CID_Len = StringLen(CID);
   ArrayResize(CTasks.ticket, 0);
   ArrayResize(CTasks.price, 0);

   
   LoadOpenTasks();
   LoadCloseTasks();
   
   IsDragging = false;
   DragName = "";
   
   FirstRun = true;
   
   return(0);
}

int deinit()
{
   int count = ObjectsTotal();
   for (int i = count - 1; i >= 0; i--)
   {
      string name = ObjectName(i);
      if (StringFind(name, ID()) != -1)
      {
         ObjectDelete(name);
      }
   }
   
   return(0);
}

int start()
{
   if (IsTesting()) return (0);
   
   if (ArraySize(CTasks.ticket) > 0 && OrdersHistoryTotal() == 0 && FirstRun)
   {
      // potential fail while processing close tasks. Trying to avoid.
      Print("Waiting for terminal synchronization");
      Sleep(10000);
   }
   FirstRun = false;
   
   while (!IsStopped() && IsExpertEnabled())
   {
      if (IsDragging)
      {
         if (CheckDrop(DragName))
         {
            OnDropped(DragName);
         }
         else
         {
            WhileDragging(DragName);
         }
      }
      else
      {
         CheckNewTasks();
   
         ProcessCloseTasks();
         ProcessOpenTasks();

         MakeList();
         DrawList();
         
         if (CheckDrag(ID() + " remove")) 
         {
            DragName = ID() + " remove";
            IsDragging = true;
         }
      }
   
      WindowRedraw();
   
      Sleep(50);
   }
   
   return(0);
}

Comments