Уроки по программированию на языке MQL4 от eevviill

Ugar

Гуру форума
Ребятишки. Так дело не пойдёт. Если никто не отпишется всё ли понятно, я продолжать не буду. Если никому не надо, то смысл что я здесь штампую?
Спасибо жмут за уроки, значит здесь они, ученики. А не отписываются, значит все вкурили в тему.
А если быстро никто не нажал спасибо. Ну может просто ученики ещё не у компа. Кто то может и на работу ходит и к компу раз в сутки подходят.
А ученикам, посоветую, не стесняться и давить кнопку спасибо. Так Вы не только обозначите себя что Вы здесь, но и за одно отблагодарите учителя.
И все будут довольны. Учитель знает что не зря кнопки топчет. И репа у него всё шире.
 
Последнее редактирование:

tommy27

Гуру форума
Ребятишки. Так дело не пойдёт. Если никто не отпишется всё ли понятно, я продолжать не буду. Если никому не надо, то смысл что я здесь штампую?

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

А здесь видимо не всё написал
надо
extern string Znak = "";
 

Mango.

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

А здесь видимо не всё написал
надо
extern string Znak = "";

Можно написать вот так, знак + будет значением по умолчанию.
extern string Znak="+";
 

Mango.

Местный житель
Я немного видоизменил то что сделал eevviill, добавил свою функцию myfunc.
#property copyright "eevviill"
#property show_inputs
extern int a = 4;
extern int b = 7;
extern string Znak="+";
string Plus = "+";
string Minus = "-";
string Umnogenie = "*";
string Delenie = "/";
int c;


int start()
{
myfunc();

return(0);
}

int myfunc ()
{
if(Znak==Plus) c=a+b;
if(Znak==Minus) c=a-b;
if(Znak==Umnogenie) c=a*b;
if(Znak==Delenie) c=a/b;
Alert(DoubleToStr(c,8));
}
 

eevviill

Заблокирован
Надо надо, пиши, я например читаю внимательно, просто этот материал уже изучен подключусь там где будет новое и непонятное.

А здесь видимо не всё написал
надо
extern string Znak = "";
Как раз там желательно(для красоты) чтобы по умолчанию ничего не было.
 

eevviill

Заблокирован
Урок 6 - скрипт открывающий ордер с заданым риском

Добрый вечер. Расписывать вступную речь не буду(она никому не нужна).

Скрипт.
PHP:
#property copyright "eevviill"
#property show_inputs

extern string Risk_by_trade_in_percents;
extern double Percent = 10;
extern bool buy = false;
extern bool sell = false;
 
extern int SL = 44;
extern int TP = 41; 
int sell_TP;
int buy_TP;
int sell_SL;
int buy_SL;
extern int Slippage = 4;
extern int Magic = 3414;
double Margin;
double Cost_of_1_lot;
double Lot_step;
double Lot_rounded;
double Max_lot;
double Min_lot;
int start()
  {
1)Margin = AccountFreeMargin();
2)Cost_of_1_lot = MarketInfo(Symbol(),MODE_MARGINREQUIRED);  
3)Lot_step = MarketInfo(Symbol(),MODE_LOTSTEP);
4)Lot_rounded = MathFloor(Margin*Percent/100/Cost_of_1_lot/Lot_step)*Lot_step ;
5)Min_lot = MarketInfo(Symbol(),MODE_MINLOT);
Max_lot = MarketInfo(Symbol(),MODE_MAXLOT);
6)if(Lot_rounded<Min_lot) Lot_rounded = Min_lot;
if(Lot_rounded>Max_lot) Lot_rounded = Max_lot;
7)double SLbuy=0, SLsell=0,TPbuy=0,TPsell=0; 
8)if(SL>0) {SLbuy=Ask-SL*Point; SLsell=Bid+SL*Point;}
if(TP>0) {TPbuy=Ask+TP*Point;TPsell=Bid-TP*Point;}
9)while(!IsTradeAllowed()) Sleep(1000);
10)if(buy) OrderSend(Symbol(),OP_BUY,Lot_rounded,Ask,Slippage,SLbuy,TPbuy,"Risk by trade",Magic,0,Blue);
while(!IsTradeAllowed()) Sleep(1000);
if(sell) OrderSend(Symbol(),OP_SELL,Lot_rounded,Bid,Slippage,SLsell,TPsell,"Risk by trade",Magic,0,Orange);
11)if(buy) Alert(Symbol(),"  Buy  ",Ask,"  ",Percent,"%  ",Lot_rounded);
if(sell) Alert(Symbol(),"  Sell  ",Bid,"  ",Percent,"%  ",Lot_rounded);
   return(0);
  }
Пояснение.
До функции Start() это всё объявление переменных. Это мы уже знаем.
1)Функция AccountFreeMargin() возвращает суму свободных средств на счете. Тоесть если в терминале у нас 400 доларов в средствах, то переменной Margin будет присвоено значение 400.00.
2)Функция MarketInfo(Symbol(),MODE_MARGINREQUIRED) узнаёт то условие торговли у нашего брокера что нам надо. Имеет 2 свойства.
2.1)MarketInfo(Symbol(),) название валютной пары. Если Symbol(), то значит проверка идёт по той валютной паре, к графику какой мы прикрипили скрипт.
2.2)MarketInfo(,MODE_MARGINREQUIRED) это то количество денег, что надо для покупки 1-го лота валютной пары.
3)MarketInfo(Symbol(),MODE_LOTSTEP) тоже что и в придыдущем примере, только MODE_LOTSTEP значит минимальный шаг на который мы можем увеличивать объём ордера.
4)Функция MathFloor округляет значения чегото то до 2 цифр после запятой. Это нам нужно, для того чтобы округлить наш 4-ох значный после запятой лот.
5)Функция MarketInfo(Symbol(),MODE_MINLOT). MODE_MINLOT это минимальный лот который разрешает брокер.
6)if(Lot_rounded<Min_lot) Lot_rounded = Min_lot; Здесь мы указали что если наш рисковый лот меньше минимальнодопустимого лота, то рисковый лот будет минимальнодопустимым.
7)double SLbuy=0, SLsell=0,TPbuy=0,TPsell=0; Здесь мы объявили переменные для ТП и СЛ. Они должны стоять со значениями 0.
8)if(SL>0) {SLbuy=Ask-SL*Point; SLsell=Bid+SL*Point;}
Здесь, мы указали что если СЛ больше 0, то(расчёт СЛ).
Квадратные скобки нужны если после if мы используем 2 и больше действия в случае if(истина).
Расчёт СЛ нужен потому что в ордере что мы открываем нужно указывать цену СЛ, а не на сколько пунктов она от цены открытия.
Point это то что переводит наш СЛ в цену.
9)Функция while(!IsTradeAllowed()) Sleep(1000);
while будет выполнять(зацикливание) то что у неё в скобках пока оно не станет ЛОЖЬ. (!IsTradeAllowed()) значит что скрипт не будет дальше выполнятся, пока не будет разрешена торговля(отключение терминала, торговля запрещена и т.д.) IsTradeAllowed значит что разрешена торговля, но у нас стоит знак ! значит не разрешена.
Sleep(1000) это количество милисекунд на выполнение цыкла.
10)if(buy) OrderSend(Symbol(),OP_BUY,Lot_rounded,Ask,Slippage,SLbuy,TPbuy,"Risk by trade",Magic,0,Blue);
Это уже окрытие ордера. Мы написали условие для его открытия, а именно если мы поставим buy=true(при прикреплении к графику).
OrederSend имеет 11 свойств.
10.1)Валютная пара.
10.2)бай, сел, бай стоп, сел стоп, бай лимит, сел лимит.
10.3)Лот.
10.4)Цена. Ask Bid.
10.5)Проскальзывание(в пунктах).
10.6)СЛ(в цене).
10.7)ТП(в цене).
10.8)Коментарий(будет виден в столбце Коментарии).
10.9)Магик намбер. Индивидуальный номер ордера.
10.10)Время истечения действия отложенного ордера.
10.11)Цвет стрелки на графике при открытии ордера.
11)if(buy) Alert(Symbol()," Buy ",Ask," ",Percent,"% ",Lot_rounded);
Это обычный алерт, но с условием и показан пример как делать растояние между значением переменных.
 
Последнее редактирование модератором:

krezi

Активный участник
eevviill, товарищ учите людей сразу использовать функции. Но всё равно респект за труд
 

Ugar

Гуру форума
eevviill, товарищ учите людей сразу использовать функции.
Учит как умеет. Кроме того, у каждого программиста есть выбор как именно писать. Сколько использовать пользовательских функций и использовать ли вообще.
Я много раз встречал что внутри start() нахлодится одна функция и все расчёты в ней. А она ссылается ещё на функции... ИМХО дурь. Есть же функция старт. Почему брезгуют рассчёты в ней делать. Лишние функции, лишние нагрузки на комп.
А некоторые любители составлять программу из пользовательских функции как из модулей вообще не заботятся о работе программы.
Надо обнаружить ордера. Накидали функций. Одна в цикле перебрала все ордера и вернула количество Buy ордеров, другая аналогично Sell, третья BuyStop, четвёртая Sellstop. Потом ещё фкнуция трала переберает ордера. Потом функция удаления отложенных ордеров перебирает ордера... Программист лентяй. Конечно ему проще заготовленных функций накидать в код. Но этот код будет такой же тормоз как и этот программист. Ведь можно всё это выполнить за один перебор ордеров в цикле, без всяких функций. Конечно надо иметь некоторые функции как модули, но применять их надо с умом. Что бы на работе программы это не отражалось.
Конечно если в коде несколько раз повторяется какой то кусок, то лучше его вынести в функцию и просто несколько раз её вызывать. Код будет менее захламлён и ошибки искать легче.
ИМХО Всё надо использовать с умом. А начинающим всё пихать в пользовательские функции вообще вредно. Научитесь сначала без них писать. Наклепаете кривых функций, начнёте ими делиться, а ведь те коды которые здесь приводятся хороши только теоретически, в качестве примера. В практическом применении к ним будет много вопросов у пользователя. Со временем сами на них наткнётесь и решите. Наступание на собственные грабли, это и есть набор опыта. А наступане на чужие грабли, это глупость.
 

krezi

Активный участник
Ugar, ну к примеру у нас задача считать сколько ордеров в бай сколько в сэлл, и что? мы будем в инт старт описывать это? ведь разница только в проверке ордеров на счету (OP_SELL || OP_BUY)....
Передали переменную в функцию и всё, а в инт старт дублировать то же самое не резонно.

ИМХО: я в инт старт описываю лишь логику проверок и действий (если ордеров бай нет и сигналит в бай{открыть в бай}).

P.S. сразу не увидел (только начал програмировать)
 

Ugar

Гуру форума
Ugar, ну к примеру у нас задача считать сколько ордеров в бай сколько в сэлл, и что? мы будем в инт старт описывать это? ведь разница только в проверке ордеров на счету (OP_SELL || OP_BUY)....
Передали переменную в функцию и всё, а в инт старт дублировать то же самое не резонно.
Ничего дублировать не надо. Я уже описал своё мнение. Делайте как хотите.
 

Ugar

Гуру форума
Уважаемые ученики. Если кто то вам говорит что "так писать не надо", а вы считаете что "только так и надо". Делайте как вы считаете и никого не слушайте. Это ваши грабли и если вы добросовестно на все наступите, они вам дадут ваш опыт.
И наоборот. Если есть задача, и никак не даётся, не зазорно заглянуть в код чужого программиста что бы узнать как он её решил.

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

eevviill

Заблокирован
Урок 7 - советник на основе МА и ATR

Сегодня будем писать и разбирать советник на основе МА и ATR.
Вход при пересечении цены первой МА и ATR больше определённого уровня.
Выход при пересечении цены второй МА или ТП||СЛ.

Советник.

PHP:
#property copyright "eevviill"
 
extern double Lot = 0.1;
extern int MA_Enter_period = 30;
extern int MA_Exit_period = 60;
extern double ATR_level=0.0002;
extern int Size_of_Enter_Candle=5;
extern int Stop_Loss = 24;
extern int Take_Profit = 21;
extern int Slippage = 4;

int Magic = 284;
double MA1;
double MA2;
double ATR;

int init()
  {
return(0);
  }
int deinit()
  {
return(0);
  }
 
int start()
  {
 1)MA1=iMA(Symbol(),0,MA_Enter_period,0,MODE_LWMA,PRICE_CLOSE,1);
 MA2=iMA(Symbol(),0,MA_Exit_period,0,MODE_LWMA,PRICE_CLOSE,1);
 2)ATR=iATR(Symbol(),0,14,1);
 
 
double SLbuy=0, SLsell=0,TPbuy=0,TPsell=0; 
if(Stop_Loss>0) {SLbuy=Ask-Stop_Loss*Point; SLsell=Bid+Stop_Loss*Point;}
if(Take_Profit>0) {TPbuy=Ask+Take_Profit*Point;TPsell=Bid-Take_Profit*Point;}
 
3)if(Volume[0]>1) return;
while(!IsTradeAllowed()) Sleep(2000);
4)if(OrdersTotal()<1)
5){if(Open[1]>MA1&&Close[1]<MA1&&ATR>=ATR_level&&High[1]-Low[1]>=Size_of_Enter_Candle*Point) OrderSend(Symbol(),OP_SELL,Lot,Bid,Slippage,SLsell,TPsell,"MA",Magic,0,Green);
 if(Open[1]<MA1&&Close[1]>MA1&&ATR>=ATR_level&&High[1]-Low[1]>=Size_of_Enter_Candle*Point) OrderSend(Symbol(),OP_BUY,Lot,Ask,Slippage,SLbuy,TPbuy,"MA",Magic,0,Green);}
 
if(Volume[0]>1) return;
while(!IsTradeAllowed()) Sleep(2000);
6)OrderSelect(0,SELECT_BY_POS);
7)if(OrderMagicNumber()==284) 
 8){int ticket = OrderTicket();
 9)if (Open[1]>MA2&&Close[1]<MA2 && OrderType()==OP_BUY) 
10)OrderClose(ticket,Lot,Bid,Slippage,OrangeRed);
 if (Open[1]<MA2&&Close[1]>MA2 && OrderType()==OP_SELL) OrderClose(ticket,Lot,Ask,Slippage,OrangeRed);}
 return(0);
 }

Пояснение.
1)MA1=iMA(Symbol(),0,MA_Enter_period,0,MODE_LWMA,PRICE_CLOSE,1);
Здесь мы присвоили переменной МА1 значение(цену где находится) индикатор МovingАvarage. Если индикатор встроееный в терминал, то перед его названием надо дописать i
МА имеет 7 свойств.
1.1)Название валютной пары(если Symbol(), то текущая валютная пара).
1.2)Таймфрейм(если 0, то текущий ТФ).
1.3)Период МА.
1.4)Сдвиг индикатора относительно ценового графика.
1.5)Метод усреднения(Simple==SMA и т.д.).
1.6)Цена закрытия или открытия свечи(цена открытия свечи==PRICE_OPEN и т.д.).
1.7)С какой свечи брать инфомацию(0==с текущей,1==с прошлой закрытой свечи,2==с позапрошлой закрытой свечи и .т.д.).
2)ATR=iATR(Symbol(),0,14,1);
Здесь мы присвоили переменной ATR значение(уровень) индикатора ATR. Имеет 4 свойства.
2.1)Название валютной пары(если Symbol(), то текущая валютная пара).
2.2)Таймфрейм(если 0, то текущий ТФ).
2.3)Период индикатора.
2.4)С какой свечи брать инфомацию(0==с текущей,1==с прошлой закрытой свечи,2==с позапрошлой закрытой свечи и .т.д.).
3)if(Volume[0]>1) return; здесь мы написали чтобы персчёт начинался только с новой свечи.
Volume содержит данные всех тиков. [0] здесь записывается номер свечи. Выходит мы написали если на свече больше 1 тика, то остальные действия прерываются.
4)if(OrdersTotal()<1) здесь мы написали что если открытых(и отложенных) ордеров меньше 1, то... Функция rdersTotal() возвращает значение всех открытых и отложеных ордеров.
5){if(Open[1]>MA1&&Close[1]<MA1&&ATR>=ATR_level&&High[1]-Low[1]>=Size_of_Enter_Candle*Point) здесь мы написали условие для открытия ордера, а именно SELL. Итак.
5.1)Open[1]>MA1&&Close[1]<MA1
Open это цена открытия свечи. Номер свечи записывается в[](0==текущая свеча,1==прошлая закрытая свеча,2==позапрошлая закрытая свеча и т.д.).
Close это цена закрытия свечи. Номер свечи записывается в[](0==текущая свеча,1==прошлая закрытая свеча,2==позапрошлая закрытая свеча и т.д.).
5.2)ATR>=ATR_level здесь мы указали что минимальный уровень ATR должен ровнятся или быть больше ATR_level.
5.3)High[1]-Low[1]>=Size_of_Enter_Candle*Point здесь мы указали что входная свеча должа быть больше определённой величины.
High это максимальная цена свечи. Номер свечи записывается в[](0==текущая свеча,1==прошлая закрытая свеча,2==позапрошлая закрытая свеча и т.д.).
Low это минимальная цена свечи. Номер свечи записывается в[](0==текущая свеча,1==прошлая закрытая свеча,2==позапрошлая закрытая свеча и т.д.).
6)OrderSelect(0,SELECT_BY_POS); если нам надо закрыть ордер, то надо сначало его выбрать с помощю функции OrderSelect(). Она имеет 3 свойства.
6.1)Если второе свойство SELECT_BY_POS, то здесь вводим порядковый номер в списке открытых ордеров. Если SELECT_BY_TICKET, то номер тикета.
6.2)SELECT_BY_POS==выбор ордера по порядковому номеру в списке.
SELECT_BY_TICKET==выбор ордера по тикету ордера.
6.3)MODE_TRADES==выбор с открытых ордеров.
MODE_HISTORY==выбор с закрытых ордеров.
7)if(OrderMagicNumber()==284) здесь мы использовали функцию OrderMagicNumber(). Эта функция находит(среди выбраных) ордер с определённым меджиком.
8)int ticket = OrderTicket() здесь мы присвоили переменной int ticket тикет выбраного нами ордера с помощю функции OrderTicket()
9)if (Open[1]>MA2&&Close[1]<MA2 && OrderType()==OP_BUY) здесь мы указали условие на закрытие ордера.
9.1)OrderType()==OP_BUY значит что мы с помощю функции OrderType()(которая возвращает тип нашего ордера) будем закрывать только BUY.
10)OrderClose(ticket,Lot,Bid,Slippage,OrangeRed); это функция закрытия ордера. Имеет 5 свойств.
10.1)Номер тикета.
10.2)Лот закрытия.
10.3)Цена(Bis,Ask).
10.4)Проскальзывание.
10.5)Цвет значка на графике при закрытиии ордера.
 

Вложения

  • Leeson 7.jpg
    Leeson 7.jpg
    69,9 КБ · Просмотры: 233
  • MA - eevviill.mq4
    1,6 КБ · Просмотры: 141
Последнее редактирование модератором:

KrasKosha

Активный участник
Здравствуйте!
Пока пытался сформулировать, что не понял, сам разобрался.
Остался такой вопрос: почему
if(Volume[0]>1) return;
while(!IsTradeAllowed()) Sleep(2000); стоит там, где стоит?
Расчет ТП и СЛ выполняется 1 раз, может его лучше поставить в init() ?
Т.е.:
double SLbuy=0, SLsell=0,TPbuy=0,TPsell=0;

int init() {
if(Stop_Loss>0) {SLbuy=Ask-Stop_Loss*Point; SLsell=Bid+Stop_Loss*Point;}
if(Take_Profit>0) {TPbuy=Ask+Take_Profit*Point;TPsell=Bid-Take_Profit*Point;}
return(0);
}
int deinit()
{
return(0);
}

int start()
{
if(Volume[0]>1) return;
while(!IsTradeAllowed()) Sleep(2000);
MA1=iMA(Symbol(),0,MA_Enter_period,0,MODE_LWMA,P RICE_CLOSE,1);
MA2=iMA(Symbol(),0,MA_Exit_period,0,MODE_LWMA,PRIC E_CLOSE,1);
ATR=iATR(Symbol(),0,14,1);
и далее.

Просьба к сенсею :). Учителю то есть. Ни в коем случае не прекращать начатое!
В конце урока сообщать о теме следующего, да и озвучить общий, или хотя бы ближайший план.
Пояснения и комментарии писать до- или сразу после комментируемой строки.
Думаю, будет гораздо удобнее. А то вдруг начнем рассматривать что-то типа крот-BUY.mql ( на первой странице, 28 кб ) :).
С уважением.
 

eevviill

Заблокирован
1)if(Volume[0]>1) return;
while(!IsTradeAllowed()) Sleep(2000); стоит там, где стоит?

2)Расчет ТП и СЛ выполняется 1 раз, может его лучше поставить в init() ?


3)ближайший план.
4)Пояснения и комментарии писать до- или сразу после комментируемой строки.
Добрый день.

1)Это условие при котором расчёты ведутся только на первом тике нового бара. Если мы его поставим в конец, то от него не будет толку.
2)Почему один раз??? Для каждого ордера ТП и СЛ же разный. Соответственно при открытии ордера будет по новому пересчитан ТП и СЛ.
3)
функция for()
трейлинг стоп
пользовательские функции
советник по откр по времени
создание индикатора
фунция iCustom
4)Буду оформлять как и раньше. Если писать коментарий сразу в строке или после неё, то всё будет сливатся.

Уроки будут выходить редко. На освоение нового материала нужно время.
 

Ugar

Гуру форума
int init() {
if(Stop_Loss>0) {SLbuy=Ask-Stop_Loss*Point; SLsell=Bid+Stop_Loss*Point;}
if(Take_Profit>0) {TPbuy=Ask+Take_Profit*Point;TPsell=Bid-Take_Profit*Point;}
return(0);
}
Так нельзя. init() выполняется один раз, при запуске советника. Во время работы советника цена меняется. Это надо считать перед открытием ордера, относительно той Ask и Bid которая будет в этот момент.
Вообще, с init() нужно быть осторожней. В ней не все правильно будет работать, даже из того что нужно считать один раз.
 

Bill Vill

Новичок форума
eevviill Добрый вечер )Скажите вы под Нинзю пишите? Скрипты вот сетки отложенные ордера и т.д.
 

KrasKosha

Активный участник
1) Понятно.
2) Понятно. Прокатило бы если
int init() {
if(Stop_Loss>0) {SLbuy=Stop_Loss*Point; SLsell=Stop_Loss*Point;}
if(Take_Profit>0) {TPbuy=Take_Profit*Point;TPsell=Take_Profit*Point;}
return(0);
}
int start()
{
======= ===== =====
OrderSend(Symbol(),OP_SELL,Lot,Bid,Slippage,Bid+SLsell ,Bid-TPsell,"MA",Magic,0,Green);
======= ===== =====
OrderSend(Symbol(),OP_BUY,Lot,Ask,Slippage,Ask-SLbuy,Ask+TPbuy,"MA",Magic,0,Green);
======= ===== =====

?

3) Имею шкурный интерес :)
Можно помимо трейлинг стопа рассмотреть трейлинг отложенных ордеров,
при этом чтобы трал не попадал в некоторую зону вблизи открытых ордеров?
4) Попробовал оформить комментарий в предлагаемом варианте - действительно
получилась ерунда... :(
 
Верх