АвторСообщение



Сообщение: 27
Зарегистрирован: 17.10.14
Репутация: 0
ссылка на сообщение  Отправлено: 15.12.14 18:05. Заголовок: Программное определение закрытия ордера по стопу


Интересно, можно ли программно определить, если ордер закрылся по стоп-лосс? А нужно это вот для чего. У меня советник уже пару раз открывал позицию в том же направлении (т.е. buy-buy или sell-sell) сразу после срабатывания стопа, и получался двойной убыток. Хотелось бы запретить открытие ордера в том же направлении в течение некоторого времени после срабатывания стопа. Но для этого надо определить факт такого срабатывания. Функция OrderStopLoss() как я понимаю просто определяет цену закрытия открытого ордера в случае достижения уровня стоп-лосс и пользы от этого мало. Или я ошибаюсь? Интуиция подсказывает, что надо сделать что-то типа следующего ниже блока (на примере ордера buy), но не уверен:

int i=OrdersHistoryTotal()-1;
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true)
if(OrderStopLoss()!=OrderClosePrice() && OrderType()=0) // если цена закрытия не равна стопу и был ордер buy
int ticket=OrderSend(Symbol(), 0, …… ); // то разрешаем открыть ордер buy
else ..... // запрет на открытие ордера buy


Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 18 , стр: 1 2 All [только новые]







Сообщение: 1047
Зарегистрирован: 03.03.13
Откуда: Украина, Днепродзержинск
Репутация: 3
ссылка на сообщение  Отправлено: 15.12.14 20:59. Заголовок: В этом коде не учиты..


В этом коде не учитывается два момента:
1. Нельзя напрямую сравнивать два числа типа double (OrderStopLoss и OrderClosePrice)
2. При закрытии по стопу цена закрытия далеко не всегда будет равна уровню цены, указанному в OrderStopLoss.

То есть условие определения закрытия по стопу должно быть таким:

 цитата:
if ((OrderType() == OP_BUY && OrderStopLoss() - OrderClosePrice() >= -_Point / 10) ||
(OrderType() == OP_SELL && OrderClosePrice() - OrderStopLoss() >= -_Point / 10))
{
// Выбранный в истории счета ордер был закрыт по стопу
}



Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 28
Зарегистрирован: 17.10.14
Репутация: 0
ссылка на сообщение  Отправлено: 16.12.14 16:32. Заголовок: Спасибо, Учитель. Д..


Спасибо, Учитель. Действительно, ведь ордер по стопу обычно закрывается из-за проскальзывания за уровнем стопа по менее выгодной цене. Так что разница между ценой закрытия и уровнем стопа может сильно отличаться от нуля. Поэтому должно быть вместо равенства неравенство. А знак минус на случай, если все-таки цена закрытия будет равна уровню стопа. Но поскольку эти цены - действительные числа, то разница между ними может быть не точно равна нулю, а плюс-минус 1.Е-16 или около того. Поэтому применено -Point/10.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 1052
Зарегистрирован: 03.03.13
Откуда: Украина, Днепродзержинск
Репутация: 3
ссылка на сообщение  Отправлено: 17.12.14 10:58. Заголовок: Stoletov пишет: А з..


Stoletov пишет:

 цитата:
А знак минус на случай, если все-таки цена закрытия будет равна уровню стопа.


В данном случае это эквивалент "больше или равно". Ведь бывают случаи, когда число, записанное в одной ячейке памяти, отличается от себя самого, записанного в другой ячейке памяти, на пренебрежительно малую величину. Заранее нам неизвестно, какое именно из этих "равных" чисел больше. То есть при вычитании может быть получен отрицательный результат со значением, равным "минус пренебрежительно малой величине". Отсюда и сравнение не с нулем, а с "минус дельтой".

Дельта - это точность наших вычислений. В данном случае, когда речь идет о ценах, достаточно использовать дельту, равную одной десятой пункта. Все, что больше этой дельты, указывает на различие сравниваемых чисел, а все, что меньше, это равные числа. То есть все числа с разностью от (-_Point / 10) до (_Point / 10) считаются равными другу. При выходе за этот интервал - не равны.


Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 32
Зарегистрирован: 17.10.14
Репутация: 0
ссылка на сообщение  Отправлено: 06.01.15 13:19. Заголовок: Суммируя все вместе,..


Суммируя все вместе, я написал такой фрагмент для запрета открытия ордера в том же направлении в течение заданного времени после срабатывания стопа:

bool buy=true, sell=true;
i=OrdersHistoryTotal()-1;
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderCloseTime()>Time[1])
{if(OrderType()==0 && OrderStopLoss()-OrderClosePrice()>=-_Point/10)
buy=false;
if(OrderType()==1 && OrderClosePrice()-OrderStopLoss()>=-_Point/10)
sell=false;}

Далее флаги buy и sell используются для разрешения или запрета открытия ордера до вызова оператора OrderSend.
Условие OrderCloseTime()>Time[1] запрещает повторное открытие в том же направлении, если закрытие по стопу произошло позднее начала первого бара. Вместо этого условия можно написать и другое, например OrderCloseTime()>TimeCurrent()-3600. Тогда повторное открытие в том же направлении разрешается через час после срабатывания стопа. Данный фрагмент не запрещает открытие в противоположном направлении сразу после срабатывания стопа. Но это нормально, т.к. движение цены после срабатывания стопа том же направлении более вероятно, чем в противоположном и такой переворот часто дает прибыль.
Еще раз спасибо за ценный совет, Scriptong.


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 1093
Зарегистрирован: 03.03.13
Откуда: Украина, Днепродзержинск
Репутация: 3
ссылка на сообщение  Отправлено: 07.01.15 20:14. Заголовок: По сути - верно. Еди..


По сути - верно. Единственное, что не учтено в этом коде - текущая сортировка истории счета. Не всем известно (а в документации это не описано), что программные позиции ордеров в списках рабочих ордеров и истории счета полностью соответствуют тому порядку ордеров, который установлен пользователем в соответствующих закладках окна "Терминал".

В итоге, если история счета отсортирована пользователем по убыванию времени закрытия, то указанный код будет выбирать не последний закрытый, а первый закрытый ордер. Таким образом, перед тем, как выполнить данный код, следует пройтись по всей истории счета и найти ордер с наибольшим временем закрытия.

Но, к сожалению, на этом "беды" не заканчиваются. Пользователь может так настроить закладку истории счета, чтобы она вообще не показывала закрытых ордеров (выбрать начало отображения в будущем; бред, но теоретически возможно). В итоге советник никогда не увидит закрытых ордеров, т. к. список истории счета будет вечно пуст.

Получаем, что использовать данные истории счета в своей программе нежелательно (нет уверенности в том, что история счета отображает правильные данные в правильном порядке). Для этого лучше формировать в советнике собственную историю счета - самостоятельно следить за открывающимися и закрывающимися ордерами, сравнивая списки рабочих ордеров на текущем и предыдущих тиках. Историю счета можно использовать только в самом начале функционирования программы для формирования начальных данных.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 34
Зарегистрирован: 17.10.14
Репутация: 0
ссылка на сообщение  Отправлено: 09.01.15 10:00. Заголовок: Спасибо за предупреж..


Спасибо за предупреждение , Scriptong. Такая предусмотрительность на все случаи жизни меня не перестает восхищать. Однако я проверил (путем вывода Alert характеристик последнего ордера в тестовом скрипте и эксперте) : после сортировки истории по убыванию времени закрытия программа выдает последний ордер тот же самый, т.е. физически самый последний независимо от сортировки. А вот если ограничить историю более ранней датой, то программа выдает уже не самый последний ордер, а более ранний. Если выбрать начало отображения в будущем и тем самым удалить историю вообще, то закрытых ордеров программа действительно не видит. Таким образом получается, что проходить по всей истории счета необходимости нет, надо только следить за тем, чтобы в окне терминала была выбрана либо вся история, либо история за последний период (а то иначе пришлось бы пройти цикл в несколько тысяч итераций, по количеству сделок истории; конечно для современного компа это как слону дробина, только жалко насиловать полезный прибор).
Но есть еще одна закавыка. Дело в том, что последний закрытый ордер в истории может относиться к другой валютной паре (а не к той, на которой работает эксперт). Поэтому все-таки надо частично пройтись по истории назад, чтобы отследить ордер нужной валютной пары. Но назад не далее, чем заданный промежуток времени, в течение которого хотим запретить повторное открытие ордера в том же направлении после срабатывания стопа, например 1 час. С учетом сказанного правильный фрагмент программы будет такой:

for(i=OrdersHistoryTotal()-1; i>=0; i--)
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol()==Symbol())
if(OrderCloseTime()<TimeCurrent()-3600)
break; // более старые ордера не проверяем
else
{if(OrderType()==0 && OrderStopLoss()-OrderClosePrice()>=-Point/10)
{buy=false; break;}
if(OrderType()==1 && OrderClosePrice()-OrderStopLoss()>=-Point/10)
{sell=false; break;}}

А теперь рассмотрю вариант формирования в советнике собственной истории счета, как предлагает Scriptong. Для этого в моем советнике уже сделана подготовительная работа – двумя циклами произведено сравнение старого и нового массивов ордеров и выявлен закрытый ордер (старый массив - это тот, который был перед последним тиком). В качестве примера такого отслеживания ордеров можно обратиться к учебнику по МТ4 (процедура events в советнике usialexpert.mq4). Допустим, после перебора старых и новых ордеров выяснилось, что ордер с порядковым номером “old” перед последним тиком был закрыт. В упомянутом учебнике элемент старого массива Mas_Ord_Old[old][6] соответствует типу ордера, а элемент Mas_Ord_Old[old][2] – курсу стоп-лосс. Тогда фрагмент программы по запрету повторного открытия ордера в том же направлении после срабатывания стопа может выглядеть так:

bool buy=true, sell=true; // эти переменные задаются в головной программе
static double Bid_old=1000, Ask_old=1000; // отсюда весь блок в процедуре event
static datetime tstop;
if (Mas_Ord_Old[old][6]==0 && Mas_Ord_Old[old][2]-Bid_old>=-Point/10)
{buy=false; tstop=TimeCurrent();} // ордер Buy был закрыт по стопу
if (Mas_Ord_Old[old][6]==1 && Ask_old-Mas_Ord_Old[old][2]>=-Point/10)
{sell=false; tstop=TimeCurrent();} // ордер Sell был закрыт по стопу
Bid_old=Bid; Ask_old=Ask;
if(TimeCurrent()-tstop>3600)
buy=sell=true;

Оба фрагмента программы я проверил на demo-счете. Чтобы было побольше сделок, бросил эксперт на 15-минутный график четырех валютных пар и задал стоп всего 5 четырехзначных пунктов. Тест показал, что оба фрагмента работают нормально - ордер в том же направлении после срабатывания стопа не открывается . Для большей достоверности надо конечно погонять тест подольше. Если будут сбои, то напишу.


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 1096
Зарегистрирован: 03.03.13
Откуда: Украина, Днепродзержинск
Репутация: 3
ссылка на сообщение  Отправлено: 09.01.15 19:04. Заголовок: Stoletov пишет: пос..


Stoletov пишет:

 цитата:
после сортировки истории по убыванию времени закрытия программа выдает последний ордер тот же самый, т.е. физически самый последний независимо от сортировки


Проверил. Да, действительно, теперь порядок ордеров в списке истории счета, который получает программа на MQL4, не зависит от сортировки в закладке "История счета". Видимо, в каких-то билдах МТ4 после 225-го это поведение наконец-то было изменено. С 2008-го года я не проверял этот момент. Жаль, что не отвязали программный список от содержимого закладки истории счета, как в МТ5. Но, возможно, и это будет.

Stoletov пишет:

 цитата:
В качестве примера такого отслеживания ордеров можно обратиться к учебнику по МТ4


Учебник писался в 2006-2007 гг. Поэтому не использует новые возможности. К примеру, в новом MQL4 намного удобнее использовать массив структур для хранения данных об ордерах вместо безликого второго измерения массива. К примеру, во многих программах использую такой подход:


 цитата:

#define MAX_ORDERS_AMOUNT 500 // Максимальное поддерживаемое количество ордеров

struct OrderInfo
{
int ticket;
int orderType;
int magic;
datetime openTime;
double volume;
double openPrice;
double slPrice;
double tpPrice;

string symbol;
};

int g_oldOrdersCnt,
g_curOrdersCnt;

OrderInfo g_oldOrderInfo[MAX_ORDERS_AMOUNT],
g_curOrderInfo[MAX_ORDERS_AMOUNT];

//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Сбор информации об ордерах |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void FindOrders()
{
g_curOrdersCnt = 0;
for (int i = OrdersTotal() - 1; i >= 0; i--)
{
if (!OrderSelect(i, SELECT_BY_POS))
continue;

if (g_curOrdersCnt >= MAX_ORDERS_AMOUNT)
{
Alert(WindowExpertName(), ": превышено максимально допустимое количество ордеров (", MAX_ORDERS_AMOUNT, "). Эксперт остановлен.");
ExpertRemove();
return;
}

g_curOrderInfo[g_curOrdersCnt].magic = OrderMagicNumber();
g_curOrderInfo[g_curOrdersCnt].openPrice = OrderOpenPrice();
g_curOrderInfo[g_curOrdersCnt].orderType = OrderType();
g_curOrderInfo[g_curOrdersCnt].slPrice = OrderStopLoss();
g_curOrderInfo[g_curOrdersCnt].ticket = OrderTicket();
g_curOrderInfo[g_curOrdersCnt].tpPrice = OrderTakeProfit();
g_curOrderInfo[g_curOrdersCnt].volume = OrderLots();
g_curOrderInfo[g_curOrdersCnt].openTime = OrderOpenTime();
g_curOrderInfo[g_curOrdersCnt].symbol = OrderSymbol();

g_curOrdersCnt++;
}
}



Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 35
Зарегистрирован: 17.10.14
Репутация: 0
ссылка на сообщение  Отправлено: 11.01.15 14:08. Заголовок: Я бы сказал, что стр..


Я бы сказал, что структура еще имеет то преимущество, что позволяет использовать различные типы данных в отличие от массива. В учебнике в эксперте usialexpert.mq4 объявлены массивы ордеров типа double, а содержат они элементы по смыслу не только типа double, но и int. В этом эксперте во многих местах производятся сравнения элементов массива ордеров типа double посредством операции ==, например if(Mas_Ord_Old[old][6]==0). Но ведь этого делать нельзя, не так ли? Такое равенство скорее всего не будет выполняться (с массивом типа int оно выполнялось бы) . В общем действительно пора переделать в эксперте массивы ордеров на структуры.

Scriptong, просьба ответить на 2 вопроса:
1)Как инициализировать весь массив структуры нулями или пустыми значениями? Я пытался сделать это путем ArrayInitialize(g_curOrderInfo,0) и ArrayInitialize(g_curOrderInfo, EMPTY_VALUE), но компилятор выдает ошибку'ArrayInitialize' - no one of the overloads can be applied to the function call. В то же время на оператор ArrayCopy( g_oldOrderInfo, g_curOrderInfo) компилятор не ругается. Почему же операция с массивом структуры ArrayCopy разрешается, а ArrayInitialize запрещается?
2) В вашей процедуре есть условие if (!OrderSelect(i, SELECT_BY_POS)), т.е. i-й ордер не найден. Это значит, что ордер когда-то был, но на момент исполнения программы закрыт или удален? А если так, то значит переиндексация текущих ордеров после закрытия или удаления одного из них не производится?


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 1102
Зарегистрирован: 03.03.13
Откуда: Украина, Днепродзержинск
Репутация: 3
ссылка на сообщение  Отправлено: 12.01.15 19:13. Заголовок: Stoletov пишет: В э..


Stoletov пишет:

 цитата:
В этом эксперте во многих местах производятся сравнения элементов массива ордеров типа double посредством операции ==, например if(Mas_Ord_Old[old][6]==0). Но ведь этого делать нельзя, не так ли?


Конкретно для значения "0.0" это позволительно, т. к. ноль он и в Африке ноль. Таких чисел, которые в двоичной записи являются конечной дробью, существует немало. Просто все их не упомнишь, а потому и существует правило - сравнивать вещественные числа только заранее определяясь с точностью сравнения. А вот ноль, думаю, запомнить нет никакого труда.

Stoletov пишет:

 цитата:
1)Как инициализировать весь массив структуры нулями или пустыми значениями? Я пытался сделать это путем ArrayInitialize(g_curOrderInfo,0) и ArrayInitialize(g_curOrderInfo, EMPTY_VALUE), но компилятор выдает ошибку'ArrayInitialize' - no one of the overloads can be applied to the function call. В то же время на оператор ArrayCopy( g_oldOrderInfo, g_curOrderInfo) компилятор не ругается. Почему же операция с массивом структуры ArrayCopy разрешается, а ArrayInitialize запрещается?


Посмотрите на определения приведенных Вами функций. Так функция ArrayInitialize имеет 8 вариантов определения, но каждый из вариантов ожидает на вход массив определенного типа (char, short, ushort и т. д.). А вот функция ArrayCopy принимает в качестве параметра массив любого типа. Потому и такое разное поведение.
По самой же задаче - нужно самому беспокоиться об инициализации массива структур:

 цитата:

struct OrderInfo
{
int ticket;
double openPrice;
};

OrderInfo orderInfo[10];

void OrderInfoInit()
{
for (int i = 0; i < 10; i++)
{
orderInfo[ i ].ticket = -1;
orderInfo[ i ].openPrice = 0.0;
}
}



Можно сделать немного красивее - через конструктор структуры:

 цитата:
struct OrderInfo
{
int ticket;
double openPrice;

OrderInfo()
{
ticket = -1;
openPrice = 0.0;
Print("Структура инициализирована");
}
};

OrderInfo orderInfo[10];



Если еще не сталкивались с конструкторами, то просто запустите последний пример на исполнение, добавив его в скрипт. Я специально добавил Print в конструктор - увидите, как происходит инициализация.


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 1103
Зарегистрирован: 03.03.13
Откуда: Украина, Днепродзержинск
Репутация: 3
ссылка на сообщение  Отправлено: 12.01.15 19:18. Заголовок: Stoletov пишет: 2) ..


Stoletov пишет:

 цитата:
2) В вашей процедуре есть условие if (!OrderSelect(i, SELECT_BY_POS)), т.е. i-й ордер не найден. Это значит, что ордер когда-то был, но на момент исполнения программы закрыт или удален? А если так, то значит переиндексация текущих ордеров после закрытия или удаления одного из них не производится?


Просто дань правильному использованию функции. Ведь если функция возвращает какое-то значение, то лучше проверить результат. Так, сходу, не могу привести пример, когда это необходимо в циклах применительно к OrderSelect, но интуитивно осознаю, что это спасает от каких-то ошибок, которые очень трудно локализовать. С такими ошибками никогда не сталкивался, потому что всегда применял именно такой синтаксис вызова OrderSelect.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 37
Зарегистрирован: 17.10.14
Репутация: 0
ссылка на сообщение  Отправлено: 14.01.15 16:45. Заголовок: Scriptong пишет: Ко..


Scriptong пишет:

 цитата:
Конкретно для значения "0.0" это позволительно, т. к. ноль он и в Африке ноль.


Проверил. Действительно элементы массива типа double можно приравнивать не только к целым, но и вещественным числам. Во всяком случае, если элемент массива явно инициализировать вещественным числом, а потом с этим же числом сравнить, то равенство будет истинно.

Scriptong пишет:

 цитата:
По самой же задаче - нужно самому беспокоиться об инициализации массива структур


Похоже в блоке инициализации структуры OrderInfo пропущен индекс i или он просто не отобразился. Блок работает при записи orderinfo[ i ] .ticket=-1
Конструктор структуры тоже проверил – работает. Если вывести в цикле по i от 0 до 9 orderinfo[ i ] .ticket=-1, то видно, что всем 10 элементам присвоено -1.

В итоге переписал свой 2-й фрагмент проверки повторного открытия в том же направлении после стопа на структуру вместо массивов и еще нашел ошибку (вместо Bid_old и Ask_old надо использовать текущие Bid и Ask) . Получилось теперь так:

bool buy=true, sell=true; // эти переменные задаются глобальными
static datetime tstop;
if (Mas_Ord_Old[old].type==0 && Mas_Ord_Old[old].stop-Bid>=-Point/10)
{buy=false; tstop=TimeCurrent();} // ордер Buy был закрыт по стопу
if (Mas_Ord_Old[old]. type ==1 && Ask-Mas_Ord_Old[old].stop>=-Point/10)
{sell=false; tstop=TimeCurrent();} // ордер Sell был закрыт по стопу
if(TimeCurrent()-tstop>3600) // прошел час от срабатывания стопа
buy=sell=true;

При проверке на демо-счете этот фрагмент работает почти нормально, но не совсем. Изредка почему-то цена закрытия Bid (для buy) или Ask (для sell) в программе не равна цене закрытия по стопу в графе s/l в истории счета. Отличие этих цен было в пятом знаке, проскальзывание нулевое. Из-за этого расхождения цен неравенства >=-Point/10 уже не выполнялись, и программа не фиксировала закрытия по стопу. В результате после срабатывания стопа сразу же происходило повторное открытие в том же направлении. Такое ощущение, что цена успела измениться с момента закрытия ордера до подхода программы к выполнению данного фрагмента. Может чтобы этого избежать, надо Point не разделить, а умножить на 10? Хоть это и некорректно, но зато нежелательных открытий в том же направлении после стопа уже точно не будет.


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 1113
Зарегистрирован: 03.03.13
Откуда: Украина, Днепродзержинск
Репутация: 3
ссылка на сообщение  Отправлено: 14.01.15 17:42. Заголовок: Stoletov пишет: Пох..


Stoletov пишет:

 цитата:
Похоже в блоке инициализации структуры OrderInfo пропущен индекс i или он просто не отобразился. Блок работает при записи orderinfo[ i ] .ticket=-1


В предыдущем сообщении исправил: поставил пробелы в скобках - индекс появился. Все время забываю, что выражение "квадратная скобка i закрывающая квадратная скобка" воспринимается форумом как BB-код "курсив".

Stoletov пишет:

 цитата:
В итоге переписал свой 2-й фрагмент проверки повторного открытия в том же направлении после стопа на структуру вместо массивов и еще нашел ошибку (вместо Bid_old и Ask_old надо использовать текущие Bid и Ask) . Получилось теперь так:


Для того, чтобы определить, был ли закрыт ордер или нет, не нужно использовать текущие цены Bid и Ask - они ни к чему. Проверяйте принадлежность ордера тому или иному списку - рабочих ордеров или истории счета. Для этого ордер нужно выбрать по тикету и сравнить время закрытия с нулем. Нулевое время закрытия - ордер в списке рабочих ордеров, отличное от нуля - в истории счета:

 цитата:
if (OrderSelect(Mas_Ord[old].ticket, SELECT_BY_TICKET))
{
if (OrderCloseTime() == 0)
{
// ордер не закрыт, существует
}
else
{
// ордер закрылся, если нужно, то можно приступить к определению, по какой причине он закрылся
}
}



В советнике предложенный Вами метод не всегда срабатывает, т. к. советник получает не все тики, которые приходят в терминал.


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 4
Зарегистрирован: 05.01.15
Репутация: 0
ссылка на сообщение  Отправлено: 15.01.15 06:16. Заголовок: Здравствуйте уважаем..


Здравствуйте уважаемый Scriptong. К вам еще вопросик, посмотрите на рисунку: http://shot.qip.ru/00Esu2-5SNS8HMSU/
Код для МТ5. Пожалуйста помогите?!

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 39
Зарегистрирован: 17.10.14
Репутация: 0
ссылка на сообщение  Отправлено: 15.01.15 17:38. Заголовок: skilful_coder пишет:..


Scriptong пишет:

 цитата:
Для того, чтобы определить, был ли закрыт ордер или нет, не нужно использовать текущие цены Bid и Ask - они ни к чему. Проверяйте принадлежность ордера тому или иному списку - рабочих ордеров или истории счета. Для этого ордер нужно выбрать по тикету и сравнить время закрытия с нулем. Нулевое время закрытия - ордер в списке рабочих ордеров, отличное от нуля - в истории счета:


Scriptong, вы не поняли. Здесь ордер, определяемый элементом массива Mas_Ord_Old[old], уже выявлен как закрытый (другим методом-путем сравнения старого и нового массивов ордеров в двух циклах). Теперь стоит задача - определить цену закрытия.

Scriptong пишет:

 цитата:
В советнике предложенный Вами метод не всегда срабатывает, т. к. советник получает не все тики, которые приходят в терминал.


Да, я уже понял, что нельзя использовать цены Bid и Ask для сравнения c ценой s/l. Цены Bid и Ask верны для момента запуска эксперта на последнем тике. Но неизвестно, по какой цене закрылся ордер – возможно по цене, которая была на предыдущем тике, или по новой последней цене, отличной от той, которая была при запуске эксперта на последнем тике. Чтобы узнать цену закрытия по стопу, приходится все равно обращаться к истории посредством функции OrderClosePrice(). Таким образом возвращаюсь снова к моему первому фрагменту с анализом истории ордеров – см. мое сообщение от 09.01.2015. В нем допущена ошибка, которая проявлялась в том, что ордер после стопа иногда открывался в том же направлении через время, меньшее чем 1 час. Но при этом следующий ордер после стопа через время, меньшее чем 1 час, всегда открывался в противоположном направлении – уже прогресс! Теперь после исправлений все стало ОК – см. исправленный фрагмент ниже. При использовании такого похода надо только следить за тем, чтобы в окне терминала была выбрана либо вся история, либо история за последний период. На этом тему для себя считаю исчерпанной и хочу поблагодарить Scriptong”а за поддержку и хорошие идеи.

static datetime tstop_buy, tstop_sell;
static bool buy=true, sell=true;
for(i=OrdersHistoryTotal()-1; i>=0; i--)
if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol()==Sym)
if(OrderCloseTime()<TimeCurrent()-3600)
break; // более старые ордера не проверяем
else
{if(OrderType()==0 && OrderStopLoss()-OrderClosePrice()>=-Point/10)
{buy=false;
tstop_buy=OrderCloseTime();
break;}
if(OrderType()==1 && OrderClosePrice()-OrderStopLoss()>=-Point/10)
{sell=false;
tstop_sell=OrderCloseTime();
break;}}
if(TimeCurrent()-tstop_buy>3600)
buy=true;
if(TimeCurrent()-tstop_sell>3600)
sell=true;


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 1117
Зарегистрирован: 03.03.13
Откуда: Украина, Днепродзержинск
Репутация: 3
ссылка на сообщение  Отправлено: 15.01.15 20:02. Заголовок: Stoletov пишет: Scr..


Stoletov пишет:

 цитата:
Scriptong, вы не поняли. Здесь ордер, определяемый элементом массива Mas_Ord_Old[old], уже выявлен как закрытый (другим методом-путем сравнения старого и нового массивов ордеров в двух циклах). Теперь стоит задача - определить цену закрытия.


Возможно, опять чего-то не понял. Но если мы имеем дело с закрытым ордером, то его цена закрытия - OrderClosePrice(). Если же имеется в виду, что необходимо определить причину закрытия ордера, то это решается таким кодом:

 цитата:
enum ENUM_CLOSE_REASON
{
CLOSE_REASON_TP, // Ордер закрыт по достижению Take Profit
CLOSE_REASON_SL, // Ордер закрыт по достижению Stop Loss
CLOSE_REASON_MARKET, // Ордер закрыт по с рынка
CLOSE_REASON_ERROR // Ошибка определения причины закрытия - ордер не найден
};

ENUM_CLOSE_REASON GetOrderCloseReason(int ticket)
{
double delta = -_Point / 10;
if (!OrderSelect(ticket, SELECT_BY_TICKET) || OrderCloseTime() == 0)
return CLOSE_REASON_ERROR;

// Ордер Buy
if (OrderType() == OP_BUY)
{
if (OrderClosePrice() - OrderTakeProfit() >= delta && OrderTakeProfit() != 0)
return CLOSE_REASON_TP;

if (OrderStopLoss() - OrderClosePrice() >= delta && OrderStopLoss() != 0)
return CLOSE_REASON_SL;

return CLOSE_REASON_MARKET;
}

// Ордер Sell
if (OrderTakeProfit() - OrderClosePrice() >= delta && OrderTakeProfit() != 0)
return CLOSE_REASON_TP;

if (OrderClosePrice() - OrderStopLoss() >= delta && OrderStopLoss() != 0)
return CLOSE_REASON_SL;

return CLOSE_REASON_MARKET;
}



Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 18 , стр: 1 2 All [только новые]
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  2 час. Хитов сегодня: 0
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет