Ошибки, баги, вопросы - страница 3748

 

Демо счёт MQ, валюта депозита USD, плечо 100, лот 1 тип ордера - покупка - на инструменте функция OrderCalcMargin() выдаёт значение 1000, в то время как в спецификации значение 1152,42.
Почему маржу выдаёт в евро? А если счёт в рублях, то пытается конвертировать в рубли, но по EURUSD есть ошибка.
Вот таблица:



Вот наброски кода

//+------------------------------------------------------------------+
//|                                         Test_OrderCalcMargin.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
//---
   string Sym_All=Symbol();//Символ
   double Lot=1;//Объём
   double Price_Open_Buy=1;//Цена открытия покупки
   double Price_Open_Sell=1;//Цена открытия продажи
   double Price_Open=0;//Цена для передачи в функцию
   double Obyazatelstvo=0;//Размер обязательств
   double Size_kontrakt=0;//Размер контракта (1 лота) в базовой валюте

   double Margin=0;//Маржа по MT5
   double Plecho=0;//Плечё по MT5
   ENUM_ORDER_TYPE type=ORDER_TYPE_BUY;//Тип ордера


   string Sym_Depo="USDRUBrfd";//Символ для конвертации в депозит
   string Depo_Valuta="";//Валюта депозита
   string Base_Valuta="";//Первая валюта в паре
   string Get_Sym_Name="";//Дополнительное имя символа для расчёта стоимости контракта (отдельного договора)
   string Get_Sym_Base="";//Базовая валюта инструмента
   string Get_Sym_PV="";//Валюта прибыли

   long Baze_One=0;//Базовая (первая) валюта в USD - true или нет false
   long Baze_Dop=0;//Базовая (первая) валюта дополнительного символа в USD - true или нет false
   bool Use_Obez_Kurs=false;//Использовать кросс-курс для расчёта обязательств в USD

   double arr_Sym_Tick_P[2];//Цена Ask/Bid символа в пунктах
   double arr_Sym_Tick_O[2];//Цена Ask/Bid символа в пунктах
   double arr_Dep_Tick[2];//Цена Ask/Bid валюты депозита - для рубля USD/RUB
   double arr_Calc_Obyazatelstva[2];///Массив для получения результата вычисления оценочного размера обязательства
   double Calc_margin=0.0;//Расчётное значение маржи


   Get_Sym_Base=SymbolInfoString(Sym_All,SYMBOL_CURRENCY_BASE);//Базовая валюта инструмента
   Get_Sym_PV=SymbolInfoString(Sym_All,SYMBOL_CURRENCY_PROFIT);//Валюта прибыли

   if(Get_Sym_Base!="USD" && Get_Sym_PV!="USD")//Нет USD в названии валюты
   {
      Use_Obez_Kurs=true;
      Get_Sym_Name=Get_Cross_Symbol_Base(Sym_All);
      Get_Sym_Base=SymbolInfoString(Get_Sym_Name,SYMBOL_CURRENCY_BASE);//Базовая валюта инструмента
      if(Get_Sym_Base=="USD")//Если первая валюта (Базовая) USD
      {
         Baze_Dop=1;
      }
      else
      {
         Baze_Dop=0;
      }
   }
   else
   {
      Get_Sym_Name=Sym_All;
      Use_Obez_Kurs=false;
      if(Get_Sym_Base=="USD")//Если первая валюта (Базовая) USD
      {
         Baze_One=1;
      }
      else
      {
         Baze_One=0;
      }
   }

   Size_kontrakt=SymbolInfoDouble(Sym_All,SYMBOL_TRADE_CONTRACT_SIZE);//Размер торгового контракта

   arr_Sym_Tick_P[0]=SymbolInfoDouble(Sym_All,SYMBOL_ASK);//Цена Ask символа в пунктах
   arr_Sym_Tick_P[1]=SymbolInfoDouble(Sym_All,SYMBOL_BID);//Цена Bid символа в пунктах

   arr_Sym_Tick_O[0]=SymbolInfoDouble(Get_Sym_Name,SYMBOL_ASK);//Цена Ask символа в пунктах
   arr_Sym_Tick_O[1]=SymbolInfoDouble(Get_Sym_Name,SYMBOL_BID);//Цена Bid символа в пунктах

   arr_Dep_Tick[0]=SymbolInfoDouble(Sym_Depo,SYMBOL_ASK);//Цена Ask валюты депозита - для рубля USD/RUB
   arr_Dep_Tick[1]=SymbolInfoDouble(Sym_Depo,SYMBOL_BID);//Цена Bid валюты депозита - для рубля USD/RUB

   Depo_Valuta=AccountInfoString(ACCOUNT_CURRENCY);//Валюта депозита
   if(Depo_Valuta=="USD")
   {
      arr_Dep_Tick[0]=1.0;
      arr_Dep_Tick[1]=1.0;
   }

   Plecho=(double)AccountInfoInteger(ACCOUNT_LEVERAGE);//Размер предоставленного плеча


//--- объявим переменные, в которые будут записаны коэффициенты
   double initial_margin_rate = 0;     // коэффициент взимания начальной маржи
   double maintenance_margin_rate = 0; // коэффициент взимания поддерживающей маржи

   for(int i=0;i<2;i++)
   {
      switch(i)
      {
      case 0:
         type=ORDER_TYPE_BUY;
         Price_Open=Price_Open_Buy;
         Price_Open=arr_Sym_Tick_P[0];
         SymbolInfoMarginRate(Sym_All,ORDER_TYPE_BUY,initial_margin_rate,maintenance_margin_rate);
         Print("Коэффициенты маржи для Buy, начальная маржа=",initial_margin_rate," поддерживающая маржа=",maintenance_margin_rate);
         break;
      case 1:
         type=ORDER_TYPE_SELL;
         Price_Open=Price_Open_Sell;
         Price_Open=arr_Sym_Tick_P[1];
         SymbolInfoMarginRate(Sym_All,ORDER_TYPE_SELL,initial_margin_rate,maintenance_margin_rate);
         Print("Коэффициенты маржи для Sell, начальная маржа=",initial_margin_rate," поддерживающая маржа=",maintenance_margin_rate);
         break;
      }

      Calc_Obyazatelstva(
         Lot,//Размер лота ордера/позиции
         Size_kontrakt,//Размер контракта - стоимость 1 лота в базовой валюте
         (int)type,//Тип позиции - Buy/Sell в момент открытия
         Baze_One,//Базовая (первая) валюта в USD - true или нет false
         Use_Obez_Kurs,//Использовать кросс-курс для расчёта обязательств в USD
         Baze_Dop,//Базовая (первая) валюта в USD - true или нет false
         arr_Sym_Tick_P,//Цена Ask/Bid символа в пунктах
         arr_Sym_Tick_O,//Цена Ask/Bid символа в пунктах
         arr_Dep_Tick,//Цена Ask/Bid валюты депозита - для рубля USD/RUB
         arr_Calc_Obyazatelstva///Массив для получения результата вычисления оценочного размера обязательства
      );



      Calc_margin=NormalizeDouble(arr_Calc_Obyazatelstva[1]/Plecho*initial_margin_rate,2);

      if(!OrderCalcMargin(type, Sym_All, Lot, Price_Open, Margin))
      {
         Print("OrderCalcMargin() failed. Error ",GetLastError());
         return;
      }
      else
      {
         Print("arr_Sym_Tick_P Ask=",arr_Sym_Tick_P[0]," Bid=",arr_Sym_Tick_P[1]);
         Print("arr_Sym_Tick_O Ask=",arr_Sym_Tick_O[0]," Bid=",arr_Sym_Tick_O[1]);
         Print("arr_Dep_Tick Ask=",arr_Dep_Tick[0]," Bid=",arr_Dep_Tick[1]);
         Print(i," Margin=",Margin);
         ArrayPrint(arr_Calc_Obyazatelstva);
         Print(i," Расчётное значение маржи=", Calc_margin);
         Print(i," Разница между фактическим и расчётным значением маржи=", DoubleToString(NormalizeDouble((Margin-Calc_margin),2),2));
      }
   }


}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|Функция возвращает валютную пару для непрямых с USD котировок - для базовой валюты
//+------------------------------------------------------------------+
string Get_Cross_Symbol_Base(string inp_Sym)
{
   bool found_Sym = false;
   int total_Sym = SymbolsTotal(false);
   string inp_Base_Sym="";
   string Base_Sym="";
   string Profit_Sym="";
   string name_Sym="start";

   inp_Base_Sym=SymbolInfoString(inp_Sym,SYMBOL_CURRENCY_BASE);

   for(int i=0; i<total_Sym; i++)
   {
      //--- получаем имя символа в списке по индексу цикла
      name_Sym = SymbolName(i, false);

      Base_Sym=SymbolInfoString(name_Sym,SYMBOL_CURRENCY_BASE);//Первая валюта в паре - Базовая валюта
      Profit_Sym=SymbolInfoString(name_Sym,SYMBOL_CURRENCY_PROFIT);//Вторая валюта в паре - валюьа прибыли
      //Print(i," - Имя символа = ",name_Sym);
      //--- если это искомый символ - распечатаем в журнале его имя и позицию в списке и выйдем из цикла
      //if(Base_Sym == "USD" && Profit_Sym==inp_Profit_Sym)
      if((Base_Sym == inp_Base_Sym && Profit_Sym=="USD") || (Base_Sym == "USD" && Profit_Sym==inp_Base_Sym))
      {
         found_Sym = true;
         break;
      }
   }
   return(name_Sym);
}
//+------------------------------------------------------------------+
//+---------------------------------------------------------------------------------+
//|Функция для расчёта оценчной стоимость обязательства в USD и  в валюте депозита  |
//+-------------------------------------------------------м-------------------------+
void Calc_Obyazatelstva(
   double Lot_Poz,//Размер лота позиции
   double Size_Konrakt,//Размер торгового контракта (1 лота) в базовой валюте
   int Type_Poz,//Тип позиции - Buy/Sell в момент открытия
   long Baze_USD,//Базовая (первая) валюта в USD - true(1) или нет false(0)
   bool  Use_Obez_Kurs,//Используется дополнительный курс для расчёта обязательст - true(1) или нет false(0)
   long Baze_USD_0,//Базовая (первая) валюта в USD для расчёта обязательств - true(1) или нет false(0)
   double &arr_Price_P[],//Цена Ask/Bid символа в пунктах
   double &arr_Price_O[],//Цена Ask/Bid символа для расчёта обязательства в USD
   double &arr_Price_D[],//Цена Ask/Bid валюты депозита - для рубля USD/RUB
   double &arr_Calc_Obyaz_Rez[]//Массив для получения результата вычисления оценочного размера рбязательства
)
{
   int Variant=-1;//Вариант применения формулы для расчёта
   /*
   Variant=0;//Для рассчета не используется кросс-курс валюта прибыли USD - базовая валюта не USD
   Variant=1;//Для рассчета не используется кросс-курс валюта прибыли не USD - базовая валюта USD
   Variant=2;//Для рассчета используется кросс-курс валюта прибыли кросс-курса USD - базовая валюта не USD
   Variant=3;//Для рассчета используется кросс-курс валюта прибыли кросс-курса не USD - базовая валюта USD
   */

   bool Baze_Valuta_USD=false;//Базовая валюта инструмента в USD - true или нет - false
   bool Baze_Valuta_Obyaz_USD=false;//Базовая валюта инструмента для расчёта обязательств в USD - true или нет - false
   double Lot_in_Bazis=0;//Обём похиции (отдельного договора в валюте базового актива)

   if(Baze_USD==1)Baze_Valuta_USD=true;
   if(Baze_USD_0==1)Baze_Valuta_Obyaz_USD=true;

   Lot_in_Bazis=Size_Konrakt*Lot_Poz;


   if(Use_Obez_Kurs==false)//Для рассчета обязательства в USD не используется другой кросс-курс
   {
      if(Baze_Valuta_USD==false)//Базовая валюта не USD
      {
         Variant=0;
      }
      else//Базовая валюта USD
      {
         Variant=1;
      }
   }
   else//Для рассчета обязательства в USD используется другой кросс-курс
   {
      if(Baze_Valuta_Obyaz_USD==false)//Базовая валюта не USD
      {
         Variant=2;
      }
      else//Базовая валюта USD
      {
         Variant=3;
      }
   }

   switch(Type_Poz)
   {
   case 0:
      switch(Variant)//Buy
      {
      case 0://Не используется дополнительный курс для расчёта обязательств - базовая валюта не USD
         arr_Calc_Obyaz_Rez[0]=arr_Price_P[0]*Lot_in_Bazis;
         arr_Calc_Obyaz_Rez[1]=arr_Price_P[0]*Lot_in_Bazis*arr_Price_D[0];
         break;
      case 1://Не используется дополнительный курс для расчёта обязательств - базовая валюта USD - ok.
         arr_Calc_Obyaz_Rez[0]=Lot_in_Bazis;
         arr_Calc_Obyaz_Rez[1]=Lot_in_Bazis*(arr_Price_D[0]);
         break;
      case 2://используется дополнительный курс для расчёта обязательств - базовая валюта не USD - ok.
         arr_Calc_Obyaz_Rez[0]=arr_Price_O[0]*Lot_in_Bazis;
         arr_Calc_Obyaz_Rez[1]=arr_Price_O[0]*Lot_in_Bazis*arr_Price_D[0];
         break;
      case 3://используется дополнительный курс для расчёта обязательств - базовая валюта USD
         arr_Calc_Obyaz_Rez[0]=1.0/arr_Price_O[1]*Lot_in_Bazis;
         arr_Calc_Obyaz_Rez[1]=1.0/arr_Price_O[1]*Lot_in_Bazis*arr_Price_D[0];
         break;
      }
      break;
   case 1:
      switch(Variant)//Sell
      {
      case 0://Не используется дополнительный курс для расчёта обязательств - базовая валюта не USD
         arr_Calc_Obyaz_Rez[0]=arr_Price_P[1]*Lot_in_Bazis;
         arr_Calc_Obyaz_Rez[1]=arr_Price_P[1]*Lot_in_Bazis*arr_Price_D[1];
         break;
      case 1://Не используется дополнительный курс для расчёта обязательств - базовая валюта USD - ok.
         arr_Calc_Obyaz_Rez[0]=Lot_in_Bazis;
         arr_Calc_Obyaz_Rez[1]=Lot_in_Bazis*(arr_Price_D[1]);
         break;
      case 2://используется дополнительный курс для расчёта обязательств - базовая валюта не USD - ok.
         arr_Calc_Obyaz_Rez[0]=arr_Price_O[1]*Lot_in_Bazis;
         arr_Calc_Obyaz_Rez[1]=arr_Price_O[1]*Lot_in_Bazis*arr_Price_D[1];
         break;
      case 3://используется дополнительный курс для расчёта обязательств - базовая валюта USD
         arr_Calc_Obyaz_Rez[0]=1.0/arr_Price_O[0]*Lot_in_Bazis;
         arr_Calc_Obyaz_Rez[1]=1.0/arr_Price_O[0]*Lot_in_Bazis*arr_Price_D[1];
         break;
      }
      break;
   }

}
//+------------------------------------------------------------------+