Правильный расчет лота от % депо - страница 5

 
EverAlex:

Поэтому lSL - это сколько пунктов до SL

Point = 0.00001 (на 5 значных котировках)

dLotStep = 0.01


Формула (lSL*dLotCost*dLotStep))*dLotStep - неправильная

Должно быть что-то типа (lSL*dLotCost*Point))*dLotStep


Не надо ничего выдумывать. Размер лота в каждом ДЦ свой и надо его приводить к нужному размеру. Пункты тут не причем
 
Vinin:

Не надо ничего выдумывать. Размер лота в каждом ДЦ свой и надо его приводить к нужному размеру. Пункты тут не причем


По условиям задачи lSL - это размер просадки в пунктах котировок, а не в пунктах лота.

Т.е. пункты тут как раз причем.

Значит, и в формуле расчета умножать (то что в скобках) надо на Point, а не на dLotStep.

Другое дело - что это уже происходит за счет dLotCost (заодно с пересчетом в валюту депозита)...

Т.е. мы сначала в

MathRound(AccountFreeMargin()*lRisk*0.01/(lSL*dLotCost*dLotStep))

получаем целое число, а потом пересчитываем обратно в правильные единицы лота за счет умножения на dLotStep ?

 
double lotSize(double deposSize=1000.0, string currName="USDCHF", double proc=2.0, int pipsLoss=1000)// функция лота
{  
   //проверка достаточности средств 
   if(deposSize < 
   MarketInfo(currName,MODE_MARGINREQUIRED)*MarketInfo(currName,MODE_MINLOT))
   //для проведения торговли
   {
      Alert("Величина вашего депозита недостаточна \nдля торговли на инструменте\""+currName+"\" \nc минимальнодопустимым лотом");
      return 0.0;
   }
   //проверка, на стоп-аут
   ENUM_ACCOUNT_STOPOUT_MODE stopOutMode=(ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
   double procUsed;
   if(stopOutMode==ACCOUNT_STOPOUT_MODE_PERCENT)//если стоп-аут в процентах
     {
         if(proc > AccountInfoDouble(ACCOUNT_MARGIN_SO_SO))
           {
               Alert("Потеря выше уровня STOPOUT!\nРасчет лота производиться по величине STOPOUT.");
               procUsed=AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)/100;
               //Print(MarketInfo(currName,MODE_MARGINREQUIRED)," ",procUsed);
               return deposSize/(pipsLoss+procUsed*MarketInfo(currName,MODE_MARGINREQUIRED));               
           }
     }
     //а вот здесь нужна доработка, для платформ, где стоп-аут в пунктах
     //как сказал один наш товарищ "у кого идеи ростут из нужного места".. доделает
     
   double currMove=deposSize*proc/100;// расчет процента от величины депозита
   double lotCount=currMove/(pipsLoss*MarketInfo(currName,MODE_TICKVALUE));//ну а тут и ведеться сам расчет лота

   if(lotCount<MarketInfo(currName,MODE_MINLOT))
   {
      return MarketInfo(currName,MODE_MINLOT);
   }
   if(lotCount>MarketInfo(currName,MODE_MAXLOT))
   {
      return MarketInfo(currName,MODE_MAXLOT);  
   }
   return NormalizeDouble(lotCount,2);
   //return lotCount;
}

есть еще вариант с депозом в 3 бакса пару "EURUSD" торговать и 30% на проиграш выставить.. но это уже из серии извращенств

 
EverAlex:


По условиям задачи lSL - это размер просадки в пунктах котировок, а не в пунктах лота.

Т.е. пункты тут как раз причем.

Значит, и в формуле расчета умножать (то что в скобках) надо на Point, а не на dLotStep.

Другое дело - что это уже происходит за счет dLotCost (заодно с пересчетом в валюту депозита)...

Т.е. мы сначала в

получаем целое число, а потом пересчитываем обратно в правильные единицы лота за счет умножения на dLotStep ?




Да
 
Vinin:


Всё равно формула неправильная (для блока iSL>0).

TICKVALUE дает цену для TICKSIZE.

А lSL задается в пунктах POINT.

POINT не всегда совпадает с TICKSIZE (см. 3-значную пару XAUUSD у Альпари).

Значит - надо пересчитать lSL из POINT в TICKSIZE.

Иначе - будем получать завышенный в 10 раз лот (что я и наблюдал на паре XAUUSD, пока не добавил пересчет).

if (lSL>0){

lSL= (int)(MarketInfo(lSymbol,MODE_TICKSIZE) / MarketInfo(lSymbol,MODE_POINT) )* lSL; // TICKSIZE/POINT даст целое число (1 или 10), по-этому можно использовать lSL типа int

// дальше как и было

 double dLotCost=MarketInfo(lSymbol,MODE_TICKVALUE);
 dLot=MathRound(AccountFreeMargin()*lRisk*0.01/(lSL*dLotCost*dLotStep))*dLotStep;
}

PS: для ТС, которые оптимизируются за много проходов (>10млн) все неизменяемые параметры символа (TICKSIZE, POINT, TICKVALUE, LOTSTEP, MINLOT, MAXLOT и пр.) надо в функции init() присваивать переменным и использовать значения этих переменных в расчетах.

В т.ч. вынести в переменную значение TickSize/Point.

 
EverAlex:

Всё равно формула неправильная (для блока iSL>0).

TICKVALUE дает цену для TICKSIZE.

А lSL задается в пунктах POINT.

POINT не всегда совпадает с TICKSIZE (см. 3-значную пару XAUUSD у Альпари).

Значит - надо пересчитать lSL из POINT в TICKSIZE.

Иначе - будем получать завышенный в 10 раз лот (что я и наблюдал на паре XAUUSD, пока не добавил пересчет).

if (lSL>0){

lSL= (int)(MarketInfo(lSymbol,MODE_TICKSIZE) / MarketInfo(lSymbol,MODE_POINT) )* lSL; // TICKSIZE/POINT даст целое число (1 или 10), по-этому можно использовать lSL типа int

// дальше как и было

PS: для ТС, которые оптимизируются за много проходов (>10млн) все неизменяемые параметры символа (TICKSIZE, POINT, TICKVALUE, LOTSTEP, MINLOT, MAXLOT и пр.) надо в функции init() присваивать переменным и использовать переменных в расчетах.

В т.ч. вынести в переменную значение TickSize/Point.




Спасибо
 
Vinin:

Спасибо

Топикстартер еще на первой странице послал свой респект, и больше не появлялся.

Несколько лет назад где-то на форуме этот вопрос обсуждался. Перескажу по памяти, но, без формул.

Предположим, мы торгуем пару AUDCHF. Взято совершенно произвольно, чтобы объяснить, как формируется профит или убыток по позиции. Примерно такая же тема поднималась в ветке https://www.mql5.com/ru/forum/150912

Если мы торгуем один лот 100000 AUD, то ( на пятизнаке ) каждый пипс приносит 1 CHF (знаменатель пары) прибыли или убытка (зависит от того, в какую сторону стали, и, куда идет цена).

Соответственно, в каждый момент времени, мы знаем, сколько CHF мы заработали/проиграли. Выигрыш/проигрыш конвертируется в валюту депозита по курсу USDCHF на текущий момент, если валюта депозита USD, или EURCHF, если валюта депозита EUR. По аналогии, для всех пар и валют депозита.

Отсюда ответ: абсолютно точно правильный размер лота мы можем оценить не всегда. Ориентиром может быть MarketInfo() с параметром запроса MODE_TICKVALUE.

 
Mislaid:

Отсюда ответ: абсолютно точно правильный размер лота мы можем оценить не всегда. Ориентиром может быть MarketInfo() с параметром запроса MODE_TICKVALUE.


Так оно и учитывается давно. По крайней мере - в красиво оформленных постах Vininпока неправильным расчетом лота для несовпадающих TICKSIZE c POINT) и старом посте от Martingeil (с правильным расчетом лота, но без возможности задаяния просадки ==0).

Главное - чтобы от ДЦ прилетало правильное значение TICKVALUE (или правильно на клиенте расчитывалось, если расчитывается в МТ).


Когда эта тема стартовала, я так понял, TICKVALUE ещё не было.

А с его появлением всё упростилось и эта тема зачахла на какое-то время.

PS: скоро выложу свою версию - гибрид варианта Vinin'a (у него формула проще и предусмотрено iSL==0) и Martingeil'a (контроль нехватки средств даже на мин. лот).

Особенности: 1) расчет баланса от AccountFreeMargin(), а не от AccountBalance().

2) И (для перевертышей) учтено, что баланс уменьшится на определенную сумму, когда открытый трейд закроется по SL.

Если не будет хватать средств даже на мин. баланс - будет выдавать объем лота -134 (ошибка 134 - нехватка средств для открытия трейда)

В связи с чем вопрос к Vinin (и др. опытным камрадам): код сам раскрашивается или Вы сами раскрашиваете? Я пробовал задать фрагмент стиль "код", но он не раскрасился. Или он только после отправки поста раскрашивается?

 
EverAlex:

В связи с чем вопрос к Vinin (и др. опытным камрадам): код сам раскрашивается или Вы сами раскрашиваете? Я пробовал задать фрагмент стиль "код", но он не раскрасился. Или он только после отправки поста раскрашивается?

Раскрашивается сам. Но, не всегда.
 

доработал до ума свою идею (для платформ з процентом для стоп-аута).. делюсь кодом.. конструктивная критика принимается

double lotSize(double deposSize=1000.0, string currName="USDCHF", double proc=2.0, int pipsLoss=1000)
{  
   double lotCount=0;
   //1) проверка достаточности средств для проведения торговли
   if(deposSize < 
   MarketInfo(currName,MODE_MARGINREQUIRED)*MarketInfo(currName,MODE_MINLOT))
   {
      //Alert("Величина вашего депозита недостаточна \nдля торговли на инструменте\""+currName+"\" \nc минимальнодопустимым лотом");
      return 0.0;
   }
   
   double currMove=deposSize*proc/100;// расчет процента от величины депозита
   
  
   //расчивываем максимально допустимый лот, до стоп-аута
   double SOlot = deposSize/(pipsLoss*MarketInfo(currName,MODE_TICKVALUE)+
   MarketInfo(currName,MODE_MARGINREQUIRED)*AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)/100);     
   //расчет величины депозита, при котором сработает стоп-аут
   double SOval = SOlot*pipsLoss*MarketInfo(currName,MODE_TICKVALUE);
   
   
   ENUM_ACCOUNT_STOPOUT_MODE stopOutMode=(ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
   
   if(stopOutMode==ACCOUNT_STOPOUT_MODE_PERCENT)//если стоп-аут в процентах
   {  
     
     if((deposSize-currMove)<SOval)//проверяем остаток на депозите на превышение значения стоп-аут
     {     
         if(SOlot<MarketInfo(currName,MODE_MINLOT))//если лот стоп-аута меньше минимального лота
         {
             lotCount = MarketInfo(currName,MODE_MINLOT);
             //находим количесвто пунктов до вылета по стоп-ауту и выбрасываем предупреждение
             int pipsSO=(int)round((deposSize - SOval)/(lotCount * MarketInfo(currName,MODE_TICKVALUE)));
             Print("При прохождении ценой больше ", pipsSO," пп.- \nторговля будет прекращена по STOP OUT!");             
             
             
         }
         else//если наш стоп-аут лот больше равно минимального
         {
              lotCount = SOlot;              
              int pipsSO=(int)round((deposSize - SOval)/(lotCount * MarketInfo(currName,MODE_TICKVALUE)));
              Print("Достижение STOP OUT, произойдет через ", pipsSO, " и работа будет проведена с максимальнодоступимым лотом до STOP OUT");
                           
         }
     }
     else//если же остаток на депозите будет меньше стоп-аута
     {     
     lotCount = currMove/(pipsLoss*MarketInfo(currName,MODE_TICKVALUE));
         if(lotCount<MarketInfo(currName,MODE_MINLOT))//если лот меньше минимального лота
         {            
            int pipsProc=(int)round(currMove/(MarketInfo(currName,MODE_MINLOT)*MarketInfo(currName,MODE_TICKVALUE)));
            Print(proc,"%-й уровень депозита будет достигнут, з минимальнолопустимым лотом, за ",pipsProc," пп.");
            lotCount=MarketInfo(currName,MODE_MINLOT);      
         }         
     }     
     
   }
   else{
   //а вот здесь нужна доработка, для платформ, где стоп-аут в пунктах
   //как сказал один наш товарищ "у кого идеи ростут из нужного места".. доделает
   /*
   */}      
  
   //"прическа" для лота   
   lotCount = MathFloor(lotCount/MarketInfo(currName,MODE_MINLOT))*MarketInfo(currName,MODE_MINLOT);   

   if(lotCount<MarketInfo(currName,MODE_MINLOT))
   {
      return MarketInfo(currName,MODE_MINLOT);
   }
   if(lotCount>MarketInfo(currName,MODE_MAXLOT))
   {
      return MarketInfo(currName,MODE_MAXLOT);  
   }   
   return lotCount;
}
Причина обращения: