Точный подсчет, необходимых свободных средств для открытия позиции.

 
Прошу помощи, в создании стандартного элемента кода, где будет вестись проверка свободных средств, желательно с большой точностью. Причем, я либо через массив, либо обычной строкой, буду передовать валютные(ую) пары(у). Это проверка будет проверяться перед открытием ордера.
 
int start()
  {
//----
  int a;
  string para    = "EURUSD";
  double ask     =MarketInfo(para,MODE_ASK);
  double lotsize =MarketInfo(para,MODE_LOTSIZE);
  double minlot  =MarketInfo(para,MODE_MINLOT);
   
  a=(ask*lotsize/AccountLeverage()*minlot);
  if (AccountFreeMargin()<a)
    {Print ("Недостаточно средств на счете !!!"); return (0);}
  Print ("Para: ",para);
//----
   return(0);
  }
При OP_BUY это выглядит где-то так.
 
А если валютная пара, кросскурс. То тогда как ???
 
DEan писал (а):
int start()
  {
//----
  int a;
  string para    = "EURUSD";
  double ask     =MarketInfo(para,MODE_ASK);
  double lotsize =MarketInfo(para,MODE_LOTSIZE);
  double minlot  =MarketInfo(para,MODE_MINLOT);
   
  a=(ask*lotsize/AccountLeverage()*minlot);
  if (AccountFreeMargin()<a)
    {Print ("Недостаточно средств на счете !!!"); return (0);}
  Print ("Para: ",para);
//----
   return(0);
  }
При OP_BUY это выглядит где-то так.

Кто знает какова история этого, и почему так?
 
Истории не знаю, дошел своим умом:
double LotSize()
{
    double     lot_min        = MarketInfo( _Symbol, MODE_MINLOT  );
    double     lot_max        = MarketInfo( _Symbol, MODE_MAXLOT  );
    double     lot_step       = MarketInfo( _Symbol, MODE_LOTSTEP );
    double     freemargin     = AccountFreeMargin();
    int        leverage       = AccountLeverage();
    int        lotsize        = MarketInfo( _Symbol, MODE_LOTSIZE );
 
    if( lot_min < 0 || lot_max <= 0.0 || lot_step <= 0.0 || lotsize <= 0 ) 
    {
        Print( "LotSize: invalid MarketInfo() results [", lot_min, ",", lot_max, ",", lot_step, ",", lotsize, "]" );
        return(-1);
    }
    if( leverage <= 0 )
    {
        Print( "LotSize: invalid AccountLeverage() [", leverage, "]" );
        return(-1);
    }
 
    double lot = NormalizeDouble( freemargin * MaximumRisk / leverage / 10.0, 2 );
 
    lot = NormalizeDouble( lot / lot_step, 0 ) * lot_step;
    if ( lot < lot_min ) lot = lot_min;
    if ( lot > lot_max ) lot = lot_max;
 
    double needmargin = NormalizeDouble( lotsize / leverage * Ask * lot, 2 );
 
    if ( freemargin < needmargin )
    {
        Print( "LotSize: We have no money. Free Margin = ", freemargin );
        return(-1);
    }
 
    return(lot);
}

Для селл надо вместо Аск надо использовать Бид, но поскольку Аск всегда будет больше, это не принципиально (погрешность небольшая, и не в опасную сторону).
 
Integer писал (а):
DEan писал (а):
int start()
  {
//----
  int a;
  string para    = "EURUSD";
  double ask     =MarketInfo(para,MODE_ASK);
  double lotsize =MarketInfo(para,MODE_LOTSIZE);
  double minlot  =MarketInfo(para,MODE_MINLOT);
   
  a=(ask*lotsize/AccountLeverage()*minlot);
  if (AccountFreeMargin()<a)
    {Print ("Недостаточно средств на счете !!!"); return (0);}
  Print ("Para: ",para);
//----
   return(0);
  }
При OP_BUY это выглядит где-то так.

Кто знает какова история этого, и почему так?
История банальна, не пропускали советник на конкурс без проверки свободных средств.
Написал этот код и все ОК. ;)
А, в общем, у каждого своя точка зрения..
 
Написал, для общего случая. Жду ваших замечаний.
int start()
  {
//----
  double Lots = 1.0;
  int n = StringFind(Symbol(),AccountCurrency(),0);
    
  if (n>=0)
   {
   // Находим Валюту нашего счета в текущей валютной паре.
   //Print("Найдено ",AccountCurrency()," в паре ",Symbol()," n=",n);
   
   }
  else
   {
   // Не находим. Т.е. У нас кросс курс. рассмотрим для покупки.
   string Buy = StringSubstr(Symbol(),3);
   Buy = "USD"+Buy;
   double AskBuy = MarketInfo(Buy,MODE_ASK);
   
   //Print("не найдено ",AccountCurrency()," в паре ",Symbol()," Byu=",Buy);
   double Deneg = (MarketInfo(Symbol(),MODE_LOTSIZE)*Lots*Ask)/(AccountLeverage()*AskBuy);
   Print("Необходимо средст для открытия Длинной позиции по ",Symbol(),", ",AccountCurrency(),"  = ",Deneg);
   }
  
  
//----
   return(0);
  }
проверил, пересчитал на бумаге вроде работает.
 
komposter писал (а):
Истории не знаю, дошел своим умом:
..............
Проверку на наличие/отсутствие подстроки "USD" не делаете или не надо? Последнее время тема постоянно на слуху :).

//+------------------------------------------------------------------+
//|                                                    _Open_BUY.mq4 |
//|                                           "СКРИПТЫ ДЛЯ ЛЕНИВОГО" |
//|              Скрипт открывает BUY на задаваемую часть FreeMargin |
//|                                                                  |
//|                                   Только для пар USDххх и хххUSD |
//|                                                                  |
//|                           Bookkeeper, 2006, yuzefovich@gmail.com |
//+------------------------------------------------------------------+
#property copyright ""
#property link      ""
#property show_inputs // Если есть желание менять экстерны в процессе
//+------------------------------------------------------------------+
extern int    Interest   = 35;   // Выделить процент FreeMargin на позу
extern int    DistSL     = 35;   // StopLoss в пунктах
extern int    DistTP     = 35;   // TakeProfit в пунктах
extern int    Slippage   = 7;    // Проскальзывание
extern bool   StopLoss   = true; // Ставить или нет
extern bool   TakeProfit = true; // Ставить или нет
//+------------------------------------------------------------------+
void start() 
{
int    ticket=0;
double SL=0,TP=0,Stake,MinLotDgts,Share,QQ=1.0;
double MinLot=MarketInfo(Symbol(),MODE_MINLOT);   
double MaxLot=MarketInfo(Symbol(),MODE_MAXLOT);   
double LotStep=MarketInfo(Symbol(),MODE_LOTSTEP);   
int    Dgts=MarketInfo(Symbol(),MODE_DIGITS);     
int    Credit=AccountLeverage();     
string FirstPart=StringSubstr(Symbol(), 0, 3 );   
string SecondPart=StringSubstr(Symbol(), 3, 3 );
   Share=0.01*Interest;
   if(SecondPart == "USD") QQ=Ask;
   else
   {
      if(FirstPart != "USD") 
         Alert("OpenBUY: Who is that - ",Symbol(),"? I do not know..."); // :)
   }
   if(AccountFreeMargin()<MinLot*QQ*100000/Credit)
   {
      Alert("Open_BUY: No maney...");
      return;
   }
   if(Share>1.0) Share=1.0; // Часть не бывает больше целого
   if(Share<0) Share=0;    // (???)
   if(MinLot<0.1) MinLotDgts=2;
   else
   {
      if(MinLot<1.0) MinLotDgts=1;
      else MinLotDgts=0;
   }
   Stake=NormalizeDouble(AccountFreeMargin()*Share*Credit/100000/QQ,MinLotDgts);
   //Если выделенная часть депо будет меньше минимально допустимого лота,
   //поза будет открыта на минимальный лот
   if(Stake<MinLot) Stake=MinLot;
   //Если выделенная часть депо будет больше максимально допустимого лота,
   //поза будет открыта на максимальный лот
   if(Stake>MaxLot) Stake=MaxLot;
   RefreshRates();
   if(StopLoss==true) SL=Bid-DistSL*Point;
   if(TakeProfit==true) TP=Ask+2*DistTP*Point;
   ticket=OrderSend(Symbol(),OP_BUY,Stake,
                    // Не смотря на рефреш вместо Ask ставим:
                    NormalizeDouble(MarketInfo(Symbol(),MODE_ASK),Dgts), 
                    Slippage,
                    NormalizeDouble(SL,Dgts),
                    NormalizeDouble(TP,Dgts),
                    "",0,0,CLR_NONE);
   if(ticket<=0) Alert("Open_BUY LastError: ",GetLastError()); 
   return(0);
}
//+------------------------------------------------------------------+
Правильно или нет не знаю. Работает.
 
Я выложил очень простой вариант расчета маржевых требований для форексных символов:

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

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

'MarginCalculate'

//+------------------------------------------------------------------+
//|                                              MarginCalculate.mq4 |
//|                      Copyright © 2006, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, MetaQuotes Software Corp."
#property link      "https://www.metaquotes.net/"
//+------------------------------------------------------------------+
//| Очень простая функция расчета маржи для форексных символов.      |
//| Расчет автоматически идет в базовой валюте счета и не работает   |
//| для сложных видов курсов, которые не имеют прямого пересчета     |
//| в базовую валюту торгового счета.                                |
//+------------------------------------------------------------------+
double MarginCalculate(string symbol,double volume)
  {
   string first   =StringSubstr(symbol,0,3);         // первый символ,    например EUR
   string second  =StringSubstr(symbol,3,3);         // второй символ,    например USD
   string currency=AccountCurrency();                // валюта депозита,  например USD
   double leverage=AccountLeverage();                // кредитное плечо,  например 100
   double contract=MarketInfo(symbol,MODE_LOTSIZE);  // размер контракта, например 100000
   double bid     =MarketInfo(symbol,MODE_BID);      // цена бид
//---- допускаем только стандартные форексные символы XXXYYY
   if(StringLen(symbol)!=6)
     {
      Print("MarginCalculate: '",symbol,"' must be standard forex symbol XXXYYY");
      return(0.0);
     }
//---- проверка наличия данных
   if(bid<=0 || contract<=0) 
     {
      Print("MarginCalculate: no market information for '",symbol,"'");
      return(0.0);
     }
//---- проверяем самые простые варианты - без кроссов
   if(first==currency)   return(contract*volume/leverage);           // USDxxx
   if(second==currency)  return(contract*bid*volume/leverage);       // xxxUSD
//---- проверяем обычные кроссы, ищем прямое преобразование через валюту депозита
   string base=currency+first;                                       // USDxxx
   if(MarketInfo(base,MODE_BID)>0) return(contract/MarketInfo(base,MODE_BID)*volume/leverage);
//---- попробуем наоборот
   base=first+currency;                                              // xxxUSD
   if(MarketInfo(base,MODE_BID)>0) return(contract*MarketInfo(base,MODE_BID)*volume/leverage);
//---- нет возможности прямого перерасчета
   Print("MarginCalculate: can not convert '",symbol,"'");
   return(0.0);
  }
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   Print("Margin EURUSD: ",MarginCalculate("EURUSD",1.0));
   Print("Margin USDCHF: ",MarginCalculate("USDCHF",1.0));
   Print("Margin GBPCHF: ",MarginCalculate("GBPCHF",1.0));
   Print("Margin CHFJPY: ",MarginCalculate("CHFJPY",1.0));
//----
   return(0);
  }
//+------------------------------------------------------------------+
 
Bookkeeper:
Проверку на наличие/отсутствие подстроки "USD" не делаете или не надо? Последнее время тема постоянно на слуху :).

Делал только для конкурса, поэтому не вникал =)
Для универсальной функции все будет сложнее )
 
komposter писал (а):
Bookkeeper писал (а):
Проверку на наличие/отсутствие подстроки "USD" не делаете или не надо? Последнее время тема постоянно на слуху :).

Делал только для конкурса, поэтому не вникал =)
Для универсальной функции все будет сложнее )


Еще чуть-чуть, и может быть Ренат, чтоб отвязались, и этот вариант выложит... :).

Ренат, большое спасибо, куски добротного кода действительно очень нужны. Это для вас все легко и понятно...
Причина обращения: