//+------------------------------------------------------------------+
//|                                       Visual_Handle_Tranning.mq4 |
//+------------------------------------------------------------------+
//|  b - открыть позицию Buy;                                        |
//|  s - открыть позицию Sell;                                       |
//|  "стрелка вверх" - закрыть все BUY;                              |
//|  "стрелка вниз" - закрыть все SELL;                              |
//|  t - включает трейлинг стоп общий;                               |
//|  r - выключает трейлинг стоп;                                    |
//|  d - удаление всех отложенных ордеров.                           |
//|    Для выставления отложенного ордера мышкой выбираем из меню    |
//|  значков "Стрелочку вверх" для Buy-ев и щелкаем в том месте,     |
//|  где планируем поставить ордер. Если щелкнуть выше цены, то      |
//|  будет BuyStop, если ниже - будет BuyLimit.                      |
//|  для Sell-ов, соответственно, значек "стрелочка вниз".           |
//|              Модификация отдельных ордеров:                      |
//|  Двойным щелчком мыши выделяем нужный нам значек-ордер           |
//|  далее, щелкаем по нему правой клавишей мыши                     |
//|  и выбираем свойства Arrow.                                      |
//|  Далее, меняем в поле "Описание" нужные параметры отдельного     |
//|  ордера.                                                         |
//|  Можно менять SL, TP, а также закрыть рыночный ордер             |
//|  или удалить отложенный Вместо EMPTY пишем close или del         |
//|   ВАЖНО сохранить пробелы - это разделители !!!                  |
//|  Формат поля "Описание", разделитель-"ПРОБЕЛ!!!":                |
//|  |  1   |  2   | 3 |  4   | 5 |  6   |   7    |  8  |            |
//|  Price= 1.2565 SL= 1.2765 TP= 1.2265 Команда= close              |
//|  |      |      |   |      |   |      |        |     |            |
//|  Команда на закрытие рыночного ордера - close                    |
//|  Удаление отложенного - del                                      |
//+------------------------------------------------------------------+

#property copyright "Copyright © 2005, klot"
#property link      "klot@mail.ru"
#define MAGICEXP 00000001
//----
#include <stdlib.mqh>
#include <WinUser32.mqh>
//----
#import "IdleLib.dll"
int GetLastKeyWP();
int GetLastMouseWP();
int IdleLibInit();
int IdleLibUnInit();
string GetActiveWndName();
#import
//----
extern double Lots = 0.1;
extern double TrailingStop = 15.0;
//----
static datetime lastsd;
static int tral = 0;
//color clModifyBuy = Aqua;
//color clModifySell = Magenta;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
// инициализируем Dll для перехвата событий 
   IdleLibInit();
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
// деинициализируем Dll для перехвата событий 
   IdleLibUnInit();
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   if(IsDllsAllowed() == false)
     {
       Print("Вызов DLL-функций из библиотек невозможен. Эксперт не может выполняться.");
       return(0);
     }
   if(IsLibrariesAllowed() == false)
     {
       Print("Библиотечные вызовы запрещены. Эксперт не может выполняться.");
       return(0);
     }
   if(!IsTesting()) 
     { 
       Print("Эксперт запущен не в режиме тестирования"); 
       return(0);
     }
   if(IsOptimization())
     { 
       Print("Эксперт запущен в режиме оптимизации"); 
       return(0);
     } 
// устранение дребезга клавиш
   static int trigger = 0; 
// Опрашиваем код последней нажатой клавиши
   int lastkey = GetLastKeyWP(); 
// Имя окна Metatrader, где произошло событие
   string lastwnd = GetActiveWndName();
//----
   if((lastkey != 0) && (lastwnd != ""))
     {
       //устранение дребезга клавиш
       if(trigger != lastkey) 
           trigger = lastkey; 
       else 
         { 
           lastkey = 0; 
           trigger = 0; 
         }
       //---
       switch(lastkey)
         {
           case 66: buy_open(0, 0); 
                    break;
           case 83: sell_open(0, 0); 
                    break;
           case 38: close_order(1); 
                    break;
           case 40: close_order(-1); 
                    break;
           case 84: if(tral == 0) 
                        tral = 1; 
                    Comment("Tralling включен = ", TrailingStop); 
                    break;
           case 82: if(tral == 1 ) 
                        tral = 0; 
                    Comment("Tralling выключен"); 
                    break;
           case 68: delete_pending_all(); 
                    break;
           //case ..: можно придумать любую собственню фичу
           default : break;
         }
     }
   send_pending();
   managers_market_orders();
