Обучение языку MQL4 под MetaTrader 4📌

От xbms, 13 апреля, 2013 в Уголок Программиста

#5026

Возможно, если сумма объёмов разных сеток - разная и цена движется в сторону большего объёма. Чем больше разность объёмов, тем ближе ТП. Для одной сетки нужно двигать СЛ, для другой ТП.
Задача не столько сложная, сколько геморройная...



все так, но почему то какие то позиции пропускаются... с чем связано не могу понять...
#5027
Kasatik я не знаю почему пропускаются ордера, но я знаю, что эта строчка:
if ( Bid>GetLastPriceOpen(OP_BUY) && GetLastPriceOpen(OP_BUY)могла быть вынесена из цикла перебора ордеров, ибо все значения известны заранее. Надо выпрямить логику.
Нам известны: уровень БУ - be, дистанция срабатывания трала trstart, отступ СЛ/ТП от цены - trstep
Я бы ещё вычислил:
направление траления, например: trdir = lot(OP_BUY) > lot(OP_SELL) ? -1 : 1;
( BUY ордера тралим снизу от текущей цены (-1), SELL сверху (1) )
последний уровень трала, здесь два этапа - 1. момент включения трала (первая цена), и 2. трал уже включен

double trLastPrice = -1;
double dist = trdir * ( be - Bid ) /_Point; ( если цена не с нужной стороны от БУ, то dist будет // если трал ещё не включен, БУ с нужной стороны и дистанция > trstart
if ( trLastPrice = trstart ) trLastPrice = be; // условия на включение трала

// если трал включен и дистанция >= trstart - двигаем СЛ/ТП всех ордеров
if ( trLastPrice > 0 )
{
// пока делаем для тестера - терминал никогда не выключается!!!
dist = trdir * ( trLastPrice - Bid ) /_Point;
if ( dist >= trstart ) // тут и сделаем цикл по ордерам
{
double newLevel = Bid + trdir * trstep; // для направления трала Бай - будет ниже цены, для Селл наоборот
bool result = true;

for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol()==smb && OrderMagicNumber()==magic && OrderType() {
if(OrderType()==OP_BUY ) result = result && ModifyOrders(OP_BUY, -1, newLevel, 0);
if(OrderType()==OP_SELL ) result = result && ModifyOrders(OP_SELL, -1, 0, newLevel);
}}
}
if ( result ) trLastPrice = newLevel;
}
}
PS: в функции ModifyOrders должна быть встроена проверка на корректность нового уровня SL/TP, чтобы не было возврата false на ровном месте...

Изменено 27 марта, 2018 пользователем 0ll

#5028

Решилось...
ввел дополнительные переменные ot, oop и другие все пошло...


double sl_=0, tp_=0, oop=0, osl=0, otp=0, be=PriceBE(-1);
int err=0, ot=-1, ticket=0;

for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol()==smb && OrderMagicNumber()==magic && OrderType() {
ot = OrderType();
ticket = OrderTicket();
oop = OrderOpenPrice();
osl = OrderStopLoss();
otp = OrderTakeProfit();
if(Bid>GetLastPriceOpen(OP_BUY) && GetLastPriceOpen(OP_BUY) {
if(Bid-be>trstart*pnt)
{
if(ot==OP_BUY && osl {
if(osl==0) sl_ = NDD(be +trstep*pnt);
if(osl>0) sl_ = NDD(osl+trstep*pnt);
if(osl {
bool res=OrderModify(ticket, oop, sl_, 0, 0, clrGreen);
if(!res) {
err=GetLastError();
Print("Ошибка выполнения TrailingStop! Ticket: " + IntegerToString(ticket) + ". Ошибка: " + ErrorDescription(err));
} else {
Print("Установка общего TrailingStop выполнена успешно! № 1, Ticket: " + IntegerToString(ticket));
}
}
}
if(ot==OP_SELL && otp {
if(otp==0) tp_ = NDD(be +trstep*pnt);
if(otp>0) tp_ = NDD(otp+trstep*pnt);
if(otp {
bool res=OrderModify(ticket, oop, 0, tp_, 0, clrGreen);
if(!res) {
err=GetLastError();
Print("Ошибка выполнения TrailingStop! Ticket: " + IntegerToString(ticket) + ". Ошибка: " + ErrorDescription(err));
} else {
Print("Установка общего TrailingStop выполнена успешно! № 1 Ticket: " + IntegerToString(ticket));
}
}
}
}
}//
if(Bid=be)
{
if(be-Bid>trstart*pnt)
{
if(ot==OP_BUY && (otp>Bid+trstart*pnt || otp==0))
{
if(otp==0) tp_ = NDD(be -trstep*pnt);
if(otp>0) tp_ = NDD(otp-trstep*pnt);
if(otp>tp_ || otp==0)
{
bool res=OrderModify(ticket, oop, 0, tp_, 0, clrGreen);
if(!res) {
err=GetLastError();
Print("Ошибка выполнения TrailingStop! Ticket: " + IntegerToString(ticket) + ". Ошибка: " + ErrorDescription(err));
} else {
Print("Установка общего TrailingStop выполнена успешно! № 2, Ticket: " + IntegerToString(ticket));
}
}
}
if(ot==OP_SELL && (osl>Bid+trstart*pnt || osl==0))
{
if(osl==0) sl_ = NDD(be -trstep*pnt);
if(osl>0) sl_ = NDD(osl-trstep*pnt);
if(osl>sl_ || osl==0)
{
bool res=OrderModify(ticket, oop, sl_, 0, 0, clrGreen);
if(!res) {
err=GetLastError();
Print("Ошибка выполнения TrailingStop! Ticket: " + IntegerToString(ticket) + ". Ошибка: " + ErrorDescription(err));
} else {
Print("Установка общего TrailingStop выполнена успешно! № 2 Ticket: " + IntegerToString(ticket));
}
}
}
}
}//
}
}
}
}


Добавлено: 27-03-2018 10:05:08

Я бы ещё вычислил:
направление траления, например: trdir = lot(OP_BUY) > lot(OP_SELL) ? -1 : 1;
( BUY ордера тралим снизу от текущей цены (-1), SELL сверху (1) )
последний уровень трала, здесь два этапа - 1. момент включения трала (первая цена), и 2. трал уже включен

double trLastPrice = -1;
double dist = trdir * ( be - Bid ) /_Point; ( если цена не с нужной стороны от БУ, то dist будет // если трал ещё не включен, БУ с нужной стороны и дистанция > trstart
if ( trLastPrice = trstart ) trLastPrice = be; // условия на включение трала

// если трал включен и дистанция >= trstart - двигаем СЛ/ТП всех ордеров
if ( trLastPrice > 0 )
{
// пока делаем для тестера - терминал никогда не выключается!!!
dist = trdir * ( trLastPrice - Bid ) /_Point;
if ( dist >= trstart ) // тут и сделаем цикл по ордерам
{
double newLevel = Bid + trdir * trstep; // для направления трала Бай - будет ниже цены, для Селл наоборот
bool result = true;

for(int i=OrdersTotal()-1; i>=0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol()==smb && OrderMagicNumber()==magic && OrderType() {
if(OrderType()==OP_BUY ) result = result && ModifyOrders(OP_BUY, -1, newLevel, 0);
if(OrderType()==OP_SELL ) result = result && ModifyOrders(OP_SELL, -1, 0, newLevel);
}}
}
if ( result ) trLastPrice = newLevel;
}
}





Да спасибо.. учту..

Добавлено: 27-03-2018 11:49:55

Проблема решилась, но это я методом тыка (где то натыкался на такое решение и запомнил, не поняв смысла)..
Может ли кто прояснить, если не затруднит, почему именно это помогло ^:)^

Изменено 27 марта, 2018 пользователем Kasatik

#5029

Может ли кто прояснить, если не затруднит, почему именно это помогло

Логика-то поменялась, даже переменная trstep стала использоваться по другому
Было:
sl = NDD(Bid-trstep*pnt);
if(OrderStopLoss()Стало:
if(osl==0) sl_ = NDD(be +trstep*pnt);
if(osl>0) sl_ = NDD(osl+trstep*pnt);
if(osl
#5030

Логика-то поменялась, даже переменная trstep стала использоваться по другому
Было:
sl = NDD(Bid-trstep*pnt);
if(OrderStopLoss()Стало:
if(osl==0) sl_ = NDD(be +trstep*pnt);
if(osl>0) sl_ = NDD(osl+trstep*pnt);
if(osl



дело в том что сначала появился этот второй алгоритм, который также выдавал ошибку...
а после введения новых переменных oop, otp и тд.. все заработало))))))))
#5031

Вам не нужен счётчик, ибо всегда в истории сделок будут и бай и селл.
Вам нужно условие пересечения МА, а не просто нахождение цены за МА.
Пробуйте вместо части условия: maprice >= Bid , писать ( Open[0] > maprice && Close[0]



да в истории всегда будет бай и селл. но вот как бы задать так, что если последний был селл то... не открывать снова селл (пока там не будет - не появиться бай).
эти вар: "вместо >= Bid , писать ( Open[0] > maprice && Close[0] может через создания массива истор орд попробовать и цикл while ?

Изменено 27 марта, 2018 пользователем Ar4i

#5032

вот как бы задать так, что если последний был селл то... не открывать снова селл

Это просто:
делайте переменную-семафор: int last_type = -1;
в условие открытия ордера, например Бай, добавьте:
if ( CountBay() == 0 && Ask && last_type != OP_BUY )
после открытия ордера, там где идёт модификация - last_type = OP_BUY;
для Селл аналогично и будет работать строго по очереди!
#5033

да спасибо, это то что я хотел. но с флагами дело еще не имел. может подскажите что, куда ставить. и почему вы предлагаете инициализировать last_type сразу как -1(наверное для формальности)?

там где идёт модификация - last_type = OP_BUY


вот если так:

int last_type = -1;

if ( CountBay() == 0 && Ask && last_type != OP_BUY )
{
ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask , Slippadge,0,0,"РОБОТ", Magic, Blue);
if (ticket > 0)
{
SL = NormalizeDouble(Ask - StopLotss *Point, Digits);
TP = NormalizeDouble(Ask + TakeProfit *Point, Digits);

if(OrderSelect(ticket, SELECT_BY_TICKET))
if(OrderModify(ticket, OrderOpenPrice(), SL, TP, 0)== true)
Print ("ошибка модиф бая");
last_type = OP_SELL; // по идеи здесь. но так он не дает эффекта. пробовал OrderSelect(ticket, SELECT_BY_POS) - тоже нет

// if (OrderSelect(ticket, SELECT_BY_POS, MODE_HISTORY)) так тоже нет
// last_type = OP_SELL;



} else Print( "ошибка открытия ордера на бай" + " error ", GetLastError());

}

то куда именно надо вставить, last_type = OP_BUY ? и это все? буду благодарен если покажите.

Изменено 28 марта, 2018 пользователем Ar4i

#5034
Ar4i
1. Объявлять флаг только на глобальном уровне советника, т.е.:
int last_type = -1; // можете присвоить любое значение кроме 0 и 1, например = 99999;
void OnTick() ....
2. Задавать значение здесь:
ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask , Slippadge,0,0,"РОБОТ", Magic, Blue);
if (ticket > 0)
{
last_type = OP_BUY; // если открываете ордер Бай, то и флаг = OP_BUY - ибо это и есть последний тип.
#5035

спасибо, получилось :). ну прикольно, так легко оказалось, что смешанные чувства :-o. какое только значение имел вынос last_type на на глобальный уровень? что из того поменялось для машины? ведь с точки зрения видимости переменных (из мох знаний) - это было одинаково.

#5036

с точки зрения видимости переменных (из мох знаний) - это было одинаково

Это очень сильно не одинаково. Вам следует почитать справку mql.
#5037

Всем хорошего настроения! Подскажите, требуются ли специальные дополнения в код совы, чтобы сова одновременно торговал на разных валютных парах, помимо смены магика и параметров совы для каждой пары? Взять тех же черепах с форума или какой-нибудь ишимоку?

#5038

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

#5039

Получается как делают большие и опытные дяди трейдеры просто берут пакет надежных сов с месячным приростом процентов 5 (или просто одну сову затачивают под несколько валютных пар), дописывают что надо и конечный результат получается: кол-во сов*5%= ямиллионер?

Изменено 1 апреля, 2018 пользователем Serhoo

#5040

просто берут пакет надежных сов

:)) Спасибо, ещё раз порадовал.
Почему сова даёт только 5%, ведь можно увеличить нагрузку на депо и будет 10% (например)? Ответ - нагружать депо опасно, значит "надёжная" сова даёт 5% при риске не менее 30%, 70% оставляют для запаса прочности.
Теперь представь: возникает ситуация на рынке и сова уходит в просадку на 50%, которой в тестере не видел - Ваши действия? - 1. закрыть убыток и начать заново, 2. продолжить торговлю до полного слива.
Что выберете? и это на одной паре! а если их больше?
Тут можно книгу писать, одно ясно - "просто" не получится...
#5041

Думал где лучше спросить, решил что тут, если неправ, модераторы скажите где написать?
Суть вопроса: Какие коды ошибок сервера необходимо отрабатывать в советнике, и необходимо ли вообще?
Есть совята, которые работают, уже достаточно длительное время. Проблем не было, но мозг терзает смутная мысль, что если?......
Например как это делает Игорь Ким в своей библиотеке:

Спойлер

//+----------------------------------------------------------------------------+
//| Автор : Ким Игорь В. aka KimIV, |
//+----------------------------------------------------------------------------+
//| Версия : 02.08.2008 |
//| Описание : Установка ордера. |
//+----------------------------------------------------------------------------+
//| Параметры: |
//| sy - наименование инструмента (NULL или "" - текущий символ) |
//| op - операция |
//| ll - лот |
//| pp - цена |
//| sl - уровень стоп |
//| tp - уровень тейк |
//| mn - Magic Number |
//| co - комментарий |
//| ex - Срок истечения |
//+----------------------------------------------------------------------------+
void SetOrder(string sy, int op, double ll, double pp,
double sl=0, double tp=0, int mn=0, string co="", datetime ex=0) {
color cl=IIFc(op==OP_BUYLIMIT || op==OP_BUYSTOP, clOpenBuy, clOpenSell);
datetime ot;
double pa, pb, mp;
int err, it, ticket, msl;

if (sy=="" || sy=="0") sy=Symbol();
msl=MarketInfo(sy, MODE_STOPLEVEL);
if (co=="") co=WindowExpertName()+" "+GetNameTF(Period());
if (ex>0 && ex for (it=1; it if (!IsTesting() && (!IsExpertEnabled() || IsStopped())) {
Print("SetOrder(): Остановка работы функции");
break;
}
while (!IsTradeAllowed()) Sleep(5000);
RefreshRates();
ot=TimeCurrent();
ticket=OrderSend(sy, op, ll, pp, Slippage, sl, tp, co, mn, ex, cl);
if (ticket>0) {
if (UseSound) PlaySound(SoundSuccess); break;
} else {
err=GetLastError();
if (err==128 || err==142 || err==143) {
Sleep(1000*66);
if (ExistOrders(sy, op, mn, ot)) {
if (UseSound) PlaySound(SoundSuccess); break;
}
Print("Error(",err,") set order: ",ErrorDescription(err),", try ",it);
continue;
}
if (UseSound) PlaySound(SoundError);
mp=MarketInfo(sy, MODE_POINT);
pa=MarketInfo(sy, MODE_ASK);
pb=MarketInfo(sy, MODE_BID);
if (pa==0 && pb==0) Message("SetOrder(): Проверьте в обзоре рынка наличие символа "+sy);
Print("Error(",err,") set order: ",ErrorDescription(err),", try ",it);
Print("Ask=",pa," Bid=",pb," sy=",sy," ll=",ll," op=",GetNameOP(op),
" pp=",pp," sl=",sl," tp=",tp," mn=",mn);
// Неправильные стопы
if (err==130) {
// Корректировка ценовых уровней
if (modeSetOrders==1) {
Sleep(1000*5.3);
switch (op) {
case OP_BUYLIMIT:
if (pp>pa-msl*mp) pp=pa-msl*mp;
if (sl>pp-(msl+1)*mp) sl=pp-(msl+1)*mp;
if (tp>0 && tp break;
case OP_BUYSTOP:
if (pp if (sl>pp-(msl+1)*mp) sl=pp-(msl+1)*mp;
if (tp>0 && tp break;
case OP_SELLLIMIT:
if (pp if (sl>0 && sl if (tp>pp-(msl+1)*mp) tp=pp-(msl+1)*mp;
break;
case OP_SELLSTOP:
if (pp>pb-msl*mp) pp=pb-msl*mp;
if (sl>0 && sl if (tp>pp-(msl+1)*mp) tp=pp-(msl+1)*mp;
break;
}
Print("SetOrder(): Скорректированы ценовые уровни");
continue;
}
// Вход по текущим ценам
if (modeSetOrders==2) {
Print("SetOrder(): Вход по текущим ценам");
if (op==OP_BUYLIMIT || op==OP_BUYSTOP) OpenPosition(sy, OP_BUY, ll, sl, tp, mn, co);
if (op==OP_SELLLIMIT || op==OP_SELLSTOP) OpenPosition(sy, OP_SELL, ll, sl, tp, mn, co);
break;
}
}
// Блокировка работы советника
if (err==2 || err==64 || err==65 || err==133) {
gbDisabled=True; break;
}
// Длительная пауза
if (err==4 || err==131 || err==132) {
Sleep(1000*300); break;
}
// Слишком частые запросы (8) или слишком много запросов (141)
if (err==8 || err==141) Sleep(1000*100);
if (err==139 || err==140 || err==148) break;
// Ожидание освобождения подсистемы торговли
if (err==146) while (IsTradeContextBusy()) Sleep(1000*11);
// Обнуление даты истечения
if (err==147) {
ex=0; continue;
}
if (err!=135 && err!=138) Sleep(1000*7.7);
}
}
}
//+----------------------------------------------------------------------------+


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

Вот я лошара, под спойлер не убрал :)) Спасибо.

Изменено 2 апреля, 2018 пользователем djnet

#5042
djnet конечно ошибки надо обрабатывать. Брокеры часто банят за спам рабочего сервера.
Ошибки СЛ, ТП и цены ордера, достаточность маржи надо проверять до отправки ордера брокеру.
Я разделил ошибки на 3 вида: 1. пустяк - можно пропустить, 2. повтор запроса через паузу, 3. критичные - стоп торговля.
1. 0, 1, 128, 132, 139, 145, 147, 4108
2. 6 // Нет связи с торговым сервером
4, 137 // Брокер или Торговый сервер занят
8, 141, 146 // Слишком частые или Слишком много запросов, Подсистема торговли занята
129, 135, 138 // Цена изменилась или Неправильная или Новые цены
136 // Нет цен - ждать тика
3. Все остальные.
#5043

Ошибки СЛ, ТП и цены ордера, достаточность маржи надо проверять до отправки ордера брокеру.


Это само собой, за остальные подсказки спасибо, буду реализовывать.
#5044

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

#5045


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


Так можете им назначить одинаковый тейк и все.
#5046

А как закрыть ордера по сигналу, например по пересечению средних ?

#5047
Roman 13 перебирают все открытые ордера в цикле и передают брокеру приказ на закрытие по текущей цене
#5048

Добрый день. Подскажите, есть ли вариант передачи сигнала из МТ4 в другие программы? Например есть недобот для Биномо(написан на Python), и хотелось бы чтобы опционы покупались по показаниям МТ4

#5049
Sacred70 варианты есть, но они предполагают использование АПИ Виндовс. например самое простое: через нажатие комбинаций клавиш или через файл на диске.
#5050

А как закрыть ордера по сигналу, например по пересечению средних ?


из справки по муклю
Спойлер


iMA
Возвращает значение технического индикатора Moving Average.
double iMA(
string symbol, // имя символа
int timeframe, // таймфрейм
int ma_period, // период
int ma_shift, // сдвиг средней
int ma_method, // метод усреднения
int applied_price, // тип цены
int shift // сдвиг
);


Параметры

symbol

[in] Символьное имя инструмента, на данных которого будет вычисляться индикатор. NULL означает текущий символ.

timeframe

[in] Период. Может быть одним из значений перечисления ENUM_TIMEFRAMES. 0 означает период текущего графика.

ma_period

[in] Период усреднения для вычисления индикатора.

ma_shift

[in] Сдвиг индикатора относительно ценового графика.

ma_method

[in] Метод усреднения. Может быть любым из значений перечисления ENUM_MA_METHOD.

applied_price

[in] Используемая цена. Может быть одним из значений перечисления ENUM_APPLIED_PRICE.

shift

[in] Индекс получаемого значения из индикаторного буфера (сдвиг относительно текущего бара на указанное количество периодов назад).


соответственно как бы я сделал:
создаем четыре переменные типа double
назначаем им значение быстрой и медленной машки за предыдущий бар и предпредидущий(например) смотреть пересечение машек будем только по закрытым свечам.
пишем функцию:
Спойлер


int macross()
{
double mafst1, mafst2, maslw1, maslw2;
mafst1= iMA(NULL, timeframe, 21, 0, тип машки, тип цены,1); //предыдущий бар быстрая машка
mafst2= iMA(NULL, timeframe, 21, 0, тип машки, тип цены,2); //предпредидущий быстрая машка
maslw1= iMA(NULL, timeframe, 50, 0, тип машки, тип цены,1); //предыдущий бар медленная машка
maslw2= iMA(NULL, timeframe, 50, 0, тип машки, тип цены,2); //предпредидущий бар медленная машка
// сравниваем значения
if(mafst1>maslw1 && mafst2 {
direction=1;
return (direction); // возвращаем 1
}
if(mafst1maslw2) // второй вариант быстрая машка пересекла медленную сверху тип сигнала "2"
{
direction=2;
return (direction); // возвращаем 2
}
direction=0;
return (direction); // возвращаем 0 если никаких пересечений не было.
}



Теперь имея значения 1 или 2 вы можете их использовать как флаг на закрытия ордеров, ну или в других вариантах.

Изменено 4 апреля, 2018 пользователем djnet

Для публикации сообщений создайте учётную запись или авторизуйтесь

Перейти к списку тем
Форум · 2.0.20260627.0025