Как правильно рассчитать объем позиции?

 
Не для кого не секрет, что часто в советнике для достижения максимальной отдачи приходиться рассчитывать объем ордера выпускаемый на рынок.
Есть множество подходов в этом отношении, но вопрос возник в принципе, почему часто невозможно от сервера получить ответ на запрос о маржинальном требовании средств на 1 лот или 1 контракт?
double marg1lot=SymbolInfoDouble(symbol,SYMBOL_MARGIN_INITIAL);
Особенно часто это возникает именно на биржевом рынке.
Вот пример функции, где на ответ сервера у некоторых брокеров не приходит ничего, а вернее чаще возвращается 0, в результате чего возникает ошибка деления на 0.

double InitLotPercentDepozit(string symbol,double percent=1.0,int digitsfloatvolume=2)
{
  double lot=0.0;
  double marg1lot=SymbolInfoDouble(symbol,SYMBOL_MARGIN_INITIAL);
  double minlot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
  double riskbalans=NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE)*percent/100,2);
  lot=NormalizeDouble(riskbalans/marg1lot,digitsfloatvolume);
  if(lot<minlot) lot=minlot;
  return(lot);
}

Как можно обойти это решение? Временно видоизменил эту функцию, если в результате запроса приходит 0, то присваиваю внешнее значение залога.

double InitLotPercentDepozit(string symbol,double marginlot=1000,double percent=1.0,int digitsfloatvolume=2)
{
  double lot=0.0;
  double marg1lot=SymbolInfoDouble(symbol,SYMBOL_MARGIN_INITIAL);
  if(marg1lot==0) marg1lot=marginlot;
  double minlot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
  double riskbalans=NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE)*percent/100,2);
  lot=NormalizeDouble(riskbalans/marg1lot,digitsfloatvolume);
  if(lot<minlot) lot=minlot;
  return(lot);
}

Но это только временный выход, да и можно забыть или неправильно указать этот залог, а как гарантированно получить эти данные для расчета?
 

попробуйте такой вариант. Если задан стоплосс в пипсах то расчет по первой функции, если задан 0, то по второй.

//+------------------------------------------------------------------+
//|                                                       test09.mq5 |
//|                                                   Sergey Gritsay |
//|                         https://www.mql5.com/ru/users/sergey1294 |
//+------------------------------------------------------------------+
#property copyright "Sergey Gritsay"
#property link      "https://www.mql5.com/ru/users/sergey1294"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_TYPE_BALANS
  {
   Balance=0,
   Equity=1,
   FreeMargin=2
  };

input ENUM_TYPE_BALANS Type_Balanse=Balance;//Method calculation Volume
input double Risk=1.0;
input int StopLoss=300;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double Volume = (StopLoss!=0)?volume(_Symbol,Risk,StopLoss):volume(_Symbol,ORDER_TYPE_BUY,Risk);
   Comment("Volume = ",Volume);
  }
//+------------------------------------------------------------------+
double volume(string symbol,double risk,double sl)
  {
   double lot=0.0;
   double procent=0.0;
   double balans=0.0;
   double tc = SymbolInfoDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   double tv = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE_LOSS);
   double ts=SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE);
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
   double LotStep=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
   if(Type_Balanse==Balance) balans=AccountInfoDouble(ACCOUNT_BALANCE);
   if(Type_Balanse==Equity) balans=AccountInfoDouble(ACCOUNT_EQUITY);
   if(Type_Balanse==FreeMargin) balans=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   procent=(balans/100.0)*risk;

   switch((ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol,SYMBOL_TRADE_CALC_MODE))
     {
      case SYMBOL_CALC_MODE_FOREX:if(sl!=0 && tv!=0)lot=procent/(sl*tv);break;
      case SYMBOL_CALC_MODE_FUTURES:if(sl!=0 && point!=0 && tv!=0 && ts!=0) lot=procent/(sl*point*(tv/ts));break;
      case SYMBOL_CALC_MODE_CFD:if(sl!=0 && point!=0 && tc!=0) lot=procent/(sl*point*tc);break;
      case SYMBOL_CALC_MODE_CFDINDEX:if(sl!=0 && point!=0 && tc!=0) lot=procent/(sl*point*tc);break;
      case SYMBOL_CALC_MODE_CFDLEVERAGE:if(sl!=0 && point!=0 && tc!=0) lot=procent/(sl*point*tc);break;
      case SYMBOL_CALC_MODE_EXCH_STOCKS:if(sl!=0 && point!=0 && tc!=0) lot=procent/(sl*point*tc);break;
      case SYMBOL_CALC_MODE_EXCH_FUTURES:if(sl!=0 && point!=0 && tv!=0 && ts!=0) lot=procent/(sl*point*(tv/ts));break;
      case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:if(sl!=0 && point!=0 && tv!=0 && ts!=0) lot=procent/(sl*point*(tv/ts));break;
     }
   return(NormalizeVolume(symbol,lot));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double volume(string symbol,ENUM_ORDER_TYPE type,double risk)
  {
   double lot=0.0;
   double balans=0.0;
   double margin=0.0;
   int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
   double bid=NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_BID),digits);
   double ask=NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_ASK),digits);
   double price=(type==ORDER_TYPE_BUY)?ask:bid;
   if(!OrderCalcMargin(type,symbol,1.0,price,margin))return(NormalizeVolume(symbol,lot));

   if(Type_Balanse==Balance) balans=AccountInfoDouble(ACCOUNT_BALANCE);
   if(Type_Balanse==Equity) balans=AccountInfoDouble(ACCOUNT_EQUITY);
   if(Type_Balanse==FreeMargin) balans=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   if(margin!=0)lot=(balans*Risk)/(margin*100.0);
   return(NormalizeVolume(symbol,lot));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double NormalizeVolume(string symbol,double lot)
  {
   double MinLot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
   double MaxLot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
   double volume_step=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
   int volume_digits=(int)(MathLog(1.0/volume_step)/MathLog(10.0));

   if(lot<MinLot)lot=MinLot;
   if(lot>MaxLot)lot=MaxLot;

   return(NormalizeDouble(lot,volume_digits));
  }