//----
   if(lastkey != 0)
       Print(" "+lastkey);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Управление рыночными ордерами (изменение SL,TP,price)            |
//| Все писать в Свойствах Arrow, в поле "Описание"                  |
//| Формат поля "Описание", разделитель-"ПРОБЕЛ!!!":                 |
//| |  1   |  2   | 3 |  4   | 5 |  6   |   7    |  8  |             |
//|  Price= 1.2565 SL= 1.2765 TP= 1.2265 Команда= close              |
//| |      |      |   |      |   |      |        |     |             |
//| Команда на закрытие рыночного ордера - close                     |
//| Удаление отложенного - del                                       |
//|    
//+------------------------------------------------------------------+
void managers_market_orders()
  {     
   string desc, name, exec, _EMPTY = "EMPTY";
   string array_param[];
   int count, arrow_code, ticket, pos, nGetLastError;
   double price, sl, tp;
   int TrailingStep = 5;
   int obj_total = ObjectsTotal();
//----
   if(obj_total == 0) 
       return;
//----
   for(int i = obj_total - 1; i >= 0; i--)
     {
       name = ObjectName(i);
       //----
       if(ObjectType(name) != OBJ_ARROW) 
           continue;
       arrow_code = ObjectGet(name, OBJPROP_ARROWCODE);
       if(arrow_code != 1 && arrow_code != 2) 
           continue;
       else
         {
           //Вычисляем тикет ордера по значку Arrow 
           pos = StringFind(name, " ", 0);
           ticket = StrToInteger(StringSubstr(name, 1, pos)); 
           //Print("ticket= ",ticket);
           //---
           if(OrderSelect(ticket, SELECT_BY_TICKET) == true)
             {
               if(OrderCloseTime()!=0) 
                   continue;
               //Читаем поле Описание в свойствах Arrow
               desc = ObjectDescription(name);
               // Если строчка пустая заполним начальными значениями
               if(StringLen(desc) == 0) 
                 { 
                   desc = StringConcatenate("Price= ", OrderOpenPrice(), " SL= ", 
                                            OrderStopLoss(), " TP= ", OrderTakeProfit(),
                                            " Команда= ",_EMPTY); 
                   ObjectSetText(name, desc); 
                 }
               // заполнение массива параметров ордера
               count = StrSplit(desc, array_param, " ");
               if(count != 8)
                 {
                   desc = StringConcatenate("Price= ", OrderOpenPrice(), " SL= ", 
                                            OrderStopLoss(), " TP= ", OrderTakeProfit(),
                                            " Команда= ",_EMPTY);
                   ObjectSetText(name, desc);
                   Print(" Ошибка в формате поля Оисание. Поле востановлено!!!");
                 }
               else
                 {
                   price = StrToDouble(array_param[1]);
                   sl = StrToDouble(array_param[3]);
                   tp = StrToDouble(array_param[5]);
                   exec = array_param[7];
                 }
               //---
               if(OrderType()==OP_BUY)
                 {
                   if(TrailingStop > MarketInfo(Symbol(), MODE_STOPLEVEL) && tral == 1)
                     {
                       if(Bid - OrderOpenPrice() > TrailingStop*Point)
                         {
                           if(OrderStopLoss() < Bid - (TrailingStop + TrailingStep - 1)*Point)
                             {
                               sl = Bid - TrailingStop*Point;
                               desc = StringConcatenate("Price= ", OrderOpenPrice(), " SL= ", 
                                                        sl, " TP= ", OrderTakeProfit(),
                                                        " Команда= ", _EMPTY);
                               ObjectSetText(name, desc);
                             }
                         }
                     }
                   //---
                   if(sl != 0 && sl != OrderStopLoss()) 
                       ModifyStopLoss(sl);
                   if(tp != 0 && tp != OrderTakeProfit()) 
                       ModifyTakeProfit(tp);
                   //---
                   if(exec == "close") 
                     {
                       RefreshRates();
                       OrderClose(OrderTicket(), OrderLots(), Bid, 3, Aqua);
                       nGetLastError = GetLastError();
                       if(nGetLastError != 0) 
                       Print("Error closing BUY order : ", ErrorDescription(nGetLastError));
                     }               
                 }
               if(OrderType() == OP_SELL)
                 {
                   if(TrailingStop > MarketInfo(Symbol(), MODE_STOPLEVEL) && tral == 1)
                     {
                       if(OrderOpenPrice() - Ask > TrailingStop*Point)
                         {
                           if(OrderStopLoss() > Ask + (TrailingStop + TrailingStep - 
                              1)*Point || OrderStopLoss() == 0)
                             {
                               sl = Ask + TrailingStop*Point;
                               desc = StringConcatenate("Price= ", OrderOpenPrice(), 
                                            " SL= ", sl, " TP= ", OrderTakeProfit(),
                                            " Команда= ",_EMPTY);
                               ObjectSetText(name, desc);
                             }
                         }
                     }
                   //---
                   if(sl != 0 && sl != OrderStopLoss()) 
                       ModifyStopLoss(sl);
                   if(tp != 0 && tp != OrderTakeProfit()) 
                       ModifyTakeProfit(tp);
                   //---
                   if(exec=="close") 
                     {
                       RefreshRates();   
                       OrderClose(OrderTicket(), OrderLots(), Ask, 3, Yellow);
                       nGetLastError = GetLastError();
                       if(nGetLastError != 0)
                           Print("Error closing SELL order : ", 
                                 ErrorDescription(nGetLastError));
                     }
                 }
               if(OrderType() == OP_SELLLIMIT || OrderType() == OP_BUYLIMIT || 
                  OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP)
                 {
                   // если мышкой переместили ордер
                   if(NormalizeDouble(ObjectGet(name, OBJPROP_PRICE1), Digits) != price)
                     {
                       price = NormalizeDouble(ObjectGet(name, OBJPROP_PRICE1), Digits);
                       desc = StringConcatenate("Price= ", price, " SL= ", OrderStopLoss(), 
                                              " TP= ", OrderTakeProfit(), " Команда= ",
                                              _EMPTY);
                       ObjectSetText(name, desc);
                     }
                   //---
                   if(price != OrderOpenPrice() && MathAbs(price - Ask) > 
                      (MarketInfo(Symbol(), MODE_STOPLEVEL)*Point) )
                     {
                       OrderModify(OrderTicket(), price, OrderStopLoss(), OrderTakeProfit(),
                                   OrderExpiration(),CLR_NONE);
                       nGetLastError = GetLastError();
                       if(nGetLastError != 0)
                           Print("Error closing SELL order : ", 
                                 ErrorDescription(nGetLastError));
                       else 
                           ObjectDelete(name);
                     }
                   //----
                   if(sl != 0 && sl != OrderStopLoss()) 
                       ModifyStopLoss(sl);
                   if(tp != 0 && tp != OrderTakeProfit()) 
                       ModifyTakeProfit(tp);
                   //----
                   if(exec == "del")
                     {
                       OrderDelete(OrderTicket());
                       nGetLastError = GetLastError();
                       if(nGetLastError != 0)
                           Print("Error closing SELL order : ", 
                                 ErrorDescription(nGetLastError));
                     }
                 }
             }
           else  
               Print("OrderSelect() вернул ошибку - ", GetLastError());
         }
     }
  }
//+------------------------------------------------------------------+
//| Установка отложенных ордеров                                     |
//| просто перетаскиваем значек "стрелочка вверх" на место, куда     |
//| хотим поставить отложенный ордер. Если выше цены будет ByuStop   |
//| если ниже цены - будет BuyLimit. Для Sel-ов - соответственно     |
//| значек "стрелочка вниз"                                          |
//+------------------------------------------------------------------+
void send_pending()
  {
   int arrow_code;
   string name;
   double price;
   int obj_total = ObjectsTotal();
//----
   for(int i = 0; i < obj_total; i++)
     {
       name = ObjectName(i);
       if(ObjectType(name) != OBJ_ARROW) 
           continue;
       arrow_code = ObjectGet(name, OBJPROP_ARROWCODE);
       if(arrow_code != 242 && arrow_code != 241) 
           continue;
       //---
       if(arrow_code == 242)
         { 
           price = NormalizeDouble(ObjectGet(name, OBJPROP_PRICE1), Digits);
           if(price < Bid - (MarketInfo(Symbol(), MODE_STOPLEVEL)*Point))
             {
               sellstop_open(price, 0, 0);  
               ObjectDelete(name);
             }
           if(price > Ask + (MarketInfo(Symbol(), MODE_STOPLEVEL)*Point))
             {
               selllimit_open(price, 0, 0);
               ObjectDelete(name);
             }
         }
       //---
       if(arrow_code == 241)
         { 
           price = NormalizeDouble(ObjectGet(name, OBJPROP_PRICE1), Digits);
           //----
           if(price > Ask + (MarketInfo(Symbol(), MODE_STOPLEVEL)*Point))
             {
               buystop_open(price, 0, 0);
               ObjectDelete(name);
             }
           if(price < Bid - (MarketInfo(Symbol(), MODE_STOPLEVEL)*Point))
             {
               buylimit_open(price, 0, 0);
               ObjectDelete(name);
             }
         }
     }
//----
   return;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void delete_pending_all()
  {
   bool result;
   int cmd, total;
   total = OrdersTotal();
//----
   if(total == 0) 
       return;
//----
   for(int i = total - 1; i >= 0; i--)
     {
       if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         {
           cmd = OrderType();
           //---- pending orders only are considered
           if(cmd != OP_BUY && cmd != OP_SELL)
             {
               //---- print selected order
               OrderPrint();
               //---- delete first pending order
               result = OrderDelete(OrderTicket());
               //----
               if(result != TRUE)
                 { 
                   Print("LastError = ", GetLastError());
                   break;
                 }
             }
         }
       else 
         { 
           Print( "Error when order select ", GetLastError()); 
           break; 
         }
     }
//----
   return;
 }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void selllimit_open( double price, double SL=0, double TP=0 )
  {
   int ticket, expiration;
//----
   expiration = CurTime() + PERIOD_D1*60;
//----
   ticket = OrderSend(Symbol(), OP_SELLLIMIT, Lots, price, 0, SL, TP, "", MAGICEXP, 
                      expiration, Green);
   if(ticket <= 0) 
       Print("Error = ", GetLastError());
   else 
     { 
       Print("ticket = ", ticket); 
       lastsd = CurTime(); 
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void sellstop_open( double price, double SL=0, double TP=0 )
  {
   int ticket, expiration;
//----
   expiration = CurTime() + PERIOD_D1*60;
//----
   ticket = OrderSend(Symbol(), OP_SELLSTOP, Lots,price, 0, SL, TP, "", MAGICEXP,
                      expiration, Green);
   if(ticket <= 0) 
       Print("Error = ", GetLastError());
   else 
     { 
       Print("ticket = ", ticket); 
       lastsd = CurTime(); 
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void buylimit_open(double price, double SL = 0, double TP = 0)
  {
   int ticket,expiration;
//----
   expiration = CurTime() + PERIOD_D1*60;
//----
   ticket = OrderSend(Symbol(), OP_BUYLIMIT, Lots, price, 0, SL, TP, "", MAGICEXP,
                      expiration, Green);
   if(ticket <= 0)
       Print("Error = ", GetLastError());
   else
     {
       Print("ticket = ", ticket);
       lastsd = CurTime();
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void buystop_open(double price, double SL = 0, double TP = 0)
  {
   int ticket, expiration;
//----
   expiration = CurTime() + PERIOD_D1*60;
//----
   RefreshRates();
   ticket = OrderSend(Symbol(), OP_BUYSTOP, Lots, price, 0, SL, TP, "", MAGICEXP,
                      expiration,Green);
   if(ticket <= 0)
       Print("Error = ", GetLastError());
   else
     {
       Print("ticket = ", ticket);
       lastsd = CurTime();
     }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void buy_open(double SL, double TP)
  {
   int ticket, lasterror;
   RefreshRates();
   ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 5, SL, TP, 0, MAGICEXP, 0, Aqua);
   if(ticket > 0)
     {
       if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
           Print("BUY order opened : ", OrderOpenPrice());
       lastsd = CurTime();
     }
   else
       Print("Error opening BUY order : ", ErrorDescription(GetLastError()));
   return;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void sell_open(double SL, double TP)
  {
   int ticket, lasterror;
   RefreshRates();
   ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 5, SL, TP, 0, MAGICEXP, 0, Red);
   if(ticket > 0)
     {
       if(OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
           Print("Sell order opened : ", OrderOpenPrice());
       lastsd=CurTime();
     }
   else
       Print("Error opening Sell order : ", ErrorDescription(GetLastError()));
   return;
  }
//+------------------------------------------------------------------+
//|   Закрытие ордеров n=1 - закрыть Buy, n=-1 - закрыть Sell        |
//+------------------------------------------------------------------+
void close_order(int n = 0)
  {
   int nGetLastError;
   int nOrdersTotal = OrdersTotal();
//----
   for(int i = nOrdersTotal - 1; i >= 0; i--)
     {
       OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
       nGetLastError = GetLastError();
       //----
       if(nGetLastError != 0)
         {
           Print("Error selecting order : ", ErrorDescription(nGetLastError));
           continue;
         }
       //----
       if(OrderMagicNumber() != MAGICEXP || OrderSymbol() != Symbol())
           continue;
       //---- check order type 
       if(OrderType() == OP_BUY && n == 1)
         {
           RefreshRates();
           OrderClose(OrderTicket(), OrderLots(), Bid, 3, Aqua);
           nGetLastError = GetLastError();
           if(nGetLastError != 0)
              Print("Error closing BUY order : ", ErrorDescription(nGetLastError));
         }
       //----
       if(OrderType() == OP_SELL && n==-1)
         {
           RefreshRates();
           OrderClose(OrderTicket(), OrderLots(), Ask, 3, Yellow);
           nGetLastError = GetLastError();
           if(nGetLastError != 0)
               Print("Error closing SELL order : ", ErrorDescription(nGetLastError));
         }
     }
  }
//+------------------------------------------------------------------+
//| Перенос уровня StopLoss               "Copyright" © KimIV        |
//| Параметры:                                                       |
//|   ldStopLoss - уровень StopLoss                                  |
//|   clModify   - цвет модификации                                  |
//+------------------------------------------------------------------+
void ModifyStopLoss(double ldStop, color clModify = Magenta )
  {
   bool fm;
   double ldOpen = OrderOpenPrice();
   double ldTake = OrderTakeProfit();
   int err;
//----
   if(IsTradeAllowed())
     {
       fm = OrderModify(OrderTicket(), ldOpen, ldStop, ldTake, 0, clModify);
       if(!fm)
         {
           err = GetLastError();
           Print("Error(",err,") modifying SL: ", ErrorDescription(err));
         }
     }
  }
//+------------------------------------------------------------------+
//| Перенос уровня TakeProfit                                        |
//| Параметры:                                                       |
//|   ldTake - уровень TakeProfit                                    |
//|   clModify   - цвет модификации                                  |
//+------------------------------------------------------------------+
void ModifyTakeProfit(double ldTake, color clModify = Magenta )
  {
   bool fm;
   double ldOpen = OrderOpenPrice();
   double ldStop = OrderStopLoss();
   int  err;
//----
   if(IsTradeAllowed())
     {
       fm = OrderModify(OrderTicket(), ldOpen, ldStop, ldTake, 0, clModify);
       if(!fm)
         {
           err = GetLastError();
           Print("Error(",err,") modifying SL: ", ErrorDescription(err));
         }
     }
  }
//+------------------------------------------------------------------+
//| Разбиение строки на массив элементов                             |
//| Возврат:                                                         |
//|   Количество элементов в массиве                                 |
//| Параметры:                                                       |
//|   source      - текстовая строка                                 |
//|   dest        - выходной массив                                  |
//|   delimeter   - разделитель                                      |
//+------------------------------------------------------------------+
int StrSplit(string source, string& dest[], string delimeter = ";")
  {
   int cnt = 0;
   int last_pos = 0;
   int pos = StringFind(source, delimeter, last_pos);
//----
   while(pos != -1)
     {
       ArrayResize(dest, cnt + 1);
       dest[cnt] = StringSubstr(source, last_pos, pos - last_pos);
       cnt++;
       last_pos = pos + 1;
       pos = StringFind(source, delimeter, last_pos);
     }
   if(last_pos != 0 && last_pos < StringLen(source))
     {
       ArrayResize(dest, cnt + 1);
       dest[cnt] = StringSubstr(source, last_pos, StringLen(source) - last_pos);
       cnt++;
     }
   return (cnt);
  }
//+------------------------------------------------------------------+



