Баланс и P/L по неделям

 

У кого-нить функция вычисления баланса и profit/loss по неделям с учётом пополнений/снятий ?

Понадобилось вот, но перед тем как писать лучше поспрашивать - такое 100500 раз должно быть уже написано

 
Maxim Kuznetsov:

У кого-нить функция вычисления баланса и profit/loss по неделям с учётом пополнений/снятий ?

Понадобилось вот, но перед тем как писать лучше поспрашивать - такое 100500 раз должно быть уже написано

Раз ни у кого нет или все супер-жадные пришлось написать.

В деталях не отлажено, но работает, можете пользоваться. Если какие идеи, замечания - пишите

//+------------------------------------------------------------------+
//|                                                 BalanceAndPL.mqh |
//|                                   Copyright 2018, MaximKuznetsov |
//|                                          https://www.luxtrade.tk |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018,Maxim Kuznetsov"
#property link      "https://www.luxtrade.tk"
#property strict
/** отчётная периодичность
**/
enum ENUM_TIME_PERIODIC {
   MODE_DAILY,    /// ежедневно 
   MODE_WEEKLY,   /// еженедельно. с понедельника по воскресенье. 
   MODE_MONTHLY   /// ежемесячно
};

/** Вычисление баланса и зафиксированной прибыли
    на начало периода 
    @arg mode выбор перода (см. ENUM_TIME_PERIODIC)
    @arg count кол-во периодов для рассчёта
    @arg balance массив для сохранения балансов
    @arg pl массив для заполнения profit/loss
    @return int 0 при успешном завершениее иначе код ошибки
**/    
int
BalanceAndPL(ENUM_TIME_PERIODIC mode,int count,double &balance[],double &pl[])
{
   // проверка аргументов
   if (count<0) {
      return -1;
   }
   if (ArraySize(balance)<count && !ArrayResize(balance,count)) {
      return -1;
   }
   if (ArraySize(pl)<count && !ArrayResize(pl,count)) {
      return -1;
   }
   // вычисление времени начала периодов
   datetime period[];
   if (!ArrayResize(period,count)) {
      return -1;
   }
   datetime now=TimeCurrent();
   switch (mode) {
      case MODE_DAILY:
      {
         MqlDateTime dt;
         if (!TimeToStruct(now,dt)) {
            return -1;
         }
         dt.sec=0;
         dt.min=0;
         dt.hour=0;
         period[0]=StructToTime(dt);
         for(int t=1;t<count;t++) {
            period[t]=period[t-1]-24*60*60;
         }
      }
      break;
      case MODE_WEEKLY:
      {
         MqlDateTime dt;
         if (!TimeToStruct(now,dt)) {
            return -1;
         }
         dt.sec=0;
         dt.min=0;
         dt.hour=0;
         period[0]=StructToTime(dt)-((dt.day_of_week+6)%7)*24*60*60;
         for(int t=1;t<count;t++) {
            period[t]=period[t-1]-7*24*60*60;
         }
      }
      break;
      case MODE_MONTHLY:
      {
         MqlDateTime dt;
         if (!TimeToStruct(now,dt)) {
            return -1;
         }
         dt.day=1;
         dt.sec=0;
         dt.min=0;
         dt.hour=0;
         period[0]=StructToTime(dt);
         for(int t=1;t<count;t++) {
            dt.mon--;
            if (dt.mon==0) {
               dt.mon=12;
               dt.year--;
            }
            period[t]=StructToTime(dt);
         }
      }
      break;
   }
   int curr=0; // текущий период
   balance[curr]=AccountBalance();
   pl[curr]=0;
   for(int pos=OrdersHistoryTotal()-1;pos>=0 ;pos--) {
      if (!OrderSelect(pos,SELECT_BY_POS,MODE_HISTORY)) {
         continue;
      }
      int type=OrderType();
      if (type==OP_BUY || type==OP_BUYLIMIT || type==OP_BUYSTOP || type==OP_SELL || type==OP_SELLLIMIT || type==OP_SELLSTOP) {
         // ордер
         // ориентируемся по времени закрытия
         datetime orderTime=OrderCloseTime();
         if (orderTime<period[curr]) {
            // ордер относится к какому-то пред.периоду
            do {
               curr++;
               if (curr==count) {
                  // все периоды посчитаны
                  break;
               }
               balance[curr]=balance[curr-1];
               pl[curr]=0;
            } while(orderTime<period[curr]);
            if (curr==count) break;
         }
         if (type==OP_BUY || type==OP_SELL) {
            double profit=OrderProfit()+OrderSwap()+OrderCommission();
            balance[curr]-=profit;
            pl[curr]+=profit;
         }
      } else {
         // изменения баланса
         // ориентируемся по времени открытия
         datetime orderTime=OrderOpenTime();
         if (orderTime<period[curr]) {
            // ордер относится к какому-то пред.периоду
            do {
               curr++;
               if (curr==count) {
                  // все периоды посчитаны
                  break;
               }
               balance[curr]=balance[curr-1];
               pl[curr]=0;
            } while(orderTime<period[curr]);
            if (curr==count) break;
         }
         double profit=OrderProfit()+OrderSwap()+OrderCommission();
         balance[curr]-=profit;
      }
   }
   // если не все периоды заполнены - заполнить
   for(curr++;curr<count;curr++) {
      balance[curr]=balance[curr-1];
      pl[curr]=0;
   }
   return 0;
}


 

А зачем столько операций сравнения?

if (type==OP_BUY || type==OP_BUYLIMIT || type==OP_BUYSTOP || type==OP_SELL || type==OP_SELLLIMIT || type==OP_SELLSTOP)

Данное выражение всегда true

А вот это:

if (type==OP_BUY || type==OP_SELL)

лучше так писать: if (type<2). Оно вроде при современном быстродействии и не существенно, но, тут лишняя команда процессору, тут две, а потом на медленный тестер жалуемся.

 

Туда же и вот это:

7*24*60*60

Сложно разве макрос определить?

#define _WEEK   604800
 
Vladimir Simakov:

А зачем столько операций сравнения?

Данное выражение всегда true

А вот это:

лучше так писать: if (type<2). Оно вроде при современном быстродействии и не существенно, но, тут лишняя команда процессору, тут две, а потом на медленный тестер жалуемся.

заблуждаетесь в обоих случаях :-)

1. при пополнении/снятии type отличен от типа ордера

2. не стоит опираться на конкретные числовые значения перечислений

 
Maxim Kuznetsov:

заблуждаетесь в обоих случаях :-)

1. при пополнении/снятии type отличен от типа ордера

2. не стоит опираться на конкретные числовые значения перечислений

Виноват, тогда:

if (type<6)
Причина обращения: