Советник форекс — это просто. Терминал 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().
Так выглядит прогон советника в тестере стратегий.