Как рассчитать стоимость пункта в валюте депозита

 

Добрый день. Простая задача - зная  стоплосс рассчитать размер лота, чтобы в случае неудачи потерять, например,  не более  50 процентов депозита.

Для решения  нужно  знать стоимость пункта в валюте депозита. Казалось бы, задача тривиальная, но, как оказалось не совсем ( или я в трех соснах запутался...)    Вот здесь довольно грамотно все рассказано - https://www.mql5.com/ru/articles/113  Но может быть есть проще способы -какими-нибудь стандартными средствами (пишу на MQL4) ?

Меня смущает, что при тестировании на истории (для кросс пары) я все время должен обращаться  не только к информации по тестируемой паре, но и другим парам. А будет ли она доступна ? 

Функции для управления капиталом в экспертах
Функции для управления капиталом в экспертах
  • 2010.07.06
  • MetaQuotes Software Corp.
  • www.mql5.com
Язык MQL5 предоставляет возможность получения огромного количества информации о текущем состоянии терминала, mql5-программы, а также о финансовом инструменте и торговом счете. Для организации функций управлений капиталом нам потребуется изучить свойства из двух последних перечисленных разделов, а также познакомиться со следующими функциями...
 
Alex406:

Добрый день. Простая задача - зная  стоплосс рассчитать размер лота, чтобы в случае неудачи потерять, например,  не более  50 процентов депозита.

Для решения  нужно  знать стоимость пункта в валюте депозита. Казалось бы, задача тривиальная, но, как оказалось не совсем ( или я в трех соснах запутался...)    Вот здесь довольно грамотно все рассказано - https://www.mql5.com/ru/articles/113  Но может быть есть проще способы -какими-нибудь стандартными средствами (пишу на MQL4) ?

Меня смущает, что при тестировании на истории (для кросс пары) я все время должен обращаться  не только к информации по тестируемой паре, но и другим парам. А будет ли она доступна ? 

Проверьте, должно работать

#property strict

void OnTick()
 {
   Comment( sLot(5, 50) ); // 5% со стопом 50
 }
 
//===============================================================================================
//------------------------------ Расчет лота по риску и StopLoss -------------------------------+
//===============================================================================================
double sLot(double Percent=1, double Stloss=100, string symb="0") {
 if(symb=="0") symb=Symbol();
 double TickValue   =SymbolInfoDouble(symb,SYMBOL_TRADE_TICK_VALUE),
        TickSize    =SymbolInfoDouble(symb,SYMBOL_TRADE_TICK_SIZE),
        ContractSize=SymbolInfoDouble(symb,SYMBOL_TRADE_CONTRACT_SIZE),
        Min_Lot     =SymbolInfoDouble(symb,SYMBOL_VOLUME_MIN),
        Max_Lot     =SymbolInfoDouble(symb,SYMBOL_VOLUME_MAX),
        Step        =SymbolInfoDouble(symb,SYMBOL_VOLUME_STEP),
        Free        =AccountInfoDouble(ACCOUNT_FREEMARGIN),
        Lots_New    =0.0;
 int CalcMode=(int)SymbolInfoInteger(symb,SYMBOL_TRADE_CALC_MODE);

  if(Percent > 100) Percent = 100;
  if(Stloss <=0) return(0);
  if(Percent == 0) Lots_New = Min_Lot;
   else {
    if(CalcMode==0 || CalcMode==4)
      Lots_New = MathFloor((((Free*Percent/100)/Stloss)/TickValue)/Step)*Step;
    if(CalcMode==1||CalcMode==2||CalcMode==3)
      Lots_New = MathFloor(((((Free*Percent)/100)/Stloss)/((TickSize*TickValue)*ContractSize/TickValue))/Step)*Step;
   }
   if(Lots_New > Max_Lot) Lots_New = Max_Lot;
   if(Lots_New < Min_Lot) return(0);
  return(NormalizeDouble(Lots_New,LotDigit()));
 }
//===============================================================================================
//-------------------- Кол-во знаков после точки в значении торгового лота ---------------------+
//===============================================================================================
int LotDigit(string symb="0") {
 if(symb=="0") symb=_Symbol;
  double lotStep = SymbolInfoDouble(symb, SYMBOL_VOLUME_STEP);
  return((int)MathCeil(MathAbs(MathLog(lotStep)/MathLog(10))));
 }
 
Vitaly Muzichenko:

Проверьте, должно работать

Спасибо, буду разбираться

 

Вот еще, может, пригодится. Использую для задания Sl и TP не в пунктах, а в значениях валюта_депозита/лот. Например, для EURUSD и депозите в USD значение $100/lot == 100 poits for 5-digits. Вроде как и с кроссами правильно работает

bool Price2Quote(double &diff, double price4lot, string symbol = "EURUSD")
{
    long dig = 0;
    double tickSize, tickValue; 
    if(!SymbolInfoInteger(symbol, SYMBOL_DIGITS, dig))
        return(false); // операция неуспешна
    if(!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE, tickSize))
        return(false); 
    if(!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE, tickValue))
        return(false); 
    if(tickValue > 0)    
    {
        diff = price4lot*tickSize / tickValue;
        diff = NormalizeDouble(diff, (int)dig);
    }
    else
        return false;    
    return true;
}
 
Vitaly Muzichenko:

Проверьте, должно работать

Спасибо, проверил, действительно работает, правда  пока до конца не понимаю почему и как  -))

 

@Vitaly Muzichenko, у меня так же примерно. Только я мани-менеджмент, в отличие от торговых алгоритмов сам не писал ещё. Так вот тут нюанс. Зачем вообще MathLog(10) используется? И почему логарифм именно от 10 и именно натуральный? И вообще зачем делить на то, что MathLog(10) возвращает?

Надеюсь, кто-нить понимает это и пояснить.. так.. для общего кругозора. А то висит такая же реализация, но я не понимаю её целиком. А это не вариант...))

 
hoz:

@Vitaly Muzichenko, у меня так же примерно. Только я мани-менеджмент, в отличие от торговых алгоритмов сам не писал ещё. Так вот тут нюанс. Зачем вообще MathLog(10) используется? И почему логарифм именно от 10 и именно натуральный? И вообще зачем делить на то, что MathLog(10) возвращает?

Надеюсь, кто-нить понимает это и пояснить.. так.. для общего кругозора. А то висит такая же реализация, но я не понимаю её целиком. А это не вариант...))

И все-таки я поторопился, когда сказал, что работает... Работает для пар одного порядка, eur usd и пр. А для пар, где значение исчисляется сотнями (AUDJPY например) , врет на  два порядка    - дает очень маленькое значение лота.Пока использую для определения стоимости пункта  кустарный, но понятный способ - делю прибыль от профита предыд ордера на число пунктов .   

 
Alex406:

И все-таки я поторопился, когда сказал, что работает... Работает для пар одного порядка, eur usd и пр. А для пар, где значение исчисляется сотнями (AUDJPY например) , врет на  два порядка    - дает очень маленькое значение лота.Пока использую для определения стоимости пункта  кустарный, но понятный способ - делю прибыль от профита предыд ордера на число пунктов .   

У меня сделано так для валютных пар из валют "USD EUR GBP JPY AUD CHF CAD NZD "

//+------------------------------------------------------------------+
//| Функция возвращает результат торгов по паре Pair минимальным     |
//| лотом на покупку без учета спреда, свопов и комиссий на интервале|
//| времени [ptime, ctime] Результат в USD                           |
//| Вызывается из GetPrices()                                        |
//| Вызываются модули: LastKnownPrice(), TickValueVariant()          |
//+------------------------------------------------------------------+
double ResultForPair( string Pair, datetime ctime, datetime ptime)
{
   int variant;
   string SecondSymbol;
   double w1, w2, result, tv2;
   
   w1 = LastKnownPrice( Pair, ptime);
   w2 = LastKnownPrice( Pair, ctime);

   variant = TickValueVariant( Pair );
   SecondSymbol = StringSubstr( Pair, 3, 3);
   
   switch( variant )
   {
      case 0: // второй символ USD
         tv2 = 1.0;
         break;
      case 1: // второй символ прямая котировка USD
         tv2 = LastKnownPrice( SecondSymbol + "USD", ctime);
         break;
      case 2: // второй символ обратная котировка USD
         tv2 = 1.0 / LastKnownPrice( "USD" + SecondSymbol, ctime);
         break;                  
     default:
         break;
   }
   result = ( w2 - w1 ) * tv2;
   result *= 1000.0;

   return( result );
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Функция возвращает вариант расчета TickValue для пары pair       |
//| Вызывается из ResultForPair()                                    |
//| Вызываются модули:                                               |
//+------------------------------------------------------------------+
int TickValueVariant( string pair )
{
   int variant;
   string SecondSymbol;

   // список мажоров для варианта расчета TickValue определен в глобальном блоке
   // string MajorSymbolList = "EURUSD GBPUSD AUDUSD USDJPY USDCHF USDCAD NZDUSD ";
   SecondSymbol = StringSubstr( pair, 3, 3 );
   if ( SecondSymbol == "USD" ) variant = 0;
   else
   {
      if ( StringFind( MajorSymbolList, SecondSymbol + "USD") >= 0 )
         variant = 1;
      else variant = 2;
      // для variant = 2 будет верно
      // StringFind( MajorSymbolList, "USD" + SecondSymbol ) >= 0
   }
   return( variant );
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Функция возвращает последнее известное на момент времени cTime   |
//| цены для пары SymbolName                                         |
//| Вызывается из ResultForPair()                                    |
//| Вызываются модули:                                               |
//+------------------------------------------------------------------+
double  LastKnownPrice( string SymbolName, datetime cTime)
{
   int   shift;
   
   shift = iBarShift( SymbolName, 0, cTime, false);
   if (iTime(SymbolName, 0, shift) > cTime) shift++;
   return( iClose(SymbolName, 0, shift) );
}
//+------------------------------------------------------------------+
 
Mislaid:

У меня сделано так для валютных пар из валют "USD EUR GBP JPY AUD CHF CAD NZD "

А есть ещё "EURUSD_i", "EURUSD.m", "USOil" - для них не прокатит.
 

а что функция

SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE)

не работает

 
Yury Kirillov #:
А есть ещё "EURUSD_i", "EURUSD.m", "USOil" - для них не прокатит.
Верно, надо смотреть на валюту прибыли, а не разбирать пару
Причина обращения: