Сообщение: 886
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация:
0
Отправлено: 25.10.16 09:34. Заголовок: Такой алгоритм нужен..
цитата:
Такой алгоритм нужен? Даже если он, то это несколько сотен строк кода. Ну и в самом алгоритме еще такой момент не предусмотрен: а что, если цена не вернется к начальному уровню открытия?
Имеются ввиду ордера, которые находятся в рынке. Если цена идет вверх и должен открыться Бай, но на этом уровне уже есть Бай, то не должен открывать - сейчас открывает. Вот я и спрашиваю, какое дополнительное условие прописать в коде открытия ордеров. чтобы на одном уровне ордера чередовались. Сформулируйте логику словами - я сам напишу.
Отправлено: 25.10.16 16:19. Заголовок: Эдуард пишет: Вот я..
Эдуард пишет:
цитата:
Вот я и спрашиваю, какое дополнительное условие прописать в коде открытия ордеров. чтобы на одном уровне ордера чередовались. Сформулируйте логику словами - я сам напишу.
Еще раз: не существует такого условия, это целый алгоритм. В идеале требуется:
1. Найти все ордера, открытые экспертом и записать их в массив. 2. Обработать полученный массив и выяснить, где нужно установить/открыть ордер, а где - нет.
Обычно для этой цели я произвожу нумерацию ордеров, чтобы можно было отличать их друг от друга. Номер ордера кодирую в поле MagicNumber ордера. Например, если идентификатор ордеров эксперта 345, то в поле MagicNumber записываю 345 * 100 + 1 = 34501. Такая запись означает, что ордер открыт экспертом с идентификатором 345. Номер ордера в серии - 1. Работа с ордерами, если стратегия сеточная, это достаточно сложная вещь.
Сообщение: 887
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация:
0
Отправлено: 25.10.16 10:17. Заголовок: Надо сделать перебор..
Надо сделать перебор ордеров, запомнить уровень, запомнить тип последнего ордера и если при открытии текущего ордера типы совпадают, то не открывать ордер того же типа - так ?
Отправлено: 06.11.16 17:18. Заголовок: Эдуард пишет: Подск..
Эдуард пишет:
цитата:
Подскажите пожалуйста, может есть другой способ открывать ордера на уровнях?
По кускам кода никто ничего не сможет сказать. Так, в этом коде непонятно, что есть massiv_o (как он объявлен и как и чем заполняется), что такое функция Tipordera, что такое переменная step? То есть Вы, находясь в своем контексте рассуждений, задаете вопрос, на который невозможно ответить, не зная этого самого контекста.
Также непонятно, почему задается вопрос о необходимости открытия ордера, но ведется работа с уже открытыми ордерами?
Сообщение: 889
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация:
0
Отправлено: 06.11.16 21:20. Заголовок: По кускам кода никто..
цитата:
По кускам кода никто ничего не сможет сказать. Так, в этом коде непонятно, что есть massiv_o (как он объявлен и как и чем заполняется), что такое функция Tipordera, что такое переменная step? То есть Вы, находясь в своем контексте рассуждений, задаете вопрос, на который невозможно ответить, не зная этого самого контекста.
Также непонятно, почему задается вопрос о необходимости открытия ордера, но ведется работа с уже открытыми ордерами?
for (int j=0; j<ArrayRange(massiv_o,0); j++)// объявлен глобально определяет количество цен ордеров в массиве, строит виртуально сетку на расстоянии шага (step), после открытия первого ордера.
if(NormalizeDouble(massiv_o[j], _Digits)>0 && (MathAbs(Bid-NormalizeDouble(massiv_o[j], _Digits))/_Point)<=10)// 10 это в пунктах погрешность вверх/вниз, когда можно выставить ордер.
Тип ордера, он и есть тип ордера if(OrderType()==OP_BUY) tipordera=0; if(OrderType()==OP_SELL) tipordera=1;
Вопрос в том, можно ли это сделать проще и надежней ?
Отправлено: 07.11.16 15:27. Заголовок: Эдуард пишет: for (..
Эдуард пишет:
цитата:
for (int j=0; j<ArrayRange(massiv_o,0); j++)// объявлен глобально определяет количество цен ордеров в массиве, строит виртуально сетку на расстоянии шага (step), после открытия первого ордера.
Если известен шаг сетки и отправная точка, то для чего массив? Ведь цена любого уровня рассчитывается путем решения простого линейного уравнения... В любом случае нужно видеть, как массив заполняется. Там вполне может быть ошибка.
Эдуард пишет:
цитата:
Тип ордера, он и есть тип ордера if(OrderType()==OP_BUY) tipordera=0; if(OrderType()==OP_SELL) tipordera=1;
Зачем, если OP_BUY это и есть 0, а OP_SELL - 1?
Эдуард пишет:
цитата:
Вопрос в том, можно ли это сделать проще и надежней ?
Проще уже некуда. Тем более, что используемый алгоритм явно слишком примитивен для решения поставленной задачи далеко не низкого уровня (средний или даже чуть выше среднего). А вот надежнее - конечно.
Чтобы решить задачу, пора ли открывать новый ордер по сетке, нужно:
1. Перебрать все открытые ордера из списка рабочих и сохранить свои ордера в массив. Попутно сформировать максимальные и минимальные цены открытых ордеров. Возможно, еще придется вычислять бреши в ордерах. 2. Вычислить цену открытия следующего ордера на основании максимальной и минимальной цен текущих ордеров. 3. Проверить, нужно ли теперь открывать ордер (попадает ли он в нужный диапазон цен)?
Таким образом, пп. 2 и 3 никакого отношения к имеющимся ордерам уже не имеют. А в приведенном Вами коде - имеют.
И далее остающаяся половина открытого ордера на покупку с лотом 0.01 не тралится. Когда убираешь открытый ордер BuyStop, то трейлинг работает. Как сделать, чтобы трейлинг работал после закрытия половины позиции при открытом отложенном ордере BuyStop?
Отправлено: 13.06.17 20:33. Заголовок: Ошибки во втором и т..
Ошибки во втором и третьем блоках. Ошибки грубые - неправильное использование функции OrderSelect(). Эта функция выбирает ордер по тикету (первый случай) или по индексу в списке (второй случай). В первом случае ей нужно передать индекс строки в списке рабочих ордеров или истории счета, при этом указав вторым параметром SELECT_BY_POS. Во втором случае ей нужно передать уникальный идентификатор ордера (тикет) и вторым параметром указать SELECT_BY_TICKET. Здесь же видим, что делается попытка передачи тикета (OrderTicket()) и при этом указывается второй параметр SELECT_BY_POS. Уже явное несоответствие. Далее обращаю внимание на тот факт, что функция OrderTicket() возвращает тикет выбранного ордера. Таким образом, функция никак не может быть аргументом при вызове функции OrderSelect(), которая выполняет этот выбор. Исходя из того, что в обоих блоках используется цикл перебора ордеров (предположительно по списку рабочих ордеров), следовало бы строку:
Здравствуйте. Прошу подсказать как реализовать сравнение депо до открытия начальной сделки с текущим балансом эквити. Сова мартинит после убытка и интересует не разница AccountEquity() и AccounBallance(), а разница AccountEquity() и того первого значения AccountBalance() в самом начале серии "догона"(до входа в рынок с начальным лотом). Понятно, что здесь не обойтись без массивов, потому прошу подсказать направление, а лучше с примерами кода, если не затруднит.
Прошу подсказать как реализовать сравнение депо до открытия начальной сделки с текущим балансом эквити. Сова мартинит после убытка и интересует не разница AccountEquity() и AccounBallance(), а разница AccountEquity() и того первого значения AccountBalance() в самом начале серии "догона"(до входа в рынок с начальным лотом)
На мой взгляд, принципиально неверное решение. Ведь необходимо учитывать, что на одном счете может работать одновременно несколько подобных экспертов. Поэтому текущий баланс или эквити не даст достоверной информации. Единственно верным решением будет отслеживание экспертом собственных сделок в истории счета или в списке рабочих ордеров, если используется открытие встречных/доливочных ордеров.
... Подскажите, по-возможности, что не так. Вот, в сове хочу добавить умножитель лота при срабатывании SL.
"реализовал" так:
цитата:
int slippage=10;
int start() { ... string txt; static int n; if (Orders>OrdersTotal()) txt=I(); { if (txt=="SL" || txt!="TP") {n++; LOT=Lot[n]; if (n>=10) {n=0; LOT=Lot1;}} if (txt=="TP") {n=0; LOT=Lot1;} } Orders=OrdersTotal(); ... return(0); }
и функция:
цитата:
string I() { string txt=NULL; int a=OrdersHistoryTotal()-1; if(OrderSelect(a,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol()==Symbol() && OrderMagicNumber()==ID) { if (MathAbs(OrderStopLoss()-OrderClosePrice())<=_Point*slippage) txt="SL"; if (MathAbs(OrderTakeProfit()-OrderClosePrice())<=_Point*slippage) txt="TP"; } return(txt); }
Поставленную задачу это выполняет лишь частично. При закрытии руками или по "SL" происхOдит увеличение последующих лотов, но после закрытия по "TP" лот не сбрасывается до Lot1 а дальше растет... Что предпринять? Благодарю заранее.
Отправлено: 07.07.17 09:41. Заголовок: allisbob пишет: но ..
allisbob пишет:
цитата:
но после закрытия по "TP" лот не сбрасывается до Lot1 а дальше растет
По приведенным обрывкам кода сложно сказать, что именно не так. По идее, должно работать, если TakeProfit установлен у ордеров. С другой стороны объем по этому коду должен повышаться на каждом новом тике. Ведь условие:
цитата:
if (txt=="SL" || txt!="TP")
сработает и тогда, когда не было закрытия ордера (переменная txt будет содержать пустую строку). Также нужно заметить, что блок, в котором находится эта строка, не принадлежит условию:
цитата:
if (Orders>OrdersTotal())
т. е. блок просто сам по себе. С таким же успехом можно убрать эти фигурные скобки - ничего не изменится.
Хотя, конечно, решение задачи подвержено многим "если". К примеру, функция I() будет работать правильно только в тестере. А вот онлайн она может обработать ордер, который просто последний в списке. Ведь сортировать список пользователь может как угодно: по времени открытия, закрытия, по объему и т. д. Также почему то решено, что проскальзывание у стопа и профита обязательно должно лежать в пределах проскальзывания, задаваемого пользователем. Видимо, в этих мелочах и кроется проблема.
Для поиска последнего закрытого ордера лучше всего сканировать весь список истории счета и находить в нем наибольшее время закрытия:
цитата:
int GetLastCloseOrderTicket() { datetime dtLastTime = 0; int nLastTicket = -1; for (int i = OrdersHistoryTotal() - 1; i >= 0; i--) { if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
if (OrderSymbol() != Symbol()) continue;
if (m_nMagicNumber != OrderMagicNumber()) continue;
Далее по полученному тикету определяем причину закрытия:
цитата:
enum ENUM_CLOSE_REASON { CLOSE_REASON_ERROR, // Ошибка определения причины закрытия CLOSE_REASON_MARKET, // Ордер закрыт "по рынку" - не по SL и не по TP CLOSE_REASON_TP, // Ордер закрыт по достижении Take Profit CLOSE_REASON_SL // Ордер закрыт по достижении Stop Loss };
Отправлено: 09.07.17 16:05. Заголовок: Большое спасибо Вам,..
Большое спасибо Вам, Игорь, за объяснение. Правда, у меня целый код совы не намного больше приведенного примера
Теперь хотел бы уточнения: что присваивается переменной dtLastOrderTime?
цитата:
int GetLastCloseOrderTicket() { datetime dtLastTime = 0; int nLastTicket = -1; for (int i = OrdersHistoryTotal() - 1; i >= 0; i--) { if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
if (OrderSymbol() != Symbol()) continue;
if (m_nMagicNumber != OrderMagicNumber()) continue;
Все даты в формате GMT
2 час. Хитов сегодня: 3
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет