Elder-Ray Биржевой рентген (Bulls Power и Bears Power)
Введение
Торговую систему "Биржевой рентген" (Elder-Ray) описал Александр Элдер в своей книге "Как играть и выигрывать на бирже" (Trading for a living). Она основывается на осцилляторах Bulls Power (индекс силы быков), Bears Power (индекс силы медведей) и трендовом индикаторе Moving Average (EMA — экспоненциальное усреднение).
Торговая система одновременно и простая и сложная:
- простая — если читать и воспринимать буквально: сигнал к покупке — тенденция идёт вверх (EMA) и Bears Power (индекс силы медведей) ниже нуля, но повышается;
- сложная — если читать внимательнее, а также посмотреть на график, на котором запущены и EMA, и Bears Power: оказывается, не всё так просто, и таких условий очень мало.
В этой статье мы пройдем все этапы от простого к сложному и проверим две разновидности торговой системы:
- все индикаторы на одном графике (а значит, на одном таймфрейме);
- в сочетании с системой "Тройной выбор".
Советники в статье ориентированы на работу только с неттинговыми счетами.
Основные постулаты
Для понимания сущности торговой системы необходимо четко усвоить, что означает каждый элемент Биржевого рентгена: цена, EMA, максимумы и минимумы индикаторов Bulls Power и Bears Power на каждом баре, сила быков и сила медведей.
- Цена — сиюминутное соглашение о стоимости актива в данный момент. Все покупки совершаются в расчете на подъем цены, а продажи — в расчете на падение. Только когда покупатель согласен купить, а продавец — продать, совершается сделка.
- EMA — экспоненциальное скользящее среднее. Отражает среднее соглашение о стоимости актива за определенный промежуток. Например, EMA(13) на таймфрейме D1 представляет собой среднее соглашение о стоимости актива за последние 13 дней. Почему лучше использовать экспоненциальное, а не простое скользящие среднее? А. Элдер ответил на этот вопрос в главе 4.2 ("Скользящие средние"). Если вкратце, то EMA более чувствительна к изменениям тенденции, чем простое среднее.
- Максимум Bulls Power показывает максимальную силу быков на данном баре. Когда цена растет, быки зарабатывают, поэтому быки покупают, пока цена не поднимется до максимума. Максимум Bulls Power — это тот момент, когда у быков есть желание двигать цену выше, но денег уже нет.
- Минимум Bears Power показывает максимальную силу медведей на данном баре. Медведи зарабатывают, когда цена падает, и поэтому продают, пока цена не достигнет своего минимума. Минимум Bears Power — тот момент, когда у медведей есть желание двигать цену вниз, но уже нет возможностей.
- Сила быков показывает способность быков поднять цену над средним соглашением о ценности актива. Как правило сила быков выше нуля, если же она ниже нуля, значит, в стаде быков паника и они тонут.
- Сила медведей отражает способность медведей опустить цену ниже среднего соглашения о ценности актива. Обычно сила медведей ниже нуля, а если она выше нуля, значит, необычайно сильные быки подняли на рога медведей и те болтаются в воздухе.
Вариант 1: все индикаторы на одном графике
Исследовать будем фьючерсы и акции на таймфрейме D1. Все три индикатора (Bulls Power, Bears Power и EMA) располагаются на одном графике. Период усреднения всех индикаторов равен 13.
Правила для покупки
- тенденция идет вверх (ориентируемся по индикатору EMA);
- индекс силы медведей (Bears Power) ниже нуля, но повышается;
- отложенный ордер Buy stop размещается выше максимума двух последних дней, а защитный стоп-лосс ставится ниже последнего минимума.
CAT, Daily Buy signals
Правила для продажи
- тенденция идет вниз (опираемся на показания индикатора EMA);
- индекс силы быков (Bulls Power) выше нуля, но падает;
- отложенный Sell stop размещается ниже минимума последних двух дней, а защитный стоп-лосс — выше последнего максимума.
CAT, Daily Sell signals
Торговые правила
По рисункам 1 и 2 можно заметить, что в варианте торговой системы "Все индикаторы на одном графике" правила для покупки и для продажи срабатывают при откатах на устойчивом тренде. А таких благоприятных моментов встречается довольно мало, тем более что анализируемый таймфрейм — D1. Поэтому в варианте "Все индикаторы на одном графике" необходимо проводить анализ очень большого количества инструментов для увеличения частоты сделок на торговом счете.
Но в графиках D1 есть и один весомый плюс: анализ наклона EMA и показаний индикаторов Bulls Power и Bears Power можно проводить только один раз в сутки — в момент рождения нового бара. Именно так и будет работать советник: ожидать по каждому заданному символу на таймфрейме D1 новый бар и только после этого проводить анализ возможности входа.
Так как фьючерсы или акции — это только неттинг, разнонаправленные позиции (хедж) недопустимы, а вот наращивание объема позиции вполне допустимо. Советник может торговать или только по текущему символу, или по нескольким символам, которые хранятся в текстовом файле. Если с текущим символом всё понятно, то выбор нескольких символов может представлять следующие проблемы:
- нужно указать около ста символов одного рынка (например, только ценные бумаги);
- нужно указать множество символов с разных рынков (например, фьючерсы и ценные бумаги).
Как отобрать все символы с одного рынка? К примеру, есть символ "CAT", и он расположен по следующему пути: "Stock Markets\USA\NYSE/NASDAQ(SnP100)\CAT"
Допустим, этот символ нас устраивает, и мы хотим выбрать все остальные инструменты из ветки "\NYSE/NASDAQ(SnP100)\". В таком случае можно поступить так:
- открыть график этого символа;
- запустить скрипт (назовем его Symbols on the specified path.mq5), который получит путь символа (в примере выше для символа "CAT" это будет "Stock Markets\USA\NYSE/NASDAQ(SnP100)") и сохранит в текстовый файл все символы из полученного пути. Текстовый файл будет сохраняться в общую папку Common Data Folder;
- останется в настройках советника указать название текстового файла.
Реализация скрипта Symbols on the specified path.mq5 будет описана ниже.
Сборка советника. Вариант 1: все индикаторы на одном графике
Symbols on the specified path.mq5 — скрипт, с помощью которого получим текстовой файл с символами.
ВНИМАНИЕ: только распечатка текста "Everything is fine. There are no errors" во вкладке "Эксперты" гарантирует, что скрипт отработал без ошибок и полученный файл с символами можно использовать для работы советника!
Для сокращения кода файловых операций подключается класс CFileTxt, и работу с тестовым файлом ведёт m_file_txt — объект класса CFileTxt. Скрипт выполняет свою работу в семь шагов:
//+------------------------------------------------------------------+ //| Symbols on the specified path.mq5 | //| Copyright © 2018, Vladimir Karputov | //| http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2018, Vladimir Karputov" #property link "http://wmua.ru/slesar/" #property version "1.002" #property script_show_inputs //--- #include <Files\FileTxt.mqh> CFileTxt m_file_txt; // file txt object //--- input parameters input string InpFileName="Enter a unique name.txt"; // File name //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- STEP 1 string current_path=""; if(!SymbolInfoString(Symbol(),SYMBOL_PATH,current_path)) { Print("ERROR: SYMBOL_PATH"); return; } //--- STEP 2 string sep_="\\"; // A separator as a character ushort u_sep_; // The code of the separator character string result_[]; // An array to get strings //--- Get the separator code u_sep_=StringGetCharacter(sep_,0); //--- Split the string to substrings int k_=StringSplit(current_path,u_sep_,result_); //--- STEP 3 //--- Now output all obtained strings if(k_>0) { current_path=""; for(int i=0;i<k_-1;i++) current_path=current_path+result_[i]+sep_; } //--- STEP 4 string symbols_array[]; int symbols_total=SymbolsTotal(false); for(int i=0;i<symbols_total;i++) { string symbol_name=SymbolName(i,false); string symbol_path=""; if(!SymbolInfoString(symbol_name,SYMBOL_PATH,symbol_path)) continue; if(StringFind(symbol_path,current_path,0)==-1) continue; int size=ArraySize(symbols_array); ArrayResize(symbols_array,size+1,10); symbols_array[size]=symbol_name]; } //--- STEP 5 int size=ArraySize(symbols_array); if(size==0) { PrintFormat("ERROR: On path \"%s\" %d symbols",current_path,size); return; } PrintFormat("On path \"%s\" %d symbols",current_path,size); //--- STEP 6 if(m_file_txt.Open(InpFileName,FILE_WRITE|FILE_COMMON)==INVALID_HANDLE) { PrintFormat("ERROR: \"%s\" file in the Data Folder Common folder is not created",InpFileName); return; } //--- STEP 7 for(int i=0;i<size;i++) m_file_txt.WriteString(symbols_array[i]+"\r\n"); m_file_txt.Close(); Print("Everything is fine. There are no errors"); //--- } //+------------------------------------------------------------------+
Алгоритм работы скрипта:
- STEP 1: для текущего символа определяется SYMBOL_PATH — путь в дереве символов;
- STEP 2: полученный путь разбирается на подстроки с разделителем "\";
- STEP 3: заново собираем текущий путь, но уже без последней подстроки, так как последняя подстрока — это название символа;
- STEP 4: цикл по всем доступным символам; если у символа путь в дереве символов совпадает с текущим путем, выделяем название символа и добавляем в массив найденных символов;
- STEP 5: проверяем размер массива найденных символов;
- STEP 6: создаем файл;
- STEP 7: записываем в файл наш массив найденных символов и закрываем файл.
Elder-Ray 1 — советник (или несколько советников) с номерами версий 1.xxx, который будет торговать по варианту 1: все индикаторы на одном графике.
Как задавать объем позиции — минимальный лот может различаться
Простой эксперимент: проверим размер минимального лота у фьючерсов и ценных бумаг: по аналогии со скриптом Symbols on the specified path.mq5 переберем все символы, расположенные по тому же пути, что и текущий символ, только вместо сохранения символов в файл, выведем статистику по размеру минимального лота.
Gets minimal volume.mq5 — скрипт, с помощью которого выведем статистику по минимальному объему группы символов. Скрипт обходит группу символов и накапливает статистику (minimal volume to close a deal и counter) в двухмерном массиве:
//--- STEP 4 /* symbols_array[][2]: [*][minimal volume to close a deal] [*][counter] */
Полный код скрипта:
//+------------------------------------------------------------------+ //| Gets minimal volume.mq5 | //| Copyright © 2018, Vladimir Karputov | //| http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2018, Vladimir Karputov" #property link "http://wmua.ru/slesar/" #property version "1.000" //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- STEP 1 string current_path=""; if(!SymbolInfoString(Symbol(),SYMBOL_PATH,current_path)) { Print("ERROR: SYMBOL_PATH"); return; } //--- STEP 2 string sep_="\\"; // A separator as a character ushort u_sep_; // The code of the separator character string result_[]; // An array to get strings //--- Get the separator code u_sep_=StringGetCharacter(sep_,0); //--- Split the string to substrings int k_=StringSplit(current_path,u_sep_,result_); //--- STEP 3 //--- Now output all obtained strings if(k_>0) { current_path=""; for(int i=0;i<k_-1;i++) current_path=current_path+result_[i]+sep_; } //--- STEP 4 /* symbols_array[][2]: [*][minimal volume to close a deal] [*][counter] */ double symbols_array[][2]; int symbols_total=SymbolsTotal(false); for(int i=0;i<symbols_total;i++) { string symbol_name=SymbolName(i,false); string symbol_path=""; if(!SymbolInfoString(symbol_name,SYMBOL_PATH,symbol_path)) continue; if(StringFind(symbol_path,current_path,0)==-1) continue; double min_volume=0.0; if(!SymbolInfoDouble(symbol_name,SYMBOL_VOLUME_MIN,min_volume)) continue; int size=ArrayRange(symbols_array,0); bool found=false; for(int j=0;j<size;j++) { if(symbols_array[j][0]==min_volume) { symbols_array[j][1]=symbols_array[j][1]+1; found=true; continue; } } if(!found) { ArrayResize(symbols_array,size+1,10); symbols_array[size][0]=min_volume; symbols_array[size][1]=1.0; } } //--- STEP 5 int size=ArrayRange(symbols_array,0); if(size==0) { PrintFormat("ERROR: On path \"%s\" %d symbols",current_path,size); return; } //--- STEP 6 for(int i=0;i<size;i++) PrintFormat("Minimal volume %.2f occurs %.1f times",symbols_array[i][0],symbols_array[i][1]); Print("Everything is fine. There are no errors"); //--- } //+------------------------------------------------------------------+
Алгоритм работы скрипта:
- STEP 1: для текущего символа определяется SYMBOL_PATH — путь в дереве символов;
- STEP 2: полученный путь разбирается на подстроки с разделителем "\";
- STEP 3: заново собираем текущий путь, но уже без последней подстроки, так как последняя подстрока — это название символа;
- STEP 4: цикл по всем доступным символам; если у символа путь в дереве символов совпадает с текущим путем, получаем минимальный объем символа и производим поиск в массиве символов. Если такое значение уже есть, то увеличиваем счетчик. Если такого значения еще нет, добавляем в массив и счетчик ставим в "1.0";
- STEP 5: проверяем размер массива найденных символов;
- STEP 6: выводим статистику.
Результат запуска на ценных бумагах:
Gets minimal volume (CAT,D1) Minimal volume 1.00 occurs 100.0 times
и на фьючерсах:
Gets minimal volume (RTSRIU8,D1) Minimal volume 1.00 occurs 77.0 times
- на двух рынках размер лота одинаковый — 1.0.
Значит, не будем усложнять систему и примем за минимальный лот размер "1.0".
Визуализация используемых индикаторов
Когда вы в тестере запускаете визуальное тестирование, то вы видите индикаторы, которые использует советник. Но когда этот советник запускается на графике в терминале, индикаторы не показываются. В этой торговой системе я бы хотел видеть эти индикаторы на графике в терминале для визуального контроля работы советника. Что-то вроде этого:
Как видите, здесь я для всех индикаторов использовал свои настройки цвета и толщины линии (конечно, это всё было проделано вручную). А вот для автоматической визуализации индикаторов, используемых на графике в терминале, необходимо немного переписать индикаторы Moving Average, Bulls Power и Bears Power. Нечто подобное я уже реализовывал в коде Custom Moving Average Input Color — во входные параметры был вынесен цвет индикатора: этот входной параметр доступен при создании индикатора из советника. Остается по образу и подобию написать еще три индикатора.
Эти индикаторы (Custom Moving Average Inputs, Custom Bulls Power Inputs и Custom Bears Power Inputs) можно скачать в CodeBase. Обратите внимание, что скачанные индикаторы необходимо поместить в корень папки [data folder]\MQL5\Indicators\.
Elder-Ray 1.001.mq5 — визуализация используемых индикаторов, у которых можно настраивать цвет и ширину. Работает как в тестере стратегий, так и при запуске советника на графике:
Как это реализовано?
Главное условие — это наличие индикаторов Custom Moving Average Inputs, Custom Bulls Power Inputs и Custom Bears Power Inputs в папке [data folder]\MQL5\Indicators\
Управление внешним видом индикаторов, а также задание периода производится во входных параметрах, а для работы с индикаторами объявляются три переменные, в которых потом будут храниться хендлы индикаторов (handle_iCustom_MA, handle_iCustom_Bulls и handle_iCustom_Bears).
//+------------------------------------------------------------------+ //| Elder-Ray 1.mq5 | //| Copyright © 2018, Vladimir Karputov | //| http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2018, Vladimir Karputov" #property link "http://wmua.ru/slesar/" #property version "1.000" //--- //--- enum ENUM_INPUT_SYMBOLS { INPUT_SYMBOLS_CURRENT=0, // current symbol INPUT_SYMBOLS_FILE=1, // text file }; //--- input parameters input ENUM_INPUT_SYMBOLS InpInputSymbol = INPUT_SYMBOLS_FILE; // works on ... input uint InpNumberMinLots = 1; // Number of minimum lots //--- Custom Moving Average Inputs input int Inp_MA_ma_period = 13; // MA: averaging period input int Inp_MA_ma_shift = 0; // MA: horizontal shift input ENUM_MA_METHOD Inp_MA_ma_method = MODE_EMA; // MA: smoothing type input ENUM_APPLIED_PRICE Inp_MA_applied_price = PRICE_CLOSE; // MA: type of price input color Inp_MA_Color = clrChartreuse; // MA: Color input int Inp_MA_Width = 2; // MA: Width //--- Custom Bulls Power Inputs input int Inp_Bulls_ma_period = 13; // Bulls Power: averaging period input color Inp_Bulls_Color = clrBlue; // Bulls Power: Color input int Inp_Bulls_Width = 2; // Bulls Power: Width //--- Custom Bears Power Inputs input int Inp_Bears_ma_period = 13; // Bears Power: averaging period input color Inp_Bears_Color = clrRed; // Bears Power: Color input int Inp_Bears_Width = 2; // Bears Power: Width int handle_iCustom_MA; // variable for storing the handle of the iCustom indicator int handle_iCustom_Bulls; // variable for storing the handle of the iCustom indicator int handle_iCustom_Bears; // variable for storing the handle of the iCustom indicator //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit()
В OnInit() создаются хендлы пользовательских индикаторов (применяется iCustom), и созданные индикаторы добавляются на график (применяется ChartIndicatorAdd).
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create handle of the indicator iCustom handle_iCustom_MA=iCustom(Symbol(),Period(),"Custom Moving Average Inputs", Inp_MA_ma_period, Inp_MA_ma_shift, Inp_MA_ma_method, Inp_MA_Color, Inp_MA_Width, Inp_MA_applied_price); //--- if the handle is not created if(handle_iCustom_MA==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Moving Average Inputs\") for the symbol %s/%s, error code %d", Symbol(), EnumToString(Period()), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } //--- create handle of the indicator iCustom handle_iCustom_Bulls=iCustom(Symbol(),Period(),"Custom Bulls Power Inputs", Inp_Bulls_ma_period, Inp_Bulls_Color, Inp_Bulls_Width); //--- if the handle is not created if(handle_iCustom_Bulls==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Bulls Power Inputs\") for the symbol %s/%s, error code %d", Symbol(), EnumToString(Period()), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } //--- create handle of the indicator iCustom handle_iCustom_Bears=iCustom(Symbol(),Period(),"Custom Bears Power Inputs", Inp_Bears_ma_period, Inp_Bears_Color, Inp_Bears_Width); //--- if the handle is not created if(handle_iCustom_Bears==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Bears Power Inputs\") for the symbol %s/%s, error code %d", Symbol(), EnumToString(Period()), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } ChartIndicatorAdd(0,0,handle_iCustom_MA); int windows_total=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL); ChartIndicatorAdd(0,windows_total,handle_iCustom_Bulls); ChartIndicatorAdd(0,windows_total+1,handle_iCustom_Bears); //--- return(INIT_SUCCEEDED); }
Экономим ресурсы. Elder-Ray 1.010.mq5
Исследуемых символов одной группы может быть около сотни. Поэтому резонно возникает вопрос экономии оперативной памяти, ведь на каждом графике будут по три индикатора. Как и в случае с минимальным лотом, нет ничего лучше, чем взять и проверить потребление ресурсов советником. А заодно немного продвинемся в сборке нашего советника - добавим код, который читает из текстового файла имена символов одной группы и работает с ними.
В советнике подключается класс CFileTxt (мы его уже применяли в скрипте Symbols on the specified path.mq5) — объект этого класса m_file_txt отвечает за доступ к текстовому файлу и чтение информации из файла. Также подключаем класс CSymbolInfo — объект этого класса m_symbol отвечает за проверку существования символа и за добавление символа в окно "Обзор рынка". Почему выбор пал именно на CSymbolInfo, а не на реализацию через SymbolInfoInteger и SymbolSelect функции? Всё просто: в классе CSymbolInfo весь код по проверке, добавлению или сообщениям об ошибках спрятан внутри класса, и в советнике нужно лишь прописать эти три строки:
if(!m_symbol.Name(name)) // sets symbol name { m_file_txt.Close(); return(INIT_FAILED); }
Здесь не лишним будет вспомнить, что все символы мультивалютного эксперта должны быть добавлены в окно "Обзор рынка": Включение необходимых символов в окне "Обзор рынка" для мультивалютных экспертов.
Итак, советник работает по такому алгоритму: в OnInit() открывает текстовой файл, считывает символ и сразу пытается создать три пользовательских индикатора (Custom Moving Average Inputs, Custom Bulls Power Inputs и Custom Bears Power Inputs) по считанному символу и на текущем таймфрейме. Если индикатор создать не удалось (например, банально не хватило баров для создания Custom Moving Average Inputs), то просто идем по циклу дальше. Если же индикаторы были созданы, заносим имя символа в массив m_symbols_array, а хендлы трех индикаторов — в трехмерный массив m_handles_array. Таким образом по первому измерению оба массива синхронно содержат информацию по имени символа и о хендлах на этом символе:
//--- if(m_file_txt.Open(InpFileName,FILE_READ|FILE_COMMON)==INVALID_HANDLE) { PrintFormat("ERROR: \"%s\" file in the Data Folder Common folder is not open: %d",InpFileName,GetLastError()); return(INIT_FAILED); } //--- symbol info object OR file txt object if(InpInputSymbol==INPUT_SYMBOLS_FILE) { //--- read data from the file int counter=0; while(!m_file_txt.IsEnding()) { counter++; Print("Iteration ",counter); string name=m_file_txt.ReadString(); if(!m_symbol.Name(name)) // sets symbol name { m_file_txt.Close(); return(INIT_FAILED); } int MA,Bulls,Bears; if(!CreateHandles(name,Period(),MA,Bulls,Bears)) continue; //return(INIT_FAILED); int size=ArraySize(m_symbols_array); ArrayResize(m_symbols_array,size+1,10); ArrayResize(m_handles_array,size+1,10); m_symbols_array[size]=name; m_handles_array[size][0]=MA; m_handles_array[size][1]=Bulls; m_handles_array[size][2]=Bears; } m_file_txt.Close(); } else { if(!m_symbol.Name(Symbol())) // sets symbol name return(INIT_FAILED); } //--- ChartIndicatorAdd(0,0,handle_iCustom_MA);
Хендлы индикаторов создаются в CreateHandles().
Итак, потребление памяти замерялось через TERMINAL_MEMORY_USED и визуально в диспетчере задач Windows 10. Чтобы определить потребление памяти по шагам, в версии 1.010 специально отключались некоторые строки (строки были закомментированы). В итоговой версии 1.010 все строки по добавлению символов и созданию индикаторов раскомментированы.
- Запуск советника обычным способом: советник прикреплен на график:
- старт терминала (символы из текстового файла еще не добавлены в окно "Обзор рынка") — TERMINAL_MEMORY_USED 345 МБ, диспетчер задач от 26 до 90 МБ;
- добавляем около сотни символов в окно "Обзор рынка" — TERMINAL_MEMORY_USED 433 МБ, диспетчер задач + 10 МБ;
- а теперь по каждому символу создаем три индикатора — TERMINAL_MEMORY_USED 5523 МБ, диспетчер задач 300 МБ.
- Запуск тестера (без визуализации) — TERMINAL_MEMORY_USED 420 МБ, а в диспетчера задач 5 ГБ.
Вывод: TERMINAL_MEMORY_USED показывает суммарное потребление ОЗУ и дискового пространства. И так как потребление ОЗУ в обычном режиме не превышает 300 МБ, ничего экономить не будем.
Тенденция (EMA) идет...
Определить направление тренда (EMA) — это главная задача советника. На одном баре тренд не определить — необходима информация с нескольких баров. Обозначим этот параметр "bars". Вот три графика ценных бумаг — CAT, MCD и V. Пусть обозначения тренда следующее: тренд вверх "+1", нет тренда "0" и тренд вниз "—1"
Тогда на графике "CAT" тренд "0" (4 бара вниз, 4 вверх, на остальных барах изменение индикатора мизерное), на "MCD" тренд "—1" (8 баров вниз, остальные в неопределенном состоянии) и на "V" тренд "0" (6 баров вверх, 2 или 3 вниз). Возможно, следует ввести параметр different — минимальная разница между показаниями индикатора на соседних барах.
Определяем тренд. Elder-Ray 1.020.mq5
Условия наличия тренда: EMA на протяжении bars должна быть направлена в одну сторону. Вероятно, потом следует проверить два дополнительных параметра:
- different — минимальная разница между показаниями индикатора на соседних барах;
- trend percentage — минимальный процент показаний индикатора в одну строну (на рисунке: символ CAT - индикатор EMA направлен в разные стороны на участке bars, а на символе MCD все показания индикатора EMA (или почти все) направлены в одну строну).
Что добавлено и удалено в версии 1.020:
- не реализован параметр different — минимальная разница между показаниями индикатора на соседних барах;
- "—" перечисление enum ENUM_INPUT_SYMBOLS — решено, что советник будет работать только символами из текстового файла;
- "+" параметр number of bars for identifying the trend — количество баров для идентификации тренда по EMA;
- "+" параметр minimum percentage of the trend — минимальное качество тренда (однонаправленность);
- "+" массив m_prev_bars — массив для хранения времени открытия предыдущего бара;
- "+" таймер 60 секунд — в таймере проходит проверка на новый бар.
Блок отлавливания нового бара и определения направления тренда
В OnTimer() раз в 60 секунд обходим массив символов (m_symbols_array), загруженный из текстового файла, и ловим новый бар на символе из массива. Получаем в массив ema_array данные индикатора EMA, достаточные для определения тренда. Производим подсчет: на скольких барах индикатор шел вверх, а на скольких — вниз. Выводим на печать найденные закономерности.
//+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- int size=ArraySize(m_symbols_array); for(int i=0;i<size;i++) { //--- we work only at the time of the birth of new bar datetime PrevBars=m_prev_bars[i]; datetime time_0=iTime(m_symbols_array[i],Period(),0); if(time_0==PrevBars) continue; m_prev_bars[i]=time_0; double ema_array[]; ArraySetAsSeries(ema_array,true); /* m_handles_array[*][MA][Bulls][Bears] */ if(!iMAGetArray(m_handles_array[i][0],0,InpBarsEMA+2,ema_array)) continue; int upwards=0; int downward=0; for(int j=1;j<InpBarsEMA+1;j++) { if(ema_array[j]>ema_array[j+1]) upwards++; else if(ema_array[j]<ema_array[j+1]) downward++; } if((double)upwards>InpBarsEMA*InpMinTrendPercentage/100.0) Print("On ",m_symbols_array[i]," trend UP!"); else if((double)downward>InpBarsEMA*InpMinTrendPercentage/100.0) Print("On ",m_symbols_array[i]," trend DOWN!"); else Print("On ",m_symbols_array[i]," trend NONE!"); } }
Результат определения тренда. Настройки: number of bars for identifying the trend — 6, minimum percentage of the trend — 75%. Помним, что если работаем в момент рождения нового бара, то нулевой бар не учитывается:
Выставляем отложенные ордера (Buy stop или Sell stop). Elder-Ray 1.030.mq5
Как обойти ошибку нехватки средств при открытии позиции? Так как мы работаем с отложенными ордерами, то ответ: "Никак"! Могут быть какие-то половинчатые решения, но гарантировать ничего нельзя, и основная причина — никто не знает, в какой момент сработает отложенный ордер и вообще сработает ли он когда-нибудь.
Итак, определять тренд советник вроде научился, теперь нужно, используя Правила для покупки и Правила для продажи, найти точки, в которых можно выставить отложенный ордер. Для открытия BUY будет простая проверка: значение индикатора Bears Power на баре #1 должно быть меньше нуля и больше значения Bears Power на баре #2. Для открытия SELL условие зеркальное: значение индикатора Bulls Power на баре #1 должно быть больше нуля и меньше значения Bears Power на баре #2.
В описании стратегии Александр Элдер указал, что для открытия BUY позиции "... защитный Стоп Лосс ставится ниже последнего минимума ...", а для открытия SELL позиции "... защитный Стоп Лосс - выше последнего максимума ...". Само понятие "последнего" оказалось размытым, и я проверил два варианта:
- выставлял стоп-лосс по ценам бара #1 и
- производил поиск ближайшего экстремума.
Вариант 1 оказался нежизнеспособным - очень часто были срабатывания стоп-лосса, поэтому в коде советника Elder-Ray 1.030.mq5 я остановился на варианте 2: поиске ближайшего экстремума.
Поиск ближайшего экстремума
Функция ищет ближайший экстремум:
Если экстремум не найден или обнаружена ошибка, возвращается false:
//+------------------------------------------------------------------+ //| Find the nearest extremum | //+------------------------------------------------------------------+ bool NearestExtremum(ENUM_SERIESMODE type,double &price) { if(type==MODE_LOW) { //--- search for the nearest minimum double low_array[]; ArraySetAsSeries(low_array,true); int copy=CopyLow(m_symbol.Name(),Period(),0,100,low_array); if(copy==-1) return(false); double low=DBL_MAX; for(int k=0;k<copy;k++) { if(low_array[k]<low) low=low_array[k]; else if(low_array[k]>low) break; } if(low!=DBL_MAX) { price=low; return(true); } } else if(type==MODE_HIGH) { //--- search for the nearest maximum double high_array[]; ArraySetAsSeries(high_array,true); int copy=CopyHigh(m_symbol.Name(),Period(),0,100,high_array); if(copy==-1) return(false); double high=DBL_MIN; for(int k=0;k<copy;k++) { if(high_array[k]>high) high=high_array[k]; else if(high_array[k]<high) break; } if(high!=DBL_MIN) { price=high; return(true); } } //--- return(false); }
Что добавлено и удалено в версии 1.030:
- "+" торговый класс CPositionInfo (и m_position - объект этого класса);
- "+" торговый класс CTrade (и m_trade - объект этого класса);
- "+" торговый класс COrderInfo (и m_order - объект этого класса);
- "+" трейлинг (параметры Trailing Stop и Trailing Step);
- "+" magic number — уникальный идентификатор эксперта;
- "+" OnInit() — проверка типа счета: если это хедж-счет - запретить торговлю и выгрузиться с ошибкой;
- OnInit() — изменен порядок визуализации: если запущен тестер стратегий, и текущий символ (символ, на котором запущен эксперт) есть в текстовом файле - индикаторы на текущий символ не добавляем (ChartIndicatorAdd не применяем);
- OnTimer() — добавлен код подтверждения сигнала и торговые операции по выставлению отложенных Buy Stop и Sell Stop ордеров;
- OnTradeTransaction() — добавлен механизм компенсации, если был разворот позиции или частичное закрытие;
- "+" при срабатывании Алгоритма компенсации, в OnTradeTransaction() стоп-лосс НЕ ВЫСТАВЛЯЕТСЯ, вместо этого модернизируется функция трейлинга: если в процессе перебора позиций обнаружится позиция без стоп-лосса, стоп-лосс будет выставлен по правилу поиска ближайшего экстремума;
- "+" добавлена переменная m_magic_compensation — идентификатор компенсационных сделок.
Чтобы разобраться с ситуациями, когда срабатывает отложенный ордер, противоположный по направлению к текущей позиции, нужно рассмотреть три типичных ситуации после срабатывания отложенного ордера Buy Stop:
№ | Существующая позиция, объем | Сработал отложенный ордер, объем | Получилась позиция, объем | Примечание к моменту срабатывания отложенного ордера | magic позиции был | Алгоритм компенсации (важно: перед компенсацией magic устанавливаем в m_magic_compensation) | magic позиции стал |
---|---|---|---|---|---|---|---|
1 | Sell 1.0 | Buy Stop 3.0 | Buy 2.0 | Разворот позиции (направление сделки DEAL_ENTRY_INOUT) | m_magic | Дополнительно открыть Buy объемом 3.0 — 2.0 = 1.0 | m_magic_compensation |
2 | Sell 1.0 | Buy Stop 1.0 | --- | Полное закрытие позиции (направление сделки DEAL_ENTRY_OUT) | m_magic | Поиск позиции. Если позиции нет, открыть Buy объемом 1.0 | m_magic_compensation |
3 | Sell 2.0 | Buy Stop 1.0 | Sell 1.0 | Частичное закрытие позиции (направление сделки DEAL_ENTRY_OUT) | m_magic | Поиск позиции. Если позиции есть и она противоположна Buy, открыть Buy объемом 1.0 + 1.0 = 2.0 | m_magic_compensation |
Для каждого из трех случаев я подготовил распечатку сделок и ордеров (тест на реальном неттинговом счете, но в тестере). Для формирования отчета по сделкам и ордерам я использовал код из скрипта History Deals and Orders.
#1: Sell 1.0 -> Buy Stop 3.0
Sell 1.0, Buy Stop 3.0 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |1 |0 |2016.12.08 00:00:00 |1481155200000 |DEAL_TYPE_BALANCE |DEAL_ENTRY_IN |0 |DEAL_REASON_CLIENT |0 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |0.00 |0.00000 |0.00 |0.00 |50000.00 | | | Order 0 is not found in the trade history between the dates 2010.08.07 11:06:20 and 2018.08.10 00:00:00 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |2 |2 |2016.12.08 00:00:00 |1481155200100 |DEAL_TYPE_SELL |DEAL_ENTRY_IN |15489 |DEAL_REASON_EXPERT |2 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |79.31 |0.00 |0.00 |0.00 |V | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |2 |2016.12.08 00:00:00 |ORDER_TYPE_SELL |ORDER_STATE_FILLED |2016.12.08 00:00:00 |2016.12.08 00:00:00 |1481155200100 |1481155200100 |ORDER_FILLING_FOK |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |15489 |ORDER_REASON_EXPERT |2 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |1.00 |0.00 |79.31 |0.00 |0.00 |79.39 |0.00 |Symbol |Comment |Extarnal id |V | | Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |3 |3 |2016.12.08 17:27:37 |1481218057877 |DEAL_TYPE_BUY |DEAL_ENTRY_INOUT |15489 |DEAL_REASON_EXPERT |2 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |3.00 |79.75 |0.00 |0.00 |-0.44 |V | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |3 |2016.12.08 14:30:00 |ORDER_TYPE_BUY_STOP |ORDER_STATE_FILLED |2016.12.08 14:30:00 |2016.12.08 17:27:37 |1481207400100 |1481218057877 |ORDER_FILLING_RETURN |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |15489 |ORDER_REASON_EXPERT |2 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |3.00 |0.00 |79.74 |75.17 |0.00 |79.74 |0.00 |Symbol |Comment |Extarnal id |V | | Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |4 |4 |2016.12.09 23:59:00 |1481327940000 |DEAL_TYPE_SELL |DEAL_ENTRY_OUT |0 |DEAL_REASON_CLIENT |2 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |2.00 |79.13 |0.00 |0.00 |-1.24 |V |end of test | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |4 |2016.12.09 23:59:00 |ORDER_TYPE_SELL |ORDER_STATE_FILLED |2016.12.09 23:59:00 |2016.12.09 23:59:00 |1481327940000 |1481327940000 |ORDER_FILLING_FOK |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |0 |ORDER_REASON_CLIENT |2 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |2.00 |0.00 |79.13 |0.00 |0.00 |79.13 |0.00 |Symbol |Comment |Extarnal id |V |end of test |
#2: Sell 1.0 -> Buy Stop 1.0
Sell 1.0, Buy Stop 1.0 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |1 |0 |2016.12.08 00:00:00 |1481155200000 |DEAL_TYPE_BALANCE |DEAL_ENTRY_IN |0 |DEAL_REASON_CLIENT |0 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |0.00 |0.00000 |0.00 |0.00 |50000.00 | | | Order 0 is not found in the trade history between the dates 2010.08.07 11:06:20 and 2018.08.10 00:00:00 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |2 |2 |2016.12.08 00:00:00 |1481155200100 |DEAL_TYPE_SELL |DEAL_ENTRY_IN |15489 |DEAL_REASON_EXPERT |2 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |79.31 |0.00 |0.00 |0.00 |V | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |2 |2016.12.08 00:00:00 |ORDER_TYPE_SELL |ORDER_STATE_FILLED |2016.12.08 00:00:00 |2016.12.08 00:00:00 |1481155200100 |1481155200100 |ORDER_FILLING_FOK |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |15489 |ORDER_REASON_EXPERT |2 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |1.00 |0.00 |79.31 |0.00 |0.00 |79.39 |0.00 |Symbol |Comment |Extarnal id |V | | Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |3 |3 |2016.12.08 17:27:37 |1481218057877 |DEAL_TYPE_BUY |DEAL_ENTRY_OUT |15489 |DEAL_REASON_EXPERT |2 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |79.75 |0.00 |0.00 |-0.44 |V | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |3 |2016.12.08 14:30:00 |ORDER_TYPE_BUY_STOP |ORDER_STATE_FILLED |2016.12.08 14:30:00 |2016.12.08 17:27:37 |1481207400100 |1481218057877 |ORDER_FILLING_RETURN |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |15489 |ORDER_REASON_EXPERT |2 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |1.00 |0.00 |79.74 |75.17 |0.00 |79.74 |0.00 |Symbol |Comment |Extarnal id |V | |
#3: Sell 2.0 -> Buy Stop 1.0
Sell 2.0, Buy Stop 1.0 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |1 |0 |2016.12.08 00:00:00 |1481155200000 |DEAL_TYPE_BALANCE |DEAL_ENTRY_IN |0 |DEAL_REASON_CLIENT |0 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |0.00 |0.00000 |0.00 |0.00 |50000.00 | | | Order 0 is not found in the trade history between the dates 2010.08.07 11:06:20 and 2018.08.10 00:00:00 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |2 |2 |2016.12.08 00:00:00 |1481155200100 |DEAL_TYPE_SELL |DEAL_ENTRY_IN |15489 |DEAL_REASON_EXPERT |2 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |2.00 |79.31 |0.00 |0.00 |0.00 |V | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |2 |2016.12.08 00:00:00 |ORDER_TYPE_SELL |ORDER_STATE_FILLED |2016.12.08 00:00:00 |2016.12.08 00:00:00 |1481155200100 |1481155200100 |ORDER_FILLING_FOK |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |15489 |ORDER_REASON_EXPERT |2 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |2.00 |0.00 |79.31 |0.00 |0.00 |79.39 |0.00 |Symbol |Comment |Extarnal id |V | | Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |3 |3 |2016.12.08 17:27:37 |1481218057877 |DEAL_TYPE_BUY |DEAL_ENTRY_OUT |15489 |DEAL_REASON_EXPERT |2 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |79.75 |0.00 |0.00 |-0.44 |V | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |3 |2016.12.08 14:30:00 |ORDER_TYPE_BUY_STOP |ORDER_STATE_FILLED |2016.12.08 14:30:00 |2016.12.08 17:27:37 |1481207400100 |1481218057877 |ORDER_FILLING_RETURN |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |15489 |ORDER_REASON_EXPERT |2 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |1.00 |0.00 |79.74 |75.17 |0.00 |79.74 |0.00 |Symbol |Comment |Extarnal id |V | | Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |4 |4 |2016.12.09 23:59:00 |1481327940000 |DEAL_TYPE_BUY |DEAL_ENTRY_OUT |0 |DEAL_REASON_CLIENT |2 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |79.13 |0.00 |0.00 |0.18 |V |end of test | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |4 |2016.12.09 23:59:00 |ORDER_TYPE_BUY |ORDER_STATE_FILLED |2016.12.09 23:59:00 |2016.12.09 23:59:00 |1481327940000 |1481327940000 |ORDER_FILLING_FOK |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |0 |ORDER_REASON_CLIENT |2 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |1.00 |0.00 |79.13 |0.00 |0.00 |79.13 |0.00 |Symbol |Comment |Extarnal id |V |end of test |
И еще одна ситуация уже на реальном счете и реальном времени (не в тестере): по рынку Buy объемом 2.0 (торговый приказ на открытие Buy породил две сделки объемами 1.0 — 20087494 и 20087495), затем был выставлен Sell limit объемом 2.0 для фиксации прибыли и закрытия позиции. Чуть позже этот Sell limit исполнился за два захода (сделки 20088091 и 20088145). Распечатка:
Buy 2.0, Sell limit 2.0 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |20087494 |29080489 |2018.08.10 07:23:34 |1533885814000 |DEAL_TYPE_BUY |DEAL_ENTRY_IN |0 |DEAL_REASON_CLIENT |29080489 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |14595 |-0.10 |0.00 |0.00 |RTSGZU8 | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |29080489 |2018.08.10 07:23:34 |ORDER_TYPE_BUY |ORDER_STATE_FILLED |2018.08.10 07:23:34 |2018.08.10 07:23:34 |1533885814000 |1533885814000 |ORDER_FILLING_RETURN |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |0 |ORDER_REASON_CLIENT |29080489 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |2.00 |0.00 |0 |0 |0 |14588 |0 |Symbol |Comment |External id |RTSGZU8 | |13_31861873584 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |20087495 |29080489 |2018.08.10 07:23:34 |1533885814000 |DEAL_TYPE_BUY |DEAL_ENTRY_IN |0 |DEAL_REASON_CLIENT |29080489 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |14595 |-0.10 |0.00 |0.00 |RTSGZU8 | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |29080489 |2018.08.10 07:23:34 |ORDER_TYPE_BUY |ORDER_STATE_FILLED |2018.08.10 07:23:34 |2018.08.10 07:23:34 |1533885814000 |1533885814000 |ORDER_FILLING_RETURN |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |0 |ORDER_REASON_CLIENT |29080489 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |2.00 |0.00 |0 |0 |0 |14588 |0 |Symbol |Comment |External id |RTSGZU8 | |13_31861873584 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |20088091 |29080662 |2018.08.10 08:03:08 |1533888188000 |DEAL_TYPE_SELL |DEAL_ENTRY_OUT |0 |DEAL_REASON_CLIENT |29080489 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |14626 |-0.10 |0.00 |0.46 |RTSGZU8 | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |29080662 |2018.08.10 07:27:19 |ORDER_TYPE_SELL_LIMIT |ORDER_STATE_FILLED |2018.08.10 07:27:19 |2018.08.10 08:05:42 |1533886039000 |1533888342000 |ORDER_FILLING_RETURN |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |0 |ORDER_REASON_CLIENT |29080489 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |2.00 |0.00 |14626 |0 |0 |14624 |0 |Symbol |Comment |External id |RTSGZU8 | |13_31862155871 Deal: |Ticket |Order |Time |Time msc |Type |Entry |Magic |Reason |Position ID |20088145 |29080662 |2018.08.10 08:05:42 |1533888342000 |DEAL_TYPE_SELL |DEAL_ENTRY_OUT |0 |DEAL_REASON_CLIENT |29080489 |Volume |Price |Commission |Swap |Profit |Symbol |Comment |External ID |1.00 |14626 |-0.10 |0.00 |0.46 |RTSGZU8 | | Order: |Ticket |Time setup |Type |State |Time expiration |Time done |Time setup msc |Time done msc |Type filling |29080662 |2018.08.10 07:27:19 |ORDER_TYPE_SELL_LIMIT |ORDER_STATE_FILLED |2018.08.10 07:27:19 |2018.08.10 08:05:42 |1533886039000 |1533888342000 |ORDER_FILLING_RETURN |Type time |Magic |Reason |Position id |Position by id |1970.01.01 00:00:00 |0 |ORDER_REASON_CLIENT |29080489 |0 |Volume initial |Volume current |Open price |sl |tp |Price current |Price stoplimit |2.00 |0.00 |14626 |0 |0 |14624 |0 |Symbol |Comment |External id |RTSGZU8 | |13_31862155871
Советы по тестированию 1.xxx
- Старайтесь в текстовом файле оставить ценные бумаги примерно одинаковой стоимости.
- При тестировании в текстовом файле лучше оставлять небольшое количество символов. Идеальный случай: оставлять один символ и по нему проводить тест.
Вариант 2: в сочетании с системой "Тройной выбор"
В Варианте 1 (все индикаторы на одном графике) трендовый индикатор был на том же таймфрейме. В варианте 2 трендовый индикатор будет находиться на более крупном таймфрейме. Таким образом добавится только один новый параметр — трендовый таймфрейм (Trend timeframe).
Вариант 2 реализован в советнике Elder-Ray 2.000.mq5.
Файлы, прикрепленные к статье:
Название | Тип файла | Описание |
---|---|---|
Symbols on the specified path.mq5 | Скрипт | Формирует текстовой файл с символами данной группы, сохраняется в Commom Data Folder |
Gets minimal volume.mq5 | Скрипт | Выводит статистику по минимальному объему данной группы. |
Elder-Ray 1.001.mq5 | Советник | Демонстрирует визуализацию используемых индикаторов |
Elder-Ray 1.010.mq5 | Советник | Начинаем работать с текстовым файлом и создавать индикаторы по символам из файла. Советник служит для наблюдений за расходом используемой памяти |
Elder-Ray 1.020.mq5 | Советник | Определяем тренд. Проверяем правильность определения тренда |
Elder-Ray 1.030.mq5 | Советник | Рабочая версия по Варианту 1: все индикаторы на одном графике |
Elder-Ray 2.000.mq5 | Советник | Вариант 2: в сочетании с системой "Тройной выбор" |
Заключение
Торговая система Elder-Ray Биржевой рентген (Bulls Power и Bears Power) имеет право на жизнь, особенно в сочетании с системой "Тройной выбор", когда индикатор тренда (EMA) рассчитывается на более высоком таймфрейме, чем индикаторы Bulls Power (индекс силы быков) и Bears Power (индекс силы медведей).
При тестировании советника следует понимать, что в подготовленном текстовом файле может быть до 100 символов: для старта теста по такому количеству символов может понадобиться до 10 минут только для старта и до 5 Гб памяти в процессе теста.
И как ни доверяй советнику, а всё время хочется влезть руками в процесс. Например, пока статья писалась и тестировались версии советников, я так и поступал:
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
В одном месте речь идет о фьючерсах, в другом о мультивалютной стратегии. Упоминаются рисунки, но их нет. Вижу один рисунок здесь в обсуждении, но в самой публикации пусто. А самое здравое предложение - это цитата из чужой книги:
"Как правило сила быков выше нуля, если же она ниже нуля, значит, в стаде быков паника и они тонут."
Много публикаций о возможностях метатрейдера. Программа отличная, нет сомнений, возможно лучшая. Хотелось бы встретить публикацию такого автора, который попытался докопаться до сути процессов, и был настолько дотошным, что не допускал не только смысловых, но и стилистических ошибок в своей публикации.
Вы ведь серьезно отнеслись к написанию публикации, или вы не верите, что кто-то это читает?
Ну в итоге-то льет со скоростью спреда или нет?