0
Лучше язвить, чем язву иметь. Метаквотовцам передавайте наше с кистью.

Меня всегда интересуют причинно-следственные связи.

Простой советник от того и простой. Жаловаться на него, то же, что и на отсутствие зонта во время дождя. Т.е. бесполезно. Человек с колена поделился мыслью. Не нравится — проходи мимо. А если он тебе в жилу, разберись сам, чего понедельник тяжелый день. У меня тоже, как правило.

К стати не смотрел, но уверен: там орднра открываются не таким образом.

А подобных функций валом. Почти один в один. Так как программист я еще тот, то в кодомарании я больше доверяю Хлыстову, чем себе. Так мне жизненный опыт шепчет.

Тут у нас девушка обитает. Почему-то мама OXY назвала. Так вот, ее коды гораздо симпатичнее и продуманнее, чем коды АМ2. Так она тоже не брезгует подобными подходами. Сейчас что-нибудь найду.

Блин. В моем бардаке сходу хрен что найдешь. Попался Хлыстов первым, вот его и взял.
Не важно. Взял пример. Работаю над ним. Кто-то предложит другой вариант (может гораздро лучше) поработаем и с ним. А пока что конкурентции ноль.

Всех благ.

avatar

kvashnin007

  • 23 января 2025, 19:21
0
Не факт, что брокера можно заставить таки открыть ордер, но чем настойчивее это действие, тем больше шансов.
По-этому можно еще больше обнаглеть. Завернуть одну просьбу в другую. Да, немного помедленнее. Но более убедительно.
А если учесть, что тестер при оптимизации, если нет ошибок, то с первого захода открывает сделки,
то те же 5-100 сделок в месяц ну никак не повлияют скорость работы советника.

Обратимся все к тому же Володе Хлыстову. Есть у него в свободном пользовании скрипт для открытия ордеров:

<code>#property copyright "Copyright © 2014, Хлыстов Владимир"
#property link      "cmillion@narod.ru"
#property show_inputs
#property strict
//--------------------------------------------------------------------
extern int      stoploss       = 50,       //уровень выставления SL, если 0, то SL не выставляется
                takeprofit     = 50,       //уровень выставления TP, если 0, то TP не выставляется
                MaxOrders      = 1,        //кол-во ордеров
                Magic          = 123456;   //уникальный номер ордера
extern double   LotBuy         = 0.1;      //объем ордера если 0 то не откоывать
extern double   LotSell        = 0.1;      //объем ордера если 0 то не откоывать
extern int      attempts       = 10;       //кол-во попыток открытия
extern int      Slippage       = 3;        //кол-во попыток открытия

string txt;
int n,slippage;
double STOPLEVEL;
//--------------------------------------------------------------------
int start()
{
      STOPLEVEL=MarketInfo(Symbol(),MODE_STOPLEVEL);
      
      slippage = Slippage;
      
      if (Digits==3 || Digits==5) 
         slippage=Slippage*10;
   
      for (int i=1; i<=MaxOrders; i++)
         {
         if (LotBuy>0)
            OPENORDER (OP_BUY,NormalizeDouble(Ask,Digits),LotBuy,i);
         if (LotSell>0)
            OPENORDER (OP_SELL,NormalizeDouble(Bid,Digits),LotSell,i);
         }
      Comment("Скрипт закончил свою работу, выставлено ",n," ордеров  ");
   return(0);
}
//--------------------------------------------------------------------
void OPENORDER(int ord,double Price,double LOT,int i)
{
      int error,err=0;
      double SL=0,TP=0;
      
      while (true)
         {  
         error=true;
         RefreshRates();
         
         if (ord==OP_BUY) 
            {
            if (takeprofit>=STOPLEVEL) TP  = NormalizeDouble(Price + takeprofit*Point,Digits); else TP=0;
            if (stoploss>=STOPLEVEL)   SL  = NormalizeDouble(Price - stoploss*Point,Digits);   else SL=0;     
            error=OrderSend(Symbol(),OP_BUY, LOT,Price,slippage,SL,TP,"http://cmillion.ru",Magic,0,Blue);
            }
         if (ord==OP_SELL) 
            {
            if (takeprofit>=STOPLEVEL) TP = NormalizeDouble(Price - takeprofit*Point,Digits); else TP=0;
            if (stoploss>=STOPLEVEL)   SL = NormalizeDouble(Price + stoploss*Point,Digits);   else SL=0;              
            error=OrderSend(Symbol(),OP_SELL,LOT,Price,slippage,SL,TP,"http://cmillion.ru",Magic,0,Red);
            }
         if (error==-1)
            {  
            txt=StringConcatenate(txt,"\nError ",GetLastError());
            if (ord== 1) txt = StringConcatenate(txt,"  OPENORDER BUY ",i,"   Ask =",DoubleToStr(Ask,Digits),"   Price =",DoubleToStr(Price,Digits)," (",NormalizeDouble((Price-Ask)/Point,0),")  SL =",DoubleToStr(SL,Digits)," (",NormalizeDouble((Price-SL)/Point,0),")  TP=",DoubleToStr(TP,Digits)," (",NormalizeDouble((TP-Price)/Point,0),")  STOPLEVEL=",STOPLEVEL);
            if (ord==-1) txt = StringConcatenate(txt,"  OPENORDER SELL ",i,"   Bid =",DoubleToStr(Bid,Digits),"   Price =",DoubleToStr(Price,Digits)," (",NormalizeDouble((Bid-Price)/Point,0),")  SL =",DoubleToStr(SL,Digits)," (",NormalizeDouble((SL-Price)/Point,0),")  TP=",DoubleToStr(TP,Digits)," (",NormalizeDouble((Price-TP)/Point,0),")  STOPLEVEL=",STOPLEVEL);
            Print(txt);
            Comment(txt,"  ",TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS));
            err++;Sleep(1000);RefreshRates();
            }
         else 
            {
            Comment("Ордер ",error," успешно выставлен ",TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS));
            n++;
            return;
            }
         if (err >attempts)
             return;
         }
   return;
}                  
//--------------------------------------------------------------------
</code>


Здесь у него Цикл в цикле. Циклы, если обращаются за данными к брокеру, тормоза. Основные. Но в данном случае — вещь полезная и не ручник.

Правда у него здесь основной цикл пытается запустить программу открытия ордеров столько раз, сколько указываем в
MaxOrders. По идее: сколько ордеров укажешь, столько и откроет. Но все они одинаковые. В чем смысл? Не понятненько.
При этих настройках скрипт откроет один ордер на покупку по цене Ask и один ордер на продажу по цене Bid.
Ну да ладно. Это его скрипт и для его целей. Наша задача извлечь свою выгоду.

Но это в следующий раз
.

avatar

kvashnin007

  • 23 января 2025, 16:19
0
Продолжаем.

Хочу предложить к рассмотрению функцию, предложенную Владимиром Хлыстовым (cmillion).Она с болшей вероятностью открывает ордера. Можно потом добавить и отложки. Но это потом.

<code>//--------------------------------------------------------------------
void OPENORDER(int ord,double Price,double LOT)
{
      int rez,err=0;
      double SL=0,TP=0;
      
      while (true)
         {  
         rez=true;
         RefreshRates();
         
         if (ord==OP_BUY) 
            {
            if (takeprofit>=STOPLEVEL) TP  = NormalizeDouble(Price + takeprofit*Point,Digits); else TP=0;
            if (stoploss>=STOPLEVEL)   SL  = NormalizeDouble(Price - stoploss*Point,Digits);   else SL=0;     
            rez=OrderSend(Symbol(),OP_BUY, LOT,Price,slippage,SL,TP,"http://cmillion.ru",Magic,0,Blue);
            }
         if (ord==OP_SELL) 
            {
            if (takeprofit>=STOPLEVEL) TP = NormalizeDouble(Price - takeprofit*Point,Digits); else TP=0;
            if (stoploss>=STOPLEVEL)   SL = NormalizeDouble(Price + stoploss*Point,Digits);   else SL=0;              
            rez=OrderSend(Symbol(),OP_SELL,LOT,Price,slippage,SL,TP,"http://cmillion.ru",Magic,0,Red);
            }
         if (rez==-1)
            {  
            txt=StringConcatenate(txt,"\nError ",GetLastError());
            if (ord== 1) txt = StringConcatenate(txt,"  OPENORDER BUY ","  Ask =",DoubleToStr(Ask,Digits),"   Price =",DoubleToStr(Price,Digits)," (",NormalizeDouble((Price-Ask)/Point,0),")  SL =",DoubleToStr(SL,Digits)," (",NormalizeDouble((Price-SL)/Point,0),")  TP=",DoubleToStr(TP,Digits)," (",NormalizeDouble((TP-Price)/Point,0),")  STOPLEVEL=",STOPLEVEL);
            if (ord==-1) txt = StringConcatenate(txt,"  OPENORDER SELL ","  Bid =",DoubleToStr(Bid,Digits),"   Price =",DoubleToStr(Price,Digits)," (",NormalizeDouble((Bid-Price)/Point,0),")  SL =",DoubleToStr(SL,Digits)," (",NormalizeDouble((SL-Price)/Point,0),")  TP=",DoubleToStr(TP,Digits)," (",NormalizeDouble((Price-TP)/Point,0),")  STOPLEVEL=",STOPLEVEL);
            Print(txt);
            err++;Sleep(1000);RefreshRates();
            }
         else 
            {
            Comment("Ордер ",rez," успешно выставлен ");
            return;
            }
         if (err >attempts)
             return;
         }
   return;
}                  
//--------------------------------------------------------------------

</code>


А пока, что мы видим?

Функция while (true) Будет пытаться attempts раз выставить ордер. Вы можете сами указать сколько это раз. Если не сможет, то вообще выйдет из OPENORDER().

Но это уже к психотерапевту.

Перед походом, на всякий случай, проверте валидность выдаваемого лота. Журнал вам в помощь. А вообще-то, проверять надо всегда.

SL и ТР здесь сразу выставляются. Что не совсем комильфо. Думаю лучше обнулить. А выставление ограничений можно сделать отдельной функцией. Тоже настойчиво.

Это потом, а пока, думаю, функция должна выглядеть примерно так.

<code>//--------------------------------------------------------------------
void OPENORDER_2(int ord,double Price,double LOT)
{
      int rez,err=0;
      double SL=0,TP=0;
      
      while (true)
         {  
         rez=true;
         RefreshRates();
         
         if (ord==OP_BUY) 
            rez=OrderSend(Symbol(),OP_BUY, LOT,Price,slippage,0,0,"",Magic,0,Blue);
         if (ord==OP_SELL) 
            rez=OrderSend(Symbol(),OP_SELL,LOT,Price,slippage,0,0,"",Magic,0,Red);
         if (rez==-1)
            {  
            txt=StringConcatenate(txt,"\nError ",GetLastError());
            if (ord== 1) 
               txt = StringConcatenate(txt,"  OPENORDER BUY ","  Ask =",DoubleToStr(Ask,Digits),"   Price =",DoubleToStr(Price,Digits)," (",NormalizeDouble((Price-Ask)/Point,0),")  SL =",DoubleToStr(SL,Digits)," (",NormalizeDouble((Price-SL)/Point,0),")  TP=",DoubleToStr(TP,Digits)," (",NormalizeDouble((TP-Price)/Point,0),")  STOPLEVEL=",STOPLEVEL);
            if (ord==-1) 
               txt = StringConcatenate(txt,"  OPENORDER SELL ","  Bid =",DoubleToStr(Bid,Digits),"   Price =",DoubleToStr(Price,Digits)," (",NormalizeDouble((Bid-Price)/Point,0),")  SL =",DoubleToStr(SL,Digits)," (",NormalizeDouble((SL-Price)/Point,0),")  TP=",DoubleToStr(TP,Digits)," (",NormalizeDouble((Price-TP)/Point,0),")  STOPLEVEL=",STOPLEVEL);
            Print(txt);
            err++;
            Sleep(1000);
            RefreshRates();
            }
         else 
            {
            Comment("Ордер ",rez," успешно выставлен ");
            return;
            }
         if (err >attempts)
             return;
         }
   return;
}                  
//--------------------------------------------------------------------

</code>


Ограничения, если нужны выставим другой функцией.
avatar

kvashnin007

  • 23 января 2025, 14:56
0
Наверно можно и так. Но у меня есть советник, который лучше всего работает на дневках. А за три месяца делает до семиста сделок. Есть советники, которые привязываются именно к TF. Видимо поэтому мне никогда в голову не приходил такой способ.

Но, как говорил выше, каждому свое.
avatar

kvashnin007

  • 21 января 2025, 19:48
0
И да. Вы правы. Скорость для меня имеет значение. Особенно в тестировании. Здесь тоже есть варианты. Например работать по ценам закрытия минутных свечей.

Но это должно быть продолжением топика.
avatar

kvashnin007

  • 21 января 2025, 19:13
0
Глупо спрашивать: как просчитать это количество.

Но согласен, что каждому свое. А на счет пропуска сделок — для этого и топик.
Расчитывал на похожих на вас, пробовавших всякое и имеющих результаты. Вот бы общаком и вывели максимально оптимальное.

У меня есть своих пара мыслей, как заставить брокера открыть, выставить, поставить и пр. Но прежде надо быть уверенным, что ты не нарушаешь никакие правила. Топик и об этом.
avatar

kvashnin007

  • 21 января 2025, 19:06
0
Алекс, доброго дня, вечера, жизни.

Рад, что хоть кто-то…

Поэтому отвечу на вопрос.

Начну с названия топика: Функции…
Их много. Думаю, что прибегали хоть раз к услугам АМ2. Если так, то вы видели его вариант PutOrder(). Ну вот вы родили толкову мысль, с помощью Андрея получили советник для тестера, потестировали, чуть поправили алгоритм и… Сами охренели.

Как красиво пишет зараза. Куплю жене сапоги. Положили на счет котлету и на всю начали зарабатывать, зеленея от надежды. А что-то идет не по феншую. Вы его и так и сяк. А он все херет и хренет. Не понятненько… "- Андрей, а чего так-то?" Так советник то для тестера. Под реал адаптировать надо. Пару копеек и любой каприз.
А уверенность в работоспособности поубавилась до нуля. Зачем тратить деньги? Так вот и пропадают хорошие идеи.

А если бы вы позанимались в моем топике, то сами бы привели советник в реальное состояние. Погоняли бы его в этом измененном состоянии, а затем бы делали оргвыводы. Если бы вы получили приемлемые результаты, то и с деньгами бы расставались бы осознанно.

Это так. Лирика о смысле топика.

Теперь по существу.

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

Что значит работает в тестере? Вы наверно имели ввиду процес оптимизации. У меня есть советник, который тормозит оптимизацию практически до нуля, а на демо работает без задержек.Ибо такие задержки на реальную торговлю не влияют.
Я вас уверяю, что вы в теле советника сорок раз пропишете один и тот же код, что сорок раз обратитесь к внешней функции, на скорость работы советника это практически не повлияет.
А так строк меньше, что в карму, и читаемость улучшается, что в карму для пытливых.

А советники я изучаю чисто по коду. Там все написано. В отличие от тестера.

А вы, чтоб быть объективным, а не голословным, замените в советнике Moving Average код открытия ордера на функцию PutOrder и сравните скорости. Ну если, конечно, умеете. В противном случае — ко мне в топик. Вопросы только обогащают общение.
avatar

kvashnin007

  • 21 января 2025, 17:42
0
Функция открывающая и (или) выставляющая отложенные ордера довольно индивидуальна. И, в зависимости от контекста, может сильно отличаться своим функционалом. Кто-то сразу в функцию закладывает условия, при которой производятся те или иные действия. Кто-то сразу выставляет SL и ТР. Кто-то еще что-то.

Посему найти вариантов — немеряно. Но я считаю, что эта функция должна быть заточена исключительно для открытия и (или) высталения ордеров. Условия же, при которых… должны быть в теле в OnInit().
Счета ECN не допускают открытие ордеров сразу со SL и (или) ТР. Открыл — выставил. Поэтому, считаю правильным выставлять ограничения после открытия ордера ВСЕГДА. Это подойдет для любого случая. За что и будет отвечать отдельная функция. Например, PutSL_TP(). Возможен вариант работы и вовсе без ограничений сверху-снизу.
Возможен и вариант с виртуальными SL и ТР. Например, по касании соответствующей линии, или по какому либо индюку. Вариантов тоже тьма.
Но повторюсь: эта тьма желатена к прописке в основном теле OnInit().

Единственное, что всегда надо предусматривать, чтобы таки ордера выставлялись или открывались гарантированно.
А для этого неоходимо, чтобы все цены были нормализованны. Чтобы SL и ТР были на допустимом удалении. Чтобы денег хватало на открытие ордера.

Есть и другие «козни брокера». Их то и надо предусмотреть и преодолеть.

Но это попозже.

Продолжение следует.
avatar

kvashnin007

  • 21 января 2025, 10:13
0
Ну да ладно.
Поведем караван.

Удобная штука: имеешь набор функций. Проверенных не раз. С всевозможными проверками, повторами, работой над ошибками. А в OnTick() точишь себе алгоритм. Если это, то выполняем ту-то функцию. Кроме того, что удобно, так и еще читаемость кода улучшается, а значит ошибок меньше и бороться с ними проще. Только есть несколько ТОЛЬКО.

Возьмем, например, всем вам до боли знакомую функцию Открытия рыночного и, для универсальности, выставления отложенных ордеров от АМ2:

<code>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void PutOrder(int type,double price,double lot)
  {
   int r=0;
   color clr=Green;
   double sl=0,tp=0;

   if(type==1 || type==3 || type==5)
     {
      clr=Red;
      if(StopLoss>0)
         sl=NormalizeDouble(price+StopLoss*_Point,_Digits);
      if(TakeProfit>0)
         tp=NormalizeDouble(price-TakeProfit*_Point,_Digits);
     }

   if(type==0 || type==2 || type==4)
     {
      clr=Blue;
      if(StopLoss>0)
         sl=NormalizeDouble(price-StopLoss*_Point,_Digits);
      if(TakeProfit>0)
         tp=NormalizeDouble(price+TakeProfit*_Point,_Digits);
     }

   r=OrderSend(NULL,type,lot,NormalizeDouble(price,_Digits),Slip,sl,tp,Comm,Magic,0,clr);
   return;
  } 
//+------------------------------------------------------------------+
</code>


Обычная так себе функция. В чем универсальность? Да одна функция на все случаи жизни. Удобно таки.
Хочешь ордер по рынку — укажи тип 0 или 1, хочешь выставить отложку — 2,3,4 или 5, соответственно выбору.
Ах да, цену открытия надо выставлять. А какая она у единицы? Или нуля? А, не дай бог, и поболее. Тут надо напрячся. А почему не написать PutOrder (OP_BUY), вместо PutOrder (0)? Мало того, что красным цветом пойдет так и лишний раз и напрягаться не надо. Хотя это одна и таже команда. Ну Lot можно по-разному. Иногда проще в теле, а иногда лучше отдать его расчет отдельной функции. Часто, если алгоритм предполагает дележ ордеров на группы, указывают в скобках еще int magic.

Теперь — «обвязка» ордера. SL,TP, Slippage и т.д.

Тут тоже хватает нюансов.
Кто-то хочет, чтобы настройки советника были одинаковыми для четырех и пяти знаковых терминалов.
Поэтому _Point часто превращают в глобальную переменню double pnt, например. Для чего? Да просто: если пятизнак, то _Point увеличивают *10. А в связи с тем, что эта величина постоянная, pnt задают один раз в OnInit(). Плюс к этому, не надо будет каждый раз обращаться к терминалу с запросом величины Point(). Исходя из этих же соображений я бы ввел еще переменную string symbol. И один раз бы в OnInit() приравнял бы ее Symdol(). Аналогично и с _Digits.

Особое внимание надо обратить на SL и ТР. Первым делом, в связи с тем, что эти переменные не меняются по ходу работы советника, я бы ввел глобальные переменные _double sl, tp; по аналогии, о чем выше в OnInit() сразу один бы раз перевел в стоимост, избегая дальнейших лишних телодвижений. Т.е. в OnInit() sl=StopLoss*_Point и tp=TakeProfit*_Point. Аналогично можно поступить и с другими пунктовыми переменными, которые остаются неизменным по ходу работы советника. Например, Step, Trail, BU и т.д.

В связи с тем, что было выше писано, функция от Андрея должна выглядеть приблизительно ТАК:

<code>//+------------------------------------------------------------------+
//|                                                       Locker.mq4 |
//|                                              Copyright 2022, AM2 |
//|                                     https://www.forexsystems.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, AM2"
#property link      "https://www.forexsystems.biz"
#property version   "1.00"
#property strict

//--- Inputs
extern int    StopLoss      = 23;        // лось   в пунктах
extern int    TakeProfit    = 78;        // язь    в пунктах
extern int    Slippage      = 3;         // реквот в пунктах

strig  symbol; 
int    digits, slippage;
double pnt,sl,tp;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
      symbol = Symbol(); 
      digits = Digits;
      pnt    = Point;
   
      if(digits==3 || digits==5)
        {
        tp       = TakeProfit*pnt*10;
        sl       = StopLoss*pnt*10;     
        slippage = Slippage*pnt*10;
        }
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   if(CountTrades()==Count && !TimeSession(StartHour,StartMin,EndHour,EndMin,TimeCurrent()))
      {
      if(Sell)
         PutOrder(OP_BUY,Ask,Lot);
      if(Buy)
         PutOrder(OP_SELL,Bid,Lot);
      }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void PutOrder(int type,double price,double lot)
  {
   int r=0;
   color clr=Green;

   if(type==OP_SELL || type==OP_SELLLIMIT || type==OP_SELLSTOP)
     {
      clr=Red;
      if(StopLoss>0)
         sl=NormalizeDouble(price+sl,digits);
      if(TakeProfit>0)
         tp=NormalizeDouble(price-tp,digits);
     }

   if(type == OP_BUY || type == OP_BUYLIMIT || type==OP_BUYSTOP)
     {
      clr=Blue;
      if(StopLoss>0)
         sl=NormalizeDouble(price-sl,digits);
      if(TakeProfit>0)
         tp=NormalizeDouble(price+tp,digits);
     }

   r=OrderSend(NULL,type,lot,NormalizeDouble(price,digits),slippage,sl,tp,Comm,Magic,0,clr);
   return;
  }
//+------------------------------------------------------------------+</code>


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

А функцию для работы на реале мы попробуем слепить в следующий раз.
avatar

kvashnin007

  • 20 января 2025, 16:02
+1
Поражен.

Всем подай кнопку «Рубить бабло».

Нет такой, наивные.

Только своими головой и руками.
avatar

kvashnin007

  • 19 января 2025, 17:15
0
Андрей, спасибо за внимание. Но Здесь не требуется дописать под реал что-то конкретное. Это сможет сделать каждый, самостоятельно напрямую обратившись к программистам.

Идея топика в ЛИКБЕЗе. В обучении самостоятельно делать тривиальные вещи. Я бы был благодарен, если ли бы Вы взялись в топике переводить функции на mql5, периодически поглядывая сюда, возможно, внося какие-либо комментарии или исправления. Добавления.

Топику просто необходим грамотный и ответственный специалист.
avatar

kvashnin007

  • 18 января 2025, 16:02
0
С чего-то надо начинать. Предлагаю кому-нибудь дать свой советник, написанный упрощенно для проверки идеи. Советник желателен посложнее. Многофункциональный. На его примере мы можем заняться заменой функций Что-то я предложу. Что-то другие. Поищем варианты.

В конечном итоге топика должен получиться файл с функциями для замены.
avatar

kvashnin007

  • 18 января 2025, 12:20
0
Пока хочу начать с общих рассуждений.

У кого нет идей — у того нет ни малейшего понятия, как работает рынок. Ну а как оттуда денег поиметь… Желание есть. А как? Кто-то работает лапками и, даже, более менее успешно. Это люди, которые лучше остальных познают торговлю. Мое же мнение (и не только мое) — лапами с малыми деньгами ни хрена не заработаешь. Робот неустанно, днем и ночью, без выходных, без неВРов… Нег.., пардон, темнокожий человек. Четко выполняющий заложенные в его голову инструкции.

Алгоритм.

Это и есть главный камень преткновения, за который постоянно цепляемся на пути извлечения денег из рынка. Но тут у каждого свои камни. Кто-то делится своими идеями, кто-то ни-ни. Кто-то хочет «подтесать» чужие камни, находя в них что-то интересное.

Но как? Падаем в колени местным программистам, а те, чаще на «отЫбись», что-то пишут. А сейчас даже денег просят за это. Пишут «близко к тексту», а не «копейка в копейку». В результате наших всяких тестирований и прочих извращений, мы приходим к выводу, что все это фуфло. Чаще всего так оно и есть. Но иногда и стоящие идеи сметаются в мусорное ведро. Чаще безвозвратно. Но если ты не программист, с этим стоит смириться.
Обидно. Денег дал, хорошую идею в ведро выкинул, а на выходе…

Но часто попадаются в базе и интересные советники. Слегка причесать алгоритм, добавить пару дополнительных функций, ускорить существующий код, заменить некоторые функции на функции, которые я планирую подготовить в этом топике и вуаля. Добро пожаловать на центовый счет для доотладки после тестера. А там, возможно, и до нормальных счетов дойдем.

Любой советник может приносить прибыль. Большую ли, маленькую. С просадкой или не очень. Некоторой время суток, недели, а иногда и больше.
Главное определить его слабые места, учесть козни брокера и его терминала и постоянно контролировать работу оветника, перенастраивая его.

И еще одна ВАЖНАЯ вещь. По закону падающего бутерброда, все пойдет не так, как вы расчитываете. Посему надо ограничивать или страховать потери. Надо всегда знать, как вы будете реагировать на «баба Яга против».

Но это больше алгоритм, включая SL, trail, ММ и другие извращения.

В этом же топике я хочу затронуть вопросы борьбы с брокером. Его палками в колеса. Проверки, работа над ошибками типа GetLastError().
avatar

kvashnin007

  • 18 января 2025, 11:56
0
Так как я плохо знаком с mql5, общаться будем в основном на языке mql4.
Возможно, в наших рядах появится кто-то более продвинутый и возмет на себя нагрузку по «переводу» нашего «птичего» mql4 на более продвинутый язык. Будем только рады.
avatar

kvashnin007

  • 18 января 2025, 10:16
0
Не пойму — лучше в банк? Или или всетаки 20% в месяц?
avatar

kvashnin007

  • 4 января 2025, 22:31
0
Это было всего лишь открытие ордеров.Самое интересное потом.
Не интересно? Да и ладно.
Всем удачи.
avatar

kvashnin007

  • 26 декабря 2024, 08:25
0


Образовалась временнAя коробка.
Делим ее пополам. Имеем три линии-цены. Цена находится между внешними линиями. И чаще линии ближе stoplevel.
Поэтому, отложками здесь сработать практически не возможно. Надо открывать ордера по пересечению линий.
Ценой Bid или Ask — варианты на рассмотрение.

Далее ожидаем три события:
— пересечение вехней линии снизу вверх (сверху вниз — не реагируем);
— пересечение нижней линии сверху вниз (снизу вверх — не реагируем);
— пересечение средней линии сверху вниз или снизу вверх;

Так как будем работать с двумя полосами (верхней и нижней), для упрощения логики предлагаю Ордера,
соответствующие им, отличить по magik number. Например верхняя полоса — Magic, а нижняя — Magic+1.

Итак — три события.

— Если цена пробила верхнюю линию, то открываем OP_BUY с Magic. Лот определяется по следующим параметрам:
если сумма лотов OP_SELL с Magic равна нулю, то лот равен стартовому лоту;
если сумма лотов OP_SELL с Magic больше нуля, то суммарный лот OP_BUY с Magic должен оказаться
в два раза больше, чем сумма лотов OP_SELL с Magic. Если меньше — добавляем до удвоенной суммы.
Lot(OP_BUY,Magic) = SummLot(OP_SELL,Magic)*2 — SummLot(OP_BUY,Magic);

Прошу заметить: при колебаниях цены, если цена пробила верхнюю линию сверху вниз, мы ничего не делаем.
— При пробитии нижней линии сверху вниз открыватся OP_SELL аналогично пересечению верхней, но с Magic+1.
Lot(OP_SELL, Magic+1) = SummLot(OP_BUY, Magic+1)*2 — SummLot(OP_SELL, Magic+1);

— С пересечением средней линии все гораздо интереснее:
Открываются два ордера. OP_BUY с Magic+1 и OP_SELL с Magic.

Лоты определяются в следующем порядке:

— если цена пробила среднюю линию снизу вверх, то

Для OP_BUY с Magic+1
* если суммарный лот OP_SELL с Magic+1 равен нулю,
то лот OP_BUY с Magic+1 равен удвоенному стартовому лоту.
* Если цена также пробила среднюю линию снизу вверх, но суммарный лот OP_SELL с Magic+1 больше нуля,
то суммарный лот OP_BUY с Magic+1 должен оказаться в два раза больше, чем сумма лотов OP_SELL с Magic+1.
Если меньше — добавляем до удвоенной суммы. Если равна — ничего не делаем.
Lot(OP_BUY, Magic+1) = SummLot(OP_SELL, Magic+1)*2 — SummLot(OP_BUY, Magic+1);

Для OP_SELL с Magic
* если суммарный лот OP_BUY с Magic равен нулю,
то лот OP_SELL с Magic просто равен стартовому лоту.
* Если цена также пробила среднюю линию снизу вверх, но суммарный лот OP_BUY с Magic больше нуля,
то суммарный лот OP_SELL с Magic должен оказаться в два раза больше, чем сумма лотов OP_BUY с Magic.
Если меньше — добавляем до удвоенной суммы. Если равна — ничего не делаем.
Lot((OP_SELL, Magic) = SummLot(OP_BUY, Magic)*2 — SummLot(OP_SELL, Magic);

— если цена пробила среднюю линию сверху вниз, то

тоже открываем два ордера OP_BUY с Magic+1 и OP_SELL с Magic,
только лоты рассчитываются симметрично наоборот.

Для лучшего понимания:

каждая полоса имеет свои ордера со своими мagic. Снизу полосы ордера на продажу. Сверху — на покупку.
Наша задача следить, чтобы лотов на границах полосы суммарно было в два раза больше, чем
на противоположной границе этой же полосы. Нюансы только в начале открытия ордеров каждой полосы.

А вообщето выше практически написан код советника.
Подправить только в код mql4. Ну и индюк, конечно. Хотя можно и без него.

Получение прибыли и ограничение убытков в следующий раз, если комe-то будет интересно.
Можно простоограничиться тралом прибили-убытка. Но есь варианты и поинтереснее.
avatar

kvashnin007

  • 24 декабря 2024, 13:42