Оптимальный график при закрытии позиций - страница 2

 
Vladimir Zubov:

суть такая, что среди полотенца ордеров надо их смешать при закрытии, с пропорцией 1к3 или ещё лучше, но что бы не было 5 убытка подрят. в гугле инфы нет даже и намёков.

Написал функцию, проверял принтами, вроде работает нормально, в понедельник проверю на реале. 

Функция большая получилась, немного сжал форматирование кода там где всё и так понятно, там где разбор массива, оставил с нормальным форматированием - можно сжать. 

Работает по принципу: закрывает от большего лота к меньшему, так-же учитывает пропорцию прибыльные/убыточные. Пока особого смысла не пойму зачем делать закрытие по пропорции, но на выходных почитаю о преимуществе. 

Функция в любом случае работает быстрее, чем брокер закрывает позиции. Извиняюсь что долго, но в такой рынок заниматься писаниной - глупо и тупо, нужно торговать )

//===============================================================================================
//------------- Закрытие позиций в порядке сортировки по пропорции: прибыль/убыток -------------+
//===============================================================================================
void ClosePosSort(string symb="0",int type=-1,int mg=-1,color cl=clrNONE) {
 int c=0,pl=0,ms=0;
 double m[][3],pr=0;
  if(symb=="0") symb=_Symbol;
  if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) return;
   for(int i=0; i<OrdersTotal(); i++) {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
     if((OrderSymbol()==symb||symb=="")&&(type<0||OrderType()==type)&&(mg<0||OrderMagicNumber()==mg)) {
      if(OrderType()==OP_BUY || OrderType()==OP_SELL) {
       pr=(OrderProfit()+OrderSwap()+OrderCommission());
       if(pr>0) pl++; else ms++; // счетчик количества прибыльных/убыточных позиций
        c++; // счетчик общего количества позиций
         ArrayResize(m, c); // собираем массив закрываемых позиций
         m[c-1][0]=OrderLots();
         m[c-1][1]=OrderTicket();
         m[c-1][2]=pr;
   }}}}
  if(c>0) PosBySort(m, c, pl, ms, symb, type ,mg, cl); // если есть что закрывать
  return;
 }
 
//----------------- Сортируем прибыльные/убыточные для пропорционального закрытия (+/-)
void PosBySort(double& mas[][],int c,double pl,double ms,string symb,int type,int mg,color cl) {
 double Plus[], Minus[], dfp=0, dfm=0;
 int p=0, m=0, plus=0, minus=0;
 
// Сортируем по размеру лотов от большего к меньшему
  ArraySort(mas, WHOLE_ARRAY, 0, MODE_DESCEND);

// Создадим массивы прибыльных и убыточных позиций
  for(int am=0; am<c; am++) {
   if(mas[am][2]>0) { // если профит больше "0"
     plus++;
      ArrayResize(Plus, plus);
      Plus[plus-1]=mas[am][1];   // прибыльные тикеты
   } else {
     minus++;
      ArrayResize(Minus, minus);
      Minus[minus-1]=mas[am][1]; // убыточные тикеты
    }
  }
  
// Узнаем соотношение прибыльные/убыточные
  pl=pl==0?1:pl;
  ms=ms==0?1:ms;
  dfp=MathCeil(pl/ms); dfp=dfp==0?1:dfp;
  dfm=MathCeil(ms/pl); dfm=dfm==0?1:dfm;
  
 // Comment("dfm ",dfm," dfp ",dfp," ms ",ms," pl ",pl);

// Пройдем по массивам
  while(c > 0) {
   int jm=0, jp=0;
   if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
 // Минусовые доминируют - начинаем закрывать с минусовых
   if(pl<=ms) {
    // минусовые
     for(int im=0; im<ArraySize(Minus); im++) {
      jm++;
      c--;
      m++;
      if(m>ArraySize(Minus)) break;       // не выйти за пределы массива
       ClosePosTicket((int)Minus[m-1], cl);
       if(jm==dfm) break;                 // соблюдение пропорции
     }
    // плюсовые
     for(int ip=0; ip<ArraySize(Plus); ip++) {
      jp++;
      c--;
      p++;
      if(p>ArraySize(Plus)) break;        // не выйти за пределы массива
       ClosePosTicket((int)Plus[p-1], cl);
       if(jp==dfp) break;                 // соблюдение пропорции
     }
   }
 // Плюсовые доминируют - начинаем закрывать с плюсовых
   if(pl>ms) {
    // плюсовые
     for(int ip=0; ip<ArraySize(Plus); ip++) {
      jp++;
      c--;
      p++;
      if(p>ArraySize(Plus)) break;        // не выйти за пределы массива
       ClosePosTicket((int)Plus[p-1], cl);
       if(jp==dfp) break;                 // соблюдение пропорции
     }
    // минусовые
     for(int im=0; im<ArraySize(Minus); im++) {
      jm++;
      c--;
      m++;
      if(m>ArraySize(Minus)) break;       // не выйти за пределы массива
       ClosePosTicket((int)Minus[m-1], cl);
       if(jm==dfm) break;                 // соблюдение пропорции
     }
   }
//-
  } // while

// Проверяем, все закрылись или нет. Возможно нужен флаг, чтоб не закрыть ново-открытые.
   ClosePosSort(symb, type ,mg, cl);
  return;
 } // end

//----------------- Закрытие позиций по переданному тикету
void ClosePosTicket(int tic, color cl=clrNONE) {
 double l, p, pr;
 bool res=false;

 if(OrderSelect(tic, SELECT_BY_TICKET)) {
  if(OrderCloseTime()==0) {
   for(int i=1; i<=5; i++) {    // количество попыток закрытия при ошибке
    if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
     while(!IsTradeAllowed()) Sleep(5000);
      RefreshRates();
      p=MarketInfo(OrderSymbol(), OrderType()==OP_BUY? MODE_BID:MODE_ASK);
      l=OrderLots();
      p=NormalizeDouble(p, (int)MarketInfo(OrderSymbol(), MODE_DIGITS));
      pr=OrderProfit()+OrderSwap()+OrderCommission();
      res=OrderClose(OrderTicket(), l, p, Slippage, cl);
       if(res) {
        break;
       } else {
        int err=_LastError;
        if(err==146) while(IsTradeContextBusy()) Sleep(1000);
         Print("Close Error(",err,") ",OrderType()==0?"Buy=":"Sell=",OrderSymbol(),", Ticket: ",OrderTicket(), ", Price: ",
          DoubleToStr(p,(int)MarketInfo(OrderSymbol(), MODE_DIGITS)),", Lot: ",OrderLots(),", Profit: ",DoubleToStr(pr,2));
      Sleep(1000*5);
 }}}}}
//===============================================================================================

 

Применение как всегда 

#property strict

int Slippage=30;

//===============================================================================================
void OnTick()
 {
 // Применение
 // ClosePosSort(Символ, OP_BUY или OP_SELL, Magic, Цвет значка);
   if(условие закрытия) {
     ClosePosSort(_Symbol, -1, 14, clrYellow);        // по текущему символу BUY и SELL с Magic=14
     ClosePosSort("GBPCAD", OP_SELL, 35, clrYellow);  // по конкретному символу только SELL с Magic=35 
     ClosePosSort("", OP_BUY , -1, clrYellow);        // по всему счету только BUY и любым Magic номером
   }
//-
 }

 

Конструктивная критика работы кода - приветствуется.

 
Vitaly Muzichenko:

Написал функцию, проверял принтами, вроде работает нормально, в понедельник проверю на реале. 

Функция большая получилась, немного сжал форматирование кода там где всё и так понятно, там где разбор массива, оставил с нормальным форматированием - можно сжать. 

Работает по принципу: закрывает от большего лота к меньшему, так-же учитывает пропорцию прибыльные/убыточные. Пока особого смысла не пойму зачем делать закрытие по пропорции, но на выходных почитаю о преимуществе. 

Функция в любом случае работает быстрее, чем брокер закрывает позиции. Извиняюсь что долго, но в такой рынок заниматься писаниной - глупо и тупо, нужно торговать )

 

Применение как всегда 

 

Конструктивная критика работы кода - приветствуется.

Огромное спасибо за функцию, я бы городил огород с кучей циклов и проверок, начну тестировать тоже на реале. Смысл в том что если закрывать серию красиво и график красивее, на результат торговли не влияет, а вот визуальное восприятие да. Еще раз огромное спасибо!
 

Возник вопрос, зачем проверка в режиме тестера или нет ?

if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;

P.S. код не вставляется в сообщение нормально 

 
Vladimir Zubov:

Возник вопрос, зачем проверка в режиме тестера или нет ?

if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;

P.S. код не вставляется в сообщение нормально 

Эта проверка служит для экстренной остановки функции. Бывают ситуации, когда не нужно закрывать позиции, например на новостях, пошло резвое движение в нашу сторону, появилась возможность выжать с рынка ещё несколько пунктов, но тут начинается закрытие, и нажатием на кнопку "Авто-торговля", мы прерываем работу функции. Так-же проверка на разрешение торговли, если отжата кнопка "Авто-торговля", то функция не работает, если в режиме тестера - то игнорируем кнопку "Авто-торговля"
 
Vitaly Muzichenko:
Эта проверка служит для экстренной остановки функции. Бывают ситуации, когда не нужно закрывать позиции, например на новостях, пошло резвое движение в нашу сторону, появилась возможность выжать с рынка ещё несколько пунктов, но тут начинается закрытие, и нажатием на кнопку "Авто-торговля", мы прерываем работу функции. Так-же проверка на разрешение торговли, если отжата кнопка "Авто-торговля", то функция не работает, если в режиме тестера - то игнорируем кнопку "Авто-торговля"

Спасибо за пояснения, а так же за код. Закрывает всё правильно, перемешивает убыточные позиции при закрытии среди профитных, улучшая тем статистику и делает более плавный баланс на выходе. А также великолепно кроет при разных лотах.

 

 

 

пока проверил в тестере, на центе с понедельника проверю. 

 
Vladimir Zubov:

Спасибо за пояснения, а так же за код. Закрывает всё правильно, перемешивает убыточные позиции при закрытии среди профитных, улучшая тем статистику и делает более плавный баланс на выходе. А также великолепно кроет при разных лотах.

пока проверил в тестере, на центе с понедельника проверю. 

Вот так будет скорее всего правильнее, чем было

//===============================================================================================
//------------- Закрытие позиций в порядке сортировки по пропорции: прибыль/убыток -------------+
//===============================================================================================
void ClosePosSort(string symb="0",int type=-1,int mg=-1,color cl=clrNONE) {
 int c=0,pl=0,ms=0;
 double m[][3],pr=0;
  if(symb=="0") symb=_Symbol;
  if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) return;
   for(int i=0; i<OrdersTotal(); i++) {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
     if((OrderSymbol()==symb||symb=="")&&(type<0||OrderType()==type)&&(mg<0||OrderMagicNumber()==mg)) {
      if(OrderType()==OP_BUY || OrderType()==OP_SELL) {
       pr=(OrderProfit()+OrderSwap()+OrderCommission());
       if(pr>0) pl++; else ms++; // счетчик количества прибыльных/убыточных позиций
        c++; // счетчик общего количества позиций
         ArrayResize(m, c); // собираем массив закрываемых позиций
         m[c-1][0]=OrderLots();
         m[c-1][1]=OrderTicket();
         m[c-1][2]=pr;
   }}}}
  if(c>0) PosBySort(m, c, pl, ms, symb, type ,mg, cl); // если есть что закрывать
  return;
 }
 
//----------------- Сортируем прибыльные/убыточные для пропорционального закрытия (+/-)
void PosBySort(double& mas[][],int cw,double pl,double ms,string symb,int type,int mg,color cl) {
 double Plus[], Minus[], dfp=0, dfm=0;
 int mp=0, mm=0, pp=0, pm=0, plus=0, minus=0;
 
// Сортируем по размеру лотов от большего к меньшему
  ArraySort(mas, WHOLE_ARRAY, 0, MODE_DESCEND);

// Создадим массивы прибыльных и убыточных позиций
  for(int am=0; am<cw; am++) {
   if(mas[am][2]>0) { // если профит больше "0"
     plus++;
      ArrayResize(Plus, plus);
      Plus[plus-1]=mas[am][1];   // прибыльные тикеты
   } else {
     minus++;
      ArrayResize(Minus, minus);
      Minus[minus-1]=mas[am][1]; // убыточные тикеты
    }
  }
  
// Узнаем соотношение прибыльные/убыточные
  pl=pl==0?1:pl;
  ms=ms==0?1:ms;
  dfp=MathCeil(pl/ms); dfp=dfp==0?1:dfp;
  dfm=MathCeil(ms/pl); dfm=dfm==0?1:dfm;

// Пройдем по массивам
  for(int ci=0; ci<cw; ci++) {
   int jm=0, jp=0;
   if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
 // Минусовые доминируют
   if(pl<=ms) {
    // минусовые
     for(int im=0; im<ArraySize(Minus); im++) {
      jm++;
      ci++;
      mm++;
      if(mm>ArraySize(Minus)) break;      // не выйти за пределы массива
       ClosePosTicket((int)Minus[mm-1], cl);
       if(jm==dfm) break;                 // соблюдение пропорции
     }
    // плюсовые
     for(int ip=0; ip<ArraySize(Plus); ip++) {
      jp++;
      ci++;
      mp++;
      if(mp>ArraySize(Plus)) break;      // не выйти за пределы массива
       ClosePosTicket((int)Plus[mp-1], cl);
       if(jp==dfp) break;                 // соблюдение пропорции
     }
   }
 // Плюсовые доминируют
   if(pl>ms) {
    // плюсовые
     for(int ip=0; ip<ArraySize(Plus); ip++) {
      jp++;
      ci++;
      pp++;
      if(pp>ArraySize(Plus)) break;      // не выйти за пределы массива
       ClosePosTicket((int)Plus[pp-1], cl);
       if(jp==dfp) break;                 // соблюдение пропорции
     }
    // минусовые
     for(int im=0; im<ArraySize(Minus); im++) {
      jm++;
      ci++;
      pm++;
      if(pm>ArraySize(Minus)) break;      // не выйти за пределы массива
       ClosePosTicket((int)Minus[pm-1], cl);
       if(jm==dfm) break;                 // соблюдение пропорции
     }
   }
//-
  } // for

// Проверяем, все закрылись или нет
   ClosePosSort(symb, type ,mg, cl);
  return;
 } // end

//----------------- Закрытие позиций по переданному тикету
void ClosePosTicket(int tic, color cl=clrNONE) {
 double l, p, pr;
 bool res=false;

 if(OrderSelect(tic, SELECT_BY_TICKET)) {
  if(OrderCloseTime()==0) {
   for(int i=1; i<=5; i++) {
    if(!IsTesting() && (!IsExpertEnabled() || IsStopped())) break;
     while(!IsTradeAllowed()) Sleep(5000);
      RefreshRates();
      p=MarketInfo(OrderSymbol(), OrderType()==OP_BUY? MODE_BID:MODE_ASK);
      l=OrderLots();
      p=NormalizeDouble(p, (int)MarketInfo(OrderSymbol(), MODE_DIGITS));
      pr=OrderProfit()+OrderSwap()+OrderCommission();
      res=OrderClose(OrderTicket(), l, p, Slippage, cl);
       if(res) {
        break;
       } else {
        int err=_LastError;
        if(err==146) while(IsTradeContextBusy()) Sleep(1000);
         Print("Close Error(",err,") ",OrderType()==0?"Buy=":"Sell=",OrderSymbol(),", Ticket: ",OrderTicket(), ", Price: ",
          DoubleToStr(p,(int)MarketInfo(OrderSymbol(), MODE_DIGITS)),", Lot: ",DoubleToStr(OrderLots(),2),", Profit: ",DoubleToStr(pr,2));
      Sleep(1000*5);
 }}}}}
//===============================================================================================
 
Vitaly Muzichenko:

Вот так будет скорее всего правильнее, чем было

А можно узнать, что Вы переделали в новой версии, технические нюансы или алгоритм сортировки ? Сортировка осталась такой же как и была, судя по тесту. На реале вчера проверял функцию и был приятно удивлен скоростью работы, визуально даже быстрее закрывает чем стандартный перебор) За это ещё раз спасибо.
 
Vladimir Zubov:
А можно узнать, что Вы переделали в новой версии, технические нюансы или алгоритм сортировки ? Сортировка осталась такой же как и была, судя по тесту. На реале вчера проверял функцию и был приятно удивлен скоростью работы, визуально даже быстрее закрывает чем стандартный перебор) За это ещё раз спасибо.

Улучшена сортировка при б0льшем перекосе прибыльные/убыточные. Связано с изменением 

// Пройдем по массивам

  for(int ci=0; ci<cw; ci++) { 

То есть, сначала закрывает всё что собрано в массиве изначально по коэффициенту, после всех закрытий, остаются ещё открытые, и снова функция начинает работу заново, снова сортирует, и начинает закрытие.

Улучшено тем, что в самом конце закрывает так-же с сортировкой, а первом варианте, сначала сортирует, и если не хватает позиций для перемешивания - закрывает оставшиеся подряд. Полезно при большом перекосе, но функция может срабатывать до трёх раз.

Вот результат работы

 

 
Спасибо, тоже интересный вариант.
Причина обращения: