Скачать MetaTrader 5
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Опубликуй программу в Cobe Base. Миллионы трейдеров ее увидят!
Denis Tishkin
204
Denis Tishkin 2016.05.18 08:11 
Подскажите функцию для советника, чтобы открывал ордера процентом от депозита.
Alexey Volchanskiy
14043
Alexey Volchanskiy 2016.05.18 14:09  
Denis Tishkin:
Подскажите функцию для советника, чтобы открывал ордера процентом от депозита.

А в чем проблема? Вычисляете размер лота, потом надо этот размер нормализовать, чтобы он был кратен минимальному изменению лота. Вот функция со всеми проверками для MQL4.

// открывает ордер с проверкой, нормализацией данных и возвратом измененных данных
int OpenOrderWithCheck(string symbol, int cmd, double& volume, double& price, int slippage, 
  double &stoploss, double &takeprofit, string comment, int magic, datetime expiration, 
  color arrow_color)
{
   int dig = (int) MarketInfo(symbol, MODE_DIGITS);   // Количество знаков после запятой по инструменту
   
   double minlot = MarketInfo(symbol, MODE_MINLOT);   // Минимальный размер лота
   double lotstep = MarketInfo(symbol, MODE_LOTSTEP); // Шаг изменения размера лота 
   double maxlot = MarketInfo(symbol, MODE_MAXLOT);   // Максимальный размер лота 
   
   int lot = (int)(volume/lotstep); // округлили до целого числа шагов изменения лота
   volume = (double)lot * lotstep;  // теперь имеем правильный объем, кратный шагу изменения лота 
   
   //int n1=123, n2=33, n3=222;
   //double d = (double)n1/n2 + (double)n3;
   
   if(volume < minlot)
   {
      // я предпочитаю такую обработку, но выдаю алерт, чтобы исправить ошибку, пару раз помогало :)  
      // ниже читаете коммент про логгирование в файлы
      volume = minlot;
      Alert("OpenOrder()", "Объем меньше минимального, задаю минимальное значение = ", volume, " лот(а)");
   }
   if(volume > maxlot)
   {
      volume = maxlot;
      Alert("OpenOrder()", "Объем больше максимального, задаю максимальное значение = ", volume, " лот(а)");
   }
   
   // При открытии рыночного ордера (OP_SELL или OP_BUY) в качестве цены открытия могут использоваться 
   // только самые последние цены Bid (для продажи) или Ask (для покупки). 
   if(cmd == OP_BUY )
      price = MarketInfo(symbol, MODE_ASK);
   if(cmd == OP_SELL)
      price = MarketInfo(symbol, MODE_BID);
   
   takeprofit = NormalizeDouble(takeprofit, dig); // цены надо округлять до количества знаков после запятой
   stoploss = NormalizeDouble(stoploss, dig);
   price = NormalizeDouble(price, dig);
   
   ResetLastError();
   int ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss, takeprofit, comment, magic, expiration, arrow_color);

   if(ticket < 0)
   {
      string err = GetMyLastError();
      // тут вместо принта можно выполнить свое действие, лично я пишу протокол в лог-файл
      Print("Ошибка открытия ордера, ", err);
   }
   else
   {
      bool os = OrderSelect(ticket, SELECT_BY_TICKET);
      if(os == true)
      {
         price      = OrderOpenPrice();
         // нужно запрашивать реальный объем, т.к. на счетах ECN при посылке ордера с большим объемом может открыться несколько ордеров
         // с разными объемами и разными ценами из-за того, что в стакане просто нет заявки с нужным лотом по запрошенной цене
         volume     = OrderLots();      
         stoploss   = OrderStopLoss();
         takeprofit = OrderTakeProfit();        
      }
   }   
   return (ticket);
}
Denis Tishkin
204
Denis Tishkin 2016.05.18 17:23  
Alexey Volchanskiy:

А в чем проблема? Вычисляете размер лота, потом надо этот размер нормализовать, чтобы он был кратен минимальному изменению лота. Вот функция со всеми проверками для MQL4.

Хорошо говорить, когда знаешь как.

Спасибо.

Буду разбираться. )

Alexey Volchanskiy
14043
Alexey Volchanskiy 2016.05.18 19:43  
Denis Tishkin:

Хорошо говорить, когда знаешь как.

Спасибо.

Буду разбираться. )

Ну смотрите, вот простейший пример. У вас депо в баксах, допустим $1000, плечо 500. Вы хотите открыть сделку EURUSD 5% от суммы депо, то есть $50. 

Базовый контракт на лот 100000 евро, курс на сейчас 1,1285. При плече 1:500 получаем маржу на лот 100000*1,1285/500 = $225.

Теперь получаем кол-во лотов на наши $50. Это будет $50/$225 = 0.2222... лота. Подставляем в приведенную выше функцию, она округлит лот до нужного значения и откроет ордер.

Ihor Herasko
8429
Ihor Herasko 2016.05.18 20:04  
Alexey Volchanskiy:

Ну смотрите, вот простейший пример. У вас депо в баксах, допустим $1000, плечо 500. Вы хотите открыть сделку EURUSD 5% от суммы депо, то есть $50. 

Базовый контракт на лот 100000 евро, курс на сейчас 1,1285. При плече 1:500 получаем маржу на лот 100000*1,1285/500 = $225.

Теперь получаем кол-во лотов на наши $50. Это будет $50/$225 = 0.2222... лота. Подставляем в приведенную выше функцию, она округлит лот до нужного значения и откроет ордер.

Тоже до недавнего времени использовал подход в округлении такой как указан (int(volume / lotstep) * lotstep). Но в итоге напоролся на случай, когда этот подход работает неправильно, т. к. он не учитывает ситуации, при которых lotstep > minlot. Получается что более универсальный алгоритм такой:

int lot = (int)(volume/lotstep); // округлили до целого числа шагов изменения лота
volume = (double)lot * lotstep;  // теперь имеем правильный объем, кратный шагу изменения лота 
if (lotstep > minlot)
   volume += minlot;
Alexandr Gavrilin
26002
Alexandr Gavrilin 2016.05.18 21:32  
double NLot(double dlot,string sname="")
  {

   if(sname=="") sname=Symbol();
   int idigits=(int)MathRound(MathAbs(MathLog(MarketInfo(sname,MODE_LOTSTEP))/MathLog(10)));
   return (NormalizeLot(NormalizeDouble(dlot,idigits),sname));
  }

double NormalizeLot(double dlot,string sname="")
  {
   if(sname=="") sname=Symbol();

   if(dlot<MarketInfo(sname,MODE_MINLOT)) return (MarketInfo(sname,MODE_MINLOT));
   if(dlot>MarketInfo(sname,MODE_MAXLOT)) return (MarketInfo(sname,MODE_MAXLOT));
   return (dlot);
  }
для нормализации лота давно пользуюсь такой формулой, сбоев в расчетах не было.
Ihor Herasko
8429
Ihor Herasko 2016.05.19 06:48  
Alexandr Gavrilin:
для нормализации лота давно пользуюсь такой формулой, сбоев в расчетах не было.
Как только наткнетесь на шаг, не кратный 10 (а такое реально бывает), сбой будет ))
Alexey Volchanskiy
14043
Alexey Volchanskiy 2016.05.20 00:14  
Ihor Herasko:
Как только наткнетесь на шаг, не кратный 10 (а такое реально бывает), сбой будет ))
Теоретически верно, хотя в реале ни разу не встречал. Но вы правы, предусматривать надо все.
Sergey Gritsay
5481
Sergey Gritsay 2016.05.20 01:54  
Denis Tishkin:
Подскажите функцию для советника, чтобы открывал ордера процентом от депозита.

Я использую такой расчет при использовании стоплосса в пунктах

Для МТ4

//+------------------------------------------------------------------+
//|                                                       test_3.mq4 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_TYPE_BALANS
  {
   Balance,
   Equity,
   FreeMargin
  };

input ENUM_TYPE_BALANS Type_Balanse=Balance;//Method calculation Volume
input double Risk=0.1;
input double Lot=0.01;//Volume
input int StopLoss=300;
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   Lots=(Risk!=0.0)?Volumes(_Symbol,Risk,StopLoss):volume_n(_Symbol,Lot);
  }
//+------------------------------------------------------------------+
double Volumes(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);
   double ts=SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE);
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);

   if(Type_Balanse==Balance) balans=AccountInfoDouble(ACCOUNT_BALANCE);
   if(Type_Balanse==Equity) balans=AccountInfoDouble(ACCOUNT_EQUITY);
   if(Type_Balanse==FreeMargin) balans=AccountInfoDouble(ACCOUNT_FREEMARGIN);

   procent=(balans/100.0)*risk;

   switch((int)MarketInfo(symbol,MODE_PROFITCALCMODE))
     {
      case 0: if(sl!=0 && tv!=0) lot=procent/(sl*tv);break;
      case 1: if(sl!=0 && point!=0 && tc!=0) lot=procent/(sl*point*tc);break;
      case 2: if(sl!=0 && point!=0 && tv!=0 && ts!=0) lot=procent/(sl*point*(tv/ts));break;
     }
   return(volume_n(symbol,lot));
  }
//+------------------------------------------------------------------+
double volume_n(string symbol,double lot)
  {
   double MinLot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
   double MaxLot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
   double LotStep=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);

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

   if(LotStep==0.001) return(NormalizeDouble(lot,3));
   if(LotStep==0.01)  return(NormalizeDouble(lot,2));
   if(LotStep==0.1)   return(NormalizeDouble(lot,1));

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

Для МТ5 

//+------------------------------------------------------------------+
//|                                                      Test_02.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_TYPE_BALANS
  {
   Balance,
   Equity,
   FreeMargin
  };

input ENUM_TYPE_BALANS Type_Balanse=Balance;//Method calculation Volume
input double Risk=0.1;
input double Lot=0.01;//Volume
input int StopLoss=300;
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   Lots=(Risk!=0.0)?Volumes(_Symbol,Risk,StopLoss):volume_n(_Symbol,Lot);
  }
//+------------------------------------------------------------------+
double Volumes(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(volume_n(symbol,lot));
  }
//+------------------------------------------------------------------+
double volume_n(string symbol,double lot)
  {
   double MinLot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
   double MaxLot=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
   double LotStep=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);

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

   if(LotStep==0.001) return(NormalizeDouble(lot,3));
   if(LotStep==0.01)  return(NormalizeDouble(lot,2));
   if(LotStep==0.1)   return(NormalizeDouble(lot,1));

   return(NormalizeDouble(lot,0));
  }
//+------------------------------------------------------------------+
Alexander Bereznyak
19926
Alexander Bereznyak 2016.05.20 09:49  
if(LotStep==0.001) return(NormalizeDouble(lot,3));
у какого брокера видели такой лот
Alexey Viktorov
5174
Alexey Viktorov 2016.05.20 10:53  
Alexander Bereznyak:
у какого брокера видели такой лот

х.з. Лично я таким не пользовался, но где-то уже встречал такое, вроде-бы есть, или было у какого-то ДЦ.

Хочу предложить универсальную формулу для нормализации лота

NormalizeDouble(contractVolume, (int)MathAbs(MathLog10(MarketInfo(_Symbol, MODE_LOTSTEP))));
/ /1234
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий