Вы упускаете торговые возможности:
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Регистрация
Вход
Вы принимаете политику сайта и условия использования
Если у вас нет учетной записи, зарегистрируйтесь
Шаг пятый. Подготовка переменных к проверке размера бара.
Немного перефразируем известное высказывание: "Что бы продать что-то ненужное, нужно купить что-то ненужное!":
в фразу: "Что бы проверить размер бара, сначала нужно размер бара задать!". Размер бара задавать будем во входящих параметрах - при помощи Input переменной:
CSymbolInfo m_symbol; // symbol info object
//--- input parameters
input ushort InpSizeOfBar=10; // size of bar (in pips)
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
Обратите внимание: всё, что касается размера бара, уровней TakeProfit и StopLoss задаём при помощи
ushort
Беззнаковым типом short является тип ushort, который также имеет размер 2 байта. Минимальное значение равно 0, максимальное значение 65 535.
Во-первых - этим отсекаются возможные ошибки задания отрицательных значений, во-вторых - это привычное измерение в пунктах/пипсах (здесь не будет рассуждать, что первее было пипсы или пункты - просто запомните: размер бара должен одинаково работать на любом символе - и на "пятизнаке" и на символах у которых после запятой ноль знаков).
Типичное сравнение размера бара будет таким: цена закрытия бара (1.03456) минус цена открытия бара (1.0317). Например:
Результат равен 0.00239. "Пятизнак" хорош при техническом анализе, но сейчас это лишнее, по старой доброй шкале "четырёхзнака" размер бара составляет 23 пункта (это без округления). Как-же нам согласовать эти три величины:
Поступаем так: вводим переменную double "ExtSizeOfBar"
input ushort InpSizeOfBar=10; // size of bar (in pips)
//--- parameters
double ExtSizeOfBar=0.0; //
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
В этой переменной мы будем (после некоторых вычислений в OnInit()) хранить заданный размер бара уже в ценах текущего финансового инструмента.
Для этого в OnInit() проверим количество знаков после десятичной точки у данного финансового инструмента и в зависимости от этого скорректируем нашу переменную "ExtSizeOfBar":
//--- tuning for 3 or 5 digits
int digits_adjust=1;
if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
digits_adjust=10;
ExtSizeOfBar=InpSizeOfBar*m_symbol.Point()*digits_adjust;
//---
return(INIT_SUCCEEDED);
}
Что означает эта запись: если у финансового инструмента количество знаков после десятичной точки (метод Digits) равно 3 или 5 (то есть если в терминале используется "пятизнак"), то коэффициент "digits_adjust" равен 10. На примере "EURUSD":
ExtSizeOfBar=InpSizeOfBar*m_symbol.Point()*digits_adjust =>
ExtSizeOfBar=10*0.00001*10=0.0010
Таким образом ExtSizeOfBar=0.0010 - что соответствует 10 пунктам/пипсам на "четырёхзнаке". Теперь можно будет в программе сравнивать разницу цен закрытия и открытия бара и нашу переменную "ExtSizeOfBar".
Сохраним версию файла 1.04 в Хранилище.
Шаг шестой: момент рождения нового бара.
Нам нужно на каждом тике знать время открытия бара. Делать это можно при помощи такой простой функции:
//| Get Time for specified bar index |
//+------------------------------------------------------------------+
datetime iTime(const int index,string symbol=NULL,ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT)
{
if(symbol==NULL)
symbol=Symbol();
if(timeframe==0)
timeframe=Period();
datetime Time[1];
datetime time=0;
int copied=CopyTime(symbol,timeframe,index,1,Time);
if(copied>0) time=Time[0];
return(time);
}
добавьте эту функцию в самый конец программы.
У текущего бара время открытия бара будет больше, чем у предыдущего. Значит в OnTick() нам нужно сравнивать время открытия бара со временем открытия бара на предыдущем тике. Как только время открытия бара станет больше, чем время сохранённое на предыдущем баре - значит родился новый бар :).
А вот хранить время нам поможет статическая переменная объявленная в OnTick(). Чем удобна статическая переменная - она сохраняет своё значение при последующем входе в процедуру/функцию. Пропишем объявление статической переменной:
{
//---
static datetime prev_time=0;
if(prev_time<iTime(0))
{
//--- new bar
}
prev_time=iTime(0); // time on the previous tick
//---
if(!RefreshRates())
Введём ещё одну переменную - флаг "новый бар" - при заходе в OnTick() этот флаг будет инициализироваться значением "false", а если мы поймали новый бар, то присвоим этому флагу значение "true":
{
//---
static datetime prev_time=0;
bool new_bar=false; // flag "new bar"
if(prev_time<iTime(0))
{
//--- new bar
new_bar=true;
}
prev_time=iTime(0); // time on the previous tick
//---
if(!RefreshRates())
Теперь мы на каждом тике будем знать - мы поймали новый бар или это текущий бар.
Как обычно увеличиваем версию файла и сохраняем в Хранилище. Версия файла 1.05.
Шаг седьмой: получение цены открытия бара и цены закрытия бара.
Для получения цен открытия и закрытия бара есть такие простые функции:
//| Get Open for specified bar index |
//+------------------------------------------------------------------+
double iOpen(const int index,string symbol=NULL,ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT)
{
if(symbol==NULL)
symbol=Symbol();
if(timeframe==0)
timeframe=Period();
double Open[1];
double open=0;
int copied=CopyOpen(symbol,timeframe,index,1,Open);
if(copied>0) open=Open[0];
return(open);
}
//+------------------------------------------------------------------+
//| Get Close for specified bar index |
//+------------------------------------------------------------------+
double iClose(const int index,string symbol=NULL,ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT)
{
if(symbol==NULL)
symbol=Symbol();
if(timeframe==0)
timeframe=Period();
double Close[1];
double close=0;
int copied=CopyClose(symbol,timeframe,index,1,Close);
if(copied>0) close=Close[0];
return(close);
}
Запишите эти функции в самый конец программы. Изменяем версию на 1.06 и сохраняем в Хранилище.
Шаг восемь: подготовка к торговле.
Напомню задачи советника:
Первым делом нужен сам флаг разрешения торговли. Объявим переменную bool "TradeIsAllowed" в "шапке" программы (эта область называется область объявления глобальных переменных ПРОГРАММЫ - не путайте с глобальными переменными терминала):
double ExtSizeOfBar=0.0; //
bool TradeIsAllowed=true; //
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
и в OnInit() также будет принудительно инициализировать эту переменную:
digits_adjust=10;
ExtSizeOfBar=InpSizeOfBar*m_symbol.Point()*digits_adjust;
//---
TradeIsAllowed=true;
//---
return(INIT_SUCCEEDED);
}
Теперь в OnTick() можно прописать проверку: если торговля запрещена и мы находимся не в момент рождения бара - то выходим:
",Ask=",DoubleToString(m_symbol.Ask(),m_symbol.Digits()));
//---
if(!TradeIsAllowed && !new_bar)
return;
TradeIsAllowed=true;
}
//+------------------------------------------------------------------+
//| Refreshes the symbol quotes data |
в противном случае - разрешаем торговлю.
И если размер бара больше заданного и в зависимости от того, какой бар - бычий или медвежий - покупаем или продаём:
return;
TradeIsAllowed=true;
//--- calculate the size of bar
double open=iOpen(0);
double close=iClose(0);
if(close>open && close-open>ExtSizeOfBar) // Buy
{
}
if(open>close && open-close>ExtSizeOfBar) // Sell
{
}
}
//+------------------------------------------------------------------+
//| Refreshes the symbol quotes data |
Сохраняем версию 1.07.
Шаг девять: CTrade - класс для упрощенного доступа к торговым функциям.
Класс CTrade
Класс CTrade является классом для упрощенного доступа к торговым функциям.
Описание
Класс CTrade обеспечивает упрощенный доступ к торговым функциям.
Заголовок
#include <Trade\Trade.mqh>
Из всего многообразия будем использовать такие методы:
Установка параметров
SetExpertMagicNumber
Устанавливает идентификатор эксперта
Дополнительные методы
Buy
Открывает длинную позицию с заданными параметрами
Sell
Открывает короткую позицию с заданными параметрами
Доступ к результатам исполнения последнего запроса
ResultRetcode
Получает код результата выполнения запроса
ResultRetcodeDescription
Получает код результата выполнения запроса как строку
ResultDeal
Получает тикет сделки
И, сначала, нужно прописать использование класса CTrade:
#include <Trade\SymbolInfo.mqh>
#include <Trade\Trade.mqh>
CSymbolInfo m_symbol; // symbol info object
CTrade m_trade; // trading object
//--- input parameters
Для установки идентификатора, введём входную переменную "InpMagic":
input ushort InpSizeOfBar=10; // size of bar (in pips)
input ulong InpMagic=15489; // magic number
//--- parameters
double ExtSizeOfBar=0.0; //
и в OnInit() установим идентификатор эксперта:
{
//---
m_trade.SetExpertMagicNumber(InpMagic); // sets magic number
//---
m_symbol.Name(Symbol()); // sets symbol name
if(!RefreshRates())
Magic поможет нам, когда нужно будет закрывать все позиции - только при наличии Magic мы сможем закрыть свои позиции.
Переходим в блок открытия позиции:
{
double lot=m_symbol.LotsMin();
double price=m_symbol.Ask();
if(m_trade.Buy(lot,NULL,price)) // successful check of the structures
if(m_trade.ResultDeal()!=0) // deal ticket if the deal is executed
TradeIsAllowed=false; // trade is forbidden
}
Если метод Buy вернул true (успешное окончание работы метода) и если при этом тикет сделки не равен нулю - значит торговая операция успешна и прекращаем отслеживать размер бара до момента рождения нового бара.
Для Sell код аналогичный:
{
double lot=m_symbol.LotsMin();
double price=m_symbol.Bid();
if(m_trade.Sell(lot,NULL,price)) // successful check of the structures
if(m_trade.ResultDeal()!=0) // deal ticket if the deal is executed
TradeIsAllowed=false; // trade is forbidden
}
Наш советник уже работает: анализирует на каждом тике размер бара и при удачном размещении позиции прекращает анализировать до рождения нового бара. Осталось совсем немного - перед открытием позиции проверять: не нужно ли закрыть противоположные позиции.
Сохраним в Хранилище файл под версией 1.08.
А вот тут действительно покажите как можно шире, как написать советник, не используя сторонние файлы в виде стандартной библиотеки, и прочей шелухи.
Покажите всё стандартными функциями с полным описанием и выводом всех торговых ошибок.
Поддерживаю.
Карпутовская манера во всех своих пояснениях и в своих кодах для кодабазы -- использовать стандартную библиотеку (СБ) -- вообще не способствует пониманию и освоению языка новичками.
Удивительно, что Карпутов это не может или не хочет никак понять.
Поэтому, как по мне, пояснения на СБ -- это гарантированный "мартышкин труд".
p.s. Как заметил по форуму -- если под его пояснением дать нормальное пояснение без СБ -- то на пояснение Карпутова вообще никто внимания не обращает.
Поддерживаю.
Карпутовская манера во всех своих пояснениях и в своих кодах для кодабазы -- использовать стандартную библиотеку (СБ) -- вообще не способствует пониманию и освоению языка новичками.
Удивительно, что Карпутов это не может или не хочет никак понять.
Поэтому, как по мне, пояснения на СБ -- это гарантированный "мартышкин труд".
p.s. Как заметил по форуму -- если под его пояснением дать нормальное пояснение без СБ -- то на пояснение Карпутова вообще никто внимания не обращает.
На самом деле мне очень интересно не просто смотреть такие ветки, а именно изучать. Но изучить то здесь особо нечего, применяется СБ, поэтому что-то понять с изложенного крайне сложно, да и не интересно вовсе.
Так-же вопрос к комментариям, если уж хотите донести что либо, тогда это явно ничего не донесёт:
{
double lot=m_symbol.LotsMin();
double price=m_symbol.Bid();
if(m_trade.Sell(lot,NULL,price))
if(m_trade.ResultDeal()!=0)
TradeIsAllowed=false;
}
А вот это донесёт, и в нём легко понять, за что отвечает часть кода:
static datetime lastDnPrcMACD_extrTime=0; // время прошлого нижнего экстремума цены для MACD
//--- если внизу есть экстремум MACD (на покупку)
if(extrMACD==OP_BUY) {
//--- если центральная точка экстремума MACD ниже ноля, найдём экстремумы и дивергенции
if(macd_b<0) {
FindAndSetDivergence(symbol,periodForWork,OP_BUY,macd_b,bar_b,wnd_macd,time_b,time,i,leftMACD_tUP,leftMACD_UP,leftMACD_tDN,leftMACD_DN);
}
lastDnMACD_extrValue=macd_b; // сохраним значение "последнего" нижнего экстремума MACD для последующего сравнения с верхним экстремумом MACD (только для поиска экстремумов)
}
//--- если сверху есть экстремум MACD (на продажу)
if(extrMACD==OP_SELL) {
//--- если центральная точка экстремума MACD выше ноля, найдём экстремумы и дивергенции
if(macd_b>0) {
Может всё-же имеет смысл комментировать код, чтоб было понятнее, о чём эта часть кода. Ну и конечно не использовать СБ, а показать практичным кодом все открытия, переборы и закрытия позиций, и если можно - ордеров.
Может всё-же имеет смысл комментировать код, чтоб было понятнее, о чём эта часть кода. Ну и конечно не использовать СБ, а показать практичным кодом все открытия, переборы и закрытия позиций, и если можно - ордеров.
Комментарии добавил, спасибо, за подсказку - увлёкся и выкатил версию без пояснений. Стандартна библиотека будет всегда в примерах - потому как только так код максимально чист и читаем. По отложенным ордерам неоднократно давал примеры - что именно интересует?
Комментарии добавил, спасибо, за подсказку - увлёкся и выкатил версию без пояснений. Стандартна библиотека будет всегда в примерах - потому как только так код максимально чист и читаем. По отложенным ордерам неоднократно давал примеры - что именно интересует?
Код не читаем. Абсолютно. Это просто постоянные обращения к "чёрному ящику". Если не знать что содержит в себе этот "чёрный ящик", и как он, ящик этот, работает, и что там делается внутри и даётся на выход, то о каком понимании может идти речь?
Вот ты сам сможешь написать нормальный класс, который всё это будет делать? Написать, а потом объяснить "на пальцах" новичкам. Так, чтобы они поняли алгоритм. Понимаешь? АЛГОРИТМ. А не запрос к таинственному "нечто" и ответ от этого таинственного "нечто" потом использовать. Вот тогда они будут понимать что творится в их программах. И уже тогда они сами, без твоего навязывания решат переходить им к использованию СБ, или написать своё. Или наследоваться от классов СБ.
А так ... всё в воду...