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





Сообщение: 877
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 13.10.16 14:47. Заголовок: Программирование.


Здравствуйте. Подскажите, почему ордер не открывается?

input int Slippage=30;
input int Magic=156;
input double Lot=0.1;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTick()
{
double TP=0;
double cena_ma_1=0;
cena_ma_1=iMA(_Symbol,0,10,0,0,0,1);
int total=OrdersTotal();
for(int i=total-1; i>=0; i--)
if(OrderSelect(i,SELECT_BY_POS))
if(OrderSymbol()==Symbol())
{
double openB=OrderOpenPrice();
if(openB>cena_ma_1)
{
int tiket=OrderSend(_Symbol,OP_BUY,Lot,Ask,Slippage,0,TP,NULL,Magic,0,clrBlue);
{
Alert("Ордер открылся");
}
}
}
}


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





Сообщение: 37
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 13.10.16 15:32. Заголовок: А на основании чего ..


А на основании чего открывается ордер не понятно? Зачем цикл? Если это доливочный ордер, то имеет смысл использовать массив ордеров с маджиком.
Доливочный ордер открывается примерно так:
Был открыт ордер по какому-то условию и он был добавлен в массив ордеров советника по данному инструменту с маджиком. К нему, уже при других условиях добавляются ордера как-то так

 цитата:

if(UseMAFilter == false || Bid > ma) //MA Filter
{
tArray[T] = OrderSend(Symbol(), OP_BUY, Lots, ask, slip*PipValue, bid - StopLoss*Point*PipValue, 0, Magic);
if(tArray[T]<0) {Alert("OrderSend Error: ", GetLastError());}
T++;





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





Сообщение: 2353
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 13.10.16 16:33. Заголовок: Эдуард пишет: Здрав..


Эдуард пишет:

 цитата:
Здравствуйте. Подскажите, почему ордер не открывается?


Эдуард, Вы здесь намешали мух с котлетами. Цикл, который Вы привели, обычно служит для нахождения ордеров по текущему символу. В этом цикле не должно быть команд торговых операций. Попробуйте запустить этот код онлайн на демо-счете, предварительно открыв хотя бы один ордер с ценой открытия выше МАшки. В итоге получите шквал открытых ордеров Buy.

В текущем же виде ордер никогда не будет открыт, т. к. Вы сравниваете цену открытия имеющегося ордера с ценой MA. Если ордера нет или если цена его открытия ниже МА, то новый ордер не будет открыт.
Сформулируйте, что именно Вы хотели получить от этого кода.


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





Сообщение: 878
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 13.10.16 17:17. Заголовок: А так, почему на каж..


А так, почему на каждом тике открывает ?

input int Slippage=30;
input int Magic=156;
input double Lot=0.1;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTick()
{
double TP=0;
double ma=0;
ma=iMA(_Symbol,0,10,0,0,0,1);

if(Open[0]>ma)
{
int tiket=OrderSend(_Symbol,OP_BUY,Lot,Ask,Slippage,0,TP,NULL,Magic,0,clrBlue);
{
Alert("Ордер открылся");
}
}
}


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





Сообщение: 2354
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 13.10.16 17:56. Заголовок: Эдуард пишет: А так..


Эдуард пишет:

 цитата:
А так, почему на каждом тике открывает ?


Потому что Вы именно это и написали в коде: на каждом тике, если цена открытия свечи выше МАшки, то открывать ордер. Чтобы ордер открылся один раз, нужно предварительно произвести проверку, открывались уже ордера на текущей свече или нет. То есть циклом из первого Вашего поста собрать информацию, потом проанализировать ее и только затем выполнять код, приведенный во втором посте.

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





Сообщение: 879
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 13.10.16 18:16. Заголовок: Не открывает... in..


Не открывает...

input int Slippage=30;
input int Magic=156;
input double Lot=0.1;
input double TakeProfit=200;

double TP=0;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTick()
{
TP=NormalizeDouble(Ask+TakeProfit*_Point,_Digits);
TP=NormalizeDouble(Bid-TakeProfit*_Point,_Digits);
double ma=0;
ma=iMA(_Symbol,0,10,0,0,0,1);
int total=OrdersTotal();
for(int i=total-1; i>=0; i--)
if(OrderSelect(i,SELECT_BY_POS))
if(OrderSymbol()==Symbol())
{
if(OrderType()==OP_BUY && OrderMagicNumber()==Magic)
if(Open[0]>ma)
{
int tiket=OrderSend(_Symbol,OP_BUY,Lot,Ask,Slippage,0,TP,NULL,Magic,0,clrBlue);
{
Alert("Ордер открылся");
}
}
}
}

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





Сообщение: 2355
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 13.10.16 18:44. Заголовок: Эдуард пишет: Не от..


Эдуард пишет:

 цитата:
Не открывает...


Давайте так: что именно нужно?

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





Сообщение: 880
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 13.10.16 18:51. Заголовок: Scriptong пишет: Ко..


Scriptong пишет:

 цитата:



Когда свеча закрывается выше мувинга - Бай. Когда ниже Селл. Хотелось бы понять, что не так.
Код писать не надо, он мне не нужен в принципе.

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





Сообщение: 2356
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 13.10.16 19:57. Заголовок: Эдуард пишет: Когда..


Эдуард пишет:

 цитата:
Когда свеча закрывается выше мувинга - Бай.


В частностях у Вас все верно. А вот собрано - неверно. Так, условие открытия написано верно:

 цитата:

double ma = iMA(...);
if (Open[0] > ma)
{
// Открыть Buy
}
if (Open[0] < ma)
{
// Открыть Sell
}



Эдуард пишет:

 цитата:
Хотелось бы понять, что не так.


Не так то, что перед открытием необходимо проверить наличие уже открытых ордеров на текущей свече. Иначе Вы на каждом тике будете открывать новый ордер. Для определения времени последнего открытого ордера используйте код наподобие такого:

 цитата:

datetime GetLastOpenOrderTime()
{
datetime lastOpenOrderTime = 0;
for (int i = OrdersTotal() - 1; i >= 0; i--)
{
if (!OrderSelect(i, SELECT_BY_POS))
continue;

if (OrderSymbol() != Symbol())
continue;

if (OrderType() != OP_BUY && OrderType() != OP_SELL)
continue;

if (OrderMagicNumber() != i_magicNumber)
continue;

lastOpenOrderTime = (datetime)MathMax(lastOpenOrderTime, OrderOpenTime());
}

return lastOpenOrderTime;

}



Поэтому перед открытие нового ордера проверяйте время открытия последнего ордера путем сравнения времени открытия свечи и результата, который вернула функция GetLastOpenOrderTime().

 цитата:

datetime lastTime = GetLastOpenOrderTime();
if (lastTime >= Time[0])
{
// Новый ордер открывать нельзя, т. к. на этой свече уже был открыт ордер
}



Эдуард пишет:

 цитата:
Код писать не надо, он мне не нужен в принципе.


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


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





Сообщение: 881
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 13.10.16 19:59. Заголовок: Буду разбираться. Сп..


Буду разбираться.
Спасибо.


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





Сообщение: 882
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 16.10.16 11:57. Заголовок: Почему выдает ошибку..


Почему выдает ошибку ?

void OnTick()
{
int tiket=0;
if(OP_BUY==0)
tiket=OrderSend(_Symbol,OP_BUY,0.1,Ask,10,0,0,NULL,123,0,clrBlue);
if(tiket>=0)return(true);
else return(false);
if(OP_SELL==0)
tiket=OrderSend(_Symbol,OP_SELL,0.1,Bid,10,0,0,NULL,123,0,clrRed);
if( tiket>=0)return(true);
else return(false);
}

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





Сообщение: 2362
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 17.10.16 14:48. Заголовок: Эдуард пишет: Почем..


Эдуард пишет:

 цитата:
Почему выдает ошибку ?


Имеется в виду ошибка компиляции? Если да, то компилятор указывает на то, что функция OnTick имеет тип void (т. е. без типа), а в теле функции четыре функции return возвращают значение. Нужно убрать возврат значения.

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





Сообщение: 883
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 16.10.16 12:07. Заголовок: Когда надо делать пе..


Когда надо делать перебор ордеров ?
1. Когда открываем ордера.
2. Закрываем.
3. Модифицируем.
Когда еще ?

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





Сообщение: 2363
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 17.10.16 14:51. Заголовок: Эдуард пишет: Когда..


Эдуард пишет:

 цитата:
Когда надо делать перебор ордеров ?


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

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





Сообщение: 884
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 24.10.16 21:20. Заголовок: Подскажите на пример..


Подскажите на примере части кода. Какое условие прописать, чтобы ордера на одном уровне открывались так: Бай/Селл, то есть чередовались.

if(Tipordera(Magik)==1 && Ask>=LastPrice+step*_Point && LastPrice>0 && (Magik))
{
tiket=OrderSend(_Symbol,OP_BUY,Lot,Ask,Slippage,0,0,"",Magik,0,clrBlue);
LastPrice=Ask;
}

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





Сообщение: 2367
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 25.10.16 09:00. Заголовок: Эдуард пишет: Подск..


Эдуард пишет:

 цитата:
Подскажите на примере части кода. Какое условие прописать, чтобы ордера на одном уровне открывались так: Бай/Селл, то есть чередовались.


Не существует какого-то условия, чтобы его написал - и получил желаемое. Чаще всего, как и в этом случае, требуется составление целого алгоритма. Насколько я понял задачу, требуется:
    1. После открытия первого ордера, например, Buy, ожидаем его закрытия по стопу, профиту или по рынку (принудительное закрытие).
    2. По закрытию ордера ожидаем возврата цены к уровню открытия Buy и открываем Sell.
    3. Ожидание закрытия Sell.
    4. Ожидание возврата цены к уровню открытия Sell и открытие Buy.


Такой алгоритм нужен? Даже если он, то это несколько сотен строк кода.
Ну и в самом алгоритме еще такой момент не предусмотрен: а что, если цена не вернется к начальному уровню открытия?

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





Сообщение: 886
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 25.10.16 09:34. Заголовок: Такой алгоритм нужен..



 цитата:
Такой алгоритм нужен? Даже если он, то это несколько сотен строк кода.
Ну и в самом алгоритме еще такой момент не предусмотрен: а что, если цена не вернется к начальному уровню открытия?



Имеются ввиду ордера, которые находятся в рынке. Если цена идет вверх и должен открыться Бай, но на этом уровне уже есть Бай, то не должен открывать - сейчас открывает.
Вот я и спрашиваю, какое дополнительное условие прописать в коде открытия ордеров. чтобы на одном уровне ордера чередовались.
Сформулируйте логику словами - я сам напишу.

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





Сообщение: 2368
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 25.10.16 16:19. Заголовок: Эдуард пишет: Вот я..


Эдуард пишет:

 цитата:
Вот я и спрашиваю, какое дополнительное условие прописать в коде открытия ордеров. чтобы на одном уровне ордера чередовались.
Сформулируйте логику словами - я сам напишу.


Еще раз: не существует такого условия, это целый алгоритм.
В идеале требуется:
    1. Найти все ордера, открытые экспертом и записать их в массив.
    2. Обработать полученный массив и выяснить, где нужно установить/открыть ордер, а где - нет.

Обычно для этой цели я произвожу нумерацию ордеров, чтобы можно было отличать их друг от друга. Номер ордера кодирую в поле MagicNumber ордера. Например, если идентификатор ордеров эксперта 345, то в поле MagicNumber записываю 345 * 100 + 1 = 34501. Такая запись означает, что ордер открыт экспертом с идентификатором 345. Номер ордера в серии - 1.
Работа с ордерами, если стратегия сеточная, это достаточно сложная вещь.


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





Сообщение: 887
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 25.10.16 10:17. Заголовок: Надо сделать перебор..


Надо сделать перебор ордеров, запомнить уровень, запомнить тип последнего ордера и если при открытии текущего ордера типы совпадают, то не открывать ордер того же типа - так ?


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





Сообщение: 888
Настроение: нормальное
Зарегистрирован: 20.10.14
Откуда: Россия
Репутация: 0
ссылка на сообщение  Отправлено: 05.11.16 19:19. Заголовок: Подскажите пожалуйст..


Подскажите пожалуйста, может есть другой способ открывать ордера на уровнях?

bool OrderDist(int type)
{
bool dist=false;
RefreshRates();
for (int j=0; j<ArrayRange(massiv_o,0); j++)
{
if(NormalizeDouble(massiv_o[j], _Digits)>0 && (MathAbs(Bid-NormalizeDouble(massiv_o[j], _Digits))/_Point)<=10)
{
dist=true;
break;
}
}
for(int i=0; i<OrdersTotal(); i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) && OrderMagicNumber()==Magik)
if(OrderSymbol()==_Symbol)
if(((MathAbs(Bid-OrderOpenPrice())/_Point)<=step/2) && Tipordera(Magik)==type) dist=false;
}
return(dist);
}

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