//+------------------------------------------------------------------+


 ...

 
Sergey Gritsay:

попробуйте такой вариант. Если задан стоплосс в пипсах то расчет по первой функции, если задан 0, то по второй.



 ...

Конечно, большое спасибо за такую функцию, но сейчас стоит вопрос чем гарантированно заменить эту функцию

double marg1lot=SymbolInfoDouble(symbol,SYMBOL_MARGIN_INITIAL); 

чтобы всегда иметь правильный ответ по залогу.

 
Gennady Mazur:

Конечно, большое спасибо за такую функцию, но сейчас стоит вопрос чем гарантированно заменить эту функцию

double marg1lot=SymbolInfoDouble(symbol,SYMBOL_MARGIN_INITIAL); 

чтобы всегда иметь правильный ответ по залогу.

Попробуйте OrderCalcMargin()
 
prostotrader:
Попробуйте OrderCalcMargin()

Т.Е. Вы предлагаете заменить типа на вот это

double margin1lot;
double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin1lot);
 
Gennady Mazur:

Т.Е. Вы предлагаете заменить типа на вот это

double margin1lot;
double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin1lot);

Да, но нужно знать конкретные задачи.

Потому как есть много "подводных камней" когда резервируешь залог. 

Добавлено

Посмотрите здесь

https://www.mql5.com/ru/forum/94396/page4#comment_2783794 

 
prostotrader:

Да, но нужно знать конкретные задачи.

Потому как есть много "подводных камней" когда резервируешь залог. 

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

double InitLotPercentDepozit(string symbol,double percent=1.0,int digitsfloatvolume=2)
{
  double lot=0.0;
  double margin1lot;
  double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
  double minlot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
  double riskbalans=NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE)*percent/100,2);
  if(OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin1lot)) lot=NormalizeDouble(riskbalans/marg1lot,digitsfloatvolume);
  if(lot<minlot) lot=minlot;
  return(lot);
}
 
Gennady Mazur:

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

double InitLotPercentDepozit(string symbol,double percent=1.0,int digitsfloatvolume=2)
{
  double lot=0.0;
  double margin1lot;
  double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
  double minlot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
  double riskbalans=NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE)*percent/100,2);
  if(OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin1lot)) lot=NormalizeDouble(riskbalans/marg1lot,digitsfloatvolume);
  if(lot<minlot) lot=minlot;
  return(lot);
}
на максимальный объем тоже вставьте проверку
 
Sergey Gritsay:
на максимальный объем тоже вставьте проверку
я понял, спасибо...
 
Sergey Gritsay:
на максимальный объем тоже вставьте проверку

Вышло вот так

double InitLotPercentDepozit(string symbol,double percent=1.0,int digitsfloatvolume=2)
{
  double lot=0.0;
  double margin1lot;
  double price=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
  double minlot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
  double maxlot=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
  double riskbalans=NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE)*percent/100,2);
  if(OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin1lot))
    lot=NormalizeDouble(riskbalans/margin1lot,digitsfloatvolume);
  if(lot<minlot) lot=minlot;
  if(lot>maxlot) lot=maxlot;
  return(lot);
}


 

 
Sergey Gritsay:
на максимальный объем тоже вставьте проверку
вероятно надо еще встроить и проверку доступных средств