Virtual Ordes Library

//+------------------------------------------------------------------+

//|                                                      ArrayVO.mq4 |

//|                                                             amba |

//|                                                       2009-12-07 |

//|                                                                  |

//| Библиотека предназначена для ведения виртуальной торговли.       |

//|                                                                  |

//| Реализована замена стандартных функций по работе с ордерами      |

//| Order*() на  аналогичные v.Order*().                             |

//|                                                                  |

//| Реализованы функции загрузки/выгрузки массивов ордеров в бинарном|

//| и текстовом виде.                                                |

//|                                                                  |

//| В библиотеке использованы незначительно модифицированные функции |

//| (автор Ким Игорь В. aka KimIV,  http://www.kimiv.ru) по работе с |

//| ордерами, а также идея работы с массивом номеров предварительно  |

//|отфильтрованных ордеров (автора не знаю, но тоже очень благодарен)|                                                                 |

//|                                                                  |

//|                                                                  |

//+------------------------------------------------------------------+

#property copyright "amba"

#property link      "http://www.mql4.com/ru/users/Amba"

//#property library

#include <stdlib.mqh>


//количество колонок в массивах ордеров

#define MAX_FIELDS 15                  


// массивы ордеров действующих и закрытых

//      значения типа double

double  aHistory[][MAX_FIELDS],

       aTrade[][MAX_FIELDS];

      

//      названия символов и комментарии к ордерам

string  aHistory.strings[][2],

       aTrade.strings[][2];

      

//      счетчики количества ордеров

int aHistory.cnt = 0,

   aTrade.cnt = 0;


datetime aTrade.CurrentDT=0;

      

// константы номеров колонок массивов

//      стандартные параметры ордеров

#define PROP.Ticket     0

#define PROP.OpenDT     1

#define PROP.Type       2

#define PROP.Lots       3

#define PROP.OpenPrice  4

#define PROP.SL         5

#define PROP.TP         6

#define PROP.Magic      7

#define PROP.ExpDT      8

#define PROP.ClosePrice 9

#define PROP.CloseDT    10

#define PROP.Profit     11          // в пунктах

//      дополнительные параметры ордеров

#define PROP.LastRecalcDT   12      // дата/время последнего пересчета ордера

#define PROP.MaxDD          13      // в пунктах

#define PROP.MaxProfit      14      // в пунктах

// константы номеров колонок строковых массивов

#define PROP.Symbol      0

#define PROP.Comment     1


      

int    Slippage      = 5;           // Проскальзывание цены - рудимент от реальной торговли


string csv.dem = ",";               // CSV разделитель


int aTrade.p=-1;                    // указатель позиции в массиве текущих ордеров

int aHistory.p=-1;                  // указатель позиции в массиве закрытых ордеров

int who.selected=0;                 // селектор вида массива {MODE_TRADES|MODE_HISTORY}

int next_t=0;                       // счетчик генератора номеров ордеров




//+------------------------------------------------------------------+

//|          Группа функций по работе с ордерами                     |

//+------------------------------------------------------------------+


// константы определяют использование различных ГРУПП операций ордеров:

#define TICKET_ORD -3   // отложенные ордера - OP_BUYLIMIT OP_SELLLIMIT OP_BUYSTOP OP_SELLSTOP

#define TICKET_POS -2   // открытые позиции  - OP_BUY OP_SELL

#define TICKET_ALL -1   // любой ордер


//+------------------------------------------------------------------+

//| Проверяет соответствие текущего выбранного ордера указанным в    |

//| параметрах условиям                                              |

//| Возвращаемые значения: true|false (соответствует|нет)            |

//| Параметры:                                                       |

//|   (дефолтные значения означают отсутствие условий по данному     |

//|    признаку)                                                     |

//|   sy - название символа                                          |

//|        (напр. "EURUSD", или "0" - текущий, "" - любой)           |

//|   op - тип ордера                                                |

//|     op={[OP_BUY..OP_SELLSTOP]|TICKET_POS|TICKET_ORD|TICKET_ALL}  |

//|   mn - Magic Number                                              |

//|   ot - время открытия. Будут выбраны ордера с временем открытия, |

//|        меньшим или равным указанному                             |

//|                                                                  |

//| Используется в функциях перебора, фильтрации ордеров             |

//+------------------------------------------------------------------+

bool v.IsOrderFor(string sy="", int op=-1, int mn=-1, datetime ot=0)

{

  int ty=v.OrderType();

  if (sy=="0") sy=Symbol();

  if ((v.OrderSymbol()==sy || sy=="")

  && (ty==op || op==TICKET_ALL || (op==TICKET_POS && ty>=0 && ty<2) || (op==TICKET_ORD && ty>1 && ty<6) ) )

      if (mn<0 || v.OrderMagicNumber()==mn)

        if (ot<=v.OrderOpenTime())

           return(true);

  return(false);

}


//+------------------------------------------------------------------+

//| По заданным условиям проверяет - есть ли хотя бы один ордер, со- |

//| ответствующий условиям поиска                                    |

//| Возвращаемые значения: true|false (есть|нет)                     |

//| Параметры:  см. описание IsOrderFor()                            |

//|                                                                  |

//+------------------------------------------------------------------+

bool v.ExistOrders(string sy="", int op=-1, int mn=-1, datetime ot=0)

{

 int i, k=v.OrdersTotal(), c=0;


 for (i=0; i<k; i++)

   if (v.OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==true)

     if(v.IsOrderFor(sy,op,mn,ot))

        return(true);

 return(false);

}


//+------------------------------------------------------------------+

//| По заданным условиям подсчитывает - сколько ордеров соответствует|

//| условиям поиска                                                  |

//| Возвращаемые значения: количество ордеров                        |

//| Параметры:  см. описание IsOrderFor()                            |

//|                                                                  |

//+------------------------------------------------------------------+

int v.CountAllOrders(string sy="", int op=-1, int mn=-1, datetime ot=0)

{

 int i, k=v.OrdersTotal(), c=0;


 for (i=0; i<k; i++)

   if (v.OrderSelect(i, SELECT_BY_POS, MODE_TRADES)==true)

     if(v.IsOrderFor(sy,op,mn,ot)==true)

        c++;

 return(c);

}


//+------------------------------------------------------------------+

//| По заданным условиям ищет ордера и заполняет переданный массив   |

//| номерами найденных ордеров                                       |

//| Возвращаемые значения: количество ордеров                        |

//| Параметры:                                                       |

//|     Ticket - одномерный массив, заполняется номерами ордеров     |

//|     остальные параметры см. описание IsOrderFor()                |

//|                                                                  |

//+------------------------------------------------------------------+

int v.CreateTicketArray(int& Ticket[], string sy="", int op=-1, int mn=-1, datetime ot=0)

{

   int total=v.OrdersTotal(), i, c=0; if (total<=0) return (0);

   for(i=0;i<total;i++)

     if(v.OrderSelect(i, SELECT_BY_POS)==true)

       if(v.IsOrderFor(sy,op,mn,ot)==true) {ArrayResize(Ticket,c+1);Ticket[c] = v.OrderTicket(); c++; }

   return (c);

}


//+------------------------------------------------------------------+

//| По заданным условиям ищет ордера и закрывает/удаляет их.         |

//| Цена закрытия - Close на баре даты последнего пересчета ордера.  |

//| Сначала закрываются профитные сделки, потом - все остальные.     |

//| Возвращаемые значения: нет                                       |

//| Параметры: см. описание IsOrderFor()                             |

//|                                                                  |

//+------------------------------------------------------------------+

void v.CloseAllOrders(string sy="", int op=-1, int mn=-1, datetime ot=0)

{

   int i, total = v.OrdersTotal();    if (total<=0) return;

   int Ticket[];

   total = v.CreateTicketArray(Ticket, sy, op, mn, ot);     if (total<=0) return; //Заглушка

  

   string sym;

   double point;

   int spread;

   // Закрываем только профитные сделки

   for (i=0; i<total; i++)   

   {   

       if(v.OrderSelect(Ticket[i], SELECT_BY_TICKET) && v.OrderProfit()>0)

       {

           int ty=v.OrderType();

           if(ty<2)

           {

               sym     = v.OrderSymbol();

               point   = MarketInfo(sym, MODE_POINT);

               spread  = MarketInfo(sym,MODE_SPREAD);

               aTrade.CurrentDT=GetDoublePropArray(PROP.LastRecalcDT);

               double p=iClose(v.OrderSymbol(),0,iBarShift(v.OrderSymbol(),0,GetDoublePropArray(PROP.LastRecalcDT)));

               if(ty==OP_BUY)

                   v.OrderClose(Ticket[i], v.OrderLots(), p, 3 );

               else if(ty==OP_SELL)

                   v.OrderClose(Ticket[i], v.OrderLots(), p + point*spread, 3 );

           } else v.OrderDelete(Ticket[i]);

       }

   }

   // ... а теперь все остальные

   for (i=0; i<total; i++)   

   {   

       if(v.OrderSelect(Ticket[i], SELECT_BY_TICKET))   

       {

           ty=v.OrderType();

           if(ty<2)

           {

               sym     = v.OrderSymbol();

               point   = MarketInfo(sym, MODE_POINT);

               spread  = MarketInfo(sym,MODE_SPREAD);

               aTrade.CurrentDT=GetDoublePropArray(PROP.LastRecalcDT);

               p=iClose(v.OrderSymbol(),0,iBarShift(v.OrderSymbol(),0,GetDoublePropArray(PROP.LastRecalcDT)));

               if(ty==OP_BUY)

                   v.OrderClose(Ticket[i], v.OrderLots(),  p, 3);

               else if(ty==OP_SELL)

                   v.OrderClose(Ticket[i], v.OrderLots(),  p + point*spread, 3);

           } else v.OrderDelete(Ticket[i]);

       }

   }

     

   return;

}



//+----------------------------------------------------------------------------+

//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |

//+----------------------------------------------------------------------------+

//|  Версия   : 01.09.2005                                                     |

//|  Описание : Возвращает наименование торговой операции                      |

//+----------------------------------------------------------------------------+

//|  Параметры:                                                                |

//|    op - идентификатор торговой операции                                    |

//+----------------------------------------------------------------------------+

string GetNameOP(int op) {

 switch (op) {

   case OP_BUY      : return("Buy");

   case OP_SELL     : return("Sell");

   case OP_BUYLIMIT : return("Buy Limit");

   case OP_SELLLIMIT: return("Sell Limit");

   case OP_BUYSTOP  : return("Buy Stop");

   case OP_SELLSTOP : return("Sell Stop");

   default          : return("Unknown Operation");

 }

}


//+----------------------------------------------------------------------------+

//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |

//+----------------------------------------------------------------------------+

//|  Версия   : 01.09.2005                                                     |

//|  Описание : Возвращает наименование таймфрейма                             |

//+----------------------------------------------------------------------------+

//|  Параметры:                                                                |

//|    TimeFrame - таймфрейм (количество секунд)      (0 - текущий ТФ)         |

//+----------------------------------------------------------------------------+

string GetNameTF(int TimeFrame=0) {

 if (TimeFrame==0) TimeFrame=Period();

 switch (TimeFrame) {

   case PERIOD_M1:  return("M1");

   case PERIOD_M5:  return("M5");

   case PERIOD_M15: return("M15");

   case PERIOD_M30: return("M30");

   case PERIOD_H1:  return("H1");

   case PERIOD_H4:  return("H4");

   case PERIOD_D1:  return("Daily");

   case PERIOD_W1:  return("Weekly");

   case PERIOD_MN1: return("Monthly");

   default:             return("UnknownPeriod");

 }

}


//+----------------------------------------------------------------------------+

//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |

//+----------------------------------------------------------------------------+

//|  Версия   : 01.09.2005                                                     |

//|  Описание : Вывод сообщения в коммент и в журнал                           |

//+----------------------------------------------------------------------------+

//|  Параметры:                                                                |

//|    m - текст сообщения                                                     |

//+----------------------------------------------------------------------------+

void Message(string m) {

 Comment(m);

 if (StringLen(m)>0) Print(m);

}


//+----------------------------------------------------------------------------+

//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |

//+----------------------------------------------------------------------------+

//|  Версия   : 13.03.2008                                                     |

//|  Описание : Установка ордера.                                              |

//+----------------------------------------------------------------------------+

//|  Параметры:                                                                |

//|    sy - наименование инструмента   (NULL или "" - текущий символ)          |

//|    op - операция                                                           |

//|    ll - лот                                                                |

//|    pp - цена                                                               |

//|    sl - уровень стоп                                                       |

//|    tp - уровень тейк                                                       |

//|    mn - Magic Number                                                       |

//|    ex - Срок истечения                                                     |

//+----------------------------------------------------------------------------+

int v.SetOrder(string sy, int op, double ll, double pp,

             double sl=0, double tp=0, int mn=0, datetime ex=0, string lsComm="") {

 datetime ot;

 double   pa, pb, mp;

 int      err, it, ticket, msl;

 if(lsComm=="")   lsComm=WindowExpertName()+" "+GetNameTF(Period());

 if (sy=="" || sy=="0") sy=Symbol();

 msl=MarketInfo(sy, MODE_STOPLEVEL);


 int dg = MarketInfo(sy, MODE_DIGITS);

 pp=NormalizeDouble(pp, dg);

 sl=NormalizeDouble(sl, dg);

 tp=NormalizeDouble(tp, dg);


 if (ex>0 && ex<aTrade.CurrentDT) ex=0;

   ticket=v.OrderSend(sy, op, ll, pp, Slippage, sl, tp, lsComm, mn, ex,0);

   //Print(GetLastError());

   if (ticket>0) {

     return(ticket);

   }


 return(0);

}


//+----------------------------------------------------------------------------+

//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |

//+----------------------------------------------------------------------------+

//|  Версия   : 28.11.2006                                                     |

//|  Описание : Модификация одного предварительно выбранного ордера.           |

//+----------------------------------------------------------------------------+

//|  Параметры:                                                                |

//|    pp - цена установки ордера                                              |

//|    sl - ценовой уровень стопа                                              |

//|    tp - ценовой уровень тейка                                              |

//|    od - Срок истечения                                                     |

//|    cl - цвет значка модификации                                            |

//+----------------------------------------------------------------------------+

void v.ModifyOrder(double pp=-1, double sl=0, double tp=0, datetime od = 0, color cl=CLR_NONE) {

 bool   fm;

 double op, pa, pb, os, ot;

 int    dg=MarketInfo(OrderSymbol(), MODE_DIGITS), er, it;


 if (pp<=0) pp=v.OrderOpenPrice();

 if (sl<0 ) sl=v.OrderStopLoss();

 if (tp<0 ) tp=v.OrderTakeProfit();


 pp=NormalizeDouble(pp, dg);

 sl=NormalizeDouble(sl, dg);

 tp=NormalizeDouble(tp, dg);

 op=NormalizeDouble(v.OrderOpenPrice() , dg);

 os=NormalizeDouble(v.OrderStopLoss()  , dg);

 ot=NormalizeDouble(v.OrderTakeProfit(), dg);

 if(od==0) od=v.OrderExpiration();


 if (pp!=op || sl!=os || tp!=ot) {

   RefreshRates();

   fm=v.OrderModify(OrderTicket(), pp, sl, tp, od, cl);

   if (fm) {

   }

 }

}


//+------------------------------------------------------------------+

//| Группа функций-эмуляторов  Order*() => v.Order*()                |

//| По всем функциям с префиксом v. - см. справку по MQL4            |

//+------------------------------------------------------------------+


int         v.OrdersTotal( )        {   return(ArrayRange(aTrade,0));}

int         v.OrdersHistoryTotal( ) {   return(aHistory.cnt);}

bool        v.OrderSelect( int index, int select, int pool=MODE_TRADES)

{

   who.selected=pool;

   aTrade.p=-1;

   aHistory.p=-1;

   if(pool==MODE_TRADES)

   {

       if(select==SELECT_BY_POS)

       {

           if(index>=0&&index<v.OrdersTotal())

               {aTrade.p=index;        return(true);}

       } else {//SELECT_BY_TICKET

           for(int i=0;i<v.OrdersTotal();i++)

               if(NormalizeDouble(aTrade[i,0],0)==index)

                   {aTrade.p=i;        return(true);}

       }

   } else {//MODE_HISTORY   

       //return(false);

       if(select==SELECT_BY_POS)

       {

           if(index>=0&&index<v.OrdersHistoryTotal())

               {aHistory.p=index;        return(true);}

       } else {//SELECT_BY_TICKET

           for( i=0;i<v.OrdersHistoryTotal();i++)

               if(NormalizeDouble(aHistory[i,0],0)==index)

                   {aHistory.p=i;        return(true);}

       }

   }

  

   return(false);

}


int         v.OrderSend( string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment="", int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)

{

   int total=v.OrdersTotal();

   int nt=NextTicket();

   //datetime d1=IIF(aTrade.CurrentDT==0,TimeCurrent(),aTrade.CurrentDT);

   ArrayResize(aTrade,total+1);

   ArrayResize(aTrade.strings,total+1);

   aTrade.strings[total,PROP.Symbol]=symbol;

   aTrade.strings[total,PROP.Comment]=comment;

   aTrade[total,PROP.Ticket]=nt;

   aTrade[total,PROP.OpenDT]=aTrade.CurrentDT;

   aTrade[total,PROP.Type]=cmd;

   aTrade[total,PROP.Lots]=volume;

   aTrade[total,PROP.OpenPrice]=price;

   aTrade[total,PROP.SL]=stoploss;

   aTrade[total,PROP.TP]=takeprofit;

   aTrade[total,PROP.Magic]=magic;

   aTrade[total,PROP.ExpDT]=expiration;

   aTrade[total,PROP.LastRecalcDT]=aTrade.CurrentDT;

   //if(cmd==OP_BUY||cmd==OP_BUYSTOP||cmd==OP_BUYLIMIT)

   {

       //aTrade[total,PROP.MaxDD]=price;

       //aTrade[total,PROP.MaxProfit]=price;

   }

   //aTrade.CurrentDT=0;

   _Print("Array send "+nt);

   return(nt);

}


bool        v.OrderClose( int ticket, double lots, double price, int slippage, color Color=CLR_NONE)

{

   _Print("Closing "+ticket);

   double point   = MarketInfo(v.OrderSymbol(), MODE_POINT);

   if(v.OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))

   {

       SetDoublePropArray(PROP.CloseDT,aTrade.CurrentDT);

       //aTrade.CurrentDT=0;

       SetDoublePropArray(PROP.ClosePrice, price);

       int ty=v.OrderType();

       if(ty==OP_BUY)

       {

           SetDoublePropArray(PROP.Profit, CalcOrderProfit(price, aTrade.CurrentDT));//(price-v.OrderOpenPrice())/point);

       } else if(ty==OP_SELL)

       {

           SetDoublePropArray(PROP.Profit, CalcOrderProfit(price, aTrade.CurrentDT));//(-price+v.OrderOpenPrice())/point);

       } else {

           v.OrderDelete( ticket );

           return(true);

       }

       //SetDoublePropArray(PROP.Profit, price);

       int newsize=v.OrdersHistoryTotal()+1;

       ArrayResize_aHistory(newsize);

       ArrayCopy(aHistory,aTrade,(newsize-1)*MAX_FIELDS,aTrade.p*MAX_FIELDS,MAX_FIELDS);

       ArrayCopy(aHistory.strings,aTrade.strings,(newsize-1)*2,aTrade.p*2,2);

       v.OrderDelete( ticket );

       return(true);

   } else

       return(false);

}


bool        v.OrderDelete( int ticket, color arrow_color=CLR_NONE)

{

   if(v.OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))

   {

       double a[][MAX_FIELDS];

       string as[][2];

       int oldsize=v.OrdersTotal();

       int newsize=oldsize-1;

      

       ArrayResize(a, newsize);

       ArrayResize(as, newsize);

      

       if(newsize==0)

       {

           ArrayResize(aTrade,newsize);

           ArrayResize(aTrade.strings,newsize);

           aTrade.p=-1;

           return(true);

       }

      

       if(aTrade.p==0)

       {

           ArrayCopy(a,aTrade,0,1*MAX_FIELDS,newsize*MAX_FIELDS);

           ArrayCopy(as,aTrade.strings,0,1*2,newsize*2);

       }

       else if(aTrade.p==newsize)

       {

           ArrayCopy(a,aTrade,0,0,newsize*MAX_FIELDS);

           ArrayCopy(as,aTrade.strings,0,0,newsize*2);

       }

       else

       {

           ArrayCopy(a,aTrade,0,0,aTrade.p*MAX_FIELDS);

           ArrayCopy(as,aTrade.strings,0,0,aTrade.p*2);

           ArrayCopy(a,aTrade,aTrade.p*MAX_FIELDS,(aTrade.p+1)*MAX_FIELDS,(newsize-aTrade.p)*MAX_FIELDS);

           ArrayCopy(as,aTrade.strings,aTrade.p*2,(aTrade.p+1)*2,(newsize-aTrade.p)*2);

       }

      

       ArrayResize(aTrade,newsize);

       ArrayResize(aTrade.strings,newsize);

       ArrayCopy(aTrade,a);

       ArrayCopy(aTrade.strings,as);

       aTrade.p=-1;

      

       return(true);

   } else

       return(false);

}


bool        v.OrderModify( int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE) {}

int         v.OrderTicket( )        {    return(GetDoublePropArray(PROP.Ticket));}

datetime    v.OrderOpenTime( )      {    return(GetDoublePropArray(PROP.OpenDT));}

int         v.OrderType( )          {    return(GetDoublePropArray(PROP.Type));}

double      v.OrderLots( )          {    return(GetDoublePropArray(PROP.Lots));}

double      v.OrderOpenPrice( )     {    return(GetDoublePropArray(PROP.OpenPrice));}

double      v.OrderStopLoss( )      {    return(GetDoublePropArray(PROP.SL));}

double      v.OrderTakeProfit( )    {    return(GetDoublePropArray(PROP.TP));}

int         v.OrderMagicNumber( )   {    return(GetDoublePropArray(PROP.Magic));}

datetime    v.OrderExpiration( )    {    return(GetDoublePropArray(PROP.ExpDT));}

double      v.OrderClosePrice( )    {    return(GetDoublePropArray(PROP.ClosePrice));}

datetime    v.OrderCloseTime( )     {    return(GetDoublePropArray(PROP.CloseDT));}

double      v.OrderProfit( )        {    return(GetDoublePropArray(PROP.Profit));}

string      v.OrderSymbol( )        {    return(GetStringPropArray(PROP.Symbol));}

string      v.OrderComment( )       {    return(GetStringPropArray(PROP.Comment));}






//+------------------------------------------------------------------+

//|                Группа служебных функций.                         |

//+------------------------------------------------------------------+



//+------------------------------------------------------------------+

//| Для увеличения быстродействия при работе с большим количеством   |

//| ордеров массив для хранения OrdersHistory  увеличиваем по 100    |

//| элементов за раз.                                                |

//|                                                                  |

//+------------------------------------------------------------------+

void ArrayResize_aHistory(int newsize)

{

   int size=ArrayRange(aHistory,0);

   bool need=false;

  

   while(newsize>size)

   {

       size+=100;

       need=true;

   }

  

   if(need)

   {

       ArrayResize(aHistory,newsize);

       ArrayResize(aHistory.strings,newsize);

   }

  

   aHistory.cnt=newsize;

}


//+------------------------------------------------------------------+

//| Генератор уникальных номеров ордеров.                            |

//|                                                                  |

//+------------------------------------------------------------------+

int NextTicket()

{

   next_t++;

   return(next_t);

}


//+------------------------------------------------------------------+

//| Возращает значение указанного параметра выбранного ордера.       |

//|                                                                  |

//+------------------------------------------------------------------+

double GetDoublePropArray( int col)

{

   if(who.selected==MODE_TRADES && aTrade.p>=0)

       return(aTrade[aTrade.p,col]);

   if(who.selected==MODE_HISTORY && aHistory.p>=0)

       return(aHistory[aHistory.p,col]);

   return(-1);

}


string GetStringPropArray( int col)

{

   //Print(aTrade.p);

   if(who.selected==MODE_TRADES && aTrade.p>=0)

       return(aTrade.strings[aTrade.p,col]);

   if(who.selected==MODE_HISTORY && aHistory.p>=0)

       return(aHistory.strings[aHistory.p,col]);

   return("err");

}


//+------------------------------------------------------------------+

//| Устанавливает значение указанного параметра выбранного ордера.   |

//|                                                                  |

//+------------------------------------------------------------------+

bool SetDoublePropArray( int col, double d)

{

   //_Print(StringConcatenate(who.selected,p,aTrade.p));

   if(who.selected==MODE_TRADES && aTrade.p>=0)

   {

       aTrade[aTrade.p,col]=d;

       return(true);

   }

   return(false);

}


bool SetStringPropArray( int col, string s)

{

   if(who.selected==MODE_TRADES && aTrade.p>=0)

   {

       aTrade.strings[aTrade.p,col]=s;

       return(true);

   }

   return(false);

}


//+------------------------------------------------------------------+

//| Устанавливает "текущее время" для эмуляции сделок.               |

//| Вызывается в основном коде, например на каждом новом баре.       |

//+------------------------------------------------------------------+

void SetCurrentDateTime(datetime dt)

{

   aTrade.CurrentDT = dt;

}


//+------------------------------------------------------------------+

//| Пересчитывает массив открытых ордеров .                          |

//| Вызывается в основном коде, например на каждом новом баре.       |

//| Параметр: номер бара, на котором пересчет прекращается.          |

//|                                                                  |

//+------------------------------------------------------------------+

void RecalcTradeArray(datetime dt=0)

{

   int Ticket[];

   int K=v.CreateTicketArray(Ticket);

   //_Print("trades = "+K);

   for (int i=0;i<K;i++)

   {

       if(v.OrderSelect(Ticket[i],SELECT_BY_TICKET,MODE_TRADES))

           RecalcOrder(dt);

   }

  

}


//+------------------------------------------------------------------+

//| Пересчитывает выбранный ордер.                                   |

//| Параметр: номер бара, на котором пересчет прекращается. У каждого|

//| ордера есть служебный параметр - дата последнего пересчета. Для  |

//| выбранного ордера последовательно обсчитываются все бары от бара |

//| последнего пересчета до бара указанного в параметре. При пересче-|

//| проверяются условия на открытие отложенных, закрытие открытых по |

//| SL и TP, истечение срока жизни (работает в т.ч. и для уже откры- |

//| тых позиций, не только отложенников). Вычисляются максимальные   |

//| просадка и возможная прибыль за время жизни позиции              |

//|                                                                  |

//+------------------------------------------------------------------+

bool RecalcOrder(datetime dt=0)

{

   string sy=v.OrderSymbol( );


   double point   = MarketInfo(sy, MODE_POINT);

  

   string VD = AccountCurrency();


  


   int spread     = MarketInfo(sy,MODE_SPREAD);

   int dg         = MarketInfo(sy,MODE_DIGITS);

   double sp = NormalizeDouble(spread*point,dg);

   int ty=v.OrderType();

   int s0=iBarShift(sy,0,GetDoublePropArray(PROP.LastRecalcDT));

   int sh=0;

   if(dt>0) sh=iBarShift(sy,0,dt,true);

   if(sh<0) return;

  

   _Print("Recalc "+v.OrderTicket()+" "+sy+" "+s0);

  

   for(int i=s0;i>=sh;i--)

   {

       double

           high    = NormalizeDouble( iHigh(sy,0,i), dg),

           low     = NormalizeDouble(  iLow(sy,0,i), dg),

           close   = NormalizeDouble(iClose(sy,0,i), dg);

       double op=GetDoublePropArray(PROP.OpenPrice);

       double sl=GetDoublePropArray(PROP.SL);

       double tp=GetDoublePropArray(PROP.TP);

       datetime curdt = iTime(sy,0,i);

       bool res=SetDoublePropArray(PROP.LastRecalcDT, curdt);

       datetime exp=GetDoublePropArray(PROP.ExpDT);

       aTrade.CurrentDT=curdt;

       _Print("last recalc "+res);

      

       if((ty==OP_BUYSTOP||ty==OP_BUYLIMIT) && op>=low+sp && op<=high+sp)

       {

           SetDoublePropArray(PROP.OpenDT,curdt);

           ty=OP_BUY;

           SetDoublePropArray(PROP.Type,ty);

       }

      

       if(ty==OP_BUY)

       {

           SetDoublePropArray(PROP.Profit,CalcOrderProfit(close, aTrade.CurrentDT));

           //if(sl==0)

               SetDoublePropArray(PROP.MaxDD,MathMin(GetDoublePropArray(PROP.MaxDD),(low-op)/point));

           //if(tp==0)

               SetDoublePropArray(PROP.MaxProfit,MathMax(GetDoublePropArray(PROP.MaxProfit),(high-op)/point));

           if(sl>0 && sl>=low)

               {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),sl,2);  break;}

           else if(tp>0 && tp<=high)

               {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),tp,2);  break;}

       }

      

       if((ty==OP_SELLSTOP||ty==OP_SELLLIMIT) && op>=low && op<=high)

       {

           SetDoublePropArray(PROP.OpenDT,curdt);

           ty=OP_SELL;

           SetDoublePropArray(PROP.Type,ty);

       }

      

       if(ty==OP_SELL)

       {

           SetDoublePropArray(PROP.Profit,CalcOrderProfit((close+sp), aTrade.CurrentDT));

           //if(sl==0)

               SetDoublePropArray(PROP.MaxDD,MathMin(GetDoublePropArray(PROP.MaxDD),(op-(high+sp))/point));

           //if(tp==0)

               SetDoublePropArray(PROP.MaxProfit,MathMax(GetDoublePropArray(PROP.MaxProfit),(op-(low+sp))/point));

           if(sl>0 && sl<=high+sp)

               {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),sl,2);  break;}

           else if(tp>0 && tp>=low+sp)

               {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),tp,2);  break;}

       }

      

       if(exp>0 && exp<=aTrade.CurrentDT)

           {v.OrderClose(GetDoublePropArray(PROP.Ticket),v.OrderLots(),close,2);  break;}

   }

  

   return(true);

}


//+------------------------------------------------------------------+

//| Вычисляет стоимость сделки в валюте депозита                     |

//| Параметры:                                                       |

//|     price  текущая цена для расчета                              |

//|     dt     опорная дата/время для расчета кросс-курса            |

//|                                                                  |

//+------------------------------------------------------------------+


double CalcOrderProfit(double price, datetime dt)

{

   string sy   = v.OrderSymbol();

   double lots = v.OrderLots();

   int op      = v.OrderType();

   double LS   = MarketInfo(sy, MODE_LOTSIZE);

   double OrdProf    = lots * LS * (price - v.OrderOpenPrice()) * IIF(op==OP_BUY,1,-1);

   string FirstPart  = StringSubstr(sy, 0, 3);

   string SecondPart = StringSubstr(sy, 3, 3);

   string DepoCurr   = AccountCurrency();

  

   if( SecondPart == DepoCurr )

       { /**/ }

   else if( FirstPart == DepoCurr )

       {OrdProf /= price;}

   else

   {

       if(MarketInfo( DepoCurr + SecondPart, MODE_BID ) > 0)

           sy = DepoCurr + SecondPart;

       else

           sy = SecondPart + DepoCurr;

      

       int sh = iBarShift(sy, 0, dt, true);

       if(sh < 0)

       {

           Print("Error! No history for "+sy);

           return(-1);

       } else {

           price=iClose(sy, 0, sh);

       }

      

       FirstPart  = StringSubstr(sy, 0, 3);

       SecondPart = StringSubstr(sy, 3, 3);

       if( SecondPart == DepoCurr )

           OrdProf *= price;

       else if( FirstPart == DepoCurr )

           OrdProf /= price;

   }


   OrdProf = NormalizeDouble(OrdProf, 2) ;

   return(OrdProf);

}


//+------------------------------------------------------------------+

//| Сохраняет массивы ордеров в бинарном формате.                    |

//| Параметр: имя группы служебных файлов.                           |

//| На выходе 4 файла:                                               |

//|      "bin."+fn+".hist"                                           |

//|      "bin."+fn+".histstring"                                     |

//|      "bin."+fn+".trade"                                          |

//|      "bin."+fn+".tradestring"                                    |

//| Может применяться для промежуточного сохранения результатов, а   |

//| также для сохранения результатов между сеансами.                 |

//|                                                                  |

//+------------------------------------------------------------------+

void SaveArrays(string fn)

{

   int h=FileOpen("bin."+fn+".hist",FILE_WRITE|FILE_BIN);

   FileWriteArray(h,aHistory,0,ArraySize(aHistory));

   FileClose(h);

  

   h=FileOpen("bin."+fn+".histstring",FILE_WRITE|FILE_BIN);

   FileWriteArray(h,aHistory.strings,0,ArraySize(aHistory.strings));

   FileClose(h);

  

   h=FileOpen("bin."+fn+".trade",FILE_WRITE|FILE_BIN);

   FileWriteArray(h,aTrade,0,ArraySize(aTrade));

   FileClose(h);

  

   h=FileOpen("bin."+fn+".tradestring",FILE_WRITE|FILE_BIN);

   FileWriteArray(h,aTrade.strings,0,ArraySize(aTrade.strings));

   FileClose(h);

}


//+------------------------------------------------------------------+

//| Загружает массивы ордеров из бинарных файлов                     |

//| Параметр: имя группы служебных файлов.                           |

//| На входе 4 файла:                                                |

//|      "bin."+fn+".hist"                                           |

//|      "bin."+fn+".histstring"                                     |

//|      "bin."+fn+".trade"                                          |

//|      "bin."+fn+".tradestring"                                    |

//|                                                                  |

//+------------------------------------------------------------------+

void LoadArrays(string fn)

{

   int h=FileOpen("bin."+fn+".hist",FILE_READ|FILE_BIN);

   int h1=FileOpen("bin."+fn+".histstring",FILE_READ|FILE_BIN);

   double a[MAX_FIELDS];

   int k=v.OrdersHistoryTotal();

  

   while((!FileIsEnding(h))&&(!FileIsEnding(h)))

   {

       ArrayResize(aHistory,(k+1));

       ArrayResize(aHistory.strings,(k+1));

       FileReadArray(h,aHistory,k*MAX_FIELDS,MAX_FIELDS);

       FileReadArray(h1,aHistory.strings,k*2,2);

       aHistory.cnt++;

       k++;

   }

  

   if(k>0)

   {

       aHistory.cnt--;

       ArrayResize(aHistory,(k-1));

       ArrayResize(aHistory.strings,(k-1));

   }

  

   FileClose(h);

   FileClose(h1);

  

  

   h=FileOpen("bin."+fn+".trade",FILE_READ|FILE_BIN);

   h1=FileOpen("bin."+fn+".tradestring",FILE_READ|FILE_BIN);

   k=v.OrdersTotal();

  

   while((!FileIsEnding(h))&&(!FileIsEnding(h)))

   {

       ArrayResize(aTrade,(k+1));

       ArrayResize(aTrade.strings,(k+1));

       FileReadArray(h,aTrade,k*MAX_FIELDS,MAX_FIELDS);

       FileReadArray(h1,aTrade.strings,k*2,2);

       k++;

   }

  

   if(k>0)

   {

       ArrayResize(aTrade,(k-1));

       ArrayResize(aTrade.strings,(k-1));

   }

  

   FileClose(h);

   FileClose(h1);

  

   for(k=0;k<v.OrdersHistoryTotal();k++)

       next_t=MathMax(next_t,aHistory[k,0]);

   for(k=0;k<v.OrdersTotal();k++)

       next_t=MathMax(next_t,aTrade[k,0]);

}


//+------------------------------------------------------------------+

//| Выводит массивы ордеров в читабельном формате                    |

//| Параметр: имя группы служебных файлов.                           |

//| На выходе 2 файла:                                               |

//|      "deb."+fn+".hist.csv"                                       |

//|      "deb."+fn+".trade.csv"                                      |

//| применяется для контроля работы, а также для дальнейшего анализа |

//| сделок, например, в Excel                                        |

//|                                                                  |

//+------------------------------------------------------------------+

void DebugPrintArrays(string fn)

{

   string s="", p="";

   int i,j;

   int h=FileOpen("deb."+fn+".hist.csv",FILE_WRITE|FILE_CSV,csv.dem);

   FileWrite(h,"Ticket","OpenDT","Type","Lots","OpenPrice","SL","TP","Magic","ExpDT","ClosePrice","CloseDT",

   "Profit","LastRecalcDT","MaxDD","MaxProfit","Symbol","Comment");

  

   for(i=0;i<v.OrdersHistoryTotal();i++)

   {

       s="";

       for(j=0;j<MAX_FIELDS;j++)

       {

           if(j==PROP.OpenDT||j==PROP.ExpDT||j==PROP.CloseDT||j==PROP.LastRecalcDT)

               p=TimeToStr(aHistory[i,j],TIME_DATE|TIME_MINUTES|TIME_SECONDS);

           else if(j==PROP.Ticket||j==PROP.Type||j==PROP.Magic)

               p=DoubleToStr(aHistory[i,j],0);

           else

               p=DoubleToStr(aHistory[i,j],4);

           s=s+p+csv.dem;

       }

       s=s+aHistory.strings[i,0]+csv.dem+aHistory.strings[i,1];

       FileWrite(h,s);

   }

  

   FileClose(h);

  

   h=FileOpen("deb."+fn+".trade.csv",FILE_WRITE|FILE_CSV,csv.dem);

   FileWrite(h,"Ticket","OpenDT","Type","Lots","OpenPrice","SL","TP","Magic","ExpDT","ClosePrice","CloseDT",

   "Profit","LastRecalcDT","MaxDD","MaxProfit","Symbol","Comment");

   datetime d=0;

  

   for(i=0;i<v.OrdersTotal();i++)

   {

       s="";

       for(j=0;j<MAX_FIELDS;j++)

       {

           if(j==PROP.OpenDT||j==PROP.ExpDT||j==PROP.CloseDT||j==PROP.LastRecalcDT)

               p=TimeToStr(aTrade[i,j],TIME_DATE|TIME_MINUTES|TIME_SECONDS);

           else if(j==PROP.Ticket||j==PROP.Type||j==PROP.Magic)

               p=DoubleToStr(aTrade[i,j],0);

           else

               p=DoubleToStr(aTrade[i,j],4);

           s=s+p+csv.dem;

       }

       s=s+aTrade.strings[i,0]+csv.dem+aTrade.strings[i,1];

       FileWrite(h,s);

   }

  

   FileClose(h);

  

}


//+------------------------------------------------------------------+

//| Вывод отладочной информации в лог-файл                           |

//| Параметр: строка для записи в файл                               |

//|                                                                  |

//+------------------------------------------------------------------+

void _Print(string s)

{

/*   int fh=FileOpen("vo.log",FILE_WRITE|FILE_READ);

  FileSeek(fh, 0, SEEK_END);

  FileWrite(fh,TimeToStr(TimeCurrent())," ",s);

  FileClose(fh);*/

}


//***************************************

//

string sIIF(bool cr, string r1, string r2)

{

  if(cr)       return(r1);

  else         return(r2);

}


double IIF(bool cr, double r1, double r2)

{

  if(cr)       return(r1);

  else         return(r2);

}

//

//***************************************