Меня уже давно интересовала тема создания мультивалютных советников на MQL4, но до последнего времени я только правил чужие коды и не было своей основы. И вот благодаря следующему заказу мой первый мультик на MQL4 увидел свет
zakaz.opentraders.ru/30606.html
Все оказалось достаточно просто, для людей знакомых с языком не составит особого труда внести небольшие изменения в код обычного советника.
Советник открывает и закрывает позиции при пересечении верхнего и нижнего ADX.
Пусть наш первоначальный код выглядит таким образом:
//+------------------------------------------------------------------+
//| ADX.mq4 |
//| Copyright 2016, AM2 |
//| http://www.forexsystems.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, AM2"
#property link "http://www.forexsystems.biz"
#property version "1.00"
#property strict
extern string s="Настройки советника";
extern double Lots = 0.01; // лот
extern int TakeProfit = 3333; // Тейк
extern int StopLoss = 3333; // Лосс
extern int Slip = 30; // Проскальзывание
extern int Magic = 123; // Магик
extern string sss="Настройки индикатора ADX";
//--- input ADX parameters
extern int ADXPeriod=14; // ADX
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
Comment("");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
OpenPos();
ClosePos();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void PutOrder(int type,double price)
{
int r=0,d=0;
color clr=Green;
double sl=0,tp=0, pp=0;
pp= MarketInfo(NULL,MODE_POINT);
d =(int)MarketInfo(NULL,MODE_DIGITS);
if(type==1 || type==3 || type==5)
{
clr=Red;
if(StopLoss>0) sl=NormalizeDouble(price+StopLoss*pp,d);
if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*pp,d);
}
if(type==0 || type==2 || type==4)
{
clr=Blue;
if(StopLoss>0) sl=NormalizeDouble(price-StopLoss*pp,d);
if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*pp,d);
}
r=OrderSend(NULL,type,Lots,NormalizeDouble(price,d),Slip,sl,tp,"",Magic,0,clr);
return;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OpenPos()
{
double bid=0,ask=0;
double padx1=iADX(NULL,0,ADXPeriod,0,MODE_PLUSDI,1);
double padx2=iADX(NULL,0,ADXPeriod,0,MODE_PLUSDI,2);
double madx1=iADX(NULL,0,ADXPeriod,0,MODE_MINUSDI,1);
double madx2=iADX(NULL,0,ADXPeriod,0,MODE_MINUSDI,2);
if(CountTrades()<1)
{
bid = MarketInfo(NULL,MODE_BID);
ask = MarketInfo(NULL,MODE_ASK);
//buy
if(padx2>madx2 && padx1<madx1)
{
PutOrder(0,ask);
}
//sell
if(padx2<madx2 && padx1>madx1)
{
PutOrder(1,bid);
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ClosePos()
{
double bid=0,ask=0;
double padx1=iADX(NULL,0,ADXPeriod,0,MODE_PLUSDI,1);
double padx2=iADX(NULL,0,ADXPeriod,0,MODE_PLUSDI,2);
double madx1=iADX(NULL,0,ADXPeriod,0,MODE_MINUSDI,1);
double madx2=iADX(NULL,0,ADXPeriod,0,MODE_MINUSDI,2);
if(CountTrades()>0)
{
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
{
if(OrderType()==OP_BUY)
{
if(padx2<madx2 && padx1>madx1)
{
bid=MarketInfo(NULL,MODE_BID);
if(!OrderClose(OrderTicket(),OrderLots(),bid,Slip,White))
Print("OrderClose error ",GetLastError());
}
}
if(OrderType()==OP_SELL)
{
if(padx2>madx2 && padx1<madx1)
{
ask=MarketInfo(NULL,MODE_ASK);
if(!OrderClose(OrderTicket(),OrderLots(),ask,Slip,White))
Print("OrderClose error ",GetLastError());
}
}
}
}
}
return;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CountTrades()
{
int count=0;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
{
if(OrderType()<2) count++;
}
}
}
return(count);
}
//+------------------------------------------------------------------+
Чтобы переделать его в мульта добавим в настройки список пар по которым будем торговать:
extern string s="Выбор валютной пары";
extern string Symbol1 = "EURUSD";
extern string Symbol2 = "GBPUSD";
extern string Symbol3 = "";
extern string Symbol4 = "";
extern string Symbol5 = "";
extern string Symbol6 = "";
extern string Symbol7 = "";
extern string Symbol8 = "";
extern string Symbol9 = "";
Для установки ордера я пользуюсь следующей самописной функцией:
void PutOrder(int type,double price)
{
int r=0,d=0;
color clr=Green;
double sl=0,tp=0, pp=0;
pp= MarketInfo(symb,MODE_POINT);
d =(int)MarketInfo(symb,MODE_DIGITS);
if(type==1 || type==3 || type==5)
{
clr=Red;
if(StopLoss>0) sl=NormalizeDouble(price+StopLoss*pp,d);
if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*pp,d);
}
if(type==0 || type==2 || type==4)
{
clr=Blue;
if(StopLoss>0) sl=NormalizeDouble(price-StopLoss*pp,d);
if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*pp,d);
}
r=OrderSend(NULL,type,Lots,NormalizeDouble(price,d),Slip,sl,tp,"",Magic,0,clr);
return;
}
Чтобы сделать ее мультивалютной, нужно всего то сделать 2 замены:
1. Меняем строку
void PutOrder(int type,double price)
на
void PutOrder(int type,double price,string symb)
т.е. добавляем во входные параметры функции символ по которому будем торговать
string symb
2. И в строке:
r=OrderSend(NULL,type,Lots,NormalizeDouble(price,d),Slip,sl,tp,"",Magic,0,clr);
пропишем этот самый символ
symb
r=OrderSend(symb,type,Lots,NormalizeDouble(price,d),Slip,sl,tp,"",Magic,0,clr);
В итоге наша функция примет вид:
void PutOrder(int type,double price,string symb)
{
int r=0,d=0;
color clr=Green;
double sl=0,tp=0, pp=0;
pp= MarketInfo(symb,MODE_POINT);
d =(int)MarketInfo(symb,MODE_DIGITS);
if(type==1 || type==3 || type==5)
{
clr=Red;
if(StopLoss>0) sl=NormalizeDouble(price+StopLoss*pp,d);
if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*pp,d);
}
if(type==0 || type==2 || type==4)
{
clr=Blue;
if(StopLoss>0) sl=NormalizeDouble(price-StopLoss*pp,d);
if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*pp,d);
}
r=OrderSend(symb,type,Lot(symb,Magic),NormalizeDouble(price,d),Slip,sl,tp,"",Magic,0,clr);
return;
}
Сейчас поправим подсчет позиций:
Было:
int CountTrades()
{
int count=0;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==Symbol() && OrderMagicNumber()==magic)
{
if(OrderType()<2) count++;
}
}
}
return(count);
}
Стало:
int CountTrades(string symb)
{
int count=0;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==symb && OrderMagicNumber()==Magic)
{
if(OrderType()<2) count++;
}
}
}
return(count);
}
Далее подобным образом исправим функцию для открытия позиции:
void OpenPos()
{
double bid=0,ask=0;
double padx1=iADX(NULL,0,ADXPeriod,0,MODE_PLUSDI,1);
double padx2=iADX(NULL,0,ADXPeriod,0,MODE_PLUSDI,2);
double madx1=iADX(NULL,0,ADXPeriod,0,MODE_MINUSDI,1);
double madx2=iADX(NULL,0,ADXPeriod,0,MODE_MINUSDI,2);
if(CountTrades()<1)
{
bid = MarketInfo(NULL,MODE_BID);
ask = MarketInfo(М,MODE_ASK);
//buy
if(padx2>madx2 && padx1<madx1)
{
PutOrder(0,ask);
}
//sell
if(padx2<madx2 && padx1>madx1)
{
PutOrder(1,bid);
}
}
}
После всех замен получим:
void OpenPos(string symb)
{
double bid=0,ask=0;
double padx1=iADX(symb,0,ADXPeriod,0,MODE_PLUSDI,1);
double padx2=iADX(symb,0,ADXPeriod,0,MODE_PLUSDI,2);
double madx1=iADX(symb,0,ADXPeriod,0,MODE_MINUSDI,1);
double madx2=iADX(symb,0,ADXPeriod,0,MODE_MINUSDI,2);
if(CountTrades(symb)<1)
{
bid = MarketInfo(symb,MODE_BID);
ask = MarketInfo(symb,MODE_ASK);
//buy
if(padx2>madx2 && padx1<madx1)
{
PutOrder(0,ask,symb);
}
//sell
if(padx2<madx2 && padx1>madx1)
{
PutOrder(1,bid,symb);
}
}
}
Сейчас у нас все функции готовы и осталось совсем немного, сделать функции открытия и закрытия позиций по всем символам.
Это у нас было сначала:
void OnTick()
{
OpenPos();
ClosePos();
}
А теперь с учетом всех символов:
if(Symbol1!=""){OpenPos(Symbol1); ClosePos(Symbol1);}
if(Symbol2!=""){OpenPos(Symbol2); ClosePos(Symbol2);}
if(Symbol3!=""){OpenPos(Symbol3); ClosePos(Symbol3);}
if(Symbol4!=""){OpenPos(Symbol4); ClosePos(Symbol4);}
if(Symbol5!=""){OpenPos(Symbol5); ClosePos(Symbol5);}
if(Symbol6!=""){OpenPos(Symbol6); ClosePos(Symbol6);}
if(Symbol7!=""){OpenPos(Symbol7); ClosePos(Symbol7);}
if(Symbol8!=""){OpenPos(Symbol8); ClosePos(Symbol8);}
if(Symbol9!=""){OpenPos(Symbol9); ClosePos(Symbol9);}
Если символ не пустая строка, торгуем.
В итоге поличили достаточно компактный код мультивалютного советника для 9 пар:
//+------------------------------------------------------------------+
//| Mult.mq4 |
//| Copyright 2015, AM2 |
//| http://www.forexsystems.biz |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, AM2"
#property link "http://www.forexsystems.biz"
#property version "1.00"
#property strict
extern string s="Выбор валютной пары";
extern string Symbol1 = "EURUSD";
extern string Symbol2 = "GBPUSD";
extern string Symbol3 = "";
extern string Symbol4 = "";
extern string Symbol5 = "";
extern string Symbol6 = "";
extern string Symbol7 = "";
extern string Symbol8 = "";
extern string Symbol9 = "";
extern string ss="Настройки советника";
extern double Lots = 0.01; // лот
extern int TakeProfit = 3333; // Тейк
extern int StopLoss = 3333; // Лосс
extern int Slip = 30; // Проскальзывание
extern int Magic = 123; // Магик
extern string sss="Настройки индикатора ADX";
//--- input ADX parameters
extern int ADXPeriod=14; // ADX
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
Comment("");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(Symbol1!=""){OpenPos(Symbol1); ClosePos(Symbol1);}
if(Symbol2!=""){OpenPos(Symbol2); ClosePos(Symbol2);}
if(Symbol3!=""){OpenPos(Symbol3); ClosePos(Symbol3);}
if(Symbol4!=""){OpenPos(Symbol4); ClosePos(Symbol4);}
if(Symbol5!=""){OpenPos(Symbol5); ClosePos(Symbol5);}
if(Symbol6!=""){OpenPos(Symbol6); ClosePos(Symbol6);}
if(Symbol7!=""){OpenPos(Symbol7); ClosePos(Symbol7);}
if(Symbol8!=""){OpenPos(Symbol8); ClosePos(Symbol8);}
if(Symbol9!=""){OpenPos(Symbol9); ClosePos(Symbol9);}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void PutOrder(int type,double price,string symb)
{
int r=0,d=0;
color clr=Green;
double sl=0,tp=0, pp=0;
pp= MarketInfo(symb,MODE_POINT);
d =(int)MarketInfo(symb,MODE_DIGITS);
if(type==1 || type==3 || type==5)
{
clr=Red;
if(StopLoss>0) sl=NormalizeDouble(price+StopLoss*pp,d);
if(TakeProfit>0) tp=NormalizeDouble(price-TakeProfit*pp,d);
}
if(type==0 || type==2 || type==4)
{
clr=Blue;
if(StopLoss>0) sl=NormalizeDouble(price-StopLoss*pp,d);
if(TakeProfit>0) tp=NormalizeDouble(price+TakeProfit*pp,d);
}
r=OrderSend(symb,type,Lots,NormalizeDouble(price,d),Slip,sl,tp,"",Magic,0,clr);
return;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OpenPos(string symb)
{
double bid=0,ask=0;
double padx1=iADX(symb,0,ADXPeriod,0,MODE_PLUSDI,1);
double padx2=iADX(symb,0,ADXPeriod,0,MODE_PLUSDI,2);
double madx1=iADX(symb,0,ADXPeriod,0,MODE_MINUSDI,1);
double madx2=iADX(symb,0,ADXPeriod,0,MODE_MINUSDI,2);
if(CountTrades(symb)<1)
{
bid = MarketInfo(symb,MODE_BID);
ask = MarketInfo(symb,MODE_ASK);
//buy
if(padx2>madx2 && padx1<madx1)
{
PutOrder(0,ask,symb);
}
//sell
if(padx2<madx2 && padx1>madx1)
{
PutOrder(1,bid,symb);
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ClosePos(string symb)
{
double bid=0,ask=0;
double padx1=iADX(symb,0,ADXPeriod,0,MODE_PLUSDI,1);
double padx2=iADX(symb,0,ADXPeriod,0,MODE_PLUSDI,2);
double madx1=iADX(symb,0,ADXPeriod,0,MODE_MINUSDI,1);
double madx2=iADX(symb,0,ADXPeriod,0,MODE_MINUSDI,2);
if(CountTrades(symb)>0)
{
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==symb && OrderMagicNumber()==Magic)
{
if(OrderType()==OP_BUY)
{
if(padx2<madx2 && padx1>madx1)
{
bid=MarketInfo(symb,MODE_BID);
if(!OrderClose(OrderTicket(),OrderLots(),bid,Slip,White))
Print("OrderClose error ",GetLastError());
}
}
if(OrderType()==OP_SELL)
{
if(padx2>madx2 && padx1<madx1)
{
ask=MarketInfo(symb,MODE_ASK);
if(!OrderClose(OrderTicket(),OrderLots(),ask,Slip,White))
Print("OrderClose error ",GetLastError());
}
}
}
}
}
return;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CountTrades(string symb)
{
int count=0;
for(int i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if(OrderSymbol()==symb && OrderMagicNumber()==Magic)
{
if(OrderType()<2) count++;
}
}
}
return(count);
}
//+------------------------------------------------------------------+
П.С. Также можно сделать мультивалютный советник, который будет торговать по всем символам в окне рынка или путем перебора символов в массиве строк, мультик гридер или усреднитель. С новыми идеями и доработками можете обращаться в
Стол заказов MQL
Исходные коды советников также можно скачать по ссылке:
www.opentraders.ru/downloads/1063/
Комментарии (9)
19 lorik Сообщений: 357 - Лариса
13 Fargo Сообщений: 495
3 kiboss Сообщений: 14
16 cerber04 Сообщений: 409
В тексте статьи все есть.
35 AM2 Автор Сообщений: 16419 - Андрей
считает ордера отдельно по каждому символу?
3 kiboss Сообщений: 14
В мультике да.
35 AM2 Автор Сообщений: 16419 - Андрей
2 Cerberus Сообщений: 11 - Cerberus
2 sir Сообщений: 2
Зарегистрируйтесь или авторизуйтесь, чтобы оставить комментарий