Эксперт Bot Moving Fast-Slow

В данной статье будет подробно разобрана работа эксперта Bot Moving Fast-Slow с точки зрения программирования на языке LCRYP. Перед использованием экспертов нужно ознакомиться с общей информацией о подходе к работе экспертов и их синхронизации

 

Глобальные переменные

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

int FastLength,FastShift,SlowLength,SlowShift,LimitBars,Dir,TypeMM;
int OnMartin,CloseLoss,ProfitIsSignal,TypeCalculateValute;
double ValueMM,VolumeMinMM,VolumeMaxMM,IterMM,StartDepoMM,StepMartin;
double PipsProfit,LevelShiftPrice;

Входные данные

Входные данные можно разделить на несколько частей.

  1. Настройки, связанные с сигнальным индикатором

    • LimitBars.
    • FastLength.
    • FastShift.
    • SlowLength.
    • SlowShift.
  2. Настройки рисков (справка)

    • TypeMM.
    • ValueMM.
    • VolumeMinMM.
    • VolumeMaxMM.
    • IterMM.
    • StartDepoMM.
  3. Настройки Мартингейла

    • OnMartin - Позволяет работать с системой Мартингейла.
    • StepMartin - Шаг для системы Мартингейла.
  4. Настройки связанные с направлением работы и закрытием

    • Dir - Задает направление открытия ордеров или на buy, или на sell.
    • CloseLoss - Позволяет закрывать ордера с отрицательным профитом при появлении сигнала в противоположную сторону. Если включен этот параметр, система Мартингейла не может работать.
    • ProfitIsSignal - Создает дополнительный сигнал на закрытие при достижении профита PipsProfit.
    • PipsProfit - Профит для закрытия, если включено ProfitIsSignal. В случае использования Мартингейла - ProfitIsSignal обязательно включен.
  5. Дополнительные настройки

    • TypeCalculateValute - Задает способ пересчета объема. Например, можно задавать все объемы в BTC и они будут перечисляться в нужное значение по текущему курсу.
    • LevelShiftPrice - Задает отступ от цены. Например, сигнал появился на определенном уровне, задавая отступ, ордер выставится на расстоянии отступления от реальной цены сигнала.

Рассмотрим функцию OnInit

В первых строках используется команда s_buff. С ее помощью создаются буфера с номерами 0, 1, 2, 4. Два - для вывода информации сигнального индикатора, один - для отображения всех сигналов и буфер данных. Тип отображения данных буфера - линия и соответствующие цвета. Blue - цвет буфера 0, Red - цвет буфера 1, Green - цвет буфера 2, None - отсутствие цвета для буфера 3. В следующих строках используется команда s_par, которая устанавливает набор входных данных для пользователя. Входные данные индексируются от 0 до 18 (используется 19 входных параметра). Также команда s_par задает тип для каждого поля, название, которое будет отображаться, и значение по умолчанию. На этом работа данной части программы завершена. 

int OnInit()
  {
   s_buff(0,1,1,0,"Blue","Blue","Blue");
   s_buff(1,1,1,0,"Red","Red","Red");
   s_buff(2,4,1,0,"Green","Green","Green");
   s_buff(3,2,1,0,"None","Blue","Red");
   s_par(0,"int","LimitBars",1000);
   s_par(1,"int","TypeMM",0);
   s_par(2,"double","ValueMM",0.001);
   s_par(3,"double","VolumeMinMM",0.001);
   s_par(4,"double","VolumeMaxMM",0.01);
   s_par(5,"double","IterMM",0);
   s_par(6,"double","StartDepoMM",10);
   s_par(7,"int","FastLength",6);
   s_par(8,"int","FastShift",0);
   s_par(9,"int","SlowLength",12);
   s_par(10,"int","SlowShift",0);
   s_par(11,"int","OnMartin",1);
   s_par(12,"double","StepMartin",0.0008);
   s_par(13,"double","PipsProfit",0.0008);
   s_par(14,"int","ProfitIsSignal",0);
   s_par(15,"int","Dir",1);
   s_par(16,"int","CloseLoss",0);
   s_par(17,"double","LevelShiftPrice",0.00001);
   s_par(18,"int","TypeCalculateValute",3);
   return 0;
  }

