В продолжение темы шаблонных экспертов форекс приведу пример «допиливания» его под собственную стратегию. В данной статье рассматривается реализация долгосрочной стратегии форекс на базе скользящих средних.
Реализации подлежит простая стратегия на дневном тайм-фрейме. На график устанавливаются две простые скользящие средние с периодом 5 по ценам LOW и HIGH. Получаем своеобразный канал. Сделка на покупку открывается когда последняя свеча открывается ниже нижней линии и закрывается внутри канала. Сделка на продажу открывается когда последняя свеча открывается выше верхней линии и закрывается внутри канала. Стоп-лосс для сделок на покупку устанавливается на 25 пунктов ниже цены LOW последних 2-х свечей, на продажу — выше HIGH последних 2-х свечей. Тейк-профит устанавливаем в 4 раза больше чем стоп-лосс. Если цена проходит расстояние больше 1,5 стоп-лосс, то сделка переводится в безубыток и траллится на уровне 100 пунктов.
Для реализации используем опубликованный ранее шаблон советников, слегка поправив условия открытия позиций. У меня это заняло не более 15 минут. Ниже отчет о прогоне полученного советника в тестере стратегий. Это, кстати, пример, когда грамотное управление капиталом позволяет получать прибыль даже в случае низкого процента прибыльных сделок. Итак, имея всего 42% прибыльных сделок мы получаем фактор прибыльности 1.6 и максимальную просадку около 13%
Ну и, наконец, код советника. Здесь изменены функции Signal_Buy() и Signal_Sell() в плане условий проверки сигналов и возвращения уровня стоп-лосс, функция CheckForOpen() в плане установки SL и TP, из функции OnTick() удалена проверка времени начала-окончания, т.к. мы работаем по дням.
#property copyright "Copyright 2015, SergDeev"
#property description "EA Moving Average High-Low"
#property link "http://fx-prog.ru"
#property version "1.0"
#property strict
extern double startLot = 0.2,MaxRisk = 2,noLoss_factor = 1.5,takeProfit_factor = 4;
extern int stopLoss_shift = 25,trailStop = 100,trailStep = 5;
extern int ma_period = 5;
extern ENUM_MA_METHOD ma_method = MODE_SMA;
extern int slippage = 5, MAGIC = 20161210;
int OnInit() { // функция инициализации
if (Digits == 5) { // пересчет параметров сопровождения для 5-знака
trailStop *= 10; trailStep *= 10; slippage *= 10; stopLoss_shift *= 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(double &x) { // формирование сигнала на покупку
if (Close[1] > Open[1])
if (Open[1] < iMA(NULL,0,ma_period,0,ma_method,PRICE_LOW,1))
if (Close[1] > iMA(NULL,0,ma_period,0,ma_method,PRICE_LOW,1))
if (High[1] < iMA(NULL,0,ma_period,0,ma_method,PRICE_HIGH,1))
{
x = Low[iLowest(NULL,0,MODE_LOW,3)];
return(true);
}
return(false);
}
bool Signal_Sell(double &x) { // формирование сигнала на продажу
if (Close[1] < Open[1])
if (Open[1] > iMA(NULL,0,ma_period,0,ma_method,PRICE_HIGH,1))
if (Close[1] < iMA(NULL,0,ma_period,0,ma_method,PRICE_HIGH,1))
if (Low[1] > iMA(NULL,0,ma_period,0,ma_method,PRICE_LOW,1))
{
x = High[iHighest(NULL,0,MODE_HIGH,3)];
return(true);
}
return(false);
}
void CheckForOpen(int mode) { // проверка сигналов открытия сделок
double SL,TP,lot,x;
if (Volume[0] > 1) return; // выполняется только на открытии нового бара
if (mode==OP_BUY && Signal_Buy(x)) { // покупка
TP = 0; SL = x - stopLoss_shift * Point;
if (takeProfit_factor > 0) TP = Bid + takeProfit_factor * (Bid-SL);
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(x)) { // продажа
TP = 0; SL = SL = x + stopLoss_shift * Point;
if (takeProfit_factor > 0) TP = Ask - takeProfit_factor * (SL-Ask);
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 (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));
}