Сообщение: 2378
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 06.11.16 17:18. Заголовок: Эдуард пишет: Подск..


Эдуард пишет:

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


По кускам кода никто ничего не сможет сказать. Так, в этом коде непонятно, что есть massiv_o (как он объявлен и как и чем заполняется), что такое функция Tipordera, что такое переменная step? То есть Вы, находясь в своем контексте рассуждений, задаете вопрос, на который невозможно ответить, не зная этого самого контекста.

Также непонятно, почему задается вопрос о необходимости открытия ордера, но ведется работа с уже открытыми ордерами?

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





Сообщение: 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;

Вопрос в том, можно ли это сделать проще и надежней ?

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





Сообщение: 2381
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 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 
ПрофильЦитата Ответить



Сообщение: 427
Зарегистрирован: 25.08.13
Репутация: 1
ссылка на сообщение  Отправлено: 12.06.17 22:19. Заголовок: Добрый вечер! Помог..


Добрый вечер!

Помогите разобраться с трейлингом.
1. Открывается ордер к примеру на покупку и выше с шагом step открывается отложенный ордер Butstop:

//--- ордер на покупку
{
if (RSI_2<55 && RSI_1>55 && BuyCount == 0 && SellCount == 0)
{
OrderSend(Symbol(),OP_BUY,0.02,Ask,3,0,0,"",1,0,CLR_NONE);
}
}

//--- отложенный ордер

if (BuyCount > 0 && BuyStopCount==0)
{
OrderSend(Symbol(),OP_BUYSTOP,0.02,Ask+Step*(1+BuyStopCount)*Point,3,0,0,"",1,0,CLR_NONE);
}

2. Идет трейлинг ордера buy:

for (n=0; n<=total; n++)
{
OrderSelect(OrderTicket(),SELECT_BY_POS,MODE_TRADES);
{
if(OrderTicket()!=0 && OrderType()==OP_BUY && Bid>OrderStopLoss()+SL*Point && BuyCount == 1 && SellCount == 0)

OrderModify(OrderTicket(),OrderOpenPrice(),Bid-SL*Point,0,0,CLR_NONE);

else

if(OrderTicket()!=0 && OrderType()==OP_SELL && Ask<OrderStopLoss()-SL*Point && BuyCount == 0 && SellCount == 1)
{

OrderModify(OrderTicket(),OrderOpenPrice(),Ask+SL*Point,0,0,CLR_NONE);
}
}
}

3. Закрывается половина ордера при выполнении условия

//--- Закрытие половины позиции

for (n=0; n<=total; n++)
{
OrderSelect(OrderTicket(),SELECT_BY_POS,MODE_TRADES);
{
if(OrderTicket()!=0 && OrderType()==OP_BUY && OrderLots()==0.02 && Bid>OrderOpenPrice() && SellCount==0 && BuyCount==1 && OrderMagicNumber()==1 && RSI_1>70 && RSI_0<70)

OrderClose(OrderTicket(),0.01,Bid,3,CLR_NONE);

else

if(OrderTicket()!=0 && OrderType()==OP_SELL && OrderLots()==0.02 && BuyCount==0 && SellCount==1 && OrderMagicNumber()==1 && RSI_1<30 && RSI_0>30)
{

OrderClose(OrderTicket(),0.01,Ask,3,CLR_NONE);
}
}
}

И далее остающаяся половина открытого ордера на покупку с лотом 0.01 не тралится. Когда убираешь открытый ордер BuyStop, то трейлинг работает.
Как сделать, чтобы трейлинг работал после закрытия половины позиции при открытом отложенном ордере BuyStop?


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





Сообщение: 2512
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 13.06.17 20:33. Заголовок: Ошибки во втором и т..


Ошибки во втором и третьем блоках. Ошибки грубые - неправильное использование функции OrderSelect(). Эта функция выбирает ордер по тикету (первый случай) или по индексу в списке (второй случай). В первом случае ей нужно передать индекс строки в списке рабочих ордеров или истории счета, при этом указав вторым параметром SELECT_BY_POS. Во втором случае ей нужно передать уникальный идентификатор ордера (тикет) и вторым параметром указать SELECT_BY_TICKET.
Здесь же видим, что делается попытка передачи тикета (OrderTicket()) и при этом указывается второй параметр SELECT_BY_POS. Уже явное несоответствие.
Далее обращаю внимание на тот факт, что функция OrderTicket() возвращает тикет выбранного ордера. Таким образом, функция никак не может быть аргументом при вызове функции OrderSelect(), которая выполняет этот выбор.
Исходя из того, что в обоих блоках используется цикл перебора ордеров (предположительно по списку рабочих ордеров), следовало бы строку:

 цитата:
OrderSelect(OrderTicket(),SELECT_BY_POS,MODE_TRADES);


заменить на такие строки:

 цитата:
if (!OrderSelect(n, SELECT_BY_POS))
continue;


Здесь в случае указания индекса строки третий параметр можно не указывать, т. к. он по умолчанию равен MODE_TRADES.

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



Сообщение: 428
Зарегистрирован: 25.08.13
Репутация: 1
ссылка на сообщение  Отправлено: 14.06.17 20:53. Заголовок: Спасибо Игорь!..


Спасибо Игорь!

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



Сообщение: 1
Зарегистрирован: 16.06.17
Репутация: 0
ссылка на сообщение  Отправлено: 16.06.17 19:17. Заголовок: Здравствуйте. Прошу ..


Здравствуйте.
Прошу подсказать как реализовать сравнение депо до открытия начальной сделки с текущим балансом эквити. Сова мартинит после убытка и интересует не разница AccountEquity() и AccounBallance(), а разница AccountEquity() и того первого значения AccountBalance() в самом начале серии "догона"(до входа в рынок с начальным лотом). Понятно, что здесь не обойтись без массивов, потому прошу подсказать направление, а лучше с примерами кода, если не затруднит.

Спасибо

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





Сообщение: 2517
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 19.06.17 17:20. Заголовок: allisbob пишет: Про..


allisbob пишет:

 цитата:
Прошу подсказать как реализовать сравнение депо до открытия начальной сделки с текущим балансом эквити. Сова мартинит после убытка и интересует не разница AccountEquity() и AccounBallance(), а разница AccountEquity() и того первого значения AccountBalance() в самом начале серии "догона"(до входа в рынок с начальным лотом)


На мой взгляд, принципиально неверное решение. Ведь необходимо учитывать, что на одном счете может работать одновременно несколько подобных экспертов. Поэтому текущий баланс или эквити не даст достоверной информации.
Единственно верным решением будет отслеживание экспертом собственных сделок в истории счета или в списке рабочих ордеров, если используется открытие встречных/доливочных ордеров.

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



Сообщение: 2
Зарегистрирован: 16.06.17
Репутация: 0
ссылка на сообщение  Отправлено: 06.07.17 16:53. Заголовок: ... Подскажите, по-в..


... Подскажите, по-возможности, что не так. Вот, в сове хочу добавить умножитель лота при срабатывании 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 а дальше растет... Что предпринять?
Благодарю заранее.

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





Сообщение: 2527
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 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;

if (OrderCloseTime() > dtLastOrderTime)
{
dtLastTime = OrderCloseTime;
nLastTicket = i;
}
}

return nLastTicket;
}



Далее по полученному тикету определяем причину закрытия:

 цитата:

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


ENUM_CLOSE_REASON GetCloseReason(int nTicket)
{
if (!OrderSelect(nTicket, SELECT_BY_TICKET) || OrderCloseTime() == 0)
return CLOSE_REASON_ERROR;

if (OrderType() != OP_BUY && OrderType() != OP_SELL)
return CLOSE_REASON_ERROR;

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

if (OrderStopLoss() - OrderClosePrice() > -DBL_EPSILON)
return CLOSE_REASON_SL;

return CLOSE_REASON_MARKET;
}

// Ордер Sell
if (OrderTakeProfit() - OrderClosePrice() > -DBL_EPSILON)
return CLOSE_REASON_TP;

if (OrderStopLoss() > 0.0 && OrderClosePrice() - OrderStopLoss() > -DBL_EPSILON)
return CLOSE_REASON_SL;

return CLOSE_REASON_MARKET;
}



Пример использования:

 цитата:

static int nOrdersInHistory = 0;
if (nOrdersInHistory != OrdersHistoryTotal())
{
ENUM_CLOSE_REASON eCloseReason = GetCloseReason(GetLastCloseOrderTicket());
if (eCloseReason == CLOSE_REASON_SL)
{
// увеличение объема
}

if (eCloseReason == CLOSE_REASON_TP)
{
// возврат к начальному объему
}
}

nOrdersInHistory = OrdersHistoryTotal();



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



Сообщение: 3
Зарегистрирован: 16.06.17
Репутация: 0
ссылка на сообщение  Отправлено: 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;

if (OrderCloseTime() > dtLastOrderTime)
{
dtLastTime = OrderCloseTime();
nLastTicket = i;
}
}

return nLastTicket;
}




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





Сообщение: 2530
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 30.07.17 15:16. Заголовок: allisbob пишет: что..


allisbob пишет:

 цитата:
что присваивается переменной dtLastOrderTime?


Прошу прощения, опечатка. Это переменная dtLastTime.

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



Сообщение: 1
Зарегистрирован: 20.08.17
Репутация: 0
ссылка на сообщение  Отправлено: 20.08.17 21:18. Заголовок: Скажите, как рассчит..


Скажите, как рассчитать СЛ и ТП по ADX /

double adx(int bar)
{
return(iADX(Symbol(),0,ADX_Period,PRICE_CLOSE,MODE_MAIN,bar));
}

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





Сообщение: 2536
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 21.08.17 10:49. Заголовок: bro пишет: Скажите,..


bro пишет:

 цитата:
Скажите, как рассчитать СЛ и ТП по ADX /


Чтобы привести какой-то код, нужно сначала определиться с тем, каким именно образом хочется рассчитывать SL и TP. То есть для начала метод нужно придумать и описать. Тогда и до кода можно дойти. Пока же Вы привели только код, который получает значение главной линии ADX.

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



Сообщение: 2
Зарегистрирован: 20.08.17
Репутация: 0
ссылка на сообщение  Отправлено: 21.08.17 11:27. Заголовок: Scriptong пишет: ..


Scriptong пишет:
[quote]`
Допустим главная линия ADX показывает 47.7708
Берем 47, для пятизнака будет 470 пунктов.

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





Сообщение: 2537
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 21.08.17 15:56. Заголовок: bro пишет: Допустим..


bro пишет:

 цитата:
Допустим главная линия ADX показывает 47.7708
Берем 47, для пятизнака будет 470 пунктов.



Ну тогда так. В настроечных параметрах:

 цитата:
input uint i_uKoef = 10; // Коэффициент умножения пунктов

enum ENUM_TRADE_SIGNAL
{
TRADE_SIGNAL_NONE, // Нет торгового сигнала
TRADE_SIGNAL_BUY, // Торговый сигнал Buy
TRADE_SIGNAL_SELL // Торговый сигнал Sell
};



В функции расчета торгового сигнала:

 цитата:
ENUM_TRADE_SIGNAL GetTradeSignal()
{

if (<условия для открытия Buy>)
return TRADE_SIGNAL_BUY;
if (<условия для открытия Sell>)
return TRADE_SIGNAL_SELL;

return TRADE_SIGNAL_NONE;
}



При открытии ордера:

 цитата:

ENUM_TRADE_SIGNAL eSignal = GetTradeSignal();
if (eSignal == TRADE_SIGNAL_NONE)
return;

double fADXValue = MothRound(iADX(Symbol(),0,ADX_Period,PRICE_CLOSE,MODE_MAIN,bar));
if (eSignal == TRADE_SIGNAL_BUY)
OrderSend(Symbol(), OP_BUY, fLots, uSlippage, Ask, Ask - fADXValue * i_uKoef, Ask + fADXValue * i_uKoef);
if (eSignal == TRADE_SIGNAL_SELL)
OrderSend(Symbol(), OP_SELL, fLots, uSlippage, Bid, Bid + fADXValue * i_uKoef, Bid - fADXValue * i_uKoef);



Это грубо, конечно. Ведь перед открытием ордера нужно произвести огромное количество проверок.

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



Сообщение: 3
Зарегистрирован: 20.08.17
Репутация: 0
ссылка на сообщение  Отправлено: 23.08.17 17:00. Заголовок: Здравствуйте. Интере..


Здравствуйте. Интересует вопрос: можно ли на нулевом баре гарантированно открывать ордера. Допустим если уже есть Бай, то при состоянии "индикатор ниже уровня" гарантированно откроется противоположный ордер. Если так можно сделать то почему в этом коде не получается ?

if(NewBar()==true)
{
cluch_buy=false;
cluch_sell=false;
}
//double ma=iMA(NULL,0,Ma_Period,0,MODE_SMMA,PRICE_MEDIAN,0);
//double ma1=iMA(NULL,0,Ma_Period,0,MODE_SMMA,PRICE_MEDIAN,1);
double rsi1=iRSI(Symbol(),0,RSI1,PRICE_CLOSE,0);
double rsi2=iRSI(Symbol(),0,RSI1,PRICE_CLOSE,1);
//double rsi3=iRSI(Symbol(),0,RSI2,PRICE_CLOSE,0);
//double rsi4=iRSI(Symbol(),0,RSI2,PRICE_CLOSE,1);

if(rsi1>s1 && rsi2<s1)
if(cluch_buy==false)
{
ticket=OrderSend(Symbol(),OP_BUY,Lot,Ask,slipp,0,0,"My order",Magic,0,clrBlue);
if(ticket<0)
{
Print("OrderSend завершилась с ошибкой #",GetLastError());
}
else
Print("Функция OrderSend успешно выполнена");
cluch_buy=true;
cluch_sell=false;
}
if(rsi1<s1 && rsi2>s1)
if(cluch_sell==false)
{
ticket=OrderSend(Symbol(),OP_SELL,Lot,Bid,slipp,0,0,"My order",Magic,0,clrRed);
if(ticket<0)
{
Print("OrderSend завершилась с ошибкой #",GetLastError());
}
else
Print("Функция OrderSend успешно выполнена");
cluch_sell=true;
cluch_buy=false;
}
}

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





Сообщение: 2539
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 23.08.17 18:44. Заголовок: bro пишет: Здравств..


bro пишет:

 цитата:
Здравствуйте. Интересует вопрос: можно ли на нулевом баре гарантированно открывать ордера. Допустим если уже есть Бай, то при состоянии "индикатор ниже уровня" гарантированно откроется противоположный ордер. Если так можно сделать то почему в этом коде не получается ?


Чтобы ответить на этот вопрос, нужно видеть весь код. А здесь лишь кусок кода. В нем по поводу вопроса все нормально. Разве что заметьте, что существует функция NewBar(), которая по содержанию должна срабатывать только один раз на бар. А это влечет за собой отсутствие сброса флага cluch_buy.

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



Сообщение: 4
Зарегистрирован: 20.08.17
Репутация: 0
ссылка на сообщение  Отправлено: 23.08.17 22:22. Заголовок: Scriptong пишет: Чт..


Scriptong пишет:

 цитата:
Чтобы ответить на этот вопрос, нужно видеть весь код. А здесь лишь кусок кода. В нем по поводу вопроса все нормально. Разве что заметьте, что существует функция NewBar(), которая по содержанию должна срабатывать только один раз на бар. А это влечет за собой отсутствие сброса флага cluch_buy.


Да проверка на баре не походит. Код исполняется внутри бара. Что с чем сравнивать для корректной работы приведенной части кода ?

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





Сообщение: 2541
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 29.08.17 12:39. Заголовок: bro пишет: Да прове..


bro пишет:

 цитата:
Да проверка на баре не походит. Код исполняется внутри бара. Что с чем сравнивать для корректной работы приведенной части кода ?


К сожалению, не могу сказать. Нужно видеть всю логику. Иначе буду лишь гадать.

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



Сообщение: 5
Зарегистрирован: 20.08.17
Репутация: 0
ссылка на сообщение  Отправлено: 05.09.17 11:21. Заголовок: Здравствуйте. Как пр..


Здравствуйте. Как прописать в коде, чтобы закрытие, открытие ордера происходило не на новом(0) баре, а на первом ?

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

Можно пример кода ?

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





Сообщение: 2542
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 05.09.17 12:22. Заголовок: bro пишет: Здравств..


bro пишет:

 цитата:
Здравствуйте. Как прописать в коде, чтобы закрытие, открытие ордера происходило не на новом(0) баре, а на первом ?

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


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

 цитата:

// Выбрать ордер (по тикету или по индексу)
...
// ~--------------
if (OrderOpenTime() >= iOpen(NULL, 0, 0))
return; // или continue, если все это в цикле

if (OrderType() == OP_BUY && iOpen(NULL, 0, 1) > iClose(NULL, 0, 1))
{
// закрыть ордер
}
if (OrderType() == OP_SELL && iOpen(NULL, 0, 1) < iClose(NULL, 0, 1))
{
// закрыть ордер
}




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



Сообщение: 6
Зарегистрирован: 20.08.17
Репутация: 0
ссылка на сообщение  Отправлено: 05.09.17 13:38. Заголовок: Scriptong пишет: Ес..


Scriptong пишет:

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


Нет, не на ней, на другой свече.

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





Сообщение: 2543
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 05.09.17 14:52. Заголовок: bro пишет: Нет, не ..


bro пишет:

 цитата:
Нет, не на ней, на другой свече.


Значит, увеличьте индексы во всех функциях iOpen и iClose на столько баров, сколько требуется.

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



Сообщение: 429
Зарегистрирован: 25.08.13
Репутация: 1
ссылка на сообщение  Отправлено: 27.09.18 20:10. Заголовок: Помогите с кодом


Доброго времени, Игорь!

Подобный вопрос наверное раз в сотый Вам задают...

Открывается ордер при выполнении условий... например

{
if (RSI12_2>50 && RSI12_1<50)
{
OrderSend(Symbol(),OP_SELL,1.0,Bid,3,Bid+SL*Point,0,"",1,0,CLR_NONE);
}
}

Это происходит на часовом таймфрейме....
Ордер, к примеру, через 10 минут закрывается по стопу, т.е. внутри часового бара. Сразу открывается новый, потому что условие для открытия ордера выполняется пока не закончится час. Снова закрывается с убытком и снова открывается новый...

Что добавить в код, чтобы открывался в течение бара (часа) только один ордер. Если он закроется с убытком, то новый бы не открывался?
Может функция sleep? Подскажите пожалуйста.

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





Сообщение: 2627
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 28.09.18 17:04. Заголовок: Evgeny пишет: Ордер..


Evgeny пишет:

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

Что добавить в код, чтобы открывался в течение бара (часа) только один ордер. Если он закроется с убытком, то новый бы не открывался?


Если планируется открывать только один ордер на свече, то перед открытием ордера нужно проверить, открывался ли ордер на этой свече.
Для этого необходимо обратиться к истории счета и найти там ордер эксперта, открытый позднее заданного времени:

 цитата:

bool IsOrderOpenedLaterThanSpecifiedTime(datetime dtTime)
{
for (int i = OrdersHistoryTotal() - 1; i >= 0; --i)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
continue;
if (OrderSymbol() != Symbol())
continue;
if (OrderOpenTime() >= dtTime)
return true;
}

return false;
}


Использование:

 цитата:

if (!IsOrderOpenedLaterThanSpecifiedTime(iTime(NULL, 0, 0)))
{
// Можно открывать ордер
}



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



Сообщение: 430
Зарегистрирован: 25.08.13
Репутация: 1
ссылка на сообщение  Отправлено: 29.09.18 09:57. Заголовок: Scriptong пишет: Дл..


Scriptong пишет:

 цитата:
Для этого необходимо обратиться к истории счета и найти там ордер эксперта, открытый позднее заданного времени



Спасибо!

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

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