Советник форекс — это просто. Терминал MT4 предоставляет платформу и программные средства для автоматизации торговых систем на языке MQL4.
Язык программирования MQL4 довольно не сложен для изучения, очень схож с языком C и содержит большое количество специальных функций ведения торговых операций, получения данных о счете, параметрах торгового инструмента и пр. В общем, написание советника сводится к реализации трех основных функций: формирование сигнала, открытие сделки, сопровождение сделки.
Предлагаю вниманию общественности некоторое обобщение собственного опыта и информации из всемирной паутины в виде исходного кода форекс-эксперта, осуществляющего открытие сделок при пересечении быстрой и медленной скользящих средних, выставление стоп-лосс и тейк-профит, перевод сделки в безубыточное состояние после прохождения ценой заданного порога и трейлинг-стоп сделки на заданном уровне.
Собственно, вот он, код:
#property copyright "Copyright 2015, SergDeev"
#property description "Template Expert Advisor"
#property link "http://fx-prog.ru"
#property version "1.0"
#property strict
extern double startLot = 0.2,MaxRisk = 0,noLoss_factor = 1.0;
extern int stopLoss = 50,takeProfit = 500,trailStop = 30,trailStep = 2;
extern int ma_fast = 15,ma_slow = 80,timeStart = 10,timeEnd = 23;
extern int slippage = 5, MAGIC = 20161210;
int OnInit() { // функция инициализации
if (Digits == 5) { // пересчет параметров сопровождения для 5-знака
trailStop *= 10; trailStep *= 10; slippage *= 10; takeProfit *= 10; stopLoss *= 10;
}
return(INIT_SUCCEEDED);
}
double NormalizeLots(double v) { // функция нормализации объема торговли
double max_lot = MarketInfo(Symbol(),MODE_MAXLOT);
double min_lot = MarketInfo(Symbol(),MODE_MINLOT);
double lot_step = MarketInfo(Symbol(),MODE_LOTSTEP);
double x = NormalizeDouble((v/lot_step),0) * lot_step;
if (v > max_lot) v = max_lot;
if (x < min_lot) x = min_lot;
return(x);
}
bool Signal_Buy() { // формирование сигнала на покупку
if (iMA(NULL,0,ma_fast,0,MODE_EMA,PRICE_CLOSE,1) > iMA(NULL,0,ma_slow,0,MODE_EMA,PRICE_CLOSE,1))
if (iMA(NULL,0,ma_fast,0,MODE_EMA,PRICE_CLOSE,2) < iMA(NULL,0,ma_slow,0,MODE_EMA,PRICE_CLOSE,2))
return(true);
return(false);
}
bool Signal_Sell() { // формирование сигнала на продажу
if (iMA(NULL,0,ma_fast,0,MODE_EMA,PRICE_CLOSE,1) < iMA(NULL,0,ma_slow,0,MODE_EMA,PRICE_CLOSE,1))
if (iMA(NULL,0,ma_fast,0,MODE_EMA,PRICE_CLOSE,2) > iMA(NULL,0,ma_slow,0,MODE_EMA,PRICE_CLOSE,2))
return(true);
return(false);
}
void CheckForOpen(int mode) { // проверка сигналов открытия сделок
double SL,TP,lot;
if (Volume[0] > 1) return; // выполняется только на открытии нового бара
if (mode==OP_BUY && Signal_Buy()) { // покупка
TP = SL = 0;
if (stopLoss != 0) SL = Ask - stopLoss * Point;
if (takeProfit != 0) TP = Bid + takeProfit * Point;
if (SL != 0 && (Bid-SL)/Point < MarketInfo(NULL,MODE_STOPLEVEL)) SL = Bid - 1.1 * MarketInfo(NULL,MODE_STOPLEVEL) * Point;
if (TP != 0 && (TP-Ask)/Point < MarketInfo(NULL,MODE_STOPLEVEL)) TP = Ask + 1.1 * MarketInfo(NULL,MODE_STOPLEVEL) * Point;
if ((MaxRisk > 0) && (SL != 0)) lot = (AccountFreeMargin()*MaxRisk/100)/((Ask-SL)/Point*MarketInfo(Symbol(),MODE_TICKVALUE));
else lot = startLot;
if (AccountFreeMargin()<lot*MarketInfo(NULL,MODE_MARGINREQUIRED)) Print("No FreeMargin");
else {
if (OrderSend(Symbol(),OP_BUY,NormalizeLots(lot),Ask,slippage,NormalizeDouble(SL,Digits),NormalizeDouble(TP,Digits),MQLInfoString(MQL_PROGRAM_NAME),MAGIC,0,Blue)==-1)
Print(__FUNCTION__," BUY_ORDER_SEND Ask:",Ask," SL:",SL," TP:",TP," lot:",lot,_LastError);
}
}
if (mode==OP_SELL && Signal_Sell()) { // продажа
TP = SL = 0;
if (stopLoss != 0) SL = Bid + stopLoss * Point;
if (takeProfit != 0) TP = Ask - takeProfit * Point;
if (SL != 0 && (SL-Ask)/Point < MarketInfo(NULL,MODE_STOPLEVEL)) SL = Ask + 1.1 * MarketInfo(NULL,MODE_STOPLEVEL) * Point;
if (TP != 0 && (Bid-TP)/Point < MarketInfo(NULL,MODE_STOPLEVEL)) TP = Bid - 1.1 * MarketInfo(NULL,MODE_STOPLEVEL) * Point;
if ((MaxRisk > 0) && (SL != 0)) lot = (AccountFreeMargin()*MaxRisk/100)/((SL-Bid)/Point*MarketInfo(Symbol(),MODE_TICKVALUE));
else lot = startLot;
if (AccountFreeMargin()<lot*MarketInfo(NULL,MODE_MARGINREQUIRED)) Print("No FreeMargin");
else {
if (OrderSend(Symbol(),OP_SELL,NormalizeLots(lot),Bid,slippage,NormalizeDouble(SL,Digits),NormalizeDouble(TP,Digits),MQLInfoString(MQL_PROGRAM_NAME),MAGIC,0,Red)==-1)
Print(__FUNCTION__," SELL_ORDER_SEND Bid:",Bid," SL:",SL," TP:",TP," lot:",lot," ",_LastError);
}
}
}
//+------------------------------------------------------------------+
void CheckForClose() { // сопровождение сделок
double SL,x;
for(int i=0;i<OrdersTotal();i++) { // цикл по всем ордерам терминала
if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if ((OrderMagicNumber() != MAGIC) || (OrderSymbol() != Symbol())) continue;
if (OrderType()==OP_BUY) { // ордер на покупку
if (OrderStopLoss()<OrderOpenPrice() && noLoss_factor > 0) { // перевод в безубыток
x = OrderOpenPrice() + noLoss_factor * (OrderOpenPrice()-OrderStopLoss());
if (Ask > x) {
SL = OrderOpenPrice() + MarketInfo(NULL,MODE_SPREAD)*Point;
SL = NormalizeDouble(SL,Digits);
if (!OrderModify(OrderTicket(),OrderOpenPrice(),SL,OrderTakeProfit(),0)) Print(__FUNCTION__," BUY_NOLOSS_ERROR SL:",SL," ",_LastError);
}
}
if (OrderStopLoss() > OrderOpenPrice() && trailStop > 0) { // трейлинг-стоп
SL = NormalizeDouble((Bid-trailStop*Point),Digits);
if (((SL-OrderStopLoss())/Point) > trailStep) {
if (!OrderModify(OrderTicket(),OrderOpenPrice(),SL,OrderTakeProfit(),0)) Print(__FUNCTION__," BUY_TRAIL_STOP_ERROR SL:",SL," ",_LastError);
else continue;
}
}
}
if (OrderType()==OP_SELL) { // ордер на продажу
if (OrderStopLoss() > OrderOpenPrice() && noLoss_factor > 0) { // перевод в безубыток
x = OrderOpenPrice() - noLoss_factor * (OrderStopLoss()-OrderOpenPrice());
if (Bid < x) {
SL = OrderOpenPrice() - MarketInfo(NULL,MODE_SPREAD)*Point;
SL = NormalizeDouble(SL,Digits);
if (!OrderModify(OrderTicket(),OrderOpenPrice(),SL,OrderTakeProfit(),0,clrRed)) Print(__FUNCTION__," SELL_NOLOSS_ERROR SL:",SL," ",_LastError);
}
}
if (OrderStopLoss() < OrderOpenPrice() && trailStop > 0) { // трейлинг-стоп
SL = NormalizeDouble((Ask+trailStop*Point),Digits);
if (((OrderStopLoss()-SL)/Point) > trailStep) {
if (!OrderModify(OrderTicket(),OrderOpenPrice(),SL,OrderTakeProfit(),0,clrRed)) Print(__FUNCTION__," BUY_TRAIL_STOP_ERROR SL:",SL," ",_LastError);
else continue;
}
}
}
}
}
int CalculateCurrentOrders(int mode) { // подсчет открытых ордеров
int num=0;
for(int i=0;i<OrdersTotal();i++) {
if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if (OrderMagicNumber() == MAGIC)
if (OrderSymbol() == Symbol())
if ((OrderType()==mode) || (mode==-1)) num++;
}
return(num);
}
void OnTick() { // выполняется на каждом тике
if(Bars<100 || IsTradeAllowed()==false) return;
if ((TimeHour(Time[0]) >= timeStart) && (TimeHour(Time[0]) <= timeEnd)) { // время торговли
if (CalculateCurrentOrders(OP_BUY) == 0) CheckForOpen(OP_BUY); // проверка открытия BUY
if (CalculateCurrentOrders(OP_SELL) == 0) CheckForOpen(OP_SELL); // проверка открытия SELL
}
if (CalculateCurrentOrders(-1) > 0) CheckForClose(); // сопровождение сделок
Comment("\nProfit :",DoubleToString((AccountEquity()-AccountBalance()),2), // вывод сводной информации
"\nAccountBalance: ",DoubleToString(AccountBalance(),2),
"\nAccountEquity: ",DoubleToString(AccountEquity(),2),
"\nAccountMargin: ",DoubleToString(AccountMargin(),2),
"\nAccountFreeMargin: ",DoubleToString(AccountFreeMargin(),2),
"\nMargeenLevel: ",DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL),2));
}
//+------------------------------------------------------------------+
В коде приведены основные функции:
- Signal_Buy() — формирование сигнала на покупку;
- Signal_Sell() — формирование сигнала на продажу;
- CheckForOpen() — проверка сигналов и открытие сделок;
- CheckForClose() — сопровождение сделок.
Данный код не в коем случае не претендует на эффективную стратегию форекс. Это всего лишь шаблон, который должен облегчить написание собственного эксперта форекс для начинающего программиста. Для включения в шаблон собственных сигналов необходимо лишь отредактировать функции Signal_Buy() и Signal_Sell().
Так выглядит прогон советника в тестере стратегий.

10 декабря, 2016
Sergey
Опубликовано в рубрике
Теги: