Создаем простой мультивалютный советник с использованием MQL5 (Часть 4): Треугольная скользящая средняя — Сигналы индикатора
Введение
Под мультивалютным советником в этой статье понимается советник, или торговый робот, который может торговать (открывать/закрывать ордера, управлять ордерами, например, трейлинг-стоп-лоссом и трейлинг-профитом) более чем одной парой символов с одного графика. В этой статье советник будет торговать по 30 парам.
На этот раз мы будем использовать только один индикатор, а именно треугольную скользящую среднюю на одном или нескольких таймфреймах.Треугольная скользящая средняя - это пользовательский индикатор для MetaTrader 5, созданный Младеном Ракичем (Mladen Rakic). Я получил разрешение от автора использовать его индикатор в качестве сигнала на мультивалютном советнике TriangularMA_MTF_MCEA.
Спасибо Младену Ракичу за предоставленную возможность.
Таким образом, цель состоит в том, чтобы удовлетворить основные потребности трейдеров, которым нужны эффективные и действенные торговые роботы. Полагаясь на сильные стороны и возможности MQL5, мы можем создать простой мультивалютный советник, который в этой статье использует сигналы треугольной скользящей средней.
Примечание: Мультивалютный советник TriangularMA_MTF_MCEA создан по просьбе трейдеров.
Особенности
1. Торговые пары.
Советник будет торговать на следующих парах:
EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCAD,USDCHF,USDJPY,EURGBP,EURAUD, EURNZD, EURCAD, EURCHF, EURJPY, GBPAUD, GBPNZD, GBPCAD,GBPCHF,GBPJPY,AUDNZD,AUDCAD,AUDCHF,AUDJPY,NZDCAD,NZDCHF,NZDJPY, CADCHF, CADJPY, CHFJPY = 28 пар
Плюс 2 пары металлов: XAUUSD (золото) и XAGUSD (серебро).
Всего 30 пар.
В предыдущей статье мы использовали автоматическую функцию для обнаружения имен пар с префиксами и/или суффиксами.
В этой статье мы упростили задачу, добавив специальные входные свойства для префикса и суффикса имени пары.
Затем с помощью простой функции мы обрабатываем имена пар префиксов и/или суффиксов в сочетании с 30 зарегистрированными именами пар, так что если в MetaTrader 5 используется советник с такими специальными именами символов, все будет работать гладко.
Недостаток функции обнаружения имен символов, имеющих префиксы и суффиксы, заключается в том, что она работает только с парами или именами символов для форекс и металлов в MetaTrader 5, но не работает со специальными символами и индексами.
Кроме того, еще одним недостатком этого метода является необходимость избегать опечаток (необходимо вводить с учетом регистра) в названии префикса и/или суффикса пары.
Как и в предыдущей статье, в этот советник мы также добавили 10 опционов на торгуемые пары.
Одной из 10 пар опционов, которые будут торговаться, является Trader Wishes Pairs (трейдерские пары), где торгуемые пары должны быть введены трейдером вручную в свойствах советника. Не забывайте, что имя введенной пары уже должно быть в списке из 30 пар.
Как и в предыдущей статье, в этой версии советника мы также добавили опцию торговой сессии (часовой пояс), поэтому торгуемые пары соответствуют времени торговой сессии.
2. Индикатор сигналов.
В описании треугольной скользящей средней автор пишет:
"Использование:
В качестве сигнала можно использовать смену цвета".
Цвета индикатора треугольной скользящей средней по умолчанию:
- 0-DarkGray = неизвестный сигнал
- 1-DeepPink = сигнал на продажу
- 2-MediumSeaGreen = сигнал на покупку.
В этой версии советника мы создали два варианта использования таймфреймов при расчете сигнала треугольной скользящей средней.
1. Расчет сигналов на основе мультитаймфрейма.
В системе расчета с несколькими таймфреймами трейдеры должны выбрать из списка перечисления желаемую серию таймфреймов.
Выбранная серия таймфреймов предоставлена в диапазоне от M5 до D1 (11 таймфреймов).
Трейдеры могут выбрать серию таймфреймов - начало (например, M15) и конец (например, H4).
Итак, советник будет рассчитывать сигнал треугольной скользящей средней, начиная с таймфрейма M15 и заканчивая H4.
Расчеты треугольной скользящей средней на нескольких таймфреймах:
- Сигнал на покупку, если на всех выбранных таймфреймах индикатор окрашен в цвет MediumSeaGreen, и
- Сигнал на продажу, если на всех выбранных таймфреймах индикатор окрашен в цвет DeepPink.
2. Расчет сигналов на основе одного таймфрейма.
В системе расчета сигналов на одном таймфрейме трейдеры должны выбрать один таймфрейм из 11, начиная с M5 и заканчивая D1.
Таким образом, советник рассчитает сигнал индикатора треугольной скользящей средней на выбранном таймфрейме.
Между тем, расчет сигнала треугольной скользящей средней на одном таймфрейме выглядит так:
- Сигнал на покупку, если предыдущие 2 бара — DeepPink, предыдущий 1 бар — MediumSeaGreen и текущий бар — MediumSeaGreen.
- Сигнал на продажу, если предыдущие 2 бара — MediumSeaGreen, предыдущий 1 бар — DeepPink и текущий бар — DeepPink.
Треугольную скользящую среднюю для сигналов покупки и продажи можно увидеть на рисунках 1 и 2.
3. Управление торговлей и ордерами.
Управление торговлей в этом мультивалютном советнике имеет несколько вариантов:
1. Ордера стоп-лосс
- Варианты: Use Order Stop Loss (Yes) или (No) - использовать ордер стоп-лосс: да или нет
При выборе Use Order Stop Loss (No) все ордера будут открываться без стоп-лосса.
При выборе Use Order Stop Loss (Yes):
Снова предоставляется выбор: Use Automatic Calculation Stop Loss (Yes) или (No) - использовать автоматически рассчитываемый стоп-лосс: да или нет
При выборе Automatic Calculation Stop Loss (Yes) стоп-лосс рассчитывается советником.
При выборе Automatic Calculation Stop Loss (No) трейдеру необходимо ввести значение стоп-лосса в пипсах.
Если Use Order Stop Loss (No):
Затем советник проверит состояние сигнала для каждого открытого ордера и оценит
потенциал прибыли. Если сигнал слабеет, значит ордер необходимо закрыть, чтобы сохранить
прибыль. Или сигнал указывает на смену направления, и ордер необходимо закрыть с убытком.
Примечание:
Перед закрытием сделки из-за слабого сигнала запрашивается подтверждение пользователя.
2. Ордера тейк-профит
- Варианты: Use Order Take Profit (Yes) или (No) - использовать тейк-профит ордера: да или нет
При выборе Use Order Take Profit (No) все ордера будут открываться без тейк-профита.
При Use Order Take Profit (Yes):
Снова предоставляется выбор: Use Automatic Calculation Order Take Profit (Yes) или (No) - использовать автоматически рассчитываемый тейк-профит: да или нет
При выборе Automatic Calculation Order Take Profit (Yes) тейк-профит рассчитывается советником.
При выборе Automatic Calculation Order Take Profit (No) трейдеру необходимо ввести значение тейк-профита в пипсах.
3. Трейлинг-стоп и трейлинг тейк-профита
- Варианты: Use Trailing SL/TP (Yes) или (No) - использовать стоп-лосс/тейк-профит трейлинга: да или нет
При Use Trailing SL/TP option (No) советник не будет использовать стоп-лосс и тейк-профит трейлинга.
При Use Trailing SL/TP (Yes):
Снова предоставляется выбор: Use Automatic Trailing (Yes) или (No) - использовать автоматический трейлинг: да или нет
При Use Automatic Trailing (Yes) трейлинг-стоп выполняется советником с использованием
нулевого буфера треугольной скользящей средней (данные индикатора) на таймфрейме, который автоматически выбирается советником, и одновременно
с получением скользящей прибыли на основе значения переменной TPmin (минимальное значение скользящей прибыли).
При Use Automatic Trailing (No) трейлинг-стоп выполняется советником с использованием значения входного параметра.
Примечание: Советник осуществляет трейлинг тейк-профита одновременно с трейлинг-стопом.
Функция Trailing Stop Price:
double MCEA::TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type) { //--- int br=2; double pval=0.0; int x=PairsIdxArray(xsymb); Pips(xsymb); //-- switch(TS_type) { case 0: { RefreshTick(xsymb); if(ptype==POSITION_TYPE_BUY) pval=mc_symbol.NormalizePrice(mc_symbol.Bid()-TSval*pip); if(ptype==POSITION_TYPE_SELL) pval=mc_symbol.NormalizePrice(mc_symbol.Ask()+TSval*pip); break; } case 1: { double TriMAID[]; //-- ArrayResize(TriMAID,br,br); ArraySetAsSeries(TriMAID,true); CopyBuffer(hTriMAt[x],0,0,br,TriMAID); // Copy buffer 0 from the hTriMAt indicator handle //-- RefreshTick(xsymb); if(ptype==POSITION_TYPE_BUY && (mc_symbol.Bid()>mc_symbol.NormalizePrice(TriMAID[0]+TSval*pip))) pval=TriMAID[0]; if(ptype==POSITION_TYPE_SELL && (mc_symbol.Ask()<mc_symbol.NormalizePrice(TriMAID[0]-TSval*pip))) pval=TriMAID[0]; break; } } //-- return(pval); //--- } //-end TSPrice() //---------//
Изменение функции SL/TP:
bool MCEA::ModifySLTP(const string symbx,int TS_type) { //--- ResetLastError(); MqlTradeRequest req={}; MqlTradeResult res={}; MqlTradeCheckResult check={}; //-- int TRSP=TS_type; bool modist=false; int x=PairsIdxArray(symbx); Pips(symbx); //-- int total=PositionsTotal(); //-- for(int i=total-1; i>=0; i--) { string symbol=PositionGetSymbol(i); if(symbol==symbx && mc_position.Magic()==magicEA) { ENUM_POSITION_TYPE opstype = mc_position.PositionType(); if(opstype==POSITION_TYPE_BUY) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double vtrsb = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP)); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double netp=pos_profit+pos_swap+pos_comm; double modstart=mc_symbol.NormalizePrice(pos_open+TSmin*pip); double modminsl=mc_symbol.NormalizePrice(vtrsb+TSmin*pip); double modbuysl=vtrsb; double modbuytp=mc_symbol.NormalizePrice(price+TPmin*pip); bool modbuy = (price>modminsl && modbuysl>modstart && (pos_stop==0.0||modbuysl>pos_stop)); //-- if(modbuy && netp>0.05) { modist=mc_trade.PositionModify(symbol,modbuysl,modbuytp); } } if(opstype==POSITION_TYPE_SELL) { RefreshTick(symbol); double price = mc_position.PriceCurrent(); double vtrss = mc_symbol.NormalizePrice(TSPrice(symbx,opstype,TRSP)); double pos_open = mc_position.PriceOpen(); double pos_stop = mc_position.StopLoss(); double pos_profit = mc_position.Profit(); double pos_swap = mc_position.Swap(); double pos_comm = mc_position.Commission(); double netp=pos_profit+pos_swap+pos_comm; double modstart=mc_symbol.NormalizePrice(pos_open-TSmin*pip); double modminsl=mc_symbol.NormalizePrice(vtrss-TSmin*pip); double modselsl=vtrss; double modseltp=mc_symbol.NormalizePrice(price-TPmin*pip); bool modsel = (price<modminsl && modselsl<modstart && (pos_stop==0.0||modselsl<pos_stop)); //-- if(modsel && netp>0.05) { modist=mc_trade.PositionModify(symbol,modselsl,modseltp); } } } } //-- return(modist); //--- } //-end ModifySLTP() //---------//
4. Ручное управление ордерами.
Для повышения эффективности будет добавлено несколько кнопок.
1. Set SL / TP All Orders (установить стоп-лосс/тейк-профит для всех ордеров)
Если трейдер установит Use Order Stop Loss (No) и/или Use Order Take Profit (No),
но затем захочет использовать стоп-лосс или тейк-профит для всех ордеров, ему необходимо лишь нажать на кнопку
Set SL / TP All Orders для изменения всех ордеров и применения стоп-лосса и/или тейк-профита.
2. Close All Orders
Закрыть все ордера.3. Close All Orders Profit
Если трейдер хочет закрыть все ордера, которые уже прибыльны, то достаточно одного нажатия кнопки
Close All Orders Profit для закрытия всех открытых прибыльных ордеров.
5. Management Orders and Chart Symbols.
Очень полезной функцией для мультивалютных советников, торгующих 30 парами с одного графика, будет наличие единой панели кнопок, чтобы трейдеры могли менять графики или символы одним щелчком мыши.
Реализация планирования в MQL5-программе
1. Заголовок программы и входные параметры
Включение файла заголовка в MQL5
//+------------------------------------------------------------------+ //| Include | //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\AccountInfo.mqh> //-- CTrade mc_trade; CSymbolInfo mc_symbol; CPositionInfo mc_position; CAccountInfo mc_account; //---
Перечисление для использования часового пояса
//-- enum tm_zone { Cus_Session, // Trading on Custom Session New_Zealand, // Trading on New Zealand Session Australia, // Trading on Autralia Sydney Session Asia_Tokyo, // Trading on Asia Tokyo Session Europe_London, // Trading on Europe London Session US_New_York // Trading on US New York Session }; //--
Перечисление для выбора часов
//-- enum swhour { hr_00=0, // 00:00 hr_01=1, // 01:00 hr_02=2, // 02:00 hr_03=3, // 03:00 hr_04=4, // 04:00 hr_05=5, // 05:00 hr_06=6, // 06:00 hr_07=7, // 07:00 hr_08=8, // 08:00 hr_09=9, // 09:00 hr_10=10, // 10:00 hr_11=11, // 11:00 hr_12=12, // 12:00 hr_13=13, // 13:00 hr_14=14, // 14:00 hr_15=15, // 15:00 hr_16=16, // 16:00 hr_17=17, // 17:00 hr_18=18, // 18:00 hr_19=19, // 19:00 hr_20=20, // 20:00 hr_21=21, // 21:00 hr_22=22, // 22:00 hr_23=23 // 23:00 }; //--
Перечисление для выбора минут
//-- enum inmnt { mn_00=0, // Minute 0 mn_05=5, // Minute 5 mn_10=10, // Minute 10 mn_15=15, // Minute 15 mn_20=20, // Minute 20 mn_25=25, // Minute 25 mn_30=30, // Minute 30 mn_35=35, // Minute 35 mn_40=40, // Minute 40 mn_45=45, // Minute 45 mn_50=50, // Minute 50 mn_55=55 // Minute 55 }; //--
Перечисление для выбора пар опционов для торговли
//-- enum PairsTrade { All30, // All Forex 30 Pairs TrdWi, // Trader Wishes Pairs Usds, // Forex USD Pairs Eurs, // Forex EUR Pairs Gbps, // Forex GBP Pairs Auds, // Forex AUD Pairs Nzds, // Forex NZD Pairs Cads, // Forex CDD Pairs Chfs, // Forex CHF Pairs Jpys // Forex JPY Pairs }; //--
Перечисление YN используется для опций (Yes) или (No) в параметре советника
//-- enum YN { No, Yes }; //--
Перечисление для использования размера лота в управлении капиталом
//-- enum mmt { FixedLot, // Fixed Lot Size DynamLot // Dynamic Lot Size }; //--
Перечисление для выбора таймфрейма, которое будет использоваться в одном и нескольких таймфреймах
//-- enum TFMTF { TFM5, // PERIOD_M5 TFM15, // PERIOD_M15 TFM30, // PERIOD_M30 TFH1, // PERIOD_H1 TFH2, // PERIOD_H2 TFH3, // PERIOD_H3 TFH4, // PERIOD_H4 TFH6, // PERIOD_H6 TFH8, // PERIOD_H8 TFH12, // PERIOD_H12 TFD1 // PERIOD_D1 }; //--
Перечисление для использования одного или нескольких таймфреймов
//-- enum SMTF { MTF, // Use Multi-Timeframe STF // Use Single-Timeframe }; //--
Входные параметры советника
//--- input group "=== Global Strategy EA Parameter ==="; // Global Strategy EA Parameter input SMTF tfinuse = MTF; // Select Calculation in Multi or Single Timeframe input TFMTF singletf = TFH1; // Select Single Calculation TimeFrame, default PERIOD_H1 input TFMTF tfstart = TFM15; // Select Multi Timeframe calculation start input TFMTF tfclose = TFH4; // Select Multi Timeframe calculation end input int Trmaperiod = 14; // Input Triangular MA Indicator period, default 14 input ENUM_APPLIED_PRICE Trprice = PRICE_CLOSE; // Select Triangular MA Applied Price, default Price Close //--- input group "=== Select Pairs to Trade ==="; // Selected Pairs to trading input PairsTrade usepairs = All30; // Select Pairs to Use input string traderwishes = "eg. eurusd,usdchf"; // If Use Trader Wishes Pairs, input pair name here, separate by comma input string sym_prefix = ""; // Input the symbol prefix in case sensitive (if any) input string sym_suffix = ""; // Input the symbol suffix in case sensitive (if any) //-- input group "=== Money Management Lot Size Parameter ==="; // Money Management Lot Size Parameter input mmt mmlot = DynamLot; // Money Management Type input double Risk = 10.0; // Percent Equity Risk per Trade (Min=1.0% / Max=10.0%) input double Lots = 0.01; // Input Manual Lot Size FixedLot //--Trade on Specific Time input group "=== Trade on Specific Time ==="; // Trade on Specific Time input YN trd_time_zone = Yes; // Select If You Like to Trade on Specific Time Zone input tm_zone session = Cus_Session; // Select Trading Time Zone input swhour stsescuh = hr_00; // Time Hour to Start Trading Custom Session (0-23) input inmnt stsescum = mn_15; // Time Minute to Start Trading Custom Session (0-55) input swhour clsescuh = hr_23; // Time Hour to Stop Trading Custom Session (0-23) input inmnt clsescum = mn_55; // Time Minute to Stop Trading Custom Session (0-55) //--Day Trading On/Off input group "=== Day Trading On/Off ==="; // Day Trading On/Off input YN ttd0 = No; // Select Trading on Sunday (Yes) or (No) input YN ttd1 = Yes; // Select Trading on Monday (Yes) or (No) input YN ttd2 = Yes; // Select Trading on Tuesday (Yes) or (No) input YN ttd3 = Yes; // Select Trading on Wednesday (Yes) or (No) input YN ttd4 = Yes; // Select Trading on Thursday (Yes) or (No) input YN ttd5 = Yes; // Select Trading on Friday (Yes) or (No) input YN ttd6 = No; // Select Trading on Saturday (Yes) or (No) //--Trade & Order management Parameter input group "=== Trade & Order management Parameter ==="; // Trade & Order management Parameter input YN use_sl = No; // Use Order Stop Loss (Yes) or (No) input YN autosl = Yes; // Use Automatic Calculation Stop Loss (Yes) or (No) input double SLval = 30; // If Not Use Automatic SL - Input SL value in Pips input YN use_tp = Yes; // Use Order Take Profit (Yes) or (No) input YN autotp = Yes; // Use Automatic Calculation Take Profit (Yes) or (No) input double TPval = 10; // If Not Use Automatic TP - Input TP value in Pips input YN TrailingSLTP = Yes; // Use Trailing SL/TP (Yes) or (No) input YN autotrl = Yes; // Use Automatic Trailing (Yes) or (No) input double TSval = 5; // If Not Use Automatic Trailing Input Trailing value in Pips input double TSmin = 5; // Minimum Pips to start Trailing Stop input double TPmin = 25; // Input Trailing Profit Value in Pips input YN Close_by_Opps = Yes; // Close Trade By Opposite Signal (Yes) or (No) input YN SaveOnRev = Yes; // Close Trade and Save profit due to weak signal (Yes) or (No) //--Others Expert Advisor Parameter input group "=== Others Expert Advisor Parameter ==="; // Others EA Parameter input YN alerts = Yes; // Display Alerts / Messages (Yes) or (No) input YN UseEmailAlert = No; // Email Alert (Yes) or (No) input YN UseSendnotify = No; // Send Notification (Yes) or (No) input YN trade_info_display = Yes; // Select Display Trading Info on Chart (Yes) or (No) input ulong magicEA = 2023111; // Expert ID (Magic Number) //---
В группе свойств входных данных Global Strategy EA Parameter советника трейдеры должны выбрать, использовать ли расчет сигналов на одном таймфрейме или нескольких.
При выборе одного таймфрейма (STF) его необходимо указать.
Во входном параметре советника выберите Select Single Calculation timeframe (выбрать один таймфрейм для расчета), значение по умолчанию - PERIOD_H1.
При выборе нескольких таймфреймов (MTF), их необходимо указать.
Во входном параметре советника выберите Select Multi Timeframe calculation start (начало расчета на нескольких таймфреймах) и Select Multi Timeframe calculation end (окончание расчета на нескольких таймфреймах).
В строках 478-518 функции TriangularMA_MTF_MCEA_Config() объясняется, как работать с одним и несколькими таймфреймами.
ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1}; int arTFs=ArraySize(TFs); //-- for(int x=0; x<arTFs; x++) { if(singletf==x) TFt=TFs[x]; // TF for single-timeframe if(tfstart==x) arstr=x; // multi-timeframe start calculation timeframe if(tfclose==x) arend=x; // multi-timeframe end calculation timeframe } //-- if(arstr>=arend) { Alert("Error selecting Start and End Timeframe, Start Timeframe must be smaller than End Timeframe"); Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); } //-- switch(tfinuse) { case MTF: { TFArrays=arend-arstr+1; ArrayResize(TFTri,TFArrays,TFArrays); ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY); tfcinws=arstr+1; tftrlst=(int)TFArrays/2; TFts=TFs[tftrlst+arstr-1]; // TF for Trailing Stop TFCWS=TFs[tfcinws]; // TF for Close Order in weak signal break; } case STF: { TFArrays=arTFs; ArrayResize(TFTri,TFArrays,TFArrays); ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY); tfcinws=TFIndexArray(TFt)-2 <=0 ? 1 : TFIndexArray(TFt)-2; TFts=TFt; // TF for Trailing Stop TFCWS=TFs[tfcinws]; // TF for Close Order in weak signal break; } }
Переменная ENUM_TIMEFRAMES TFs[] должна быть свойственна опции перечисления enum TFMTF
ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1}; //-- enum TFMTF { TFM5, // PERIOD_M5 TFM15, // PERIOD_M15 TFM30, // PERIOD_M30 TFH1, // PERIOD_H1 TFH2, // PERIOD_H2 TFH3, // PERIOD_H3 TFH4, // PERIOD_H4 TFH6, // PERIOD_H6 TFH8, // PERIOD_H8 TFH12, // PERIOD_H12 TFD1 // PERIOD_D1 }; //--
Затем трейдер должен определить период индикатора Triangular MA. Период по умолчанию - 14.
Кроме того, необходимо указать цену расчета Triangular MA. Цена по умолчанию - PRICE_CLOSE.
В группе свойств входных данных Select Pairs to Trade необходимо выбрать пару для торговли из 10 предоставленных вариантов. Значение по умолчанию - All Forex 30 Pairs (все 30 форекс-пар).
Чтобы настроить торгуемую пару, вызовем функцию HandlingSymbolArrays().
С помощью функции HandlingSymbolArrays() мы будем обрабатывать все торгуемые пары.
void MCEA::HandlingSymbolArrays(void) { //--- string All30[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY","EURGBP", "EURAUD","EURNZD","EURCAD","EURCHF","EURJPY","GBPAUD","GBPNZD","GBPCAD", "GBPCHF","GBPJPY","AUDNZD","AUDCAD","AUDCHF","AUDJPY","NZDCAD","NZDCHF", "NZDJPY","CADCHF","CADJPY","CHFJPY","XAUUSD","XAGUSD"}; // 30 pairs string USDs[]={"USDCAD","USDCHF","USDJPY","AUDUSD","EURUSD","GBPUSD","NZDUSD","XAUUSD","XAGUSD"}; // USD pairs string EURs[]={"EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD","EURUSD"}; // EUR pairs string GBPs[]={"GBPAUD","GBPCAD","GBPCHF","EURGBP","GBPJPY","GBPNZD","GBPUSD"}; // GBP pairs string AUDs[]={"AUDCAD","AUDCHF","EURAUD","GBPAUD","AUDJPY","AUDNZD","AUDUSD"}; // AUD pairs string NZDs[]={"AUDNZD","NZDCAD","NZDCHF","EURNZD","GBPNZD","NZDJPY","NZDUSD"}; // NZD pairs string CADs[]={"AUDCAD","CADCHF","EURCAD","GBPCAD","CADJPY","NZDCAD","USDCAD"}; // CAD pairs string CHFs[]={"AUDCHF","CADCHF","EURCHF","GBPCHF","NZDCHF","CHFJPY","USDCHF"}; // CHF pairs string JPYs[]={"AUDJPY","CADJPY","CHFJPY","EURJPY","GBPJPY","NZDJPY","USDJPY"}; // JPY pairs //-- sall=ArraySize(All30); arusd=ArraySize(USDs); aretc=ArraySize(EURs); ArrayResize(VSym,sall,sall); ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY); //-- if(usepairs==TrdWi && StringFind(traderwishes,"eg.",0)<0) { string to_split=traderwishes; // A string to split into substrings pairs name string sep=","; // A separator as a character ushort u_sep; // The code of the separator character //--- Get the separator code u_sep=StringGetCharacter(sep,0); //--- Split the string to substrings int p=StringSplit(to_split,u_sep,SPC); if(p>0) { for(int i=0; i<p; i++) StringToUpper(SPC[i]); //-- for(int i=0; i<p; i++) { if(ValidatePairs(SPC[i])<0) ArrayRemove(SPC,i,1); } } arspc=ArraySize(SPC); } //-- SetSymbolNamePS(); // With this function we will detect whether the Symbol Name has a prefix and/or suffix //-- if(inpre>0 || insuf>0) { if(usepairs==TrdWi && arspc>0) { for(int t=0; t<arspc; t++) { SPC[t]=pre+SPC[t]+suf; } } //-- for(int t=0; t<sall; t++) { All30[t]=pre+All30[t]+suf; } for(int t=0; t<arusd; t++) { USDs[t]=pre+USDs[t]+suf; } for(int t=0; t<aretc; t++) { EURs[t]=pre+EURs[t]+suf; } for(int t=0; t<aretc; t++) { GBPs[t]=pre+GBPs[t]+suf; } for(int t=0; t<aretc; t++) { AUDs[t]=pre+AUDs[t]+suf; } for(int t=0; t<aretc; t++) { NZDs[t]=pre+NZDs[t]+suf; } for(int t=0; t<aretc; t++) { CADs[t]=pre+CADs[t]+suf; } for(int t=0; t<aretc; t++) { CHFs[t]=pre+CHFs[t]+suf; } for(int t=0; t<aretc; t++) { JPYs[t]=pre+JPYs[t]+suf; } } //-- ArrayCopy(VSym,All30,0,0,WHOLE_ARRAY); ArrayResize(AS30,sall,sall); ArrayCopy(AS30,All30,0,0,WHOLE_ARRAY); for(int x=0; x<sall; x++) {SymbolSelect(AS30[x],true);} if(ValidatePairs(Symbol())>=0) symbfix=true; if(!symbfix) { Alert("Expert Advisors will not trade on pairs "+Symbol()); Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); } //-- switch(usepairs) { case 0: // All Forex 30 Pairs { ArrayResize(DIRI,sall,sall); arrsymbx=sall; ArraySymbolResize(); ArrayCopy(DIRI,All30,0,0,WHOLE_ARRAY); pairs="Multi Currency 30 Pairs"; //-- break; } case 1: // Trader wishes pairs { ArrayResize(DIRI,arspc,arspc); arrsymbx=arspc; ArraySymbolResize(); ArrayCopy(DIRI,SPC,0,0,WHOLE_ARRAY); pairs="("+string(arspc)+") Trader Wishes Pairs"; //-- break; } case 2: // USD pairs { ArrayResize(DIRI,arusd,arusd); arrsymbx=arusd; ArraySymbolResize(); ArrayCopy(DIRI,USDs,0,0,WHOLE_ARRAY); pairs="("+string(arusd)+") Multi Currency USD Pairs"; //-- break; } case 3: // EUR pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,EURs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex EUR Pairs"; //-- break; } case 4: // GBP pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,GBPs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex GBP Pairs"; //-- break; } case 5: // AUD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,AUDs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex AUD Pairs"; //-- break; } case 6: // NZD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,NZDs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex NZD Pairs"; //-- break; } case 7: // CAD pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,CADs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex CAD Pairs"; //-- break; } case 8: // CHF pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,CHFs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex CHF Pairs"; //-- break; } case 9: // JPY pairs { ArrayResize(DIRI,aretc,aretc); arrsymbx=aretc; ArraySymbolResize(); ArrayCopy(DIRI,JPYs,0,0,WHOLE_ARRAY); pairs="("+string(aretc)+") Forex JPY Pairs"; //-- break; } } //-- return; //--- } //-end HandlingSymbolArrays() //---------//
Внутри функции HandlingSymbolArrays() вызовем функцию SetSymbolNamePS().
С ее помощью мы сможем обрабатывать имена символов, которые имеют префиксы и/или суффиксы.
void MCEA::SetSymbolNamePS(void) { //--- symbfix=false; int ptriml; int ptrimr; string insymbol=Symbol(); int sym_Lenpre=StringLen(prefix); int sym_Lensuf=StringLen(suffix); if(sym_Lenpre>0) { ptriml=StringTrimLeft(suffix); ptriml=StringTrimRight(suffix); } if(sym_Lensuf>0) { ptrimr=StringTrimLeft(suffix); ptrimr=StringTrimRight(suffix); } string sym_pre=prefix; string sym_suf=suffix; //-- pre=sym_pre; suf=sym_suf; inpre=StringLen(pre); insuf=StringLen(suf); posCur1=inpre; posCur2=posCur1+3; //-- return; //--- } //-end SetSymbolNamePS() //---------//
Примечание:
Советник проверит пары.
Если трейдер допустил ошибку при вводе названия пары или названия префикса/суффикса
либо проверка пары не удалась, советник выдаст предупреждение и будет удален с графика.
В группе свойств входных данных Trade on Specific Time, трейдеру нужно выбрать Trade on Specific Time Zone (Yes) или (No)
- торговать в определенном часовом поясе: да или нет При Yes необходимо выбрать параметры перечисления:
- Trading on Custom Session (пользовательская сессия)
- Trading on New Zealand Session (новозеландская сессия)
- Trading on Australia Sydney Session (сиднейская сессия)
- Trading on Asia Tokyo Session (токийская сессия)
- Trading on Europe London Session (лондонская сессия)
- Trading on America New York Session (нью-йоркская сессия)
Таким образом, советник будет выполнять действия только в течение указанного времени.
В остальных случаях время начала и окончания торговли выбирается советником.
Чтобы объявить все переменные, объекты и функции, необходимые в этом мультивалютном советнике, мы создадим класс, чтобы указать конструкцию и рабочие настройки советника.
В частности, переменные, используемые в функции для обработки имен префиксных символов и/или имен суффиксных символов, а также расчетов часовых поясов, мы сделали в классе MCEA.
//+------------------------------------------------------------------+ //| Class for working Expert Advisor | //+------------------------------------------------------------------+ class MCEA { //--- private: //---- int x_year; // Year int x_mon; // Month int x_day; // Day of the month int x_hour; // Hour in a day int x_min; // Minutes int x_sec; // Seconds //-- int oBm, oSm, ldig; //--- Variables used in prefix and suffix symbols int posCur1, posCur2; int inpre, insuf; bool symbfix; string pre,suf; string prefix,suffix; //--- Variables are used in Trading Time Zone int ishour, onhour; int tftrlst, tfcinws; datetime rem, znop, zncl, zntm; datetime SesCuOp, SesCuCl, Ses01Op, Ses01Cl, Ses02Op, Ses02Cl, Ses03Op, Ses03Cl, Ses04Op, Ses04Cl, Ses05Op, Ses05Cl, SesNoOp, SesNoCl; //-- string tz_ses, tz_opn, tz_cls; //-- string tmopcu, tmclcu, tmop01, tmcl01, tmop02, tmcl02, tmop03, tmcl03, tmop04, tmcl04, tmop05, tmcl05, tmopno, tmclno; //---------------------- //-- double LotPS; double slv, tpv, pip, xpip; double floatprofit, fixclprofit; //-- string pairs, hariini, daytrade, trade_mode; //-- double OPEN[], HIGH[], LOW[], CLOSE[]; datetime TIME[]; datetime closetime; //-- //------------ //------------ void SetSymbolNamePS(void); void HandlingSymbolArrays(void); void Set_Time_Zone(void); void Time_Zone(void); bool Trade_session(void); string PosTimeZone(void); int ThisTime(const int reqmode); int ReqTime(datetime reqtime,const int reqmode); //-- int DirectionMove(const string symbol,const ENUM_TIMEFRAMES stf); int TriaMASMTF(const string symbol,ENUM_TIMEFRAMES mtf); int GetTriaMASignalMTF(string symbol); int TriaMASignalSTF(const string symbol); int LotDig(const string symbol); //-- double MLots(const string symbx); double NonZeroDiv(double val1,double val2); double OrderSLSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice); double OrderTPSet(const string xsymb,ENUM_ORDER_TYPE type,double atprice); double SetOrderSL(const string xsymb,ENUM_POSITION_TYPE type,double atprice); double SetOrderTP(const string xsymb,ENUM_POSITION_TYPE type,double atprice); double TSPrice(const string xsymb,ENUM_POSITION_TYPE ptype,int TS_type); //-- string ReqDate(int d,int h,int m); string TF2Str(ENUM_TIMEFRAMES period); string timehr(int hr,int mn); string TradingDay(void); string AccountMode(); string GetCommentForOrder(void) { return(expname); } //------------ public: //--- //-- TriangularMA_MTF_MCEA Config -- string DIRI[], AS30[], VSym[]; string SPC[]; string USD[]; string EUR[]; string GBP[]; string AUD[]; string NZD[]; string CAD[]; string CHF[]; string JPY[]; //-- string expname; string indiname; //-- int hTriMAt[]; int hTriMAs[]; int hTriMAm[]; int hTriMAb[][11]; int ALO, dgts, arrsar, arrsymbx; int sall, arusd, aretc, arspc, arper; ulong slip; //-- double profitb[], profits[]; //-- int Buy, Sell; int ccur, psec, xtto, TFArrays, checktml; int OpOr[],xob[],xos[]; //-- int year, // Year mon, // Month day, // Day hour, // Hour min, // Minutes sec, // Seconds dow, // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) doy; // Day number of the year (January 1st is assigned the number value of zero) //-- ENUM_TIMEFRAMES TFt, TFts, TFT05, TFCWS; ENUM_TIMEFRAMES TFTri[]; //-- bool PanelExtra; //------------ MCEA(void); ~MCEA(void); //------------ //-- virtual void TriangularMA_MTF_MCEA_Config(void); virtual void ExpertActionTrade(void); //-- void ArraySymbolResize(void); void CurrentSymbolSet(const string symbol); void Pips(const string symbol); void TradeInfo(void); void Do_Alerts(const string symbx,string msgText); void CheckOpenPMx(const string symbx); void SetSLTPOrders(void); void CloseBuyPositions(const string symbol); void CloseSellPositions(const string symbol); void CloseAllOrders(void); void CheckClose(const string symbx); void TodayOrders(void); void UpdatePrice(const string symbol,ENUM_TIMEFRAMES xtf); void RefreshPrice(const string symbx,ENUM_TIMEFRAMES xtf,int bars); //-- bool RefreshTick(const string symbx); bool TradingToday(void); bool OpenBuy(const string symbol); bool OpenSell(const string symbol); bool ModifyOrderSLTP(double mStop,double ordtp); bool ModifySLTP(const string symbx,int TS_type); bool CloseAllProfit(void); bool ManualCloseAllProfit(void); //-- int PairsIdxArray(const string symbol); int ValidatePairs(const string symbol); int TFIndexArray(ENUM_TIMEFRAMES TF); int GetOpenPosition(const string symbol); int GetSignalMidTF(const string symbol); int GetCloseInWeakSignal(const string symbol,int exis); //-- string getUninitReasonText(int reasonCode); //-- //------------ //--- }; //-end class MCEA //---------//
Самая первая и главная функция в работе мультивалютного советника, вызываемая из OnInit(), - это TriangularMA_MTF_MCEA_Config().
В функции TriangularMA_MTF_MCEA_Config() настраиваются все используемые символы, все применяемые индикаторы хэндлов и некоторые важные функции заголовка файла include.
void MCEA::TriangularMA_MTF_MCEA_Config(void) { //--- //-- HandlingSymbolArrays(); // With this function we will handle all pairs that will be traded //-- int arstr=0, arend=0; TFT05=PERIOD_M5; ENUM_TIMEFRAMES TFs[]={PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1}; int arTFs=ArraySize(TFs); //-- for(int x=0; x<arTFs; x++) { if(singletf==x) TFt=TFs[x]; // TF for single-timeframe if(tfstart==x) arstr=x; // multi-timeframe start calculation timeframe if(tfclose==x) arend=x; // multi-timeframe end calculation timeframe } //-- if(arstr>=arend) { Alert("Error selecting Start and End Timeframe, Start Timeframe must be smaller than End Timeframe"); Alert("-- "+expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); } //-- switch(tfinuse) { case MTF: { TFArrays=arend-arstr+1; ArrayResize(TFTri,TFArrays,TFArrays); ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY); tfcinws=arstr+1; tftrlst=(int)TFArrays/2; TFts=TFs[tftrlst+arstr-1]; // TF for Trailing Stop TFCWS=TFs[tfcinws]; // TF for Close Order in weak signal break; } case STF: { TFArrays=arTFs; ArrayResize(TFTri,TFArrays,TFArrays); ArrayCopy(TFTri,TFs,0,0,WHOLE_ARRAY); tfcinws=TFIndexArray(TFt)-2 <=0 ? 1 : TFIndexArray(TFt)-2; TFts=TFt; // TF for Trailing Stop TFCWS=TFs[tfcinws]; // TF for Close Order in weak signal break; } } //-- //-- Triangular MA Indicators handle for all symbol for(int x=0; x<arrsymbx; x++) { hTriMAs[x]=iCustom(DIRI[x],TFT05,indiname,Trmaperiod,Trprice); hTriMAm[x]=iCustom(DIRI[x],TFCWS,indiname,Trmaperiod,Trprice); hTriMAt[x]=iCustom(DIRI[x],TFts,indiname,Trmaperiod,Trprice); //-- for(int i=0; i<TFArrays; i++) { if(tfinuse==MTF) // MTF indicator handle { hTriMAb[x][i]=iCustom(DIRI[x],TFTri[i],indiname,Trmaperiod,Trprice); } if(tfinuse==STF) { if(TFs[i]==TFt) // Single-TF indicator handle { hTriMAb[x][i]=iCustom(DIRI[x],TFs[i],indiname,Trmaperiod,Trprice); break; } } } } //-- ALO=(int)mc_account.LimitOrders()>sall ? sall : (int)mc_account.LimitOrders(); //-- LotPS=(double)ALO; //-- mc_trade.SetExpertMagicNumber(magicEA); mc_trade.SetDeviationInPoints(slip); mc_trade.SetMarginMode(); Set_Time_Zone(); //-- return; //--- } //-end TriangularMA_MTF_MCEA_Config() //---------//
2. Функция Expert tick
В функции Expert tick (OnTick()) мы будем вызывать одну из основных функций мультивалютного советника, а именно функцию ExpertActionTrade().
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(void) { //--- mc.ExpertActionTrade(); //-- return; //--- } //-end OnTick() //---------//
Последовательность работы советника внутри этой функции.
Функция ExpertActionTrade() будет выполнять все действия и управлять автоматической торговлей, включая открытие/закрытие ордеров, трейлинг-стоп, трейлинг тейк-профита и другие дополнительные действия.
void MCEA::ExpertActionTrade(void) { //--- //--Check Trading Terminal ResetLastError(); //-- if(!MQLInfoInteger(MQL_TRADE_ALLOWED) && mc.checktml==0) //-- Check whether MT5 Algorithmic trading is Allow or Prohibit { mc.Do_Alerts(Symbol(),"Trading Expert at "+Symbol()+" are NOT Allowed by Setting."); mc.checktml=1; //-- Variable checktml is given a value of 1, so that the alert is only done once. return; } //-- if(!DisplayManualButton("M","C","R")) DisplayManualButton(); //-- Show the expert manual button panel //-- if(trade_info_display==Yes) mc.TradeInfo(); //-- Displayed Trading Info on Chart //--- //-- int mcsec=mc.ThisTime(mc.sec); //-- if(fmod((double)mcsec,5.0)==0) mc.ccur=mcsec; //-- if(mc.ccur!=mc.psec) { string symbol; //-- Here we start with the rotation of the name of all symbol or pairs to be traded for(int x=0; x<mc.arrsymbx && !IsStopped(); x++) { //-- if(mc.DIRI[x]==Symbol()) symbol=Symbol(); else symbol=mc.DIRI[x]; //-- mc.CurrentSymbolSet(symbol); //-- if(mc.TradingToday() && mc.Trade_session()) { //-- mc.OpOr[x]=mc.GetOpenPosition(symbol); //-- Get trading signals to open positions //-- //-- and store in the variable OpOr[x] if(mc.OpOr[x]==mc.Buy) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Buy" (value=1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xos[x]>0) mc.CloseSellPositions(symbol); //-- if(mc.xob[x]==0 && mc.xtto<mc.ALO) mc.OpenBuy(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xos[x]>0 && mc.profits[x]<-1.02 && mc.xob[x]==0) {mc.CloseSellPositions(symbol); mc.OpenBuy(symbol);} else if(SaveOnRev==Yes) mc.CloseAllProfit(); } } if(mc.OpOr[x]==mc.Sell) //-- If variable OpOr[x] get result of GetOpenPosition(symbol) as "Sell" (value=-1) { //-- mc.CheckOpenPMx(symbol); //-- if(Close_by_Opps==Yes && mc.xob[x]>0) mc.CloseBuyPositions(symbol); //-- if(mc.xos[x]==0 && mc.xtto<mc.ALO) mc.OpenSell(symbol); else if(mc.xtto>=mc.ALO) { //-- mc.Do_Alerts(symbol,"Maximum amount of open positions and active pending orders has reached"+ "\n the limit = "+string(mc.ALO)+" Orders "); //-- mc.CheckOpenPMx(symbol); //-- if(mc.xob[x]>0 && mc.profitb[x]<-1.02 && mc.xos[x]==0) {mc.CloseBuyPositions(symbol); mc.OpenSell(symbol);} else if(SaveOnRev==Yes) mc.CloseAllProfit(); } } } //-- mc.CheckOpenPMx(symbol); //-- if(mc.xtto>0) { //-- if(SaveOnRev==Yes) //-- Close Trade and Save profit due to weak signal (Yes) { mc.CheckOpenPMx(symbol); if(mc.profitb[x]>0.02 && mc.xob[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Buy)==mc.Sell) { mc.CloseBuyPositions(symbol); mc.Do_Alerts(symbol,"Close BUY order "+symbol+" to save profit due to weak signal."); } if(mc.profits[x]>0.02 && mc.xos[x]>0 && mc.GetCloseInWeakSignal(symbol,mc.Sell)==mc.Buy) { mc.CloseSellPositions(symbol); mc.Do_Alerts(symbol,"Close SELL order "+symbol+" to save profit due to weak signal."); } } //-- if(TrailingSLTP==Yes) //-- Use Trailing SL/TP (Yes) { if(autotrl==Yes) mc.ModifySLTP(symbol,1); //-- If Use Automatic Trailing (Yes) if(autotrl==No) mc.ModifySLTP(symbol,0); //-- Use Automatic Trailing (No) } } //-- mc.CheckClose(symbol); } //-- mc.psec=mc.ccur; } //-- return; //--- } //-end ExpertActionTrade() //---------//
Специально для торговых часовых поясов в функцию ExpertActionTrade() добавлен вызов логической функции Trade_session().
При Trade_session() равном true, советник работает до завершения, а при false, советник будет выполнять только задачи Close Trade and Save profit due to weak signal (Yes) (закрыть сделку и сохранить прибыль из-за слабого сигнала (Да)) и Trailing stop (Yes) (трейлинг-стоп (да)).
bool MCEA::Trade_session(void) { //--- bool trd_ses=false; ishour=ThisTime(hour); if(ishour!=onhour) Set_Time_Zone(); datetime tcurr=TimeCurrent(); // Server Time //-- switch(session) { case Cus_Session: { if(tcurr>=SesCuOp && tcurr<=SesCuCl) trd_ses=true; break; } case New_Zealand: { if(tcurr>=Ses01Op && tcurr<=Ses01Cl) trd_ses=true; break; } case Australia: { if(tcurr>=Ses02Op && tcurr<=Ses02Cl) trd_ses=true; break; } case Asia_Tokyo: { if(tcurr>=Ses03Op && tcurr<=Ses03Cl) trd_ses=true; break; } case Europe_London: { if(tcurr>=Ses04Op && tcurr<=Ses04Cl) trd_ses=true; break; } case US_New_York: { if(tcurr>=Ses05Op && tcurr<=Ses05Cl) trd_ses=true; break; } } //-- if(trd_time_zone==No) { if(tcurr>=SesNoOp && tcurr<=SesNoCl) trd_ses=true; } //-- onhour=ishour; //-- return(trd_ses); //--- } //-end Trade_session() //---------//
3. Получение торговых сигналов для открытия позиций
Для получения сигнала функция ExpertActionTrade() вызывает функцию GetOpenPosition().
int MCEA::GetOpenPosition(const string symbol) // Signal Open Position { //--- int ret=0; int rise=1, down=-1; //-- int trimOp=GetTriaMASignalMTF(symbol); int getmid=GetSignalMidTF(symbol); if(trimOp==rise && getmid==rise) ret=rise; if(trimOp==down && getmid==down) ret=down; //-- return(ret); //--- } //-end GetOpenPosition() //---------//
Функция GetOpenPosition() вызовет две функции, выполняющие расчет сигналов:
1. GetSignalMidTF(const string symbol); //-- Получение сигналов по позициям среднего таймфрейма и движения цены
int MCEA::GetSignalMidTF(const string symbol) // Signal Indicator Position Close in profit { //--- int ret=0; int rise=1, down=-1; //-- int br=2; //-- double TriMACI[]; //-- ArrayResize(TriMACI,br,br); ArraySetAsSeries(TriMACI,true); int xx=PairsIdxArray(symbol); CopyBuffer(hTriMAm[xx],1,0,br,TriMACI); //#property indicator_color1 clrDarkGray,clrDeepPink,clrMediumSeaGreen // 0 1 2 //-- int dirmove=DirectionMove(symbol,TFCWS); //-- if(TriMACI[0]==2.0 && dirmove==rise) ret=rise; if(TriMACI[0]==1.0 && dirmove==down) ret=down; //-- return(ret); //--- } //-end GetSignalMidTF() //---------//
2. GetTriaMASignalMTF(const string symbol); //-- Расчет формулы треугольной скользящей средней.
Функция GetTriaMASignalMTF() вызывает функцию TriaMASMTF(), которая вычисляет сигнал треугольной скользящей средней в соответствии с запрошенным таймфреймом.
int MCEA::GetTriaMASignalMTF(string symbol) { //--- int mv=0; int rise=1, down=-1; int tfloop=tfinuse==MTF ? TFArrays : 1; //-- int trimup=0, trimdw=0; //-- for(int x=0; x<tfloop; x++) { if(TriaMASMTF(symbol,TFTri[x])>0) trimup++; if(TriaMASMTF(symbol,TFTri[x])<0) trimdw++; } //-- if(trimup==tfloop) mv=rise; if(trimdw==tfloop) mv=down; //-- return(mv); //--- } //- end GetTriaMASignalMTF() //---------//
int MCEA::TriaMASMTF(const string symbol,const ENUM_TIMEFRAMES mtf) // formula Triangular MA on the requested Timeframe { //--- int ret=0; int rise=1, down=-1; int br=3; ENUM_TIMEFRAMES TFUse=tfinuse==MTF ? mtf : TFt; //-- double TriMACI[]; ArrayResize(TriMACI,br,br); ArraySetAsSeries(TriMACI,true); int xx=PairsIdxArray(symbol); int tx=TFIndexArray(TFUse); CopyBuffer(hTriMAb[xx][tx],1,0,br,TriMACI); //#property indicator_color1 clrDarkGray,clrDeepPink,clrMediumSeaGreen // 0 1 2 //Print("Symbol = "+symbol+" TF = "+EnumToString(mtf)+" TriMACI[0] = "+string(TriMACI[0])); //-- switch(tfinuse) { case MTF: { if(TriMACI[0]==2.0) ret=rise; if(TriMACI[0]==1.0) ret=down; //-- break; } case STF: { if(TriMACI[2]==1.0 && TriMACI[1]==2.0 && TriMACI[0]==2.0) ret=rise; if(TriMACI[2]==2.0 && TriMACI[1]==1.0 && TriMACI[0]==1.0) ret=down; //-- break; } } //-- return(ret); //--- } //-end TriaMASMTF() //---------//
Как видите, мы используем и вызываем две функции внутри функции TriaMASMTF():
- 1. int xx= PairsIdxArray(symbol)
- 2. int tx=TFIndexArray(mtf).
Функция PairsIdxArray() используется для получения имени запрошенного символа, а функция TFIndexArray() — для получения последовательности массива запрошенного таймфрейма.
Затем вызывается соответствующий хэндл индикатора, чтобы получить значение буфера треугольной скользящей средней из этого таймфрейма.
Как говорит автор индикатора:
"Использование:
В качестве сигнала можно использовать смену цвета".
Итак, как мы принимаем сигнал треугольной скользящей средней?
В свойстве треугольной скользящей средней:
#property indicator_color1 clrDarkGray,clrDeepPink,clrMediumSeaGreen // 0 1 2
SetIndexBuffer(1,valc,INDICATOR_COLOR_INDEX);
valc[i] = (i>0) ?(val[i]>val[i-1]) ? 2 :(val[i]<val[i-1]) ? 1 : valc[i-1]: 0;
Итак, мы знаем, что:
- 0-DarkGray = неизвестный сигнал
- 1-DeepPink = сигнал на продажу
- 2-MediumSeaGreen = сигнал на покупку.
Итак, мы можем взять значение буфера 1 треугольной скользящей средней в качестве сигнала с помощью функции CopyBuffer, как и в функции TriaMASMTF().
double TriMACI[]; ArrayResize(TriMACI,br,br); ArraySetAsSeries(TriMACI,true); int xx=PairsIdxArray(symbol); int tx=TFIndexArray(TFUse); CopyBuffer(hTriMAb[xx][tx],1,0,br,TriMACI); //#property indicator_color1 clrDarkGray,clrDeepPink,clrMediumSeaGreen // 0 1 2
4. Функция ChartEvent
Для большей эффективности мультивалютных советников создадим несколько кнопок для управления ордерами, а также
изменения графиков и символов.
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- //--- handling CHARTEVENT_CLICK event ("Clicking the chart") ResetLastError(); //-- ENUM_TIMEFRAMES CCS=mc.TFt; //-- if(id==CHARTEVENT_OBJECT_CLICK) { int lensymbol=StringLen(Symbol()); int lensparam=StringLen(sparam); //-- //--- if "Set SL All Orders" button is click if(sparam=="Set SL/TP All Orders") { mc.SetSLTPOrders(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Set SL/TP All Orders"); //--- unpress the button ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_STATE,false); ObjectSetInteger(0,"Set SL/TP All Orders",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "Close All Order" button is click if(sparam=="Close All Order") { mc.CloseAllOrders(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Orders"); //--- unpress the button ObjectSetInteger(0,"Close All Order",OBJPROP_STATE,false); ObjectSetInteger(0,"Close All Order",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "Close All Profit" button is click if(sparam=="Close All Profit") { mc.ManualCloseAllProfit(); Alert("-- "+mc.expname+" -- ",Symbol()," -- Close All Profit"); //--- unpress the button ObjectSetInteger(0,"Close All Profit",OBJPROP_STATE,false); ObjectSetInteger(0,"Close All Profit",OBJPROP_ZORDER,0); CreateManualPanel(); } //--- if "X" button is click if(sparam=="X") { ObjectsDeleteAll(0,0,OBJ_BUTTON); ObjectsDeleteAll(0,0,OBJ_LABEL); ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL); //--- unpress the button ObjectSetInteger(0,"X",OBJPROP_STATE,false); ObjectSetInteger(0,"X",OBJPROP_ZORDER,0); //-- DeleteButtonX(); mc.PanelExtra=false; DisplayManualButton(); } //--- if "M" button is click if(sparam=="M") { //--- unpress the button ObjectSetInteger(0,"M",OBJPROP_STATE,false); ObjectSetInteger(0,"M",OBJPROP_ZORDER,0); mc.PanelExtra=true; CreateManualPanel(); } //--- if "C" button is click if(sparam=="C") { //--- unpress the button ObjectSetInteger(0,"C",OBJPROP_STATE,false); ObjectSetInteger(0,"C",OBJPROP_ZORDER,0); mc.PanelExtra=true; CreateSymbolPanel(); } //--- if "R" button is click if(sparam=="R") { Alert("-- "+mc.expname+" -- ",Symbol()," -- expert advisor will be Remove from the chart."); ExpertRemove(); //--- unpress the button ObjectSetInteger(0,"R",OBJPROP_STATE,false); ObjectSetInteger(0,"R",OBJPROP_ZORDER,0); if(!ChartSetSymbolPeriod(0,Symbol(),Period())) ChartSetSymbolPeriod(0,Symbol(),Period()); DeletePanelButton(); ChartRedraw(0); } //--- if Symbol button is click if(lensparam==lensymbol) { int sx=mc.ValidatePairs(sparam); ChangeChartSymbol(mc.AS30[sx],CCS); mc.PanelExtra=false; } //-- } //-- return; //--- } //-end OnChartEvent() //---------//
Чтобы изменить символы графика одним щелчком мыши, при нажатии на одно из названий символов, событие OnChartEvent() будет вызываться функцией ChangeChartSymbol().
void ChangeChartSymbol(string c_symbol,ENUM_TIMEFRAMES cstf) { //--- //--- unpress the button ObjectSetInteger(0,c_symbol,OBJPROP_STATE,false); ObjectSetInteger(0,c_symbol,OBJPROP_ZORDER,0); ObjectsDeleteAll(0,0,OBJ_BUTTON); ObjectsDeleteAll(0,0,OBJ_LABEL); ObjectsDeleteAll(0,0,OBJ_RECTANGLE_LABEL); //-- ChartSetSymbolPeriod(0,c_symbol,cstf); //-- ChartRedraw(0); //-- return; //--- } //-end ChangeChartSymbol() //---------//
Поскольку мы добавляем торговую сессию или торговый часовой пояс и параметры торгуемых пар на одном или нескольких таймфреймах, нам нужно добавить новые данные в отображаемой торговой информации на графике. Для этого мы внесли изменения в функцию TradeInfo().
void MCEA::TradeInfo(void) // function: write comments on the chart { //---- Pips(Symbol()); double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/xpip; rem=zntm-TimeCurrent(); string postime=PosTimeZone(); string eawait=" - Waiting for active time..!"; //-- string tradetf=tfinuse==MTF ? EnumToString(Period()) : EnumToString(TFts); string eamode=tfinuse==MTF ? "Multi-Timeframe" : "Single-Timeframe"; string comm=""; TodayOrders(); //-- comm="\n :: Server Date Time : "+string(ThisTime(year))+"."+string(ThisTime(mon))+"."+string(ThisTime(day))+ " "+TimeToString(TimeCurrent(),TIME_SECONDS)+ "\n ------------------------------------------------------------"+ "\n :: Broker : "+ TerminalInfoString(TERMINAL_COMPANY)+ "\n :: Expert Name : "+ expname+ "\n :: Acc. Name : "+ mc_account.Name()+ "\n :: Acc. Number : "+ (string)mc_account.Login()+ "\n :: Acc. TradeMode : "+ AccountMode()+ "\n :: Acc. Leverage : 1 : "+ (string)mc_account.Leverage()+ "\n :: Acc. Equity : "+ DoubleToString(mc_account.Equity(),2)+ "\n :: Margin Mode : "+ (string)mc_account.MarginModeDescription()+ "\n :: Magic Number : "+ string(magicEA)+ "\n :: Trade on TF : "+ tradetf+ "\n :: Trade Mode : "+ eamode+ "\n :: Today Trading : "+ TradingDay()+" : "+hariini+ "\n :: Trading Session : "+ tz_ses+ "\n :: Trading Time : "+ postime; if(TimeCurrent()<zntm) { comm=comm+ "\n :: Time Remaining : "+(string)ReqTime(rem,hour)+":"+(string)ReqTime(rem,min)+":"+(string)ReqTime(rem,sec) + eawait; } comm=comm+ "\n ------------------------------------------------------------"+ "\n :: Trading Pairs : "+pairs+ "\n :: BUY Market : "+string(oBm)+ "\n :: SELL Market : "+string(oSm)+ "\n :: Total Order : "+string(oBm+oSm)+ "\n :: Order Profit : "+DoubleToString(floatprofit,2)+ "\n :: Fixed Profit : "+DoubleToString(fixclprofit,2)+ "\n :: Float Money : "+DoubleToString(floatprofit,2)+ "\n :: Nett Profit : "+DoubleToString(floatprofit+fixclprofit,2); //-- Comment(comm); ChartRedraw(0); return; //---- } //-end TradeInfo() //---------//
Мы также добавили функцию для описания времени в соответствии с условиями торгового часового пояса как часть функции TradeInfo().
string MCEA::PosTimeZone(void) { //--- string tzpos=""; //-- if(ReqTime(zntm,day)>ThisTime(day)) { tzpos=tz_opn+ " Next day to " +tz_cls + " Next day"; } else if(TimeCurrent()<znop) { if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)==ReqTime(zncl,day)) tzpos=tz_opn+" to " +tz_cls+ " Today"; //else if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day)) tzpos=tz_opn+ " Today to " +tz_cls+ " Next day"; } else if(TimeCurrent()>=znop && TimeCurrent()<zncl) { if(ThisTime(day)<ReqTime(zncl,day)) tzpos=tz_opn+ " Today to " +tz_cls+ " Next day"; else if(ThisTime(day)==ReqTime(zncl,day)) tzpos=tz_opn+" to " +tz_cls+ " Today"; } else if(ThisTime(day)==ReqTime(znop,day) && ThisTime(day)<ReqTime(zncl,day)) { tzpos=tz_opn+" Today to " +tz_cls+ " Next day"; } //-- return(tzpos); //---- } //-end PosTimeZone() //---------//
Интерфейс мультивалютного советника TriangularMA_MTF_MCEA выглядит следующим образом.
Как видите, под именем советника TriangularMA_MTF_MCEA расположены кнопки M, C и R
При нажатии на M отобразится панель ручного управления
Затем трейдер может управлять ордерами, как описано в разделе "Ручное управление ордерами".
- 1. Set SL/TP All Orders (установить стоп-лосс/тейк-профит для всех ордеров)
- 2. Close All Orders (закрыть все ордера)
- 3. Close All Profits (закрыть все прибыльные ордера)
При нажатии на C отобразится кнопка панели с 30 именами символов или пар, и трейдеры смогут щелкнуть по одному из названий пар или символов.
При нажатии на любую из них символ графика будет немедленно заменен на тот, что указан на нажатой кнопке.
При нажатии на R мультивалютный советник TriangularMA_MTF_MCEA удаляется с графика, поэтому трейдерам не нужно отключать советников вручную.
Тестер стратегий
Как известно, тестер стратеггий терминала MetaTrader 5 поддерживает и позволяет тестировать стратегии, торговать на нескольких символах или тестировать автоматическую торговлю для всех доступных символов и на всех доступных таймфреймах.
Протестируем мультивалютный и мультитаймфреймовый советник TriangularMA_MTF_MCEA на одном и нескольких таймфреймах в тестере стратегий MetaTrader 5.
1. Тест TriangularMA_MTF_MCEA на нескольких таймфреймах.
/p>
2. Тест TriangularMA_MTF_MCEA на одном таймфрейме.
Заключение
Вывод по итогам создания мультивалютного и мультитаймфреймового советника для работы с одним и несколькими таймфреймами с использованием MQL5 можно сделать следующий:
- Создание мультивалютного советника на MQL5 мало чем отличается от разработки одновалютного. Но для мультивалютных советников с несколькими таймфреймами процесс немного сложнее, чем для советников с одним таймфреймом.
- Создание мультивалютного советника повысит эффективность и результативность трейдеров, поскольку трейдерам не нужно открывать много графиков.
- Правильная торговая стратегия увеличивает вероятность получения прибыли по сравнению с использованием одновалютного советника. Убытки по одной паре будут перекрываться прибылью в других парах.
- Мультивалютный советник TriangularMA_MTF_MCEA является всего лишь примером для изучения и развития собственных идей.
- Результаты тестирования в тестере стратегий по-прежнему неудовлетворительны. При реализации лучшей стратегии с более точным расчетом сигналов и лучшими таймфреймами, результат, на мой взгляд, должен быть лучше текущего.
- По результатам тестирования TriangularMA_MTF_MCEA в тестере стратегий выясняется, что результаты на одном таймфрейме лучше, чем на нескольких.
Примечание:
Если у вас есть идея создания простого мультивалютного советника на основе встроенных сигналов стандартного индикатора MQL5, предложите ее в комментариях.
Надеюсь, что статья и мультивалютный советник будут полезны трейдерам в изучении и развитии идей. Спасибо за внимание!
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/13770
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Прочитав статью, изучив ее и загрузив пример кода в конце.
Прочитав статью, изучив ее и скачав пример кода в конце.
Подскажите, пожалуйста, где можно скачать пример кода
Как объяснил модератор Фернандо Каррейро, посмотрите в самый низ статьи с надписью Прикрепленные файлы и щелкните по имени файла.
Подскажите, пожалуйста, где можно скачать пример кода