Рассмотрим функцию OnBar

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

   LimitBars=g_par(0);
   TypeMM=g_par(1);
   ValueMM=g_par(2);
   VolumeMinMM=g_par(3);
   VolumeMaxMM=g_par(4);
   IterMM=g_par(5);
   StartDepoMM=g_par(6);
   FastLength=g_par(7);
   FastShift=g_par(8);
   SlowLength=g_par(9);
   SlowShift=g_par(10);
   OnMartin=g_par(11);
   StepMartin=g_par(12);
   PipsProfit=g_par(13);
   ProfitIsSignal=g_par(14);
   Dir=g_par(15);
   CloseLoss=g_par(16);
   LevelShiftPrice=g_par(17);
   TypeCalculateValute=g_par(18);
   if(LimitBars>0)
     {
      if(ReCount>LimitBars)
        {
         ReCount=LimitBars;
        }
     }
   ShowName();

После чего используется пользовательская функция ShowName, которая выводит название индикатора с параметрами на окно чарта, используя команды prt и prt_a.

int ShowName()
  {
   prt(0,"Bot Moving Fast-Slow [");
   prt_a(0,LimitBars);prt_a(0,", ");
   prt_a(0,TypeMM);prt_a(0,", ");
   prt_a(0,ValueMM);prt_a(0,", ");
   prt_a(0,VolumeMinMM);prt_a(0,", ");
   prt_a(0,VolumeMaxMM);prt_a(0,", ");
   prt_a(0,IterMM);prt_a(0,", ");
   prt_a(0,StartDepoMM);prt_a(0,", ");
   prt_a(0,FastLength);prt_a(0,", ");
   prt_a(0,FastShift);prt_a(0,", ");
   prt_a(0,SlowLength);prt_a(0,", ");
   prt_a(0,SlowShift);prt_a(0,", ");
   prt_a(0,OnMartin);prt_a(0,", ");
   prt_a(0,StepMartin);prt_a(0,", ");
   prt_a(0,PipsProfit);prt_a(0,", ");
   prt_a(0,ProfitIsSignal);prt_a(0,", ");
   prt_a(0,Dir);prt_a(0,", ");
   prt_a(0,CloseLoss);prt_a(0,", ");
   prt_a(0,LevelShiftPrice);prt_a(0,", ");
   prt_a(0,TypeCalculateValute);
   prt_a(0,"]");
  }

Дальше несколько дополнительных условий:

if(ReCount>LimitBars){ReCount=LimitBars;}

Условие устанавливает ограничение количества входных баров для пересчета, то есть перерасчет будет не более, чем LimitBars баров, заданных пользователем. Встроенная переменная ReCount несет информацию о количестве баров, которое необходимо пересчитать.

if(ReCount<1){return -1;}

Условие завершает работу функции, если нет новых баров для пересчета.

Следующими объявлены локальные переменные p_Fast, p_Slow, p_Fast_1, p_Slow_1 - в которых будут храниться текущие и предыдущие значения скользящих средних. Основная часть функции - цикл, который проходит по всем барам ценового графика. Также обнуляем регистры, которые будут использоваться в дальнейшем для хранения некоторых значений, для чего применим команду s_reg. Обнуляются регистры с номерами 1,2,3.

   s_reg(1,0);
   s_reg(2,0);
   s_reg(3,0);
   int i;
   for(i=ReCount-1;i>=0;i=i-1)
     {
      p_Fast=avg(i, FastLength, FastShift, Count, 1);
      p_Slow=avg(i, SlowLength, SlowShift, Count, 1);
      s_dbuff(0,i,p_Fast,0,0,"",0);
      s_dbuff(1,i,p_Slow,0,0,"",0);
      s_dbuff(2,i,0,0,0,"",0);
      s_dbuff(3,i,0,0,0,"",0);
      p_Fast_1=g_dbuff(0,i+1);
      p_Slow_1=g_dbuff(1,i+1);
      if(((p_Fast_1!=0) && (p_Slow_1!=0)) && ((p_Fast!=0) && (p_Slow!=0)))
        {
         if((p_Fast>p_Slow) && (p_Fast_1<=p_Slow_1))
           {
            CoreBot(2,3,i,1);
           }
         if((p_Fast<p_Slow) && (p_Fast_1>=p_Slow_1))
           {
            CoreBot(2,3,i,-1);
           }
        }
      if(ProfitIsSignal==1)
        {
         CoreBot(2,3,i,SignalProfit(3,i));
        }
     }
   PrintStat(3);

В цикле последовательно перебираются все бары и рассчитываются значения скользящих средних. Для расчета используется команда avg и заданные пользователем параметры. После получения значений скользящих используется команда s_dbuff и информация выводится в соответствующие буфера. Следующим действием будет определение точек входа по двум скользящим средним. А именно после точки их пересечения. Для чего использовано условие для сигнала на buy:

((p_Fast>p_Slow) && (p_Fast_1<=p_Slow_1))

А также условие для сигнала на sell:

((p_Fast<p_Slow) && (p_Fast_1>=p_Slow_1))

И дополнительный сигнал для закрытия по заданному профиту, в случае, если пользователь задал соответствующую настройку ProfitIsSignal.

Для продолжения работы используется пользовательская функция CoreBot, SignalProfit а также функция PrintStat для отображения статистических данных на чарте.

Рассмотрим функцию PrintStat

Детально останавливаться на ней не будем. Используются две ключевые команды c_ind и c_real. Данные команды просчитывают статистику прибыли для сигнального буфера  и для реальных данных соответственно. Статистика сигнального буфера производится по указанному во входных параметрах значению индекса буфера - buff_sig. После расчетов используются команды для вывода результирующей информации.

Получив все нужные параметры, используя выше указанные команды и сохранив их в локальные переменные, отображаем полученную информацию на чарте, используя команды: prt и prt_a. Для отображения используется буфер с индексом 2.

int PrintStat(int buff_sig)
  {
   double max_martin,real_pro_final,max_pick_vol;
   c_ind(buff_sig,0,LimitBars,0,0,0);
   real_pro_final=m_real_pro_final(buff_sig);
   max_pick_vol=m_max_pick_vol_final(buff_sig);
   max_martin=m_max_martin_final(buff_sig);
   prt(2,"Profit [");
   prt_a(2,real_pro_final);
   prt_a(2,"].");
   prt(3,"Max Pick Volume [");
   prt_a(3,max_pick_vol);
   prt_a(3,"].");
   prt(4,"Max Step [");
   prt_a(4,max_martin);
   prt_a(4,"].");
  }

Рассмотрим функцию SignalProfit

Её задача - генерировать сигнал для закрытия серии, в случае, если достигнут профит одного или серии ордеров.

В первую очередь необходимо узнать текущую цену с помощью команды close. Также надо узнать текущее состояние трендов последней незакрытой серии (или одного ордера) на рынке (на самом деле в сигнальном буфере), используя команду c_ind. После использования команды c_ind можно узнать цену безубытка для серии, вызвав команду m_nline. Также команда m_dir укажет поточное направление серии.

Следующим шагом надо, в зависимости от направления, проверить: пробила ли цена уровень нужного профита (используя дистанцию от уровня безубытка). В результате будет сгенерирован сигнал или -1 - в случае, если надо открыть ордер sell и закрыть серию buy, или +1 - в случае, если надо открыть ордер buy и закрыть серию sell. Если результат равен 0, то ничего делать не надо.

int SignalProfit(int buff_sig,int i)
  {
   int sig,real_dir;
   double price,nline;
   sig=0;
   price=close(i);
   c_ind(buff_sig,i,ReCount,0,0,0);
   nline=m_nline(buff_sig,i);
   if((price!=0) && (nline!=0))
     {
      real_dir=m_dir(buff_sig,i);
      if(real_dir==1)
        {
         if(price>=(nline+PipsProfit))
           {
            sig=-1;
           }
        }
      if(real_dir==-1)
        {
         if(price<=(nline-PipsProfit))
           {
            sig=1;
           }
        }
     }
   return sig;
  }

Функция CoreBot.

Рассмотрим ключевую функцию CoreBot. Данная функция принимает 4 параметра на входе buff_ind, buff_sig, i и signal. Первый параметр buff_ind принимает индекс буфера, в котором будут сохраняться все сигналы сигнального индикатора с помощью команды s_dbuff. То есть, в данном буфере просто сохраняются все поступающие сигналы, сохранение происходит по индексу "i", который также передается как входной параметр. Входной параметр signal - указывает направление сигнала. Параметр buff_sig - принимает значение индекса буфера, в котом будут происходить все расчеты эксперта.

Вся функция разделяется на две части. В одной прописано поведение, если сигнал на buy (signal == 1). Другая часть обрабатывает сигнал на sell (signal == -1). Рассмотрим первую часть.

В начале команда s_dbuff сохраняет значение сигнала. После этого команда c_ind производит расчеты по индексу "i" в расчетном буфере с индексом buff_sig. После использования данной команды мы имеем доступ к актуальным данным в расчетном буфере и можем их использовать. В первую очередь команда m_dir узнает фактическое текущее направление серии (это не направление позиции, так как в серии может быть три тренда на buy и один, например последний, - на sell, причем объем последнего меньше, чем суммарный объем троих на buy. В таком случае суммарный сигнал будет на buy, именно это направление выдает команда, направление текущей серии. 

В данной функции также проверяется состояние глобальной переменной Dir, в которой указано разрешенное пользователем направление. Если направление разрешает и результат предыдущей команды, сохраненный в переменной action, говорит об успешно выполненной команде, тогда можно продолжать работу. 

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

  • (real_dir==0) - условие для первого варианта,
  • (OnMartin==1) - условие для второго варианта.

В двух вариантах используется команда определения объема по заданным пользователем параметрам риска c_risk. Также в двух случаях используется пользовательская функция для выставления ордера SetOrder. Команды m_sdd и m_ssd задают информацию, которая будет отображена на чарте в точке сигнала. 

В ветке, где используется мартингейл, нам надо узнать, на сколько просела цена в направлении против нашей сделки, для чего используем команду m_min_price, которая укажет минимальную цену всех трейдов серии. Сравнив эту информацию с текущей ценой, которая записана в переменной price, заполненной в начальной части функции с помощью команды close, также необходимо учесть отклонение минимальной цены на шаг мартингейла, заданный пользователем в настройках и сохраненный глобальной переменной StepMartin. Если все условия второй части выполнены, тогда совершается сделка.

  Вернемся на уровень назад, к строке:

 nline= m_nline(buff_sig,i);

Дальше необходимо проверить: не надо ли закрыть серию, если она достигла профита PipsProfit. Используя команду m_nline, узнаем уровень безубытка и если текущая цена пробила уровень цены безубытка вместе с профитом, необходимо создать сигнал в противоположную сторону для закрытия серии. Также надо указать суммарный объем серии, который можно узнать, используя функцию m_vol.

int CoreBot(int buff_ind,int buff_sig,int i,int signal)
  {
   double price,volume;
   double max_price,min_price;
   int real_dir,nline,prof,action;
   price=close(i);
   if(signal==1)
     {
      s_dbuff(buff_ind,i,price,volume,0,"",1);
      action=c_ind(buff_sig,i,ReCount,0,0,0);
      real_dir=m_dir(buff_sig,i);
      if((Dir==1) || (Dir==0)) && (action==0)
        {
         if(real_dir==0)
           {
            volume=c_risk(TypeMM,ValueMM,IterMM,VolumeMinMM,VolumeMaxMM,StartDepoMM);
            SetOrder(buff_sig,i,price,volume,1);
            m_sdd(buff_sig,i,volume);
            m_ssd(buff_sig,i,"0.########");
           }
         if(OnMartin==1)
           {
            min_price=m_min_price(buff_sig,i)-StepMartin;
            if((real_dir==1) && (price<min_price))
              {
               volume=c_risk(TypeMM,ValueMM,IterMM,VolumeMinMM,VolumeMaxMM,StartDepoMM);
               SetOrder(buff_sig,i,price,volume,1);
               m_sdd(buff_sig,i,volume);
               m_ssd(buff_sig,i,"0.########");
              }
           }
        }
      nline= m_nline(buff_sig,i);
      prof = m_vol(buff_sig,i);
      if((real_dir==-1) && (nline!=0))
        {
         if((price<=(nline-PipsProfit)) || (CloseLoss==1))
           {
            volume=m_vol(buff_sig,i);
            SetOrder(buff_sig,i,price,volume,1);
            m_sdd(buff_sig,i,prof);
            m_ssd(buff_sig,i,"0.########");
           }
        }
     }
   if(signal==-1)
     {
         ...
     }
  }

Функция SetOrder.

Пользовательская функция SetOrder отвечает за фиксацию сигнала в соответствующем буфере и передачу его на выполнение, если сигнал поступил в реальном времени.

int SetOrder(int buff_sig,int index,double price,double volume,int dir)
  {
   s_dbuff(buff_sig,index,price,volume,0,"",dir);
   if(index==0)
     {
      s_reg(1,dir);
      s_reg(2,volume);
      s_reg(3,price);
     }
  }

Функция s_dbuff записывает сигнал в буфер. Чтобы передать информацию о сигнале в реальном времени, используются регистры, в которые записывается нужная информация s_reg.

Функция OnTick.

Функция OnTick отвечает за обработку сигнала в реальном времени. Читая информацию из регистров, она выходит на рынок в нужном направлении. Для этого используются функции OpenSell и OpenBuy, которые пользователь может понять самостоятельно, используя справку.

int OnTick()
  {
   if(e_abot()==1)
     {
      LevelShiftPrice=g_par(17);
      TypeCalculateValute=g_par(18);
      int dir;
      double volume;
      double price;
      dir=g_reg(1);
      volume=g_reg(2);
      price=g_reg(3);
      if(dir==-1)
        {
         OpenSell(price,volume);
        }
      if(dir==1)
        {
         OpenBuy(price,volume);
        }
      prt(5,"Signal [");
      prt_a(5,dir);
      prt_a(5,"]");
     }
   else
     {
      prt(5,"Bot Disabled");
     }
   return 0;
  }

Полный листинг программы Bot Moving Fast-Slow:

//+------------------------------------------------------------------+
//|                                       Bot Moving Fast-Slow.lcryp |
//|                                     Copyright 2017, TerminalCoin |
//|                                             www.terminalcoin.com |
//+------------------------------------------------------------------+
int FastLength,FastShift,SlowLength,SlowShift,LimitBars,Dir,TypeMM;
int OnMartin,CloseLoss,ProfitIsSignal,TypeCalculateValute;
double ValueMM,VolumeMinMM,VolumeMaxMM,IterMM,StartDepoMM,StepMartin;
double PipsProfit,LevelShiftPrice;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   s_buff(0,1,1,0,"Blue","Blue","Blue");
   s_buff(1,1,1,0,"Red","Red","Red");
   s_buff(2,4,1,0,"Green","Green","Green");
   s_buff(3,2,1,0,"None","Blue","Red");
   s_par(0,"int","LimitBars",1000);
   s_par(1,"int","TypeMM",0);
   s_par(2,"double","ValueMM",0.001);
   s_par(3,"double","VolumeMinMM",0.001);
   s_par(4,"double","VolumeMaxMM",0.01);
   s_par(5,"double","IterMM",0);
   s_par(6,"double","StartDepoMM",10);
   s_par(7,"int","FastLength",6);
   s_par(8,"int","FastShift",0);
   s_par(9,"int","SlowLength",12);
   s_par(10,"int","SlowShift",0);
   s_par(11,"int","OnMartin",1);
   s_par(12,"double","StepMartin",0.0008);
   s_par(13,"double","PipsProfit",0.0008);
   s_par(14,"int","ProfitIsSignal",0);
   s_par(15,"int","Dir",1);
   s_par(16,"int","CloseLoss",0);
   s_par(17,"double","LevelShiftPrice",0.00001);
   s_par(18,"int","TypeCalculateValute",3);
   return 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int ShowName()
  {
   prt(0,"Bot Moving Fast-Slow [");
   prt_a(0,LimitBars);prt_a(0,", ");
   prt_a(0,TypeMM);prt_a(0,", ");
   prt_a(0,ValueMM);prt_a(0,", ");
   prt_a(0,VolumeMinMM);prt_a(0,", ");
   prt_a(0,VolumeMaxMM);prt_a(0,", ");
   prt_a(0,IterMM);prt_a(0,", ");
   prt_a(0,StartDepoMM);prt_a(0,", ");
   prt_a(0,FastLength);prt_a(0,", ");
   prt_a(0,FastShift);prt_a(0,", ");
   prt_a(0,SlowLength);prt_a(0,", ");
   prt_a(0,SlowShift);prt_a(0,", ");
   prt_a(0,OnMartin);prt_a(0,", ");
   prt_a(0,StepMartin);prt_a(0,", ");
   prt_a(0,PipsProfit);prt_a(0,", ");
   prt_a(0,ProfitIsSignal);prt_a(0,", ");
   prt_a(0,Dir);prt_a(0,", ");
   prt_a(0,CloseLoss);prt_a(0,", ");
   prt_a(0,LevelShiftPrice);prt_a(0,", ");
   prt_a(0,TypeCalculateValute);
   prt_a(0,"]");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnBar()
  {
   LimitBars=g_par(0);
   TypeMM=g_par(1);
   ValueMM=g_par(2);
   VolumeMinMM=g_par(3);
   VolumeMaxMM=g_par(4);
   IterMM=g_par(5);
   StartDepoMM=g_par(6);
   FastLength=g_par(7);
   FastShift=g_par(8);
   SlowLength=g_par(9);
   SlowShift=g_par(10);
   OnMartin=g_par(11);
   StepMartin=g_par(12);
   PipsProfit=g_par(13);
   ProfitIsSignal=g_par(14);
   Dir=g_par(15);
   CloseLoss=g_par(16);
   LevelShiftPrice=g_par(17);
   TypeCalculateValute=g_par(18);
   if(LimitBars>0)
     {
      if(ReCount>LimitBars)
        {
         ReCount=LimitBars;
        }
     }
   ShowName();
   if(ReCount<1){return -1;}
   if(ReCount >=1){ReCount = LimitBars;}
   double p_Fast,p_Slow;
   double p_Fast_1,p_Slow_1;
   s_reg(1,0);
   s_reg(2,0);
   s_reg(3,0);
   int i;
   for(i=ReCount-1;i>=0;i=i-1)
     {
      p_Fast=avg(i, FastLength, FastShift, Count, 1);
      p_Slow=avg(i, SlowLength, SlowShift, Count, 1);
      s_dbuff(0,i,p_Fast,0,0,"",0);
      s_dbuff(1,i,p_Slow,0,0,"",0);
      s_dbuff(2,i,0,0,0,"",0);
      s_dbuff(3,i,0,0,0,"",0);
      p_Fast_1=g_dbuff(0,i+1);
      p_Slow_1=g_dbuff(1,i+1);
      if(((p_Fast_1!=0) && (p_Slow_1!=0)) && ((p_Fast!=0) && (p_Slow!=0)))
        {
         if((p_Fast>p_Slow) && (p_Fast_1<=p_Slow_1))
           {
            CoreBot(2,3,i,1);
           }
         if((p_Fast<p_Slow) && (p_Fast_1>=p_Slow_1))
           {
            CoreBot(2,3,i,-1);
           }
        }
      if(ProfitIsSignal==1)
        {
         CoreBot(2,3,i,SignalProfit(3,i));
        }
     }
   PrintStat(3);
   return 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CoreBot(int buff_ind,int buff_sig,int i,int signal)
  {
   double price,volume;
   double max_price,min_price;
   int real_dir,nline,prof,action;
   price=close(i);
   if(signal==1)
     {
      s_dbuff(buff_ind,i,price,volume,0,"",1);
      action=c_ind(buff_sig,i,ReCount,0,0,0);
      real_dir=m_dir(buff_sig,i);
      if((Dir==1) || (Dir==0)) && (action==0)
        {
         if(real_dir==0)
           {
            volume=c_risk(TypeMM,ValueMM,IterMM,VolumeMinMM,VolumeMaxMM,StartDepoMM);
            SetOrder(buff_sig,i,price,volume,1);
            m_sdd(buff_sig,i,volume);
            m_ssd(buff_sig,i,"0.########");
           }
         if(OnMartin==1)
           {
            min_price=m_min_price(buff_sig,i)-StepMartin;
            if((real_dir==1) && (price<min_price))
              {
               volume=c_risk(TypeMM,ValueMM,IterMM,VolumeMinMM,VolumeMaxMM,StartDepoMM);
               SetOrder(buff_sig,i,price,volume,1);
               m_sdd(buff_sig,i,volume);
               m_ssd(buff_sig,i,"0.########");
              }
           }
        }
      nline= m_nline(buff_sig,i);
      prof = m_vol(buff_sig,i);
      if((real_dir==-1) && (nline!=0))
        {
         if((price<=(nline-PipsProfit)) || (CloseLoss==1))
           {
            volume=m_vol(buff_sig,i);
            SetOrder(buff_sig,i,price,volume,1);
            m_sdd(buff_sig,i,prof);
            m_ssd(buff_sig,i,"0.########");
           }
        }
     }
   if(signal==-1)
     {
      s_dbuff(buff_ind,i,price,volume,0,"",-1);
      action=c_ind(buff_sig,i,ReCount,0,0,0);
      real_dir=m_dir(buff_sig,i);
      if((Dir==-1) || (Dir==0)) && (action==0)
        {
         if(real_dir==0)
           {
            volume=c_risk(TypeMM,ValueMM,IterMM,VolumeMinMM,VolumeMaxMM,StartDepoMM);
            SetOrder(buff_sig,i,price,volume,-1);
            m_sdd(buff_sig,i,volume);
            m_ssd(buff_sig,i,"0.########");
           }
         if(OnMartin==1)
           {
            max_price=m_max_price(buff_sig,i)+StepMartin;
            if((real_dir==-1) && (price>max_price))
              {
               volume=c_risk(TypeMM,ValueMM,IterMM,VolumeMinMM,VolumeMaxMM,StartDepoMM);
               SetOrder(buff_sig,i,price,volume,-1);
               m_sdd(buff_sig,i,volume);
               m_ssd(buff_sig,i,"0.########");
              }
           }
        }
      nline= m_nline(buff_sig,i);
      prof = m_vol(buff_sig,i);
      if((real_dir==1) && (nline!=0))
        {
         if((price>=(nline+PipsProfit)) || (CloseLoss==1))
           {
            volume=m_vol(buff_sig,i);
            SetOrder(buff_sig,i,price,volume,-1);
            m_sdd(buff_sig,i,prof);
            m_ssd(buff_sig,i,"0.########");
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int SignalProfit(int buff_sig,int i)
  {
   int sig,real_dir;
   double price,nline;
   sig=0;
   price=close(i);
   c_ind(buff_sig,i,ReCount,0,0,0);
   nline=m_nline(buff_sig,i);
   if((price!=0) && (nline!=0))
     {
      real_dir=m_dir(buff_sig,i);
      if(real_dir==1)
        {
         if(price>=(nline+PipsProfit))
           {
            sig=-1;
           }
        }
      if(real_dir==-1)
        {
         if(price<=(nline-PipsProfit))
           {
            sig=1;
           }
        }
     }
   return sig;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int PrintStat(int buff_sig)
  {
   double max_martin,real_pro_final,max_pick_vol;
   c_ind(buff_sig,0,LimitBars,0,0,0);
   real_pro_final=m_real_pro_final(buff_sig);
   max_pick_vol=m_max_pick_vol_final(buff_sig);
   max_martin=m_max_martin_final(buff_sig);
   prt(2,"Profit [");
   prt_a(2,real_pro_final);
   prt_a(2,"].");
   prt(3,"Max Pick Volume [");
   prt_a(3,max_pick_vol);
   prt_a(3,"].");
   prt(4,"Max Step [");
   prt_a(4,max_martin);
   prt_a(4,"].");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnTick()
  {
   if(e_abot()==1)
     {
      LevelShiftPrice=g_par(17);
      TypeCalculateValute=g_par(18);
      int dir;
      double volume;
      double price;
      dir=g_reg(1);
      volume=g_reg(2);
      price=g_reg(3);
      if(dir==-1)
        {
         OpenSell(price,volume);
        }
      if(dir==1)
        {
         OpenBuy(price,volume);
        }
      prt(5,"Signal [");
      prt_a(5,dir);
      prt_a(5,"]");
     }
   else
     {
      prt(5,"Bot Disabled");
     }
   return 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int SetOrder(int buff_sig,int index,double price,double volume,int dir)
  {
   s_dbuff(buff_sig,index,price,volume,0,"",dir);
   if(index==0)
     {
      s_reg(1,dir);
      s_reg(2,volume);
      s_reg(3,price);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OpenSell(double price,double volume)
  {
   int o_count,time_0;
   o_count=c_trad(-1);
   if(o_count>0)
     {
      time_0=d_trad(0,-1);
      if(this_now(time_0))
        {
         return 0;
        }
     }
   o_count=c_ord(-1);
   if(o_count>0)
     {
      time_0=d_ord(0,-1);
      if(this_now(time_0))
        {
         return 0;
        }
     }
   send(price+LevelShiftPrice,volume,TypeCalculateValute,-1);
   return 1;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OpenBuy(double price,double volume)
  {
   int o_count,time_0;
   o_count=c_trad(1);
   if(o_count>0)
     {
      time_0=d_trad(0,1);
      if(this_now(time_0))
        {
         return 0;
        }
     }
   o_count=c_ord(1);
   if(o_count>0)
     {
      time_0=d_ord(0,1);
      if(this_now(time_0))
        {
         return 0;
        }
     }
   send(price-LevelShiftPrice,volume,TypeCalculateValute,1);
   return 1;
  }
//+------------------------------------------------------------------+

Для лучшего понимания работы почитайте статью "Описание торговой стратегии, основанной на двух индикаторах Moving Average".


Назад

TerminalCoin

2018-05-15 19:40:17