Расчет лота основываясь на предыдущих потерях, не мартингал

 
Здравствуйте!
Интересует такой вопрос: кто-то уже научился считать лоты экспертом, добавляя в размер лота только значение потерь? а если потери составляют 0 то и размер лота ставим по дефолту.
Пробовал искать - не нашел

Вот код, который я использую. Работает на евро-доллар для limit = 100. не работает на паре фунт-доллар с лимитом 12. Лимит = тейкпрофит.
 
int Calculate_Loss()
  {
 
//----
   double total_loss=0;
//----
   for(int i=OrdersHistoryTotal();i>0;i--)
    {
      OrderSelect(i,SELECT_BY_POS,MODE_HISTORY);
      if(OrderProfit()>PipsLoss*OrderLots()*10.0)
       {
        //Print("Profit!");
        break;
       }
      else if(OrderProfit()<0)
       {
       total_loss+=OrderProfit()+OrderSwap();
 
       //Print("OrderProfit = ",profit);
      }
    }
   
//----
   return(total_loss);
  }
 
double CalcLot()
 {
   ///////----------- SHOULD BE --------------  double lot=(PercentGain+TotalLoss)/Limit;  ------------------ /////////
  
   double calculatedlot=-Calculate_Loss()*(1+PercentGain/100.0)/Limit/10.0;
   //Print("lot size is ",calculatedlot);
   double lot=NormalizeDouble(calculatedlot,2);
   if(lot<BasicLot)
   lot=BasicLot;
   return(lot);
 }
При вызывается посылкой на CalcLot();
PercentGain = уровень потерь, которые мы хотим компенсировать сделующим ордером + 100%
Limit = TakeProfit.
BasicLot = 0.1 или 0.01

Пример:

2 лося. 0.05 бакса и 0.08 бакса

0.05 + 0.08 = 0.13

0.13 * 100% (PercentGain) = 0.26

0.26 / 12 = 0.216 (округлить вверх до 0.03)


Есть идеи как подправить? а то у меня что-то не получается... Расчет потерь вроде работает нормально. Проверял - читает данные истории. Вот только лот неправильный выходит.
Помогите найти ошибку пожалуйста!
 
Для начала предлагаю посмотреть строки
   for(int i=OrdersHistoryTotal();i>0;i--)
    {
      OrderSelect(i,SELECT_BY_POS,MODE_HISTORY);
т.к. что-то мне подсказывает, что номера ордеров идут от 0 до N-1, где N - количество ордеров, а вообще у самого давно мысль перебирать историю на предмет убытков для расчета оптимального размера позиции согласно, по моему, книге "математика управления капиталом", только там речь о самой убыточной непрерывной последовательности сделок, а в вашем случае, как я понял, он считает убыток, полученный за последнюю серию и то, только в том случае, если сделка(и) все таки принесла убыток. Если последняя сделка принесла определенную прибыль, то CalcLot() всегда вернет BasicLot.
И еще я не совсем понял больше какой величины должен быть OrderProfit(), что бы проверка сочла сделку прибыльной. Так же не совсем ясна изначальная
постановка задачи: сколькими лотами нужно играть, чтоб при получении X пунктов прибыли компенсировать Y% потерь от убыточных сделок?

З.Ы. Еще бы предложил все таки проверять
if (OrderSelect(...)==true) {...}
сами понимаете зачем.
 
  double LotsOptimized(int type)
  {
   double Lot;
   double minLots=MarketInfo(Symbol(),MODE_MINLOT);
   double maxLots=MarketInfo(Symbol(),MODE_MAXLOT);
   double tmpLot;
   
   int    orders = HistoryTotal();     // history orders total
   int    losses = 0;                  // number of losses orders without a break
//---- select lot size
   int    typeOpenOrder;
   
   if(MaximumRisk==0)
   {
      Lot=Lots;
   }
   else
      if(openCurBuy==0 && openCurSell==0)
      {
        freeMarging=AccountFreeMargin()/MaxCurentOrders;
        Lot = NormalizeDouble(freeMarging*MaximumRisk / (Bid*MathPow(10,Digits-1)), 2);
        Lots=Lot;
      }
   
   if(type==OP_BUY)
   {
       typeOpenOrder =openCurBuy;
   }   
   if(type==OP_SELL)
   {   
     typeOpenOrder =openCurSell;
   }  
   
 
   switch(OptimizeType)
   {  
      case 0:
         tmpLot=0;
         break;
      case 1:
         tmpLot=typeOpenOrder*Lot;
         break;
     case  2:
         tmpLot=(MaxCurentOrders-typeOpenOrder)*Lot;
         break;
   }
   
   Lot = Lot+(tmpLot);
     
 
  
//---- calcuulate number of losses orders without a break
   if(DecreaseFactor > 0)
     {
       for(int i = orders - 1; i >= 0; i--)
         {
           if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == false) 
             { 
               Print("Error in history!"); 
               break; 
             }
           //----
           if(OrderSymbol() != Symbol() || OrderType() > OP_SELL) 
               continue;
           //----
           if(OrderProfit() > 0) 
               break;
           //----
           if(OrderProfit() < 0) 
               losses++;
         }
       if(losses > 1) 
           Lot = NormalizeDouble(Lot - Lot*losses / DecreaseFactor, 2);
     }
//---- return lot size
   if(Lot < minLots ) 
      Lot = minLots;
   if(MaximumLots != 0 && Lot > MaximumLots ) 
       Lot = MaximumLots;
   if(Lot > maxLots)
      Lot = maxLots;
   return(Lot);
  }
Вот
if(DecreaseFactor > 0)
     {
       for(int i = orders - 1; i >= 0; i--)
         {
           if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) == false) 
             { 
               Print("Error in history!"); 
               break; 
             }
           //----
           if(OrderSymbol() != Symbol() || OrderType() > OP_SELL) 
               continue;
           //----
           if(OrderProfit() > 0) 
               break;
           //----
           if(OrderProfit() < 0) 
               losses++;
         }
       if(losses > 1) 
           Lot = NormalizeDouble(Lot - Lot*losses / DecreaseFactor, 2);
     }
как раз то что ты хочешь :-) было в каком то советнике, взял себе на вооружение :-)
 
Shinigami:
Есть идеи как подправить? а то у меня что-то не получается... Расчет потерь вроде работает нормально. Проверял - читает данные истории. Вот только лот неправильный выходит.
Помогите найти ошибку пожалуйста!

По коду вроде должно работать. Может быть дело в каких-то сопутствующих обстоятельствах? Пробовали вставлять перед

double calculatedlot=-Calculate_Loss()*(1+PercentGain/100.0)/Limit/10.0;

   Print("",Calculate_Loss()," ",PercentGain," ",Limit);
? И, кстати, для цены пункта может лучше отвести переменную.
 
А как считать цену пункта?

Добавил строку принта. Выдает что тотал лосс = -6 -3 -5 -10 и другую чепуху.
переписал total_loss=total_loss+OrderProfit()+OrderSwap() но ничего не изменилось


Переписал немного:
double CalcLot()
 { 
   ///////----------- SHOULD BE --------------  double lot=(PercentGain+TotalLoss)/Limit;  ------------------ /////////
//   Print("Loss = ",Calculate_Loss(),"    PercentGain = ",PercentGain,"      Limit = ",Limit);
   double total_loss,current_loss;
   for(int i=OrdersHistoryTotal();i>0;i--)
    {
      if (OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true) 
      OrderSelect(i,SELECT_BY_POS,MODE_HISTORY);
      if(OrderProfit()>0)//PipsLoss*OrderLots()*10.0)
       {
        break;
       }
      else if(OrderProfit()<0)
       {
        current_loss=OrderProfit()+OrderSwap();
        Print("current_loss = ",current_loss);
        total_loss=total_loss+current_loss;
        Print("total_loss = ",total_loss);
       }
    }
   double calculatedlot=0;
   calculatedlot=-total_loss*(1+PercentGain)/Limit/10.0;
   Print("-total_loss*(1+PercentGain) = ",-total_loss*(1+PercentGain));
   double lot=NormalizeDouble(calculatedlot,2);
   if(lot<BasicLot)
   lot=BasicLot;
   if(AccountBalance()<lot*100)
   return(BasicLot);
   return(lot);
 }
Теперь почти пашет. Но мне нужно округление вверх. Как такое посчитать?

При переносе из одной функции в другую похоже перекидывалось значение без запятой...
 

Вам сразу дали дельный совет, которым я настоятельно рекомендую всё-таки воспользоваться:

Bones 20.06.2007 05:50

Для начала предлагаю посмотреть строки
   for(int i=OrdersHistoryTotal();i>0;i--)
    {
      OrderSelect(i,SELECT_BY_POS,MODE_HISTORY);
т.к. что-то мне подсказывает, что номера ордеров идут от 0 до N-1 ... (конец цитаты)
В принципе, для истории можно и изменить направление цикла на прямое:
for(int i=0; i<OrdersHistoryTotal(); i++)
Как правильно применить второй совет посмотрите в хелпере (на OrderSelect()).
total_loss перед суммированием нужно обнулить.
Одним словом, первый вариант кода нравился мне больше. Кстати, есть впечатление, что и в этом фрагменте чего-то не хватает (например else):
   if(AccountBalance()<lot*100)
   return(BasicLot);
   return(lot);
 }
ИМХО, если нужно иметь уверенность в работе этого кода, проверку лучше всего начинать с именно того принта в именно том месте, о котором я писал в предыдущем посте.
Насчёт стоимости пункта воспользуйтесь поиском на стоимость пункта
 

Посмотрел хелпер, для OrderSelect пример не о особо наглядный. Так что фиг с ней, с педагогикой :) , вот вариант кода, если он не будет работать убедитесь, что до обращения к функции с PercentGain и Limit ничего не происходит

double CalcLot()
 { 
   ///////----------- SHOULD BE --------------  double lot=(PercentGain+TotalLoss)/Limit;  ------------------ /////////
   double current_loss;
   double total_loss = 0;
   for(int i=0;i<OrdersHistoryTotal();i++)
    {
      if (OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true) {
        if(OrderProfit()>0)//PipsLoss*OrderLots()*10.0)
         {
            continue;
         }
        else if(OrderProfit()<0)
              {
               current_loss=OrderProfit()+OrderSwap();
               Print("current_loss = ",current_loss);
               total_loss=total_loss+current_loss;
               Print("total_loss = ",total_loss);
              }
      }
      else {
        Print("OrderSelect() вернул ошибку - ",GetLastError());
        return(-1);
      }
    }
   double calculatedlot=0;
//   Print("Loss = ",Calculate_Loss(),"    PercentGain = ",PercentGain,"      Limit = ",Limit);
   calculatedlot=-total_loss*(1+PercentGain)/Limit/10.0;
   Print("-total_loss*(1+PercentGain) = ",-total_loss*(1+PercentGain));
   double lot=NormalizeDouble(calculatedlot,2);
   if(lot<BasicLot)
   lot=BasicLot;
   if(AccountBalance()<lot*100) return(BasicLot);
   else return(lot);
 }

Насчёт округления всегда в большую сторону можно попробовать умножить на 100, применить MathCeil и поделить обратно.

 

Сделал в коде маленькую поправку (заменил break на continue) :)

 
continue не катит - мне нужна последняя серия потерь, не более. если прилепить елсе то будет совсем худо - будут плюсоваться все потери

вот нашел проблемку. если сделать
calculatedlot=-total_loss*(1+PercentGain)/Limit/(Bid*1000/AccountBalance());
то пашет для фунта. но не пашел для евро - слишком сильно растет лот...
 

Тогда нужно for(int i=OrdersHistoryTotal()-1;i>=0;i--) Ну и вроде действительно break вернуть надо. В общем-то мне гораздо быстрее отладить код самому, но для отладки этого нюанса нужно довольно упорно создавать нужную ситуацию в истории ордеров :)

Насчёт последней новации - это что - так цена пункта считается?

 
Shinigami:
А как считать цену пункта?
Посмотрите lot lib, там есть функция расчета стоимости пункта.
Причина обращения: