Кормораздатчик мобильный электрифицированный: схема и процесс работы устройства...
Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого...
Топ:
Методика измерений сопротивления растеканию тока анодного заземления: Анодный заземлитель (анод) – проводник, погруженный в электролитическую среду (грунт, раствор электролита) и подключенный к положительному...
История развития методов оптимизации: теорема Куна-Таккера, метод Лагранжа, роль выпуклости в оптимизации...
Характеристика АТП и сварочно-жестяницкого участка: Транспорт в настоящее время является одной из важнейших отраслей народного...
Интересное:
Инженерная защита территорий, зданий и сооружений от опасных геологических процессов: Изучение оползневых явлений, оценка устойчивости склонов и проектирование противооползневых сооружений — актуальнейшие задачи, стоящие перед отечественными...
Наиболее распространенные виды рака: Раковая опухоль — это самостоятельное новообразование, которое может возникнуть и от повышенного давления...
Распространение рака на другие отдаленные от желудка органы: Характерных симптомов рака желудка не существует. Выраженные симптомы появляются, когда опухоль...
Дисциплины:
2017-09-10 | 218 |
5.00
из
|
Заказать работу |
|
|
Функция init()
Эта функция вызывается в следующих случаях:
Функция start()
Функция start() запускается на каждом новом тике. Собственно это основная функция эксперта, т.к. она вызывается на каждом тике и выполняет основную работу.
Важно: Если функция start() не успела завершить свою работу до прихода следующего тика, следующий тик пропускается и функция для него не вызывается.
Функция deinit()
С помощью UninitializeReason() можно узнать причину вызова функции deinit().
Функция deinit() вызвается в следующих случаях:
Функция UninitializeReason() возвращает 0, если скрипт самостоятельно завершил работу.
Если в течение 2.5 секунд фукция deinit() работу не завершила, то она прерывается принудительно.
Пишем простейшего эксперта
На мой взгляд, наиболее простым способом для новичка изучить процесс написания экспертов будет подробный разбор специально написанных мной для этой цели экспертов. На данный момент (да и далее в своих статьях) я не буду ставить перед собой цель написать супер гениального эксперта, который способен будет зарабатывать десятки процентов в месяц и делать это стабильно. Основная цель - показать все аспекты программирования экспертов, а не написать "грааль".
|
Итак, внимательно изучите код эксперта ниже, но не волнуйтесь, что на данный момент Вам пока еще ничего не понятно. В следующих выпусках я подробно разберу каждую строчку этого эксперта.
//+------------------------------------------------------------------+
//| My First Expert.mq4 |
//| Copyright © 2006, Andrey Vedikhin |
//| http://www.vedikhin.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, Andrey Vedikhin"
#property link "http://www.vedikhin.ru"
#define STATE_SQUARE 0
#define STATE_LONG 1
#define STATE_SHORT 2
//---- input parameters
extern int MAPeriod=13;
extern double LotsNumber=1.0;
//---- глобальные переменные
int CurrentState;
int MyOrderTicket;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
if (iMA(NULL, 0, MAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0) > Close[0])
CurrentState = STATE_SHORT;
else CurrentState = STATE_LONG;
MyOrderTicket = 0;
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
int err;
double MA;
MA = iMA(NULL, 0, MAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
if (CurrentState == STATE_LONG)
{
if (MA > Close[1]) //скользящая средняя выше цены закрытия
{
CurrentState = STATE_SHORT;
//переворачиваемся в продажу
//---закрыть позицию, если была открыта
if (MyOrderTicket!= 0)
{
if (!OrderClose(MyOrderTicket, LotsNumber, Bid, 3, CLR_NONE))
{
err = GetLastError();
Print("Ошибка при закрытии позиции: ", err);
return(0);
}
MyOrderTicket = 0;
}
RefreshRates();
//--- длинная позиция была закрыта успешно
//--- теперь откроем позицию в продажу
//--- проверим на наличие свободных средств
if (!CheckForEnoughMargin()) return(0);
MyOrderTicket = OrderSend(Symbol(), OP_SELL, LotsNumber, Bid, 3, 0, 0,
NULL, 0, 0, CLR_NONE);
if (MyOrderTicket<0)
{
err = GetLastError();
Print("Ошибка при открытии позиции: ", err);
MyOrderTicket = 0;
}
}
}
else
{
if (MA < Close[1]) //скользящая средняя ниже цены закрытия
{
CurrentState = STATE_LONG;
|
//переворачиваемся в покупку
//---закрыть позицию, если была открыта
if (MyOrderTicket!= 0)
{
if (!OrderClose(MyOrderTicket, LotsNumber, Ask, 3, CLR_NONE))
{
err = GetLastError();
Print("Ошибка при закрытии позиции: ", err);
return(0);
}
MyOrderTicket = 0;
}
RefreshRates();
//--- короткая позиция была закрыта успешно
//--- теперь откроем позицию в покупку
//--- проверим на наличие свободных средств
if (!CheckForEnoughMargin()) return(0);
MyOrderTicket = OrderSend(Symbol(), OP_BUY, LotsNumber, Ask, 3, 0, 0,
NULL, 0, 0, CLR_NONE);
if (MyOrderTicket<0)
{
err = GetLastError();
Print("Ошибка при открытии позиции: ", err);
MyOrderTicket = 0;
}
}
}
//----
return(0);
}
//+------------------------------------------------------------------+
//| Проверка наличия свободной маржи |
//+------------------------------------------------------------------+
bool CheckForEnoughMargin()
{
if (GetOneLotMargin(Symbol())*LotsNumber<AccountFreeMargin()) return(true);
else return(false);
}
//+-------------------------------------------------------------------+
//| Вычисление необходимой маржи на один лот|
//+-------------------------------------------------------------------+
double GetOneLotMargin(string s)
{
double p;
if ((StringSubstr(s, 0, 3) == "EUR")||(StringSubstr(s, 0, 3) == "GBP")||
(StringSubstr(s, 0, 3) == "AUD")||(StringSubstr(s, 0, 3) == "NZD"))
{
if (!IsTesting())
return(MarketInfo(s, MODE_LOTSIZE)*MarketInfo(StringSubstr(s, 0, 3)+"USD",
MODE_BID)/AccountLeverage());
else
{
p = iClose(StringSubstr(s, 0, 3)+"USD", Period(),
iBarShift(StringSubstr(s, 0, 3)+"USD", Period(), CurTime(), true));
return(MarketInfo(s, MODE_LOTSIZE)*p/AccountLeverage());
}
}
if (StringSubstr(s, 0, 3) == "USD")
return(MarketInfo(s, MODE_LOTSIZE)/AccountLeverage());
if (s == "CHFJPY")
{
p = iClose("USDCHF", Period(), iBarShift("USDCHF", Period(), CurTime(), true));
return(MarketInfo(s, MODE_LOTSIZE)/(AccountLeverage()*p));
}
return(77777777777777777777777777.0);
}
//+------------------------------------------------------------------+
Благодарю Вас за то, что Вы мужественно дочитали до этой строчки. Как я уже упомянул ранее, в следующих выпусках я очень подробно остановлюсь на каждой строчке этого эксперта, и проясню Вам все непонятные моменты.
Использование констант в эксперте
В прошлом выпуске я выложил код нашего первого эксперта.
Вначале разберем, что означают следующие строчки:
#define STATE_SQUARE 0
#define STATE_LONG 1
#define STATE_SHORT 2
Эти строчки дают возможность вместо написания малоинформтивных чисел 0, 1 или 2 использовать более понятные имена STATE_SQUARE, STATE_LONG или STATE_SHORT. Результат будет абсолютно таким же - если программа встретит в тексте STATE_SQUARE, STATE_LONG или STATE_SHORT, она заменит их на 0, 1 и 2 соответственно. Такая программа будет более читаемой.
Также константы используются в тех случаях, когда какое-то значение использует в нескольких местах программы и существует вероятность, что трейдеру может понадобиться изменить это значение в будущем. Если использовать константу, достаточно будет это сделать только в одном месте - в директиве #define.
|
Для объявления константы используйте следующую конструкцию:
#define имя значение
Примеры констант:
#define AUTHOR "Vedikhin Andrey"
#define Lots 1.1
#define ItemsNumber 77
Следующие две строчки абсолютно идентичны, но первая - более читаема:
for(x=1;x<=ItemsNumber;x++) Print(Lots*x);
for(x=1;x<=77;x++) Print(1.1*x);
Константа может быть любого типа: int, bool, datetime, double, color, string - см. описание типов в выпуске "Настраиваем параметры нового эксперта".
Хранение данных в переменных
Любой эксперт оперирует с некоторыми данными - ценами, значениями индикаторов, объемами, количеством открытых позиций и пр. Те, места, где эти данные хранятся в эксперте, называются переменными. В качестве имен переменных можно использовать цифры (0-9), латинские прописные и строчные буквы (а - z и А - Z, следует помнить, что буквы 'a' и 'A' - совершенно разные символы), символ подчеркивания (_). Первый символ не может быть цифрой. Также имя переменной не должно совпадать с зарезервированным словом (т.е. словом, которое имеет особый смысл в языке MetaQuotes Language 4 - но об этом позже).
Желательно в качестве имени переменной использовать такое, из которого сразу становится понятным предназначение переменной. Например, переменная, содержащая количество открытых позиций, может иметь такое имя: OpenPositionsNumber.
Можно создавать переменные разных типов:
Перед использованием переменной ее надо объявить. Это можно сделать несколькими способами:
тип имя;
или
тип имя = начальное_значение;
Примеры объявлений переменных:
int Count;
datetime InitialDate = D'2006.07.12 00:00';
string ip_address = "127.0.0.1";
В дальнейшем для того, чтобы обратиться к значению переменной, надо будет просто указать ее имя:
|
i = 5 + Count;
Иногда требуется сохранить не одно значение, а определенное количество взаимосвязанных значений. Например, значение индикатора на текущем баре, на предыдущем баре,..., N-баров назад. Для таких целей существуют массивы. Массив - это индексированная совокупность однотипных данных.
Предположим, что у нас в эксперте есть такое описание массива Prices:
double Prices[50];
Это означает, что массив-переменная Prices предоставляет доступ к 50 элементам типа double. Для доступа к i-му элементу надо указать Prices[i]. Нумерация элементов начинается с нуля и заканчивается 49-м элементов (в нашем случае).
Если Вы попробуете обратиться к элементу вне этого диапазона, то будет зафиксирована ошибка ERR_ARRAY_INDEX_OUT_OF_RANGE (4002), которую можно получить при помощи функции GetLastError().
В случае необходимости можно использовать не только одномерные массивы (у которых только один индекс), но и многомерные массивы.
Пример описания двухмерного массива, состоящего из шести массивов, каждый из которых состоит из 50 элементов:
int mas[6] [50];
При описании массива можно в фигурных скобках задать начальные значения для каждого элемента:
int a[4][4] = { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
Начальные значения элементов массивов могут быть только константами. Если Вы в фигурных скобках при инициализации массива указали меньшее количество начальных значений, чем размерность массива, то недостающие элементы инициализируются нулями.
Существует несколько видов переменных: локальные, статические, внешние, глобальные переменные и формальные параметры функций. В следующем выпуске я более подробно расскажу о локальных и статических переменных.
Локальные и статические переменные
В прошлом выпуске я рассказал о том, как использовать переменные и массивы в эксперте. Единственным нераскрытом моментом остались области видимости переменных. Дело в том, что переменные бывают нескольких типов:
Локальные переменные
Если переменная объявлена в пределах какой-нибудь функции, то она является локальной переменной и видна только в пределах этой функции. За пределами этой функции к этой переменной обращаться нельзя.
Инициализация (присвоение начального значения) локальной переменной происходит каждый раз при вызове функции. Присваиваемое начальное значение может быть как константой, так и выражением.
Пример объявления и инициализации локальной переменной:
int CalcFactorial(int n)
{
int i = 0;
...
}
Cтатические переменные
Статические переменные объявляются директивой static. Они инициализируются только один раз - при первом вызове функции и сохраняют свое значение даже после выхода из функции. В следующий раз при новом вызове функции статические переменные будут иметь то же значение, которое они имели перед выходом из функции в послений раз.
|
Статические переменные объявляются в пределах описания функции и поэтому доступны для использования только в пределах той функции, в которой они объявлены.
Пример объявления статической переменной:
int GetOpenPositionsNumber()
{
static int Count = 0;
...
}
В следующем выпуске я расскажу о внешних переменных.
Внешние переменные
В прошлом выпуске я рассказал о локальных и статических переменных. В этом выпуске я остановлюсь на внешних переменных.
Внешние переменные
Мы уже сталкивались с внешними переменными, когда описывали параметры эксперта MAPeriod и LotsNumber в коде нашего первого эксперта.
Внешние переменные описываются с помощью зарезервированного слова extern:
extern int MAPeriod=13;
extern double LotsNumber=1.0;
Внешние переменные не могут быть массивами.
Внешние переменные - это параметры эксперта, которые можно изменять.
"Прикрепите" эксперт к графику. Для этого нажмите правую кнопку мыши на названии эксперта в окне "Навигатор" и в появившемся контекстном меню выберите "Присоединить к графику". Появится окно свойств эксперта. Во вкладке "Входные параметры" Вы можете изменить значения внешних переменных, описанных в эксперте (см. рис. 1).
Рис. 1. Параметры эксперта
Если эксперт уже "прикреплен" к графику (в правом верхнем углу графика Вы видите улыбающуюся или грустную рожицу), то для изменения его параметров - значений внешних переменных - нажмите на рожице правую кнопку мыши и выберите в в появившемся контекстном меню пункт "Советники - Свойства...". Более быстрый способ - использовать горячую клавишу F7. Появится окно с параметрами эксперта (см. рис. 1), в котором Вы сможете изменить значения внешних переменных.
В следующем выпуске я расскажу о глобальных переменных.
Глобальные переменные
В прошлом выпуске я рассказал о внешних переменных. В этом выпуске я остановлюсь на глобальных переменных.
Глобальные переменные
Для человека, имеющего уже опыт написания экспертов, выражение "глобальные переменные" может внести небольшую путанницу. Дело в том, что на самом деле существует два вида "глобальных переменных":
1. переменные, которые видны из любой функции ОДНОГО эксперта (т.е. являются глобальными в пределах этого эксперта); и
2. переменные, которые являются общими для ВСЕХ экспертов.
В этом выпуске речь пойдет именно о глобальных переменных первого типа - тех, которые являются общими для всех функций ОДНОГО эксперта.
Второй же тип глобальных переменных я рассмотрю в следующих выпусках, когда буду рассказывать о функциях, с помощью которых к таким переменным получают доступ, - GlobalVariable...().
Если Вы хотите, чтобы к значению переменной можно было бы обращаться из разных функций одного эксперта, сделайте ее глобальной переменной, т.е. определите ее на том же уровне, что и функции:
//---- глобальные переменные
int CurrentState;
int MyOrderTicket;
//---- определения функций
int init()
{
...
}
Начальное значение глобальной переменной может быть только константой (если не задано никакого значения, то она инициализируется нулем). Это значение присваивается глобальной переменной только один раз, до выполнения функции init().
В следующем выпуске я расскажу о формальных параметрах функций.
Параметры функций
В выпуске "Создание собственных функций" я рассказал достаточно подробно о том, как описывать собственные функции. В этом выпуске я продолжу рассмотрение функций и детально разберу, как в функцию можно передать значения и получить результат функции.
Операции отношения
Операция | Результат |
a == b | Истина, если a равно b Ложь, если a не равно b |
a!= b | Истина, если a не равно b Ложь, если a равно b |
a < b | Истина, если a меньше b Ложь, если a больше или равно b |
a <= b | Истина, если a меньше или равно b Ложь, если a больше b |
a > b | Истина, если a больше b Ложь, если a меньше или равно b |
a >= b | Истина, если a больше или равно b Ложь, если a меньше b |
Примечание: в связи с тем, что числа с плавающей точкой (тип double) не могут быть представлены точно в связи с ограниченным количеством значащих цифр после запятой (в MetaQuotes Language 4 точность - 15 значащих цифр), нельзя производить сравнение таких чисел на равенство (==) или неравенство (!=) без предварительной нормализации (о нормализации вещественных чисел я расскажу в следующих выпусках).
В следующем выпуске я расскажу о логических операциях.
Логические операции
В прошлом выпуске я рассказал об операциях отношения, с помощью которых можно сравнить две переменные. Результатом выступало значение типа bool.
Напомню, что значение ЛОЖЬ (false) представляется в виде нулевого значения, а ИСТИНА (true) - ненулевого.
В этом выпуске я рассмотрю логические операции НЕ (!), ИЛИ (||) и И (&&).
Логическое отрицание НЕ (!)
Операнд A | Значение выражения!A |
ИСТИНА (true) | ЛОЖЬ (false) |
ЛОЖЬ (false) | ИСТИНА (true) |
Пример:
bool b;
b = false; // переменная b равна false (ЛОЖЬ)
b =!b; // переменная b равна true (ИСТИНА)
b =!b; // переменная b равна false (ЛОЖЬ)
Логическая операция ИЛИ (||)
Результат логической операции ИЛИ равен true, если хотя бы один из операндов равен true. Если оба операнда равны false, то и результат логического ИЛИ также будет равен false.
Операнд A | Операнд B | Значение выражения A || B |
ЛОЖЬ (false) | ЛОЖЬ (false) | ЛОЖЬ (false) |
ЛОЖЬ (false) | ИСТИНА (true) | ИСТИНА (true) |
ИСТИНА (true) | ЛОЖЬ (false) | ИСТИНА (true) |
ИСТИНА (true) | ИСТИНА (true) | ИСТИНА (true) |
Пример:
bool a = true; // a равно true
bool b = false; // b равно false
b = b || a; // b равно true
Логическая операция И (&&)
Результат операции логического И будет равен true только в случае, если оба операнда равны true. Во всех иных случаях результат операции будет равен false.
Операнд A | Операнд B | Значение выражения A && B |
ЛОЖЬ (false) | ЛОЖЬ (false) | ЛОЖЬ (false) |
ЛОЖЬ (false) | ИСТИНА (true) | ЛОЖЬ (false) |
ИСТИНА (true) | ЛОЖЬ (false) | ЛОЖЬ (false) |
ИСТИНА (true) | ИСТИНА (true) | ИСТИНА (true) |
Пример:
bool a = true; // a равно true
bool b = false; // b равно false
b = b && a; // b равно false
Побитовые операции
В прошлом выпуске я рассказал о логических операциях, а этот выпуск будет посвящен побитовым операциям.
Для начала необходимо рассказать о формате представления чисел в компьютере.
Мы в нашей жизни привыкли к десятичному представлению чисел: 56, 777, 10957 и т.д. Десятичное представление числа 10957 означает, что 10957 = 1*104 +0*103+9*102+5*101+7*100. Иными словами десятичное число - это a0*100+a1*101+a2*102+...+an*10n. Т.е. сумма произведений соответствующей цифры (ai) на соответствующую степень числа 10 (10i).
В компьютере внутренний формат представления чисел - двоичный. В двоичном формате все числа состоят из нулей и единиц, а в качестве множителя используется не число 10, возведенное в степень, а соответствующая степень числа 2. Например, двоичное число 10001101 равно десятичному (обычному) числу 1*27+0*26+0*25+0*24+1*23+1*22+0*21+1*20 = 128+0+0+0+8+4+0+1 = 141.
Каждая такая двоичная цифра (1 или 0) называется битом.
Теперь мы знаем достаточно, чтобы рассмотрить побитовые операции.
Побитовые операции
int b = 141; // начальное значение переменной b равно 141,
// что в двоичном представлении равно 10001101
b = ~b; // переменная b стала равна 01110010, т.е. 114
int b = 141; // начальное значение переменной b равно 141,
// что в двоичном представлении равно 10001101
b = b >> 2; // переменная b стала равна 00100011, т.е. 67
int b = 141; // начальное значение переменной b равно 141,
// что в двоичном представлении равно 10001101
b = b << 2; // переменная b стала равна 1000110100, т.е. 564
int a = 25; // начальное значение переменной a равно 25,
// что в двоичном представлении равно 00011001
int b = 141; // начальное значение переменной b равно 141,
// что в двоичном представлении равно 10001101
a = a & b; // переменная a стала равна 00001001, т.е. 9
int a = 25; // начальное значение переменной a равно 25,
// что в двоичном представлении равно 00011001
int b = 141; // начальное значение переменной b равно 141,
// что в двоичном представлении равно 10001101
a = a | b; // переменная a стала равна 10011101, т.е. 157
int a = 25; // начальное значение переменной a равно 25,
// что в двоичном представлении равно 00011001
int b = 141; // начальное значение переменной b равно 141,
// что в двоичном представлении равно 10001101
a = a ^ b; // переменная a стала равна 10010100, т.е. 148
Объединение арифметических и побитовых операций с операцией присваивания
В прошлых выпусках мы рассмотрели арифметические и побитовые операции. Ранее я рассказал об операторе присваивания.
В синтаксисе MetaQuotes Language 4 - языка написания советников - есть возможность объединить арифметические и побитовые операции с операцией присваивания.
Табл. 1. Периоды графиков
Исходя из этого мы можем описать 3 функции:
// получить магическое число из периода графика и ID эксперта
int GetMagicNumber(int chart_period, int expertID)
{
return(chart_period * 100 + expertID);
}
// получить период графика из магического числа
int GetPeriod(int magic)
{
return(magic / 100);
}
// получить ID эксперта из магического числа
int GetExpertID(int magic)
{
return(magic % 100);
}
В следующем выпуске я расскажу о функции OrderSend(). С помощью этой функции можно открывать позиции и размещать отложенные ордера.
OrderSend() - открытие позиции или размещение отложенного ордера
В прошлых выпусках я рассказал о большом количестве функций, с помощью которых можно получить информация об ордере, выделенном с помощью функции OrderSelect(). Большинство из этих функций очень важны и полезны. Однако я уверен, что Вам уже давно хочется экшина, т.е. Вы давно уже ждете от меня описания тех торговых функций, с помощью которых можно открывать и закрывать позиции, выставлять, модифировать и удалять ордера.
Сегодня я расскажу о первой такой функции - функции OrderSend().
Формат функции:
int OrderSend(string symbol, int cmd, double volume, double price, int slippage,
double stoploss, double takeprofit, string comment=NULL,
int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)
Функция OrderSend() предназначена для размещения отложенного ордера или открытия позиции. Функция вовзращает номер тикера открытой позиции или размещенного отложенного ордера. В случае неудачи функция OrderSend() возвращает число -1.
При этом:
В следующем выпуске я рассмотрю параметры функции OrderSend() более подробно.
Параметры функции OrderSend()
В прошлом выпуске я рассказал о функции OrderSend(). В этом выпуске я хотел бы остановиться на параметрах этой функции более подробно.
В параметре cmd мы передаем тип приказа:
Константа | Значение | Описание |
OP_BUY | Открыть позицию на покупку | |
OP_SELL | Открыть позицию на продажу | |
OP_BUYLIMIT | Разместить отложенный ордер BUY LIMIT | |
OP_SELLLIMIT | Разместить отложенный ордер SELL LIMIT | |
OP_BUYSTOP | Разместить отложенный ордер BUY STOP | |
OP_SELLSTOP | Разместить отложенный ордер SELL STOP |
Таблица 1. Возможные значения параметра cmd функции OrderSend()
Таким образом, для того, чтобы открыть позицию на продажу в качестве параметра cmd надо указать OP_SELL. Для открытия позиции на покупку - OP_BUY. Для установки отложенного ордера надо использовать значения OP_BUYLIMIT, OP_SELLLIMIT, OP_BUYSTOP или OP_SELLSTOP в зависимости от типа размещаемого отложенного ордера.
При открытии позиции в качестве параметра price надо использовать текущий Bid (если cmd равен OP_SELL) или текущий Ask (если cmd равен OP_BUY):
Важно:
Ни в коем случае нельзя использовать цену, которую Вы рассчитали по какой-то формуле, или цену, которую Вы не привели (нормализовали) к тому количеству знаков после запятой, сколько должно быть у данного инструмента.
Для того, чтобы "нормализовать" цену, надо использовать функцию NormalizeDouble():
double NormalizeDouble (double value, int digits)
Эта функция округляет вещественное число value с точностью до digits знаков после запятой. Число цифр после десятичной точки должно быть в диапазоне 0.. 8.
В случае использования "неправильной" цены в параметре price будут выданы следующие коды ошибок:
Если же цена устарела, но еще присутствует в потоке, то будет совершена сделка по текущей цене, если текущая цена находится в диапазоне price +/- slippage.
В следующем выпуске я расскажу об оставшихся параметрах функции OrderSend().
Параметры функции OrderSend() - продолжение
В прошлых выпусках я рассказал о функции OrderSend() и начал рассмотрение ее параметров. В прошлом выпуске мною были рассмотрены параметры cmd и price.
В этом выпуске я расскажу о параметрах StopLoss, TakeProfit и expiration.
Когда Вы открываете позициию (выставляете отложенный ордер), то ордера Stop Loss и Take Profit должны находиться по отношению к текущей цене (цене отложенного ордера) не ближе, чем на расстоянии определенного количества пунктов. Например, если Вы имеет счет в Дилинговом центре "Альпари", то Вы не можете выставлять Stop Loss и Take Profit ордера на FOREX ближе одного спрэда к текущей цене для открытой позиции или к цене отложенного ордера.
Если Вы попытаетесь разместить Stop Loss или Take Profit ближе, чем это дозволено, то функция OrderSend() вернет ошибку 130 (ERR_INVALID_STOPS).
Если Вы не знаете этого минимально допустимого значения, то Вы всегда можете его получить с помощью функции MarketInfo(). Функция MarketInfo(string symbol, int type) c параметром type, равным MODE_STOPLEVEL, возвращает это значение по инструменту, который передан ей в качестве параметра symbol.
Инструмент графика, к которому прикреплен эксперт, можно получить с помощью функции Symbol():
string Symbol()
Если функция OrderSend() возратила ошибку 147 (ERR_TRADE_EXPIRATION_DENIED), это означает, что на торговом сервере запрещены отложенные ордера с установленной датой эксперации. В этом случае следует в дальнейшем использовать функцию OrderSend() с параметром expiration, равным нулю. Дилинговый центр "Альпари" разрешает своим клиентам устанавливать любую дату и время, когда неисполненный отложенный ордер будет удален автоматически.
Если функция OrderSend() вернула ошибку 148 (ERR_TRADE_TOO_MANY_ORDERS), это означает, что на торговом сервере установлено ограничение на максимально возможное число открытых позиций и выставленных отложенных ордеров по одному счету. Пытаясь открыть еще одну позицию или выставить еще один отложенный ордер, Вы превышаете допустимый лимит, поэтому Вам в этом будет отказано.
Пример использования функции OrderSend() можно найти в нашем первом эксперте:
MyOrderTicket = OrderSend(Symbol(), OP_SELL, LotsNumber, Bid, 3, 0, 0,
NULL, 0, 0, CLR_NONE);
if (MyOrderTicket<0)
{
err = GetLastError();
Print("Ошибка при открытии позиции: ", err);
MyOrderTicket = 0;
}
В следующем выпуске я расскажу о примере использования функции OrderSend().
Пример использования функции OrderSend()
Сегодня, разбирая почту, я наткнулся на очень давнее письмо, в которым один из читателей моего блога попросил мне помочь в написании такого эксперта:
Советник должен в определенное время (параметры MyHour и MyMinute) на заранее заданном расстоянии от текущей цены (параметр MyPendingLevel) выставлять два ордера - Sell Stop и Buy Stop. При этом должны выставляться ордера Stop Loss на расстоянии MySL пипсов от цены ордера и Take Profit на расстоянии MyTP пипсов. |
Я очень долго не отвечал на эту просьбу читателя, т.к. постоянно был чем-то занят по работе, но это неотвеченное письмо мне постоянно не давало спать спокойно, и я решил завершить неначатое и опубликовать решение, о котором этот читатель просил еще в конце августа.
//+------------------------------------------------------------------+
//| 2nd Expert.mq4 |
//| Andrey Vedikhin |
//| http://www.vedikhin.ru |
//+------------------------------------------------------------------+
#property copyright "Andrey Vedikhin"
#property link "http://www.vedikhin.ru"
//---- input parameters
extern int MyPendingLevel=15;
extern int MySL=30;
extern int MyTP=15;
extern int MyHour=19;
extern int MyMinute=40;
extern int MyLots=1.0;
datetime LastTradeTime; // время последней торговой операции
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
// установим время последней торговой операции вчерашним днем
LastTradeTime = CurTime()-24*60*60;
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
// проверим, не выставляли ли мы ордер уже сегодня
// если выставляли - выходим
if (TimeDayOfYear(CurTime())==TimeDayOfYear(LastTradeTime))
return(0);
// проверим, не наступило ли время выставить ордер
if ((TimeHour(CurTime())==MyHour)&&(TimeMinute(CurTime())==MyMinute))
{
// выставим Buy Stop
if (OrderSend(Symbol(), OP_BUYSTOP, MyLots,
Ask+Point*MyPendingLevel, 0, Ask+Point*MyPendingLevel-Point*MySL,
Ask+Point*MyPendingLevel+Point*MyTP)!=-1)
LastTradeTime = CurTime();
// ордер не выставлен
else
return(0);
// обязательная пауза в 10 секунд
Sleep(10000);
// обновим текущий Bid и Ask
RefreshRates();
// выставим Sell Stop
if (OrderSend(Symbol(), OP_SELLSTOP, MyLots,
Bid-Point*MyPendingLevel, 0, Bid-Point*MyPendingLevel+Point*MySL,
Bid-Point*MyPendingLevel-Point*MyTP)!=-1)
LastTradeTime = CurTime();
// ордер не выставлен
else
return(0);
}
//----
return(0);
}
//+------------------------------------------------------------------+
В следующем выпуске я разберу этот эксперт по "косточкам".
Пример использования функции OrderSend() - продолжение
В прошлом выпуске я написал по просьбе одного из читателей моего блога эксперт, в котором воплощена следующая логика:
Советник должен в определенное время (параметры MyHour и MyMinute) на заранее заданном расстоянии от текущей цены (параметр MyPendingLevel) выставлять два ордера - Sell Stop и Buy Stop. При этом должны выставляться ордера Stop Loss на расстоянии MySL пипсов от цены ордера и Take Profit на расстоянии MyTP пипсов. |
В этом выпуске я хотел бы разобрать подробно логику работы этого эксперта.
Прежде всего этот эксперт имеет несколько параметров:
extern int MyPendingLevel=15;
extern int MySL=30;
extern int MyTP=15;
extern int MyHour=19;
extern int MyMinute=40;
extern int MyLots=1.0;
Эти параметры имеют следующих смысл:
Напомню, что о том, как описать в коде параметры эксперта, я рассказывал в выпуске "Внешние переменные".
В реальности может возникнуть ситуация, когда на баре MyHour:MyMinute может быть несколько тиков, поэтому чтобы избежать выставления отложенных ордеров на каждом тике, мы завели глобальную переменную LastTradeTime:
datetime LastTradeTime; // время последней торговой операции
Этой переменной мы присваиваем в качестве начального значения вчерашнюю дату при инициализации эксперта - в функции init():
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
// установим время последней торговой операции вчерашним днем
LastTradeTime = CurTime()-24*60*60;
//----
return(0);
}
На каждом тике вызывается функция start(), в которой мы сначала проверяем, не выставляли ли мы уже сегодня отложенные ордера:
// проверим, не выставляли ли мы ордер уже сегодня
// если выставляли - выходим
if (TimeDayOfYear(CurTime())==TimeDayOfYear(LastTradeTime))
return(0);
Здесь используется неизвестная нам пока функция TimeDayOfYear():
int TimeDayOfYear(datetime date)
Эта функция возвращает порядковый номер дня (с начала года): 1 - 1 января,..., 365 или 366 - 31 декабря.
Если же порядковый номер дня последней торговой операции - TimeDayOfYear(LastTradeTime) - равен порядковому дню текущего времени - TimeDayOfYear(CurTime()), - значит мы уже сегодня ордера выставляли,
|
|
Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого...
Индивидуальные и групповые автопоилки: для животных. Схемы и конструкции...
Типы сооружений для обработки осадков: Септиками называются сооружения, в которых одновременно происходят осветление сточной жидкости...
Наброски и зарисовки растений, плодов, цветов: Освоить конструктивное построение структуры дерева через зарисовки отдельных деревьев, группы деревьев...
© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!