Любые вопросы новичков по MQL4 и MQL5, помощь и обсуждение по алгоритмам и кодам - страница 2554

 
Alexey Viktorov #:
Я уж грешным делом подумал, что вы пошли курить анашу…

нет )

 
Alexey Viktorov #:
 И тогда показали, что есть инструменты с шагом 0.25… Вот тут и лопнули все извращения с логарифмами.

да. есть. и я это знаю.....  спс за разъяснение. 

там сейчас шаг есть на крипте в МТ4 и МТ 5:  0,001 вроде тоже.....

надо решать как в вас в варианте нормализации через мин шаг и мин лот. 

Это ок. 

В моем варианте я во внеш переменных ввел 0,1 (без второго числа) и далее уже на коэфф 1,6 уже ок.

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

 

Ох и в дебри вы полезли с этими лотами. Я для себя решил эту проблему так:

Во-первых, у меня на экране отображаются лейблы, в которых указаны суммарные лоты, например, бай-группы ордеров. Это строковая составляющая (ну, это когда нужно суммарный лот преобразовать в строку). Вот её код (для примера) и  скриншот.

// перед блоком инициализации советника пишем:
int     DGTlot;// Дигитс для лотов
double m_MinLot=MarketInfo(Symbol(),MODE_MINLOT), m_MaxLot=MarketInfo(Symbol(),MODE_MAXLOT);

//  В блоке инициализации пишем:
MinLot=(MarketInfo(SMB,MODE_MINLOT));
DGTlot =  (MinLot==1) ? 0 : (MinLot==0.1) ? 1 : (MinLot==0.01) ? 2 : (-1) ;
if(DGTlot<0){Print("Непредвиденная ошибка! DGTlot = ",DGTlot);}

// В теле советника используем переменную DGTlot в лейблах, например, вот так:
DrawLABEL(LblFont,LblFontSize,"Buy1",StringConcatenate("Buy ",DoubleToStr(SchBuy,0)," - ",DoubleToStr(SummLotBuy(),DGTlot)),X,Y,MidnightBlue);
// В результате выглядит это вот так:

Для проверки корректности вычисленного лота я уже лет дцать назад написал себе подпрограмму:

// ----------------------- ProverkaLota() ------------------------------------------------------
// функция принимает и нормализует лот ордера
//------------------------------------------------------------
double ProverkaLota(double LotOrdera){
  string Tmp;
  double CorrectLot=0;
  int    diglots=0;
  if(m_MinLot==1 || m_MinLot==0.1 || m_MinLot==0.01){
                if(m_MinLot==1){
                        diglots=0;
                }
                if(m_MinLot==0.1){
                        diglots=1;
                }
                if(m_MinLot==0.01){
                        diglots=2;
                }
        }
        Tmp=DoubleToString(LotOrdera,diglots);// отбрасываем лишние числа
        CorrectLot=StringToDouble(Tmp);
  if(CorrectLot<m_MinLot){
    CorrectLot=m_MinLot;
  }
  if(CorrectLot>m_MaxLot){
    CorrectLot=m_MaxLot;
  }
  return(CorrectLot);
}
 

В мою подпрограмму проверки лота можно подать на вход не только лот, но и вычисленный в блоке инициализации DGTlot. Тогда в подпрограмме вместо переменной diglots можно использовать  DGTlot и не делать лишних запросов.

ProverkaLota(double LotOrdera, int DG_Lots){}

У меня же эта подпрограмма лежит в инклуднике, поэтому танцы с бубном (инициализация переменной diglots) тут нужны.

P.S.

Для проверки корректности подпрогарммы сделал вот скрипт:

//+------------------------------------------------------------------+
//|                           Скрипт                           1.mq4 |
//+------------------------------------------------------------------+
#property strict
#property script_show_inputs
input double Lots=0.08;// Лот ордера
input int DG_Lot=1; // До скольки округлять
// До скольки знаков после запятой

//+------------------------------------------------------------------+
//|     ---------------- Start Work Of Script ----------------       |
//+------------------------------------------------------------------+
void OnStart(){
        double LOT=ProverkaLota(Lots,DG_Lot);
        Alert("Lots = ",Lots," нормализовался до = ",LOT);
        Alert("============ Script 1 ",Symbol()," =================");
}
//+------------------------------------------------------------------+
//|     ---------------- Подпрограммы ----------------               |
//+------------------------------------------------------------------+

// ----------------------- ProverkaLota() ------------------------------------------------------
// функция принимает и нормализует лот ордера
//-------------------------------------------
double ProverkaLota(double LotOrdera,int DG_Lotss){
  string Tmp;
  double CorrectLot=0;
  double MinLot=MarketInfo(Symbol(),MODE_MINLOT), MaxLot=MarketInfo(Symbol(),MODE_MAXLOT);
        Tmp=DoubleToString(LotOrdera,DG_Lotss);// отбрасываем лишние числа
        CorrectLot=StringToDouble(Tmp);
  if(CorrectLot<MinLot){
    CorrectLot=MinLot;
  }
  if(CorrectLot>MaxLot){
    CorrectLot=MaxLot;
  }
  return(CorrectLot);
}
 
Можно ещё тут глянуть:
Какие проверки должен пройти торговый робот перед публикацией в Маркете
Какие проверки должен пройти торговый робот перед публикацией в Маркете
  • www.mql5.com
Все продукты Маркета перед публикацией проходят обязательную предварительную проверку для обеспечения единого стандарта качества. В этой статье мы расскажем о наиболее частых ошибках, которые допускают разработчики в своих технических индикаторах и торговых роботах. А также покажем как самостоятельно проверить свой продукт перед отправкой в Маркет.
 
Vitaly Murlenko #:
только
спс. за разъяснение  - тоже думал делать через чтение строки сколько знаков после запятой на мин лоте - до стольки и округлять....
 
Yuriy Bykov #:
Можно ещё тут глянуть:

у меня на МТ4 надо, а тут ну получили что не является кратным минимальному - дальше то что делать?

      description=StringFormat("Объем не является кратным минимальной градации SYMBOL_VOLUME_STEP=%.2f, ближайший корректный объем %.2f",
                               volume_step,ratio*volume_step);

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

символы для торгов просто разные.

 
Roman Shiredchenko #:

у меня на МТ4 надо, а тут ну получили что не является кратным минимальному - дальше то что делать?

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

символы для торгов просто разные.

//+----------------------------------------------------------------------------+
//|  Описание : Возвращает нормализованное значение торгуемого лота.           |
//+----------------------------------------------------------------------------+
//|  Параметры:                                                                |
//|    v_sym - наименование инструмента                                        |
//|    v_lo - нормализуемое значение лота.                                     |
//+----------------------------------------------------------------------------+
double NormL(const string  v_sym,
             const double  v_lo
            )
  {
   double   stp=SymbolInfoDouble(v_sym,SYMBOL_VOLUME_STEP);
   return(((fmin(fmax((round(v_lo/stp))*stp,SymbolInfoDouble(v_sym,SYMBOL_VOLUME_MIN)),SymbolInfoDouble(v_sym,SYMBOL_VOLUME_MAX)))));
  }
//End

Всё проверяет для MT4 и MT5

 
Roman Shiredchenko #:
спс. за разъяснение  - тоже думал делать через чтение строки сколько знаков после запятой на мин лоте - до стольки и округлять....

Вообще, может возникнуть ошибка. Если шаг наращивания лота не равен минимальному лоту (честно говоря, я такого не встречал, но чем чёрт не шутит), то моя функция может выдать некорректный лот. В этом случае может начать упрямо вылезать ошибка типа 130, или ошибка неправильных параметров функции. В этом случае лучше запросить информацию с сервера. Я себе сделал вот такой скриптик (надо бы его в кодобазу выложить, что я сейчас и сделаю):

//+------------------------------------------------------------------+
//|                                                 All_Info_1.5.mq4 |
//|                                          Copyright © 2025, Drknn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2025, Drknn"
#property show_inputs
extern int HowManyDays=21;// количество дней для среднесуточного среднего движения валютной пары

/*
        ВНИМАНИЕ! Перед использованием скрипта нужно обновить график D1

        Добавить в скрипт:
         - Рассчёт стоимости пункта при минимальном лоте
*/

//+------------------------------------------------------------------+
//|          Старт работы скрипта                                    |
//+------------------------------------------------------------------+
int start(){
  string    SMB=Symbol();
  string    Priznak;// Признак плавающего спреда
        if(SymbolInfoInteger(SMB,SYMBOL_SPREAD_FLOAT)){
                Priznak=Text("  (Плавающий)","  (Float)");
        }
        else{
                Priznak=Text("  (Фиксированный)","  (Fixed)");
        }
        double Laverage =  MarketInfo(SMB,MODE_TICKVALUE)*Bid / MarketInfo(SMB,MODE_MARGINREQUIRED) / MarketInfo(SMB,MODE_POINT);
        string NameScript="============ All_Info_1.5 ("+SMB+") ============";
        
  int Zalog=(int)MarketInfo(SMB,MODE_MARGINCALCMODE);//Способ расчета залоговых средств. 0 - Forex; 1 - CFD; 2 - Futures; 3 - CFD на индексы
  int PoSkolkoPunktov=0;
  string Type;
  if(Zalog==0){
    Type="Forex";
  }
  if(Zalog==1){
    Type="CFD";
  }
  if(Zalog==2){
    Type="Futures";//фьючерсы
  }
  if(Zalog==3){
    Type="CFD on Index";
  }
        double FreeMargin=MarketInfo(SMB,MODE_MARGINREQUIRED);
  PoSkolkoPunktov=MarketInfo(SMB,MODE_TICKSIZE)/Point;
        Alert(Text("Уровень заморозки отложенных ордеров = ","Freezing distance for pending orders = "),MarketInfo(SMB,MODE_FREEZELEVEL)," (pt)");
        Alert(Text("Время окончания торгов = ","Trade End Time = "),TimeToString(SymbolInfoInteger(SMB,SYMBOL_EXPIRATION_TIME),TIME_DATE|TIME_MINUTES));
        Alert(Text("Время начала торгов = ","Trade Start Time = "),TimeToString(SymbolInfoInteger(SMB,SYMBOL_START_TIME),TIME_DATE|TIME_MINUTES));
        Alert(Text("Миниальная цена сегодня = ","Today Min Price = "),MarketInfo(SMB,MODE_LOW)); 
  Alert(Text("Максимальная цена сегодня = ","Today Max Price = "),MarketInfo(SMB,MODE_HIGH));
  Alert(Text("Своп для Селл-ордеров = ","Swap For Sell = "),NormalizeDouble(MarketInfo(SMB,MODE_SWAPSHORT),2)," ($)");
  Alert(Text("Своп для Бай-ордеров = ","Swap for Buy = "),NormalizeDouble(MarketInfo(SMB,MODE_SWAPLONG),2)," ($)");
        Alert("TickSize = ",PoSkolkoPunktov," pt");
        Alert("Point = ",DoubleToString(Point(),5),"    Digits = ",(int)MarketInfo(SMB,MODE_DIGITS));
        Alert(Text("Спред = ","Spraed = "),(int)MarketInfo(SMB,MODE_SPREAD),Priznak);
        Alert("Min Level = ",(int)MarketInfo(SMB,MODE_STOPLEVEL)," pt");
  Alert("Lot Step = ",MarketInfo(SMB,MODE_LOTSTEP));
  Alert("Max Lot = ",MarketInfo(SMB,MODE_MAXLOT));
  Alert("Min Lot = ",MarketInfo(SMB,MODE_MINLOT));
        Alert(Text("Залог за 1 лот = ","Zalog for 1 Lot = "),NormalizeDouble(MarketInfo(SMB,MODE_MARGININIT),2)," ($)");
        Alert(Text("Контракт в базовой валюте = ","Contract in base currency = "),MarketInfo(SMB,MODE_LOTSIZE));
  Alert(Text("Размер залоговых средств для поддержки открытых ордеров в расчете на 1 лот = ","Amount of collateral to support open orders per 1 lot = "),NormalizeDouble(MarketInfo(SMB,MODE_MARGINMAINTENANCE),2)," ($)");
        Alert(Text("Свободная маржа для открытия 1 лота = ","Free Margin for open 1 Lot = "),NormalizeDouble(FreeMargin,2)," ($)");
        Alert(Text("Текущее кредитное плечо 1 : ","Leverage at this point in time 1 : "),NormalizeDouble(Laverage,0));
        Alert(Text("В среднем валюта ходит по ","On average, the currency moves at "),Srednestatistich(HowManyDays),Text(" пунктов в день"," pt. for 1 day"));
        Alert(Text("Тип инструмента - ","Tool Type - "),Type);
        Alert(NameScript);
  return(0);
}
//+------------------------------------------------------------------+
//|          Пользовательские подпрограммы                           |
//+------------------------------------------------------------------+

// ================ Srednestatistich(int PeriodSMB) ================================================
// функция возвращает число пунктов, которое делает валюта в среднем в день
//-------------
// входные параметры:
// int PeriodSMB - число дней, на которых вычисляется, сколько валюта проходит пунктов в день
int Srednestatistich(int PeriodSMB){
        int PunktovSegodnya=0,Srednee=0;
        for(int i=1; i<=PeriodSMB; i++){
                PunktovSegodnya=(iHigh(Symbol(),PERIOD_D1,i)-iLow(Symbol(),PERIOD_D1,i))/Point;
                if(i==1){
                        Srednee=PunktovSegodnya;
                }
                else{
                        Srednee=Srednee+PunktovSegodnya;
                }
        }
        Srednee=Srednee/PeriodSMB;
        NormalizeDouble(Srednee,0);
        return(Srednee);
}
// =================== Text ========================================================================
// Функция возвращает текст на выбраном языке терминала.
// Если терминал русскоязычный, то возвращается строка на русском. В противном случае на английском.
// -------------------------------------------------------------------------------------------------
string Text(string Russ,string Engl){
        if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian"){
                return(Russ);
        }
  else return(Engl);
}
// ========================== Leverage() ==========================================================
double Leverage(int PoSkPunkt){
        double Rez=0;
        Rez=PoSkPunkt*Bid/MarketInfo(Symbol(),MODE_MARGINREQUIRED)/Point();
        return(Rez);
}

//      Формула расчета текущего кредитного плеча:
//Laverage =  MarketInfo(SMB,MODE_TICKVALUE)*Bid / MarketInfo(SMB,MODE_MARGINREQUIRED) / MarketInfo(SMB,MODE_POINT);
 

Получается, например, вот такое: