Скачать MetaTrader 5
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Вся история MQL5.community в одном месте!
Dimitr Trifonov
773
Dimitr Trifonov 2015.07.23 16:13 

Добрый день

Подскажите пожалуйста формулы расчета данных функций. В частности интересует что произходит при кроссах - например имется счет в USD, а открывается позиция на EURGBP.

Так же по формуле OrderCalcProfit() хотелось бы подсчитать Volume имея Profit. 

Спасибо 

Dimitr Trifonov
773
Dimitr Trifonov 2015.07.24 09:39  
class COrderCalculateMargin{

public: double Result;

public: void COrderCalculateMargin(string symbol,ENUM_ORDER_TYPE orderType,double openPrice,double volume){
   Result=0;
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
   if(StringSubstr(symbol,3,3)==currency)Result=CalcMarginFormula(symbol,openPrice,volume);
   else if(StringSubstr(symbol,0,3)==currency)Result=CalcMarginFormula(symbol,1,volume);
   else{
      string pair=StringSubstr(symbol,0,3)+currency;
      if(orderType==ORDER_TYPE_BUY)Result=CalcMarginFormula(pair,Bid(pair),volume);
      if(orderType==ORDER_TYPE_SELL)Result=CalcMarginFormula(pair,Ask(pair),volume);
      }
   return;
   }

double CalcMarginFormula(string symbol,double openPrice,double volume){
   return NormalizeDouble(openPrice*volume*SymbolInfoDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE)/AccountInfoInteger(ACCOUNT_LEVERAGE),0);
   } 
   
};
Писал сам, провел тесты, только на кроссах работает не всегда точно. Подскажите где ошибка.
Ihor Herasko
9020
Ihor Herasko 2015.07.24 10:56  
Dimitr Trifonov:
Писал сам, провел тесты, только на кроссах работает не всегда точно. Подскажите где ошибка.

Скажем так, на кроссах будет не то что "не всегда", а всегда неправильно.

Сама формула расчета верна: Margin = quote * volume * contract_size / leverage.

Просто вместо quote в разных случаях нужно брать разные котировки. Если базовая валюта символа котируется через валюту счета (к примеру, EURUSD при валюте счета USD), то в качестве quote, действительно, нужно брать цену открытия трейда: Ask - для Buy и Bid - для Sell. Это единственный случай, для которого приведенный Вами метод расчета верен.

Немного по-другому происходит получение значения quote символов, у которых базовая валюта совпадает с валютой счета (USDCAD при валюте счета USD). В таких случаях quote будет равно: 1.0 / Ask - для Buy и 1.0 / Bid - для Sell.

И совсем иначе рассчитывается quote для кроссов (символов, в которых отсутствует валюта счета). Так, при валюте счета USD залог для трейда по EURJPY будет рассчитан по текущей цене EURUSD. Так как EURUSD и EURJPY имеют одинаковую базовую валюту, то и quote будет определяться как в случае с просто EURUSD: Ask (от EURUSD) - для Buy и Bid (от EURUSD) - для Sell.

В случае, если кросс попался вида CHFJPY, то quote нужно рассчитать по символу USDCHF. Здесь базовые валюты символа отличаются. Поэтому quote получаем как в случае с USDCAD: 1.0 / Ask (от USDCHF) - для Buy и 1.0 / Bid (от USDCHF) - для Sell.

Надеюсь, понятно объяснил. В свое время очень долго "въезжал" в эту схему. 

Alexey Oreshkin
3627
Alexey Oreshkin 2015.07.24 13:10  
Dimitr Trifonov:
Писал сам, провел тесты, только на кроссах работает не всегда точно. Подскажите где ошибка.

вот в этой формуле: return NormalizeDouble(openPrice*volume*SymbolInfoDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE)/AccountInfoInteger(ACCOUNT_LEVERAGE),0);

вот в этом месте:  AccountInfoInteger(ACCOUNT_LEVERAGE)

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

С начала и до 3 страницы всё обсуждение по этому вопросу.

Dimitr Trifonov
773
Dimitr Trifonov 2015.08.04 18:57  

Спасибо всем за советы.

После нескольких тестов код выглядит так:

class COrderCalculateMargin{

public: double Result;

public: void COrderCalculateMargin(string symbol,ENUM_ORDER_TYPE orderType,double openPrice,double volume){
   Result=0;
   string currency=AccountInfoString(ACCOUNT_CURRENCY);
   if(StringSubstr(symbol,3,3)==currency)Result=CalcMarginFormula(symbol,openPrice,volume);
   else if(StringSubstr(symbol,0,3)==currency)Result=CalcMarginFormula(symbol,1,volume);
   else{
      string pair=StringSubstr(symbol,0,3)+currency;
      if(orderType==ORDER_TYPE_BUY)Result=CalcMarginFormula(pair,Ask(pair),volume);
      if(orderType==ORDER_TYPE_SELL)Result=CalcMarginFormula(pair,Bid(pair),volume);
      }
   return;
   }

double CalcMarginFormula(string symbol,double openPrice,double volume){
   return NormalizeDouble(openPrice*volume*SymbolInfoDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE)/AccountInfoInteger(ACCOUNT_LEVERAGE),0);
   } 
   
};

 Единственная разница выделена желтым цветом. А вот код, который проводил тесты:

   ENUM_ORDER_TYPE orderType=ORDER_TYPE_SELL;
   double price=0.5;
   double lots=1.3;
   
   string symbol[3]={"GBPUSD","USDCAD","EURJPY"};
   
   for(int i=0;i<3;i++){

      double mqlMargin=0;
      if(!OrderCalcMargin(orderType,symbol[i],lots,price,mqlMargin))Print("CompareCalcMargin Error");
      COrderCalculateMargin OrderCalculateMargin(symbol[i],orderType,price,lots);
      
      Print(symbol[i]+" ORDER_TYPE_SELL, price = "+price+", lots = "+lots+"; OrderCalcMargin() = "+(string)mqlMargin+"; COrderCalculateMargin.Result = "+(string)OrderCalculateMargin.Result); 
      }

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

CompareMargin (GBPUSD,H4)       GBPUSD ORDER_TYPE_BUY, price = 2.5, lots = 1.3; OrderCalcMargin() = 6500; COrderCalculateMargin.Result = 6500
CompareMargin (GBPUSD,H4)       USDCAD ORDER_TYPE_BUY, price = 2.5, lots = 1.3; OrderCalcMargin() = 2600; COrderCalculateMargin.Result = 2600
CompareMargin (GBPUSD,H4)       EURJPY ORDER_TYPE_BUY, price = 2.5, lots = 1.3; OrderCalcMargin() = 2848.56; COrderCalculateMargin.Result = 2848
CompareMargin (GBPUSD,H4)       GBPUSD ORDER_TYPE_SELL, price = 2.5, lots = 1.3; OrderCalcMargin() = 6500; COrderCalculateMargin.Result = 6500
CompareMargin (GBPUSD,H4)       USDCAD ORDER_TYPE_SELL, price = 2.5, lots = 1.3; OrderCalcMargin() = 2600; COrderCalculateMargin.Result = 2600
CompareMargin (GBPUSD,H4)       EURJPY ORDER_TYPE_SELL, price = 2.5, lots = 1.3; OrderCalcMargin() = 2848.51; COrderCalculateMargin.Result = 2849
CompareMargin (GBPUSD,H4)       GBPUSD ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 1300; COrderCalculateMargin.Result = 1300
CompareMargin (GBPUSD,H4)       USDCAD ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 2600; COrderCalculateMargin.Result = 2600
CompareMargin (GBPUSD,H4)       EURJPY ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 2847.1; COrderCalculateMargin.Result = 2847
CompareMargin (GBPUSD,H4)       GBPUSD ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 1300; COrderCalculateMargin.Result = 1300
CompareMargin (GBPUSD,H4)       USDCAD ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 2600; COrderCalculateMargin.Result = 2600
CompareMargin (GBPUSD,H4)       EURJPY ORDER_TYPE_SELL, price = 0.5, lots = 1.3; OrderCalcMargin() = 2847.42; COrderCalculateMargin.Result = 2847

 Если в случае USDxxx поменять CalcMarginFormula(symbol,1,volume); на CalcMarginFormula(symbol,1/openprice,volume); результаты сильно расходятся

 Почему?

Renat Akhtyamov
4779
Renat Akhtyamov 2015.08.04 19:15  
Dimitr Trifonov:
Писал сам, провел тесты, только на кроссах работает не всегда точно. Подскажите где ошибка.

кроссы считаются по другому:

      //USD/CHF Цена пункта = размер пункта * объем позиции / текущий курс
      //EUR/USD Цена пункта = размер пункта * объем позиции
      //EUR/CHF Цена пункта = объем позиции * размер пункта * текущая котировка базовой валюты по отношению к USD / текущий курс валютной пары (кросс-курс)   
Eugeniy Lugovoy
1979
Eugeniy Lugovoy 2015.08.05 16:08  

Допустим депозит у Вас в USD

Пары XXXUSD - будут считаться верно по этой формуле,

а вот для остальных пар необходим перевод в валюту депозита по текущему курсу в зависимости от направления BUY/SELL.

На MQL4 community был алгоритм расчета, насколько помнится мне

Ребята, может пора бы уже от MQ запросить функцию получения маржи ордера ? хотя бы открытого. бывает очень нужно.

/
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий