Эксперт 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;
Входные данные
Входные данные можно разделить на несколько частей.
-
Настройки, связанные с сигнальным индикатором
- LimitBars.
- FastLength.
- FastShift.
- SlowLength.
- SlowShift.
-
Настройки рисков (справка)
- TypeMM.
- ValueMM.
- VolumeMinMM.
- VolumeMaxMM.
- IterMM.
- StartDepoMM.
-
Настройки Мартингейла
- OnMartin - Позволяет работать с системой Мартингейла.
- StepMartin - Шаг для системы Мартингейла.
-
Настройки связанные с направлением работы и закрытием
- Dir - Задает направление открытия ордеров или на buy, или на sell.
- CloseLoss - Позволяет закрывать ордера с отрицательным профитом при появлении сигнала в противоположную сторону. Если включен этот параметр, система Мартингейла не может работать.
- ProfitIsSignal - Создает дополнительный сигнал на закрытие при достижении профита PipsProfit.
- PipsProfit - Профит для закрытия, если включено ProfitIsSignal. В случае использования Мартингейла - ProfitIsSignal обязательно включен.
-
Дополнительные настройки
- 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 можно узнать цену безубытка для серии, и текущее направление серии.
Следующим шагом надо, в зависимости от направления, проверить: пробила ли цена уровень нужного профита (используя дистанцию от уровня безубытка). В результате будет сгенерирован сигнал или -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. После использования данной команды мы имеем доступ к актуальным данным в расчетном буфере и можем их использовать. В первую очередь надо узнать фактическое текущее направление серии (это не направление позиции, так как в серии может быть три тренда на buy и один, например последний, - на sell, причем объем последнего меньше, чем суммарный объем троих на buy. В таком случае суммарный сигнал будет на buy, именно это направление выдает команда, направление текущей серии.
В данной функции также проверяется состояние глобальной переменной Dir, в которой указано разрешенное пользователем направление. Если направление разрешает и результат предыдущей команды, сохраненный в переменной action, говорит об успешно выполненной команде, тогда можно продолжать работу.
Дальнейший алгоритм работы в данной ветке имеет два варианта. Первый - когда сделки нет, когда завершена предыдущая серия или просто начало работы. Второй вариант - когда сделки уже есть, есть направление серии и включена возможность Мартингейла:
- (real_dir==0) - условие для первого варианта,
- (OnMartin==1) - условие для второго варианта.
В двух вариантах используется команда определения объема по заданным пользователем параметрам риска c_risk. Также в двух случаях используется пользовательская функция для выставления ордера SetOrder. Команды m_sdd и m_ssd задают информацию, которая будет отображена на чарте в точке сигнала.
В ветке, где используется мартингейл, нам надо узнать, на сколько просела цена в направлении против нашей сделки, для чего узнаем минимальную цену всех трейдов серии. Сравнив эту информацию с текущей ценой, которая записана в переменной price, заполненной в начальной части функции с помощью команды close, также необходимо учесть отклонение минимальной цены на шаг мартингейла, заданный пользователем в настройках и сохраненный глобальной переменной StepMartin. Если все условия второй части выполнены, тогда совершается сделка.
Вернемся на уровень назад, к строке:
nline= m_nline(buff_sig,i);
Дальше необходимо проверить: не надо ли закрыть серию, если она достигла профита PipsProfit. Узнаем уровень безубытка и если текущая цена пробила уровень цены безубытка вместе с профитом, необходимо создать сигнал в противоположную сторону для закрытия серии. Также надо указать суммарный объем серии, который можно узнать.
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".