В настоящий момент высокую актуальность имеют решения по переходу с платформы МТ4 - практически прекратившей своё развитие, но широко используемой и имеющей объёмный багаж наработок, на платформу МТ5 - динамично развивающуюся, но относительно небогатую в плане накопленных программных реализаций. Данная статья призвана облегчить перенос программных решений на новую платформу. Рассмотрен пример переноса советника в МТ5 с сохранением функциональности МТ4. Для облегчения понимания материала использован процедурный подход, без объектно ориентированного программирования.
Постановка задачи.
За отправную точку нашего материала возьмем советник автора Sergey Rashevskiy https://www.mql5.com/ru/users/urdala в частности советник NewMartin_V1.1.mq4 https://www.mql5.com/ru/code/17143 код советника приведён ниже
//| NewMartin_V1.0.mq4 |
//| Сергей urdala Рашевский |
//| urdala@mail.ru |
//+------------------------------------------------------------------+
#property copyright "Сергей urdala Рашевский"
#property link "urdala@mail.ru"
#property version "1.00"
#property strict
extern double Lot = 0.1; //Объем первого ордера
extern double TP = 1; //Тейкпрофит в % от цены
extern double SL = 1; //Стоплосс в % от цены
extern double KefLot = 2.0; //Коэффициент увеличения лота в случае убытка
extern int MaxNom = 5; //Максимальная длинна серии ордеров
extern int Shema = 0; //Схема работы
int i=0;
int LastProf = 0;
int Slippage = 1;
bool chk;
double Lots;
string com;
datetime LastTime,LastUpd;
string StrShema="";
//////////////////////////////////////////////////////////////////////
int OnInit()
{
LastTime = 0;
LastUpd = 0;
for(i=1;i<=MaxNom;i++)
{
StrShema=StrShema+"-"+(string)CheckNom(i,Shema);
}
Print("Схема работы : ",StrShema);
return(INIT_SUCCEEDED);
}
//////////////////////////////////////////////////////////////////////
void OnDeinit(const int reason)
{
}
//////////////////////////////////////////////////////////////////////
void OnTick()
{
//////////////////////////////////////////////////////////////////////
//проверка на наличие открытых ордеров
int openord=OrdersTotal();
if(openord>0){LastTime=Time[0];return;}
//////////////////////////////////////////////////////////////////////
//определяем начало бара
if(LastTime == Time[0])return;
LastTime=Time[0];
//////////////////////////////////////////////////////////////////////
//анализируем последний ордер в истории
if(OrderSelect(OrdersHistoryTotal()-1,SELECT_BY_POS,MODE_HISTORY))
{
if(OrderProfit()>0)LastProf=1;
else LastProf=-1;
}
else LastProf=0;
//////////////////////////////////////////////////////////////////////
//рассчитываем объем и открываем ордер
int nom = 1;
if(LastProf<0 && (int)OrderComment()<MaxNom)
{
int sh1 = StringFind(OrderComment(),"(");
int sh2 = StringFind(OrderComment(),")");
if(sh1>=0 && sh2>=0)
{
string stroka = StringSubstr(OrderComment(),sh1+1,sh2-sh1-1);
nom = (int)stroka;
if(nom < MaxNom)
{
Lots= NormalizeDouble(Lot*MathPow(KefLot,(int)nom),2);
nom ++;
com ="("+(string)nom+")";
}
else {Lots= Lot;com = "(1)";nom=1;}
}
else {Lots= Lot;com = "(1)";nom=1;}
}
else {Lots= Lot;com = "(1)";nom=1;}
if(CheckNom(nom,Shema)==0)OpenOrder(Symbol(),OP_BUY,Lots,Ask,Ask-SL/100*Ask,Ask+TP/100*Ask,com,0);
else OpenOrder(Symbol(),OP_SELL,Lots,Bid,Bid+SL/100*Bid,Bid-TP/100*Bid,com,0);
//////////////////////////////////////////////////////////////////////
}
/////////////////////////////////////////////////////////////////////
///////// Функции /////////////////
/////////////////////////////////////////////////////////////////////
int CheckNom(int nom,int shema)
{
int a = nom;
int b = shema >> (a-1);
int c = b & 1;
return(c);
}
//////////////////////////////////////////////////////////////////////
int OpenOrder(string symb,int cmd,double lot,double price,double stoploss,double takeprofit,string comf,int magic)
{
if(AccountFreeMarginCheck(Symbol(),cmd,lot)<=0)return(0);
int err=0,f=0,ticket=0;
color clr=CLR_NONE;
while(f<10)
{
RefreshRates();
if(cmd==0){price=MarketInfo(symb,MODE_ASK);clr=RoyalBlue;}
if(cmd==1){price=MarketInfo(symb,MODE_BID);clr=Red;}
ticket=OrderSend(symb,cmd,lot,NormalizeDouble(price,Digits),Slippage,0,0,comf,magic,0,clr);
err=GetLastError();
if(err==0) break;
Print(WindowExpertName(),symb," при открытии ордера.",err);
f++;
Sleep(1000);
}
if(ticket>0 && (takeprofit!=0 || stoploss!=0))
{
if(OrderSelect(ticket,SELECT_BY_TICKET))ModifyOrder(OrderTicket(),OrderOpenPrice(),stoploss,takeprofit);
}
return(ticket);
}
/////////////////////////////////////////////////////////////////////////
int CloseOrder(int ticket,double lots)
{
int err=0,f=0;
double price=0;
if(!OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))return(0);
if(lots==0)lots=OrderLots();
if(lots<MarketInfo(OrderSymbol(),MODE_MINLOT))lots=MarketInfo(OrderSymbol(),MODE_MINLOT);
while(f<10)
{
RefreshRates();
if(OrderType()==0)price=Bid;
if(OrderType()==1)price=Ask;
if(OrderType()>1){chk=OrderDelete(ticket);return(0);}
chk = OrderClose(ticket,lots,NormalizeDouble(price,Digits),Slippage,Goldenrod);
err = GetLastError();
if(err==0) break;
Print(WindowExpertName(),OrderSymbol()," при закрытии ордера.",err);
f++;
Sleep(1000);
}
return(0);
}
/////////////////////////////////////////////////////////////////////////
int ModifyOrder(int ticket,double price,double stoploss,double takeprofit)
{
int err,f=0;
while(f<10)
{
RefreshRates();
chk = OrderModify(ticket,NormalizeDouble(price,Digits),NormalizeDouble(stoploss,Digits),NormalizeDouble(takeprofit,Digits),0,CLR_NONE);
err = GetLastError();
if(err==0) break;
Print(WindowExpertName(),OrderSymbol()," при модификации ордера",err);
Sleep(1000);
f++;
}
return(0);
}
//////////////////////////////////////////////////////////////////////////
Результатом должен быть советник без изменений работающий как на платформе МТ4, так и на платформе МТ5, как можно более точно совпадающий по механизму и результатам работы с исходным советником.
Описание методики.
…
Рабочий пример.
…
Выводы и результаты.
…