Здравствуйте,
Подскажите пожалуйста, где может быть ошибка у меня в коде.
Я пытаюсь открыть позицию, но получаю ошибку 130 — invalid stops.
Вот код:
iTicket = OrderSend(Symbol(), OP_BUY, e_dLotSize, NormalizeDouble(Ask, Digits), 10, 0.0,
NormalizeDouble(dMABidMain + dSpreadCurr * e_dTakeProfitInSpreads, Digits));
if (iTicket > 0)
{
Print(g_strInf, «Opened new BUY positions #», iTicket,
«, Ask=», DoubleToStr(Ask, Digits),
«, Bid=», DoubleToStr(Bid, Digits),
«, OpenPrice=», DoubleToStr(Ask, Digits),
«, TakeProfit=», DoubleToStr(dMABidMain + dSpreadCurr * e_dTakeProfitInSpreads, Digits),
«, LotSize=», e_dLotSize
);
}
else
{
iErrorCode = GetLastError();
dNewStopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
dNewFreezeLevel = MarketInfo(Symbol(), MODE_FREEZELEVEL);
Print(g_strErr, «Failed to open new BUY position»,
«, NewStpLvl=», DoubleToStr(dNewStopLevel, Digits),
«, NewFrzLvl=», DoubleToStr(dNewFreezeLevel, Digits),
«, Ask=», DoubleToStr(Ask, Digits),
«, Bid=», DoubleToStr(Bid, Digits),
«, OpenPrice=», DoubleToStr(Ask, Digits),
«, TakeProfit=», DoubleToStr(dMABidMain + dSpreadCurr * e_dTakeProfitInSpreads, Digits),
«, LotSize=», e_dLotSize,
«, ErrCode=», iErrorCode, «, «, ErrorDescription(iErrorCode)
);
}
Вот логи:
ERR Failed to open new BUY position, NewStpLvl=0.00000, NewFrzLvl=0.00000, Ask=1.26506, Bid=1.26432, OpenPrice=1.26506, TakeProfit=1.26573, LotSize=0.1, ErrCode=130, invalid stops
Видно, что пытаюсь купить по цене Ask. TakeProfit поставлен вроде правильно. И все равно не срабатывает. Может, я где-нибудь Bid/Ask перепутал?
Грешил на StopLevel, но он нулевой. Может нельзя выставлять уровень Take Profit одновременно с открытием позиции?
Как узнать в чем проблема?
Можно предположить, что с момента получения тика цены Bid/Ask изменились, но ведь тогда ошибка должна быть уже другой, верно?
Или нельзя не указывать stop loss (ставить нулевым) при задании take profit?
Спасибо.
Содержание
- Помогите, ошибка 130 при попытке открыть Sell
- OrderSend Error 130 — What to Do?
- Market orders
- MQL4 solution to OrderSend Error 130 with market orders
- Pending orders
- MQL4 solution to OrderSend Error 130 with pending orders
- why do dolls die the power of passivity and the embodied interplay between disability and sex dolls?
- Video Tutorial
- The silent killer
- 1) StopLoss & TakeProfit are prices
- 2) 4-digits vs 5-digits
- 3) ECN brokers
- Conclusion
Помогите, ошибка 130 при попытке открыть Sell
Помогите, советник все время выдает ошибку 130 при попытке открыть Sell. При этом при попытке открыть Buy, выдал ошибку 130 один раз и после ни разу не выдавал, сколько я не присоединял советника к графику. Вот и получается, что все Buy он открывает, а Sell не может. Что это может быть.
while(true) // цикл закрытия ордера
<
if (Total==0 && Opn_B==true) // открытых ордеров нет +
< // критерий на открытие Buy
RefreshRates(); // обновление данных
SL=Bid — StopLoss*Point; // вычисление SL открываемого ордера
Alert(«Попытка открыть Buy. Ожидание ответа..»);
Ticket=OrderSend(Symb,OP_BUY,Lots,Ask,3,SL,Green); //открытие Buy
if (Ticket > 0) // получилось
<
Alert («Открыт ордер Buy «,Ticket);
return; // выход из функции start()
>
if (Fun_Error(GetLastError())==1) // обработка ошибок
continue; // повторная попытка
return; // выход из функции start()
>
if (Total==0 && Opn_S==true) // открытых ордеров нет +
< // критерий на открытие Sell
RefreshRates(); // обновление данных
SL=Ask + StopLoss*Point; // вычисление SL откр.
Alert(«Попытка открыть Sell. Ожидание ответа..»);
Ticket=OrderSend(Symb,OP_SELL,Lots,Bid,3,SL,Green); //открытие Sell
if (Ticket > 0) // получилось
<
Alert («Открыт ордер Sell «,Ticket);
return; // выход из функции start()
>
if (Fun_Error(GetLastError())==1) // обработка ошибок
continue; // повторная попытка
return; // выход из функции start()
>
break; // выход из функции while
>
Константа Значение Описание
ERR_NO_ERROR 0 Нет ошибки
ERR_NO_RESULT 1 Нет ошибки, но результат неизвестен
ERR_COMMON_ERROR 2 Общая ошибка
ERR_INVALID_TRADE_PARAMETERS 3 Неправильные параметры
ERR_SERVER_BUSY 4 Торговый сервер занят
ERR_OLD_VERSION 5 Старая версия клиентского терминала
ERR_NO_CONNECTION 6 Нет связи с торговым сервером
ERR_NOT_ENOUGH_RIGHTS 7 Недостаточно прав
ERR_TOO_FREQUENT_REQUESTS 8 Слишком частые запросы
ERR_MALFUNCTIONAL_TRADE 9 Недопустимая операция нарушающая функционирование сервера
ERR_ACCOUNT_DISABLED 64 Счет заблокирован
ERR_INVALID_ACCOUNT 65 Неправильный номер счета
ERR_TRADE_TIMEOUT 128 Истек срок ожидания совершения сделки
ERR_INVALID_PRICE 129 Неправильная цена
ERR_INVALID_STOPS 130 Неправильные стопы
ERR_INVALID_TRADE_VOLUME 131 Неправильный объем
ERR_MARKET_CLOSED 132 Рынок закрыт
ERR_TRADE_DISABLED 133 Торговля запрещена
ERR_NOT_ENOUGH_MONEY 134 Недостаточно денег для совершения операции
ERR_PRICE_CHANGED 135 Цена изменилась
ERR_OFF_QUOTES 136 Нет цен
ERR_BROKER_BUSY 137 Брокер занят
ERR_REQUOTE 138 Новые цены
ERR_ORDER_LOCKED 139 Ордер заблокирован и уже обрабатывается
ERR_LONG_POSITIONS_ONLY_ALLOWED 140 Разрешена только покупка
ERR_TOO_MANY_REQUESTS 141 Слишком много запросов
ERR_TRADE_MODIFY_DENIED 145 Модификация запрещена, так как ордер слишком близок к рынку
ERR_TRADE_CONTEXT_BUSY 146 Подсистема торговли занята
ERR_TRADE_EXPIRATION_DENIED 147 Использование даты истечения ордера запрещено брокером
ERR_TRADE_TOO_MANY_ORDERS 148 Количество открытых и отложенных ордеров достигло предела, установленного брокером.
< // критерий на открытие Sell
RefreshRates(); // обновление данных
SL=Ask + StopLoss*Point; // вычисление SL откр.
Исправте на: SL=Bid + StopLoss*Point; // вычисление SL откр.
. Что это может быть.
ERR_INVALID_STOPS | 130 | Слишком близкие стопы или неправильно рассчитанные или ненормализованные цены в стопах (или в цене открытия отложенного ордера). Попытку можно повторять только в том случае, если ошибка произошла из-за устаревания цены. Необходимо после задержки от 5 секунд обновить данные при помощи функции RefreshRates и повторить попытку. Если ошибка не исчезает, необходимо прекратить все попытки торговых операций и изменить логику программы. |
P.S. В Вашем варианте это или Слишком близкие стопы или ненормализованные цены в стопах или и то и другое.
См. также
MODE_STOPLEVEL | 14 | Минимально допустимый уровень стоп-лосса/тейк-профита в пунктах |
В команде OrderSend после SL должно стоять значение для TP.
да, что тут скажешь . rtfm
То, что это неправильные стопы, я знаю. Я пробывал и нормализовывать цену, и RefreshRates есть, так на Buy то все нормально, а на Sell — ошибка 130 и все тут, хотя мой SL очень далек от StopLevel
Константа Значение Описание
ERR_NO_ERROR 0 Нет ошибки
ERR_NO_RESULT 1 Нет ошибки, но результат неизвестен
ERR_COMMON_ERROR 2 Общая ошибка
ERR_INVALID_TRADE_PARAMETERS 3 Неправильные параметры
ERR_SERVER_BUSY 4 Торговый сервер занят
ERR_OLD_VERSION 5 Старая версия клиентского терминала
ERR_NO_CONNECTION 6 Нет связи с торговым сервером
ERR_NOT_ENOUGH_RIGHTS 7 Недостаточно прав
ERR_TOO_FREQUENT_REQUESTS 8 Слишком частые запросы
ERR_MALFUNCTIONAL_TRADE 9 Недопустимая операция нарушающая функционирование сервера
ERR_ACCOUNT_DISABLED 64 Счет заблокирован
ERR_INVALID_ACCOUNT 65 Неправильный номер счета
ERR_TRADE_TIMEOUT 128 Истек срок ожидания совершения сделки
ERR_INVALID_PRICE 129 Неправильная цена
ERR_INVALID_STOPS 130 Неправильные стопы
ERR_INVALID_TRADE_VOLUME 131 Неправильный объем
ERR_MARKET_CLOSED 132 Рынок закрыт
ERR_TRADE_DISABLED 133 Торговля запрещена
ERR_NOT_ENOUGH_MONEY 134 Недостаточно денег для совершения операции
ERR_PRICE_CHANGED 135 Цена изменилась
ERR_OFF_QUOTES 136 Нет цен
ERR_BROKER_BUSY 137 Брокер занят
ERR_REQUOTE 138 Новые цены
ERR_ORDER_LOCKED 139 Ордер заблокирован и уже обрабатывается
ERR_LONG_POSITIONS_ONLY_ALLOWED 140 Разрешена только покупка
ERR_TOO_MANY_REQUESTS 141 Слишком много запросов
ERR_TRADE_MODIFY_DENIED 145 Модификация запрещена, так как ордер слишком близок к рынку
ERR_TRADE_CONTEXT_BUSY 146 Подсистема торговли занята
ERR_TRADE_EXPIRATION_DENIED 147 Использование даты истечения ордера запрещено брокером
ERR_TRADE_TOO_MANY_ORDERS 148 Количество открытых и отложенных ордеров достигло предела, установленного брокером.
< // критерий на открытие Sell
RefreshRates(); // обновление данных
SL=Ask + StopLoss*Point; // вычисление SL откр.
Исправте на: SL=Bid + StopLoss*Point; // вычисление SL откр.
Спасибо, помогло. Открывает чудно. Я вроде пробовал так, как вы написали, и у меня ничего не получалось. Но. раз получилось сейчас, значит так пробовал.
Источник
OrderSend Error 130 — What to Do?
The expert advisors that work on one broker can stop working on another; the problem with them often lies in the OrderSend Error 130. If you see Error 130 in the log of the Experts or Journal tabs in your MetaTrader platform when your expert advisor should be opening a position, then that means that the or levels are set too close to the current market price. In the MQL4 documentation, this error is called ERR_INVALID_STOPS (Invalid stops). Some Forex brokers set the minimum distance between the current price and the / levels to prevent scalping or abusing the quote delays. That isn’t a real problem for the majority of expert advisors that aren’t used for scalping. To prevent this error from occurring, you need to change the expert advisor’s code.
First, you might want to know what the minimum stop level is set in your broker’s MetaTrader server. Adding this line of code will output the current minimum stop level for the currency pair of the chart where you run the EA:
One thing you should be wary of is that a stop level value of zero doesn’t mean that your broker doesn’t set any minimum stop distance. It could also mean that the broker uses some external system for dynamic management of their stop level. In this case, it may be variable and undetectable via MQL4.
Market orders
When opening a market order, you won’t be able to set a or level that is closer than MarketInfo(Symbol(), MODE_STOPLEVEL) to the current price.
MQL4 solution to OrderSend Error 130 with market orders
If your EA calculates stops and dynamically, below is the solution to prevent OrderSend Error 130 from occurring.
Declare a global variable for the minimum stop level; e.g.:
In the OnInit() function (or init() in older versions of MT4) of your expert advisor, define the minimum stop level:
Next time your or in points is calculated, just make sure that they aren’t less than StopLevel :
To check with actual stop-loss and take-profit price levels, a difference between them and the current Bid price for Buy orders or a difference between them and the current Ask price for Sell orders should be checked.
For Sell orders:
Don’t forget to refresh the current market rates with a call to the RefreshRates() function before adding the SL/TP distance to the current market rates or before comparing calculated stop-loss and take-profit levels to the current market rates.
Some brokers (ECN ones) don’t allow expert advisors to set or levels on market orders in the OrderSend() function even if it is greater than their MODE_STOPLEVEL value. In this case, you will have to change your EA to send market orders without SL and TP and then use OrderModify() function to set and for the open position. Alternatively, you can also switch the EA to using pending orders only.
Pending orders
For pending orders (stop or limit), MetaTrader 4 offers the following restrictions in regards to stop level:
Buy Limit — the distances between the current Ask and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level.
Sell Limit — the distances between the current Bid and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level.
Buy Stop — the distances between the current Ask and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level. Actually, the conditions are the same conditions as for the Buy Limit order, but the Entry level is located above the current Ask in Buy Stop.
Sell Stop — the distances between the current Bid and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level. Actually, the conditions are the same conditions as for the Sell Limit order, but the Entry level is located below the current Bid in Sell Stop.
MQL4 solution to OrderSend Error 130 with pending orders
Here are examples of MQL4 code checks to make sure your Entry, Stop-Loss, and Take-Profit levels for MT4 pending orders comply with the broker’s stop level restriction.
Источник
why do dolls die the power of passivity and the embodied interplay between disability and sex dolls?
By popular demand, proven strategies on how to beat every algorithmic trader’s worst nightmare – Error 130
The OrderSend Error 130 appears in MetaTrader 4 when an Expert Advisor can’t execute a marker order as expected. Also known as the Invalid Stop (ERR_INVALID_STOPS) in MQL jargon, the Error 130 happens when the TakeProfit and StopLoss levels are set to close to the current market price.
Where does this error come from? What does it mean for your Expert Advisor? How can you find the part of your code that is causing the error? We tackle all this and more…
Video Tutorial
Alright! Let’s go ahead and send some orders with OrderSend. The video below is available if you prefer watching instead of reading
To start off, a formal definition from our friend, MQL4 Documentation:
That’s right! That is all you get from MetaQuotes. And the rest… Go figure!
Ordersend Error 130 is briefly mentioned in other sections of the documentation. However, there is no thorough guide to what “Invalid Stops” actually means and how to deal with this, perhaps, most common problem in Forex programming.
But not a worry! That’s why I have written this article. Let’s get through this together!
The silent killer
So… you launched your expert advisor and… nothing happens. No BUY orders, no SELL orders, no pending orders, not even error messages in the logs…. Just silence. You decide to wait a few hours / days / weeks, and nothing really changes – the charts go up and down, but you don’t see any profit. This can go on forever…
The real reason is simple – you’re actually getting ERR_INVALID_STOPS (which is the correct technical term for the issue), but you can’t see it. That’s because 130 is a silent killer. A cold-blooded murderer of your brain and inner calm 🙂
There is no way to pick up this error through expert advisor logs or even terminal logs. The only way to catch it is by adding the right failsafe mechanisms into your code. Here’s an example you can adapt to your code:
int ticket;
ticket = OrderSend(«EURUSD», OP_BUY, 1.0, Ask, 10, StopLossLevel, TakeProfitLevel, «My 1st Order!»);
if(ticket Invalid stops is the real name for the culprit we are dealing with today. So what does invalid stops in MetaTrader 4 actually mean?
- For a market order (BUY or SELL) invalid stops means that the StopLoss and/or TakeProfit you requested were not possible to set for your order. Therefore, since a request cannot be fulfilled only partially, the order was not executed at all
- For a pending order (BUY STOP, BUY LIMIT, SELL STOP, or SELL LIMIT) invalid stops means that either (1) there were issues with the SL/TP (same as above) OR (2) the issue was with the entry price which you specified for the order itself
As we can see, the issue is always with one (or many) of the prices that your Forex Robot specified in its request to the trade server. Now that we know our enemy – let’s beat it!
1) StopLoss & TakeProfit are prices
There are several possible causes of ERR_INVALID_STOPS, and one of the more frequent ones among beginners is specifying the StopLoss and TakeProfit in pips rather than actual price levels. Like this:
OrderSend(EURUSD, OP_BUY, 0.1, 1.1606, 10, 20, 40);
This person tried to set a StopLoss of 20 pips and a TakeProfit of 40 pips. Big NO-NO….. The correct and only way of specifying your SL and TP is through price levels:
OrderSend(EURUSD, OP_BUY, 0.1, 1.1606, 10, 1.1585, 1.1645);
By the way, here we assumed that the current ASK price is 1.1606 and current BID price is 1.1605 (i.e. 1 pip spread).
2) 4-digits vs 5-digits
Another reason you could be getting ERR_INVALID_STOPS is if you are setting the input parameters of your EA in Pips (4-digit points) when the Robot is anticipating 5-digit points. Let’s look at an example:
extern int StopLoss = 20;
extern int TakeProfit = 40;
OrderSend(EURUSD, OP_BUY, 0.1, Ask, 10, Bid-StopLoss*Point(), Bid+TakeProfit*Point());
This code will work fine on a 4-digit broker, however will fail on a 5-digit broker. The reason is that on a 4-digit broker, Point() equals to 0.0001, whereas on a 5-digit broker Point() equals to 0.00001.
Basically, with no additional adjustments, on a 5-digit broker the EA will be attempting to set the StopLoss and TakeProfit at only 2 and 4 pips away from the Bid price respectively!
That’s why in the case of a 5-digit broker you have to increase your StopLoss and TakeProfit parameters tenfold. Like this:
extern int StopLoss = 200;
extern int TakeProfit = 400;
OrderSend(EURUSD, OP_BUY, 0.1, Ask, 10, Bid-StopLoss*Point(), Bid+TakeProfit*Point());
However, be careful! Some EA’s already have modules that will detect the number of digits after the decimal and will automatically adjust your input parameters for you. In these situations multiplying inputs by 10 can actually lead to erroneous performance.
Note: I plan on posting a separate article where we will discuss how to create our own modules to detect the number of digits after the decimal
3) ECN brokers
ECN accounts have their own specifics. One of them is – when trading through a ECN broker you will not be able to set a StopLoss and/or TakeProfit with your Market Order (BUY or SELL). If you try to do this – you will get Error 130.
However, of course, you do need to set a StopLoss (and maybe TakeProfit) for your order, and this must be done as soon as possible after the order has been executed. Try this code:
int MarketOrderSend(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment, int magic)
<
int ticket;
ticket = OrderSend(symbol, cmd, volume, price, slippage, 0, 0, NULL, magic);
if(ticket void OnTick()
<
//.
OrderSend(EURUSD, OP_BUY, 0.1, ND(Ask), 10, ND(Bid-StopLoss*Point()), ND(Bid+TakeProfit*Point()));
double ND(double val)
<
return(NormalizeDouble(val, Digits));
>
This neat little trick allows you to normalize (in simple terms – Round) any prices that you are inputting into the OrderSend() function. This way you cut off all ‘negligible’ digits after the decimal point.
Conclusion
Today we saw that there may be multiple (at least 5) causes to error 130. Though this is quite a few, the underlying issues are all trivial and can be corrected in a matter of minutes.
Therefore, Error 130 should not be feared! If you have encountered this culprit, it’s just a matter of going through the list above, finding the situation that applies to you and applying the prescribed solution.
Hope you found this article useful!
Let me know if you have any questions by using the comments section below.
Источник
OrderSend ошибка 130
При работе с одним из брокеров советник при вызове OrderSend выдает ошибку 130, с другими брокерами все ок. Пробовал менять стоплоссы и тэйк профиты все равно ошибка сохраняется. В чем может быть причина?
вот мой вызов функции
Еще раз повторюсь увеличение стоп лосов и профитов ни как не влияет на ошибку, она все равно есть
Ордер с нормализованной ценой и нулевым стопом и тейком дает такую ошибку?
кстати, по поводу разных брокеров: при переходе от 4 знакового брокера на 5 знаковый Digits «залипает» и помнит старые 4 знака. в этом случае на 5 значном брокере все отработает. но если первым был 5 значный и с него перешли на 4 знака, то нормализатор будет округлять данные до 5 знаков и если в последнем знаке не ноль — получится 130 🙁
обложите все значения передаваемые в OrderSend отладочной печатью и проверьте что реально передается.
Источник
OrderSend error 130 (tried everything!)
i’m trying to programm an EA that places orders at a certain time of the day and close it at another.
The EA works but i have error messages (OrderSend error 130 which means wrong stopLoss) but i cannot find where the error is. I’ve tried several stopLoss points to see if it came from that, but i couldn’t make the error messages go away.
the weird thing is, apart from these error messages, the code works ok. But i’d rather like the code without errors.
I’m backtesting the code with Alapri UK.
thanks for any help
and here is a typical log:
Could it be that you calc. the buy-price from Bid while for buy you have to use Ask and therefore the order-price is too close or even smaller than Ask?:
ionone : error 130
extern int StopLossPoints = 0 ;
extern int TakeProfitPoints = 0 ;
:
OpenBuy = OrderSend ( Symbol (), OP_BUYSTOP, Lots, p1, 3 , PriceOrPointsValue — StopLossPoints * Point * 2 + spread, PriceOrPointsValue + TakeProfitPoints * Point + spread, «woohoo» , 8675309 , time + 3600 * 1 , Green);
OpenSell = OrderSend ( Symbol (), OP_SELLSTOP, Lots, p2, 3 , PriceOrPointsValue + StopLossPoints * Point — spread, PriceOrPointsValue — TakeProfitPoints * Point — spread, «woohooooo» , 8675309 , time + 3600 * 1 , Green);
- I never got stops with SL/TP to work when I tried it years ago. I think the terminal was comparing the SL to current market not pending price. A) Open the order then set the stops. Or B) Don’t use stops. Humans must because they can’t watch the screen every second, EA’s can. Just wait for market to reach the trigger.
- For a buy you open at the Ask, the SL/TP are relative to the Bid. If P1/PriceOrPointsValue is a Bid price, you must add the spread to the pending price (to get the Ask) and not add it to the SL/TP.
- For a sell you open at the Bid. P2/PriceOrPointsValue must be a Bid price and you must add, not subtract, the spread to make the SL/TP relative to the Ask.
- If the SLP is zero your SL is the pending Ask plus the spread. SL must be below the pending Bid by at least MODE_STOPLEVEL*Point thus error 130
ionone :
HI
i’m trying to programm an EA that places orders at a certain time of the day and close it at another.
The EA works but i have error messages (OrderSend error 130 which means wrong stopLoss) but i cannot find where the error is.
Test for errors and report them and any associated variables . . . track down your error methodically.
wow thanks for your answers!
hmm that’s good (i’m a real noobie so i didn’t noticed that error), i tried that and i’ve got a new error. Now it doesn’t close the buy. here is the log:
i already did that i was printing on the screen the sl values and trying to understand why some values were passing through and others wouldn’t. And i couldn’t find a pattern in these errors.
As i’m buying at a determined time, i suppose i don’t need to use pending orders? i can use OP_BUY instead of OP_BUYSTOP? And when i do that, i end up with a «138» error that i get rid by augmenting the slippage from 3 to 10 (as i’m not scalping it’s okay).
Источник
Error 130
помогите новичку, пожалуйта, ставлю тестировать и на всех тестерах (даже в тех, что находятся в примерах метатрэйдера (MACD Sample) выходит одна и та же ошибка:
2009.04.16 18:47:35 2009.04.09 14:49 MACD Sample EURUSD,H1: Error opening SELL order : 130
2009.04.16 18:47:35 2009.04.09 14:49 MACD Sample EURUSD,H1: OrderSend error 130
2009.04.16 18:47:35 2009.04.09 14:49 MACD Sample EURUSD,H1: Error opening SELL order : 130
2009.04.16 18:47:35 2009.04.09 14:49 MACD Sample EURUSD,H1: OrderSend error 130
2009.04.16 18:47:35 2009.04.09 14:49 MACD Sample EURUSD,H1: Error opening SELL order : 130
2009.04.16 18:47:35 2009.04.09 14:49 MACD Sample EURUSD,H1: OrderSend error 130
TP и TL определены как везде. Видимо проблема в настройках. Как исправить??
ERR_INVALID_STOPS | 130 | Неправильные стопы |
P.S. Наверное, ДЦ не позволяет открывать ордера со стопами. Т.е. сначала надо открыть ордер, а потом выставить стопы.
P.P.S. Как говорит Рош, команда телепатов уже занимается решением вашей проблемы.
1. тест не на валютах или в ДЦ с котированием не инстант
2. Знаки — стоит к примеру стоп в настройках 40п а у валюты 5ть знаков после запятой. Нужно стоп * на 10 и поставить в настройки.
3. Важное и на будущее: вверху справа есть поиск, для новичков куча вопросов уже разжовывалась ( без обид )
Вообще-то, давно пора разработчикам заменить морально устаревший MACD Sample в mt4 на что-ниб. более современное («мавр сделал своё дело, . «).
Например, вставить простой код «адаптера» для 6-знач. нумерации .
Источник
OrderSend Error 130 — What to Do?
The expert advisors that work on one broker can stop working on another; the problem with them often lies in the OrderSend Error 130. If you see Error 130 in the log of the Experts or Journal tabs in your MetaTrader platform when your expert advisor should be opening a position, then that means that the or levels are set too close to the current market price. In the MQL4 documentation, this error is called ERR_INVALID_STOPS (Invalid stops). Some Forex brokers set the minimum distance between the current price and the / levels to prevent scalping or abusing the quote delays. That isn’t a real problem for the majority of expert advisors that aren’t used for scalping. To prevent this error from occurring, you need to change the expert advisor’s code.
First, you might want to know what the minimum stop level is set in your broker’s MetaTrader server. Adding this line of code will output the current minimum stop level for the currency pair of the chart where you run the EA:
One thing you should be wary of is that a stop level value of zero doesn’t mean that your broker doesn’t set any minimum stop distance. It could also mean that the broker uses some external system for dynamic management of their stop level. In this case, it may be variable and undetectable via MQL4.
Market orders
When opening a market order, you won’t be able to set a or level that is closer than MarketInfo(Symbol(), MODE_STOPLEVEL) to the current price.
MQL4 solution to OrderSend Error 130 with market orders
If your EA calculates stops and dynamically, below is the solution to prevent OrderSend Error 130 from occurring.
Declare a global variable for the minimum stop level; e.g.:
In the OnInit() function (or init() in older versions of MT4) of your expert advisor, define the minimum stop level:
Next time your or in points is calculated, just make sure that they aren’t less than StopLevel :
To check with actual stop-loss and take-profit price levels, a difference between them and the current Bid price for Buy orders or a difference between them and the current Ask price for Sell orders should be checked.
For Sell orders:
Don’t forget to refresh the current market rates with a call to the RefreshRates() function before adding the SL/TP distance to the current market rates or before comparing calculated stop-loss and take-profit levels to the current market rates.
Some brokers (ECN ones) don’t allow expert advisors to set or levels on market orders in the OrderSend() function even if it is greater than their MODE_STOPLEVEL value. In this case, you will have to change your EA to send market orders without SL and TP and then use OrderModify() function to set and for the open position. Alternatively, you can also switch the EA to using pending orders only.
Pending orders
For pending orders (stop or limit), MetaTrader 4 offers the following restrictions in regards to stop level:
Buy Limit — the distances between the current Ask and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level.
Sell Limit — the distances between the current Bid and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level.
Buy Stop — the distances between the current Ask and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level. Actually, the conditions are the same conditions as for the Buy Limit order, but the Entry level is located above the current Ask in Buy Stop.
Sell Stop — the distances between the current Bid and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level. Actually, the conditions are the same conditions as for the Sell Limit order, but the Entry level is located below the current Bid in Sell Stop.
MQL4 solution to OrderSend Error 130 with pending orders
Here are examples of MQL4 code checks to make sure your Entry, Stop-Loss, and Take-Profit levels for MT4 pending orders comply with the broker’s stop level restriction.
Источник
Какие проверки должен пройти торговый робот перед публикацией в Маркете
Для чего нужна проверка перед публикацией в Маркете
Все продукты Маркета перед публикацией проходят обязательную предварительную проверку, так как небольшая ошибка в логике советника или индикатора может привести к убыткам на торговом счете. Именно поэтому нами разработана серия базовых проверок, призванных обеспечить необходимый уровень качества продуктов Маркета.
Если в процессе проверки вашего продукта модераторами Маркета будут выявлены ошибки, то вам нужно будет обязательно их исправить. В этой статье мы расскажем о наиболее частых ошибках, которые допускают разработчики в своих торговых роботах и технических индикаторах. Рекомендуем также почитать следующие статьи:
Как быстро выловить и исправить ошибки в торговом роботе
Встроенный в платформу тестер стратегий позволяет не только проверять на истории торговые системы, но также и выявлять логические и алгоритмические ошибки, допущенные при написании торгового робота. Во время тестирования все сообщения о торговых операциях и выявленных ошибках выводятся в Журнал тестера. Эти сообщения для анализа удобно изучать в специальном Просмотрщике логов, который вызывается командой контекстного меню.
Откройте после тестирования советника Просмотрщик и включите режим «Только ошибки», как показано на рисунке. Если в вашем торговом роботе есть ошибки, вы сразу же их увидите. Если же ошибки не были обнаружены с первого раза, проведите серию тестирований со сменой инструментов/таймфреймов/входных параметров и разными значениями начального депозита. 99% ошибок выявляются этими простыми приемами, и о них мы расскажем вам в этой статье.
Для детального изучения выявленной ошибки используйте в MetaEditor Отладку на истории — так в режиме визуального тестирования вы сможете наблюдать не только графики цен и значения используемых индикаторов, но и проследить на каждом тике значения каждой переменной программы. Это позволит вам отладить вашу торговую стратегию без необходимости тратить недели в режиме реального времени.
Нехватка средств для проведения торговой операции
Перед каждой отправкой торгового приказа необходимо проверять достаточность средств на вашем счете. Нехватка средств для обеспечения будущей открытой позиции или ордера считается грубой ошибкой.
Имейте в виду, что даже для выставления отложенного ордера может потребоваться залоговое обеспечение — маржа.
Рекомендуем тестировать своего торгового робота при заведомо малом размере начального депозита, например, 1 USD или 1 Euro.
Если проверка показала, что средств на совершение торговой операции не хватает, необходимо вместо вызова функции OrderSend() выдать в журнал сообщение об ошибке. Примеры проверки:
Неправильные объемы в торговых операциях
Перед отправкой торговых приказов необходимо также проверять корректность объемов, указываемых в ордере. Количество лотов, которое собирается указать в ордере советник, нужно проверять перед тем как вызвать функцию OrderSend(). Для финансовых инструментов в Спецификации указываются минимальный и максимальный разрешенные объемы для торговли, а также градация объема. Получить эти значения в MQL5 можно из перечисления ENUM_SYMBOL_INFO_DOUBLE с помощью функции SymbolInfoDouble()
Минимальный объем для заключения сделки
Максимальный объем для заключения сделки
Минимальный шаг изменения объема для заключения сделки
Пример функции для проверки корректности объема
Ограничение на количество отложенных ордеров
Бывает также ограничение на количество действующих отложенных ордеров, которые одновременно могут быть размещены на данном счете. Пример функции IsNew Order Allowed(), которая проверяет , можно ли выставить еще один отложенный ордер.
Функция простая: в переменную max_allowed_orders получаем разрешенное количество отложенных ордеров, и если это значение не равно нулю — сравниваем с текущим количеством ордеров. Правда, этой функцией не учитывается еще одно возможное ограничение — максимально допустимый совокупный объем открытой позиции и отложенных ордеров по конкретному символу.
Ограничение на количество лотов по одному символу
Для того чтобы получить размер объема открытой позиции по заданному символу, необходимо предварительно выбрать позицию с помощью функции PositionSelect(). И только после этого запросить объем выбранной позиции с помощью функции PositionGetDouble(), которая возвращает различные свойства выбранной позиции, имеющие тип double. Для получения объема позиции по данному символу напишем функцию PositionVolume().
Для счетов с поддержкой хеджинга нужно пройтись по всем позициям на данном инструменте.
Прежде чем сделать торговый запрос на выставление отложенного ордера по символу, необходимо проверить ограничение на совокупный объем для открытый позиций и отложенных ордеров по одному символу — SYMBOL_VOLUME_LIMIT. Если ограничения нет, то объем для отложенного ордера не может превышать установленного максимального объема, который можно получить с помощью функции SymbolInfoDouble().
Но такой подход не учитывает объем в текущих отложенных ордерах по указанному символу. Приведем пример функции, которая вычисляет это значение:
С учетом объема открытой позиции и объема в отложенных ордерах, окончательная проверка будет выглядеть так:
Установка уровней TakeProfit и StopLoss в пределах минимального уровня SYMBOL_TRADE_STOPS_LEVEL
Многие советники торгуют с использованием ордеров TakeProfit и StopLoss, уровни которых вычисляются динамически в момент совершения покупки или продажи. Ордер TakeProfit служит для закрытия позиции при движении цены в благоприятном направлении, в то время как ордер StopLoss используется для ограничения убытков при движении цены в неблагоприятном направлении.
Поэтому уровни TakeProfit и StopLoss необходимо сравнивать с текущей ценой, по которой можно совершить операцию противоположного направления:
- Покупка совершается по цене Ask — уровни TakeProfit и StopLoss нужно сравнивать с текущей ценой продажи Bid.
- Продажа совершается по цене Bid — уровни TakeProfit и StopLoss нужно сравнивать с текущей ценой покупки Ask.
Покупка происходит по цене Ask | Продажа происходит по цене Bid |
---|---|
TakeProfit >= Bid StopLoss = Ask |
Для финансовых инструментов в настройках символа может быть задан параметр SYMBOL_TRADE_STOPS_LEVEL. Он указывает в пунктах минимальный отступ уровней StopLoss и TakeProfit от текущей цены закрытия открываемой позиции. Если значение этого свойства равно нулю, значит, минимальный отступ для SL/TP ордеров при покупки и продаже не задан.
В общем случае, проверка уровней TakeProfit и StopLoss с учетом минимальной дистанции SYMBOL_TRADE_STOPS_LEVEL выглядит так:
- Покупка совершается по цене Ask — уровни TakeProfit и StopLoss должны быть от текущей ценой продажи Bid на расстоянии не менее SYMBOL_TRADE_STOPS_LEVEL пунктов.
- Продажа совершается по цене Bid — уровни TakeProfit и StopLoss должны быть от текущей ценой покупки Ask на расстоянии не менее SYMBOL_TRADE_STOPS_LEVEL пунктов.
Покупка происходит по цене Ask | Продажа происходит по цене Bid |
---|---|
TakeProfit — Bid >= SYMBOL_TRADE_STOPS_LEVEL Bid — StopLoss >= SYMBOL_TRADE_STOPS_LEVEL |
Ask — TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL StopLoss — Ask >= SYMBOL_TRADE_STOPS_LEVEL |
Поэтому можно создать функцию проверки CheckStopLoss_Takeprofit(), которая требует, чтобы расстояние от TakeProfit и StopLoss до цены закрытия было не менее SYMBOL_TRADE_STOPS_LEVEL пунктов:
Сама проверка может выглядеть так:
Пример функции вы найдете в приложенных скриптах Check_TP_and_SL.mq4 и Check_TP_and_SL.mq5. Пример выполнения:
Для моделирования ситуации с неправильными значениями TakeProfit и StopLoss к статье также приложены советники Test_Wrong_TakeProfit_LEVEL.mq5 и Test_Wrong_StopLoss_LEVEL.mq5. Запускать их можно только на демо-счете. Изучите эти примеры, чтобы самостоятельно увидеть, при каких условиях возможно удачное проведение покупки.
Пример выполнения советника Test_Wrong_StopLoss_LEVEL.mq5:
Пример выполнения советника Test_Wrong_TakeProfit_LEVEL.mq5:
Проверка уровней StopLoss и TakeProfit в отложенных ордерах гораздо проще, эти уровни должны откладываться от цены открытия ордера. То есть, проверка уровней с учетом минимальной дистанции SYMBOL_TRADE_STOPS_LEVEL выглядит так: уровни TakeProfit и StopLoss должны быть от цены срабатывания ордера на расстоянии не менее SYMBOL_TRADE_STOPS_LEVEL пунктов.
BuyLimit и BuyStop | SellLimit и SellStop |
---|---|
TakeProfit — Open >= SYMBOL_TRADE_STOPS_LEVEL Open — StopLoss >= SYMBOL_TRADE_STOPS_LEVEL |
Open — TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL StopLoss — Open >= SYMBOL_TRADE_STOPS_LEVEL |
В советнике Test_StopLoss_Level_in_PendingOrders.mq5 делается серия попыток установить ордера BuyStop и BuyLimt до тех пор, пока операция не завершится успешно. С каждой попыткой уровень StopLoss или TakeProfit сдвигается на 1 пункт в правильную сторону. Пример выполнения этого советника:
Примеры проверки уровней TakeProfit и StopLoss в отложенных ордерах находятся в приложенных исходных кодах: Check_TP_and_SL.mq4 и Check_TP_and_SL.mq5.
Попытка модификации ордера или позиции в пределах уровня заморозки SYMBOL_TRADE_FREEZE_LEVEL
В настройках символа может быть задан параметр SYMBOL_TRADE_FREEZE_LEVEL, который показывает в пунктах дистанцию заморозки торговых операций для отложенных ордеров и открытых позиций. Например, если сделка по финансовому инструменту переправляется для процессинга во внешнюю торговую систему, то отложенный ордер BuyLimit может находиться в данный момент слишком близко от текущей цены Ask. И если мы отправим приказ на модификацию этого ордера в тот момент, когда цена открытия достаточно близка к цене Ask, то может получиться так, что ордер уже будет исполнен и модификация будет невозможна.
Поэтому для отложенных ордеров и открытых позиций в настройках символа может указываться дистанция заморозки, в пределах которой их нельзя модифицировать. В общем случае, прежде чем попытаться отправить приказ на модификацию, необходимо сделать проверку с учетом SYMBOL_TRADE_FREEZE_LEVEL :
Тип ордера/позиции | Активация по цене | Проверка |
---|---|---|
Buy Limit ордер | Ask | Ask-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL |
Buy Stop ордер | Ask | OpenPrice-Ask >= SYMBOL_TRADE_FREEZE_LEVEL |
Sell Limit ордер | Bid | OpenPrice-Bid >= SYMBOL_TRADE_FREEZE_LEVEL |
Sell Stop ордер | Bid | Bid-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL |
Buy позиция | Bid | TakeProfit-Bid >= SYMBOL_TRADE_FREEZE_LEVEL Bid-StopLoss >= SYMBOL_TRADE_FREEZE_LEVEL |
Sell позиция | Ask | Ask-TakeProfit >= SYMBOL_TRADE_FREEZE_LEVEL StopLoss-Ask >= SYMBOL_TRADE_FREEZE_LEVEL |
Полные примеры функций для проверки ордеров и позиций на уровень SYMBOL_TRADE_FREEZE_LEVEL вы найдете в приложенных скриптах Check_FreezeLevel.mq5 и Check_FreezeLevel.mq4.
Вы можете самостоятельно смоделировать ситуацию, когда происходит попытка модификации отложенного ордера в пределах уровня заморозки. Для этого откройте демо-счет, на котором есть финансовые инструменты с ненулевым уровнем SYMBOL_TRADE_FREEZE_LEVEL, запустите на графике советник Test_SYMBOL_TRADE_FREEZE_LEVEL.mq5 (Test_SYMBOL_TRADE_FREEZE_LEVEL.mq4) и установите вручную любой отложенный ордер. Советник сам подтянет ордер максимально близко к рынку и начнет делать запрещенные попытки модификации. При этом будет проигрываться звук с помощью функции PlaySound().
Ошибки, возникающие при работе с символами с недостаточной историей котировок
Если советник или индикатор запускается на графике с недостаточной историей, то тут возможны два варианта:
- программа делает проверку на наличие требуемой истории на всю необходимую глубину. Если доступных баров меньше, чем требуется, то программа запрашивает недостающие данные и завершает свою работу до прихода следующего тика. Этот путь самый правильный и помогает избежать множества ошибок — таких, как например, выход за пределы массива или деление на ноль;
- программа не делает никаких проверок и сразу начинает свою работу, как если бы вся необходимая история по всем требуемым символам и таймфреймам была доступна сразу же по первому требованию. Такой подход чреват многими непредсказуемыми ошибками.
Вы можете попробовать самостоятельно смоделировать такую ситуацию. Для этого запустите тестируемый индикатор или советник на графике, затем закройте терминал и удалите всю историю и снова запустите терминал. Если после такого перезапуска ошибки в Журналах не появились, то начните менять символы и таймфреймы на графиках, на которых запущена ваша программа. Многие индикаторы выдают ошибки при запуске на недельных или месячных таймфреймах, для которых количество баров, как правило, ограничено. Также, при резкой смене символа графика, например, с EURUSD на CADJPY, индикатор или советник, запущенный на графике, может налететь на ошибку, вызванную отсутствием требуемой для его расчетов истории.
Выход за пределы массива (array out of range)
При работе с массивами доступ к его элементам осуществляется по номеру индекса, который не может быть отрицательным и должен быть меньше, чем размер массива. Размер массива можно получить с помощью функции ArraySize().
Эта ошибка может возникать при работе с динамическим массивом, когда его размер еще не распределен явно функцией ArrayResize(), либо при использовании такого массива в функциях, которые самостоятельно устанавливают размер переданным им динамическим массивам. Например, функция CopyTicks() пытается записать в массив запрашиваемое количество тиков, но если тиков меньше, чем запрошено, то размер полученного массива будет меньше ожидаемого.
Другой весьма вероятный способ получить эту ошибку — попытка обратиться к данным индикаторного буфера, когда его размер еще не инициализирован. Напомним, индикаторные буферы являются динамическими массивами, и их размеры устанавливаются исполнительной системой терминала только после инициализации графика. Поэтому, например, попытка обратиться к данным такого буфера в функции OnInit() приведет к ошибке «array out of range».
Простой пример индикатора, который выдает эту ошибку, приложен в файле Test_Out_of_range.mq5.
Деление на ноль (zero divide)
Другой критической ошибкой является попытка деления на ноль. В этом случае выполнение программы сразу же останавливается, тестер выводит в Журнал имя функции и номер строки в исходном коде, на которой произошла ошибка.
Как правило, деление на ноль происходит вследствие ситуации, непредвиденной программистом, например, получения какого-либо свойства либо вычисления выражения с «плохими» данными.
Вы можете легко воспроизвести деление на ноль с помощью простого советника TestZeroDivide.mq5, исходный код которого представлен на скриншоте. Другой критической ошибкой является использование некорректного указателя объекта. Для выяснения причины такой ошибки поможет Отладка на истории .
Отправка запроса на модификацию уровней без фактического их изменения
Если по правилам торговой системы требуется модифировать отложенные ордера или открытые позиции, то перед отправкой торгового запроса на проведение транзакции необходимо убедиться, что запрашиваемая операции действительно изменит параметры ордера или позиции. Отправка торгового запроса, который фактически не делает никаких изменений, считается ошибкой. Торговый сервер в ответ на такое действие вернет код ответа TRADE_RETCODE_NO_CHANGES = 10025 ( MQL5) или код ERR_NO_RESULT=1 (MQL4)
Пример проверки для MQL5 приведен в скрипте Check_OrderLevels.mq5:
Пример проверки на языке MQL4 вы найдете в скрипте Check_OrderLevels.mq4:
Рекмендуем также почитать статьи:
Попытка импорта скомпилированных файлов (даже EX4/EX5) и DLL
Программы, распространяемые через Маркет, должны быть гарантированно безопасны для пользователей. Поэтому любые попытки использования DLL или функций из скомпилированных файлов EX4/EX5 считаются ошибкой. Такие продукты не будут опубликованы на Маркете.
Если вашей программе необходимо использовать дополнительные индикаторы, которых нет в поставке, используйте Ресурсы.
Обращение к пользовательским индикаторам через iCustom()
Если для работы вашей программы необходимо обращение к данным пользовательского индикатора, то вам необходимо поместить все нужные индикаторы в Ресурсы. Продукты из Маркета должны быть готовыми к работе в любом неподготовленном окружении, поэтому они должны содержать всё необходимое в своем EX4/EX5 файле. Рекомендуемые по теме статьи:
Передача недопустимого параметра в функцию (ошибки времени выполнения)
Этот тип ошибок встречается редко, для многих из них есть готовые коды, которые призваны помочь найти причину.
Константа | Значение | Описание |
---|---|---|
ERR_INTERNAL_ERROR | 4001 | Неожиданная внутренняя ошибка |
ERR_WRONG_INTERNAL_PARAMETER | 4002 | Ошибочный параметр при внутреннем вызове функции клиентского терминала |
ERR_INVALID_PARAMETER | 4003 | Ошибочный параметр при вызове системной функции |
ERR_NOTIFICATION_WRONG_PARAMETER | 4516 | Неверный параметр для отправки уведомления – в функцию SendNotification() передали пустую строку или NULL |
ERR_BUFFERS_WRONG_INDEX | 4602 | Ошибочный индекс своего индикаторного буфера |
ERR_INDICATOR_WRONG_PARAMETERS | 4808 | Неправильное количество параметров при создании индикатора |
ERR_INDICATOR_PARAMETERS_MISSING | 4809 | Отсутствуют параметры при создании индикатора |
ERR_INDICATOR_CUSTOM_NAME | 4810 | Первым параметром в массиве должно быть имя пользовательского индикатора |
ERR_INDICATOR_PARAMETER_TYPE | 4811 | Неправильный тип параметра в массиве при создании индикатора |
ERR_NO_STRING_DATE | 5030 | В строке нет даты |
ERR_WRONG_STRING_DATE | 5031 | В строке ошибочная дата |
ERR_TOO_MANY_FORMATTERS | 5038 | Форматных спецификаторов больше, чем параметров |
ERR_TOO_MANY_PARAMETERS | 5039 | Параметров больше, чем форматных спецификаторов |
В таблице перечислены далеко не все ошибки, которые могут встретиться во время работы запущенной программы.
Access violation
Такая ошибка возникает при попытке обратиться к памяти, доступ к которой запрещен. В каждом таком случае необходимо обратиться к разработчикам в Сервисдеск через свой Профиль или через страницу Контакты. Детальное описание шагов по воспроизведению ошибки и приложенный исходный код значительно ускорят поиск причины такой ошибки и помогут улучшить компилятор исходного кода.
Потребление ресурсов процессора и памяти
При написании программы важно использовать оптимальные по времени выполнения алгоритмы, так как в противном случае может стать затруднительной или даже невозможной работа других запущенных в терминале программ.
Важно помнить, что на каждый символ в Обзоре рынка для работы терминал выделяет один общий поток, в котором крутятся все индикаторы и графики, открытые по нему.
Это означает, что если у вас открыто 5 графиков по EURUSD на разных таймфреймах, и на этих графиках запущены 15 индикаторов, то все эти графики и индикаторы получают в распоряжение один-единственный поток для вычислений и отображения информации на графиках. Поэтому один запущенный на графике неэффективный, потребляющий много ресурсов индикатор может замедлить работу остальных индикаторов и даже затормозить отрисовку цен на всех остальных графиках этого символа.
Вы может легко проверить время, затрачиваемое вашим алгоритмом с помощью функции GetMicrosecondCount(). Сделав замеры времени между двумя строчками кода, легко получить время исполнения в микросекундах. Для перевода в миллисекунды (ms) это время необходимо разделить на 1000 (в 1 миллисекунде вмещается 1000 микросекунд). Для индикаторов критическим местом по времени исполнения обычно является обработчик OnCalculate(). Как правило, первый расчет индикатора сильно зависит от параметра Макс. баров в окне, укажите в нем значение «Unlimited» и запустите свой индикатор на символе с историей больше 10 лет на таймфрейме M1. Если первый запуск занимает много времени (например, больше 100 ms), то необходимо оптимизировать код.
Вот пример того, как измерить время выполнения обработчика OnCalculate() в индикаторе ROC, идущем в поставке терминала в исходном коде. Вставки выделены желтым фоном:
Используемую память вы можете измерить с помощью функции MQLInfoInteger( MQL_MEMORY_USED ). Ну и, конечно же, используйте Профилировщик кода для поиска самых затратных функций в вашей программе. Рекомендуем также почитать статьи Принципы экономного пересчета индикаторов и Отладка программ на MQL5.
Эксперты работают в собственных потоках, но всё сказанное выше относится и к ним. Необходимо писать оптимальный код в любых типах программ — советниках, индикаторах, библиотеках и скриптах.
Проверок много не бывает
Все приведенные советы по проверке индикаторов и советников рекомендуются не только для публикации продуктов в Маркете, но и в обычной практике, когда вы пишете для себя. В этой статье мы рассмотрели далеко не все ошибки, которые могут встретиться при торговле на реальных счетах. Здесь не рассмотрены правила обработки торговых ошибок, возникающих при пропаже связи с торговым сервером, реквотах, отказах в совершении сделок и многое другое, что может нарушить идеальные правила торговой системы. Для этих случаев каждый разработчик роботов имеет свои готовые рецепты, наработанные опытом.
Новичкам же рекомендуем читать все статьи, посвященные обработке ошибок, а также задавать вопросы на форуме и в комментариях к этой статье. Другие более опытные члены сообщества MQL5.community помогут вам разобраться в непонятных для вас вопросах. Мы надеемся, что собранная в статье информация поможет вам создавать более надежных торговых роботов и в более короткий срок.
Источник
The expert advisors that work on one broker can stop working on another; the problem with them often lies in the OrderSend Error 130. If you see Error 130 in the log of the Experts or Journal tabs in your MetaTrader platform when your expert advisor should be opening a position, then that means that the stop-loss or take-profit levels are set too close to the current market price. In the MQL4 documentation, this error is called ERR_INVALID_STOPS
(Invalid stops). Some Forex brokers set the minimum distance between the current price and the stop-loss/take-profit levels to prevent scalping or abusing the quote delays. That isn’t a real problem for the majority of expert advisors that aren’t used for scalping. To prevent this error from occurring, you need to change the expert advisor’s code.
First, you might want to know what the minimum stop level is set in your broker’s MetaTrader server. Adding this line of code will output the current minimum stop level for the currency pair of the chart where you run the EA:
One thing you should be wary of is that a stop level value of zero doesn’t mean that your broker doesn’t set any minimum stop distance. It could also mean that the broker uses some external system for dynamic management of their stop level. In this case, it may be variable and undetectable via MQL4.
Market orders
When opening a market order, you won’t be able to set a stop-loss or take-profit level that is closer than MarketInfo(Symbol(), MODE_STOPLEVEL)
to the current price.
MQL4 solution to OrderSend Error 130 with market orders
If your EA calculates stops and take-profits dynamically, below is the solution to prevent OrderSend Error 130 from occurring.
Declare a global variable for the minimum stop level; e.g.:
In the OnInit()
function (or init()
in older versions of MT4) of your expert advisor, define the minimum stop level:
Next time your stop-loss or take-profit in points is calculated, just make sure that they aren’t less than StopLevel
:
if (SL < StopLevel) SL = StopLevel; if (TP < StopLevel) TP = StopLevel;
To check with actual stop-loss and take-profit price levels, a difference between them and the current Bid price for Buy orders or a difference between them and the current Ask price for Sell orders should be checked.
For Buy orders:
if (Bid - StopLoss < StopLevel * _Point) StopLoss = Bid - StopLevel * _Point; if (TakeProfit - Bid < StopLevel * _Point) TakeProfit = Bid + StopLevel * _Point;
For Sell orders:
if (StopLoss - Ask < StopLevel * _Point) StopLoss = Ask + StopLevel * _Point; if (Ask - TakeProfit < StopLevel * _Point) TakeProfit = Ask - StopLevel * _Point;
Don’t forget to refresh the current market rates with a call to the RefreshRates()
function before adding the SL/TP distance to the current market rates or before comparing calculated stop-loss and take-profit levels to the current market rates.
Pending orders
For pending orders (stop or limit), MetaTrader 4 offers the following restrictions in regards to stop level:
Buy Limit — the distances between the current Ask and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level.
Sell Limit — the distances between the current Bid and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level.
Buy Stop — the distances between the current Ask and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level. Actually, the conditions are the same conditions as for the Buy Limit order, but the Entry level is located above the current Ask in Buy Stop.
Sell Stop — the distances between the current Bid and the Entry, between the Entry and the Stop-Loss, and between the Entry and Take-Profit should all be greater or equal to the stop level. Actually, the conditions are the same conditions as for the Sell Limit order, but the Entry level is located below the current Bid in Sell Stop.
MQL4 solution to OrderSend Error 130 with pending orders
Here are examples of MQL4 code checks to make sure your Entry, Stop-Loss, and Take-Profit levels for MT4 pending orders comply with the broker’s stop level restriction.
For Buy Limit orders:
if (Ask - Entry < StopLevel * _Point) Entry = Ask - StopLevel * _Point; if (Entry - StopLoss < StopLevel * _Point) StopLoss = Entry - StopLevel * _Point; if (TakeProfit - Entry < StopLevel * _Point) TakeProfit = Entry + StopLevel * _Point;
For Sell Limit orders:
if (Entry - Bid < StopLevel * _Point) Entry = Bid + StopLevel * _Point; if (StopLoss - Entry < StopLevel * _Point) StopLoss = Entry + StopLevel * _Point; if (Entry - TakeProfit < StopLevel * _Point) TakeProfit = Entry - StopLevel * _Point;
For Buy Stop orders:
if (Entry - Ask < StopLevel * _Point) Entry = Ask + StopLevel * _Point; if (Entry - StopLoss < StopLevel * _Point) StopLoss = Entry - StopLevel * _Point; if (TakeProfit - Entry < StopLevel * _Point) TakeProfit = Entry + StopLevel * _Point;
For Sell Stop orders:
if (Bid - Entry < StopLevel * _Point) Entry = Bid - StopLevel * _Point; if (StopLoss - Entry < StopLevel * _Point) StopLoss = Entry + StopLevel * _Point; if (Entry - TakeProfit < StopLevel * _Point) TakeProfit = Entry - StopLevel * _Point;
Summary
This should help in the majority of cases when you see OrderSend Error 130 in your MetaTrader 4 Experts tab.
You discuss your personal struggles with OrderSend Error 130 problem on our forum if you are having trouble solving this issue on your own.
By popular demand, proven strategies on how to beat every algorithmic trader’s worst nightmare – Error 130
The OrderSend Error 130 appears in MetaTrader 4 when an Expert Advisor can’t execute a marker order as expected. Also known as the Invalid Stop (ERR_INVALID_STOPS) in MQL jargon, the Error 130 happens when the TakeProfit and StopLoss levels are set to close to the current market price.
Where does this error come from? What does it mean for your Expert Advisor? How can you find the part of your code that is causing the error? We tackle all this and more…
Video Tutorial
Alright! Let’s go ahead and send some orders with OrderSend. The video below is available if you prefer watching instead of reading
To start off, a formal definition from our friend, MQL4 Documentation:
That’s right! That is all you get from MetaQuotes. And the rest… Go figure!
Ordersend Error 130 is briefly mentioned in other sections of the documentation. However, there is no thorough guide to what “Invalid Stops” actually means and how to deal with this, perhaps, most common problem in Forex programming.
But not a worry! That’s why I have written this article. Let’s get through this together!
The silent killer
So… you launched your expert advisor and… nothing happens. No BUY orders, no SELL orders, no pending orders, not even error messages in the logs…. Just silence. You decide to wait a few hours / days / weeks, and nothing really changes – the charts go up and down, but you don’t see any profit. This can go on forever…
The real reason is simple – you’re actually getting ERR_INVALID_STOPS (which is the correct technical term for the issue), but you can’t see it. That’s because 130 is a silent killer. A cold-blooded murderer of your brain and inner calm 🙂
There is no way to pick up this error through expert advisor logs or even terminal logs. The only way to catch it is by adding the right failsafe mechanisms into your code. Here’s an example you can adapt to your code:
int ticket;
ticket = OrderSend("EURUSD", OP_BUY, 1.0, Ask, 10, StopLossLevel, TakeProfitLevel, "My 1st Order!");
if(ticket < 0)
{
Alert(“OrderSend Error: “, GetLastError());
}
else
{
Alert(“Order Sent Successfully, Ticket # is: ” + string(ticket));
}
What we are doing here is taking the ticket number and that OrderSend() returns and checking if it is less than zero. If yes, then that is a signal from MetaTrader 4 telling us that there was a problem with the request.
The error code is then printed out onto the screen using Alert() and the built-in GetLastError() function. This code will give a pop-up window like in the image up at the top of this article.
Note: you can use Print() instead of Alert() to redirect the message straight to the EA’s log instead of displaying it on the screen.
Core of Ordersend Error 130
Invalid stops is the real name for the culprit we are dealing with today. So what does invalid stops in MetaTrader 4 actually mean?
- For a market order (BUY or SELL) invalid stops means that the StopLoss and/or TakeProfit you requested were not possible to set for your order. Therefore, since a request cannot be fulfilled only partially, the order was not executed at all
- For a pending order (BUY STOP, BUY LIMIT, SELL STOP, or SELL LIMIT) invalid stops means that either (1) there were issues with the SL/TP (same as above) OR (2) the issue was with the entry price which you specified for the order itself
As we can see, the issue is always with one (or many) of the prices that your Forex Robot specified in its request to the trade server. Now that we know our enemy – let’s beat it!
1) StopLoss & TakeProfit are prices
There are several possible causes of ERR_INVALID_STOPS, and one of the more frequent ones among beginners is specifying the StopLoss and TakeProfit in pips rather than actual price levels. Like this:
OrderSend(EURUSD, OP_BUY, 0.1, 1.1606, 10, 20, 40);
This person tried to set a StopLoss of 20 pips and a TakeProfit of 40 pips. Big NO-NO….. The correct and only way of specifying your SL and TP is through price levels:
OrderSend(EURUSD, OP_BUY, 0.1, 1.1606, 10, 1.1585, 1.1645);
By the way, here we assumed that the current ASK price is 1.1606 and current BID price is 1.1605 (i.e. 1 pip spread).
2) 4-digits vs 5-digits
Another reason you could be getting ERR_INVALID_STOPS is if you are setting the input parameters of your EA in Pips (4-digit points) when the Robot is anticipating 5-digit points. Let’s look at an example:
extern int StopLoss = 20;
extern int TakeProfit = 40;
//…
OrderSend(EURUSD, OP_BUY, 0.1, Ask, 10, Bid-StopLoss*Point(), Bid+TakeProfit*Point());
This code will work fine on a 4-digit broker, however will fail on a 5-digit broker. The reason is that on a 4-digit broker, Point() equals to 0.0001, whereas on a 5-digit broker Point() equals to 0.00001.
Basically, with no additional adjustments, on a 5-digit broker the EA will be attempting to set the StopLoss and TakeProfit at only 2 and 4 pips away from the Bid price respectively!
That’s why in the case of a 5-digit broker you have to increase your StopLoss and TakeProfit parameters tenfold. Like this:
extern int StopLoss = 200;
extern int TakeProfit = 400;
//…
OrderSend(EURUSD, OP_BUY, 0.1, Ask, 10, Bid-StopLoss*Point(), Bid+TakeProfit*Point());
However, be careful! Some EA’s already have modules that will detect the number of digits after the decimal and will automatically adjust your input parameters for you. In these situations multiplying inputs by 10 can actually lead to erroneous performance.
Note: I plan on posting a separate article where we will discuss how to create our own modules to detect the number of digits after the decimal
3) ECN brokers
ECN accounts have their own specifics. One of them is – when trading through a ECN broker you will not be able to set a StopLoss and/or TakeProfit with your Market Order (BUY or SELL). If you try to do this – you will get Error 130.
However, of course, you do need to set a StopLoss (and maybe TakeProfit) for your order, and this must be done as soon as possible after the order has been executed. Try this code:
int MarketOrderSend(string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment, int magic)
{
int ticket;
ticket = OrderSend(symbol, cmd, volume, price, slippage, 0, 0, NULL, magic);
if(ticket <= 0) Alert(“OrderSend Error: “, GetLastError());
else
{
bool res = OrderModify(ticket, 0, stoploss, takeprofit, 0);
if(!res) { Alert(“OrderModify Error: “, GetLastError());
Alert(“IMPORTANT: ORDER #”, ticket, ” HAS NO STOPLOSS AND TAKEPROFIT”);}
}
return(ticket);
}
You can add this function to your code (at the very end) and then use it instead of OrderSend() in your main code. This function adds an extra step in the process of sending a Market Order.
First, it send the request to execute a market order stripping out the StopLoss and TakeProfit. Next, it modifies the newly opened market order by adding the desired SL and TP.
There is, of course, a risk that the order will be executed, but the modification will fail. However, in that case the function will promptly notify the trader that the StopLoss and TakeProfit have not been set.
Feel free to modify this function to suit your needs and trading style.
4) Stop-Levels
Stop-Levels are a mechanism for brokers to protect themselves from certain volatility and liquidity related risks. In simple terms, you will not be able to set your StopLoss or TakeProfit OR any pending order closer than a predetermined number of Pips to the current market price.
To find out what the Stop Level is for a specific currency pair you need to press CTRL+U on your keyboard, select the desired currency pair and click the “Properties” button as shown on the illustration below:
In this example the Stop Level for AUDUSD is 3 Pips. This means that you will not be able to set the StopLoss for your order closer than 3 Pips to the price at which the order will be opened.
This also means that any pending order will have to be set at least 3 Pips away from the current market price.
If you Robot tries to break these rules and set a StopLoss / TakeProfit or Pending Order within the Stop Level range, then it will get Error 130 “Invalid Stops”. So just be mindful of the Stop Level of the currency where your EA’s are trading – don’t specify excessively small StopLoss and TakeProfit parameters.
It is also worth noting that more exotic currency pairs can have much more significant Stop Levels. Fore example, for AUDNZD the Stop Level with the same broker as in the above example is 20 Pips. For GBPSEK (British Pound vs Swedish Krone) – it’s 100 Pips.
5) Normalization of doubles
With some brokers you will find that for an unknown reason the Ask and Bid prices are passed onto the trader with additional negligible digits after the decimal. For example:
Instead of 1.1606 the broker would give you 1.160600001
Now this phenomenon has no effect on manual trading, moreover since the MT4 terminal is hardwired to display a certain number of digits after the decimal point (either 4 or 5) – you will not be able to notice any difference at all!
However, these ‘negligible’ digits after the decimal can have a dramatic effect on Expert Advisors causing……… that’s right! Our old friend, OrderSend Error 130!
Here’s a strategy that I personally use to protect my Robots from this issue:
void OnTick()
{
//...
OrderSend(EURUSD, OP_BUY, 0.1, ND(Ask), 10, ND(Bid-StopLoss*Point()), ND(Bid+TakeProfit*Point()));
}
double ND(double val)
{
return(NormalizeDouble(val, Digits));
}
This neat little trick allows you to normalize (in simple terms – Round) any prices that you are inputting into the OrderSend() function. This way you cut off all ‘negligible’ digits after the decimal point.
Conclusion
Today we saw that there may be multiple (at least 5) causes to error 130. Though this is quite a few, the underlying issues are all trivial and can be corrected in a matter of minutes.
Therefore, Error 130 should not be feared! If you have encountered this culprit, it’s just a matter of going through the list above, finding the situation that applies to you and applying the prescribed solution.
Hope you found this article useful!
Let me know if you have any questions by using the comments section below.
Happy trading,
Kirill
P.S: if you liked what you read in this article, here you can find the full course:
What are you waiting for?
START LEARNING FOREX TODAY!
What is MT4 error 130?
The MT4 error 130 is an OrderSend error code of the MetaTrader 4 platform. A trading platform shows this error code when an Expert Advisor fails to execute an order according to expectations. This error is also known as invalid stops.
An OrderSend error can be very crucial for the day traders because their timing of market entry and exits are equally important. Also, such errors may damage your profit factors and heavily affect your risk to reward ratio.
In this article, we will discuss when an MT4 error 130 happens and how to fix this issue ensuring a smoother trading experience.
Why does MT4 error 130 happen?
An MT4 error 130 may occur for the following reasons:
Market orders
While opening a buy or sell order if you set the stop-loss and take profit levels closer to the market price, the MT4 platform will not accept the order. Instead, it will show your the error code 130.
For direct buy orders, if your stop-loss limit is greater than the asking price and the take profit level is lower than the bidding price, the MT4 will still show the OrderSend error code. On the other hand, for market sell orders, an error code 130 appears when the stop-loss level is lower than the bidding price and the take-profit level is higher than the asking price.
Pending orders
An error code130 may also appear during placing a buy limit and buy stop order. It happens when the difference between the asking and the entry price or the difference between the entry and take profit price is less than the stop-loss limit.
For sell limit and sell stop orders, the OrderSend error occurs if the difference between the bidding and entry price or the difference between the entry and take profit price is less than the stop-loss level.
How to fix Invalid Stops errors
Time needed: 3 minutes.
Solutions for MT4 error 130 differ depending on whether you are using an Expert Advisor or not:
- Check with your broker the minimum Stop Loss & Take Profit Limits
If you are not using an Expert Advisor then what you can do best is to follow the rules set by the broker for setting the stop loss and take profit levels. Generally, most brokers don’t allow setting SL and TP less than 10 pips. When you place an order with less than 10 pips of SL or TP, the MT4 automatically denies executing the order. So, check with your broker about the minimum SL and TP limit, and place the order accordingly. If you still face the problem then it might be caused by slippage or high spreads due to the high volatility of the market.
- Buy Stop (with Expert Advisor)
When you are using Expert Advisors and receiving MT4 error 130 for a Buy Stop order, you need to make a few edits to the EA code.
- Sell Stop (with Expert Advisor)
To fix MT4 error 130 on an EA for a Sell Stop order, you need to make the following adjustments:
- Buy Limit (with Expert Advisor)
For an Expert Advisor that returns MT4 error 130 when you are attempting to place a Buy Limit order:
- Sell Limit (with Expert Advisor)
On an Expert Advisor that returns MT4 error 130 when you try to place a Sell Limit order:
The above codes will help you to prevent showing MT4 error code 130 while placing pending orders only. For market orders (direct buy/sell), check with your broker about their requirements, rules, and limits of setting stop-loss and take profit.
Разработка торговых экспертов на языке MQL4 является не такой уж простой задачей. Во-первых – алгоритмизация любой сложной торговой системы уже представляет собой проблему, так как нужно учесть очень много деталей, начиная с особенностей ТС и заканчивая спецификой среды MetaTrader 4. Во-вторых, даже наличие детальнейшего алгоритма не избавляет от сложностей, возникающих при переносе разработанного алгоритма на язык программирования MQL4.
Компилятор оказывает некоторую помощь при написании корректных экспертов. После начала компиляции MetaEditor сообщит обо всех синтаксических ошибках в вашем коде. Но, к сожалению, помимо синтаксических ошибок ваш советник может содержать еще и логические ошибки, которые компилятор выловить не может. Поэтому этим нам придется заняться самим. Как это сделать – в нашем сегодняшнем материале.
MQL4 — Ошибки и как их исправить
Самые распространенные ошибки компиляции
При наличии ошибок в коде программа не может быть скомпилирована. Для полного контроля всех ошибок рекомендуется использовать строгий режим компиляции, который устанавливается директивой:
Этот режим значительно упрощает поиск ошибок. Теперь перейдем к самым распространенным ошибкам при компиляции.
Идентификатор совпадает с зарезервированным словом
Если наименование переменной или функции совпадает с одним из зарезервированных слов:
int char[]; // неправильно int char1[]; // правильно int char() // неправильно { return(0); }
то компилятор выводит сообщения об ошибках:
Для исправления данной ошибки нужно исправить имя переменной или функции. Я рекомендую придерживаться следующей системы для именования:
Все функции должны обозначать действие. То есть это должен быть глагол. Например, OpenLongPosition() или ModifyStopLoss(). Ведь функции всегда именно что-то делают, верно?
Кроме того, функции желательно называть в так называемом CamelCase стиле. А переменные в cebab_case стиле. Это общепринятая практика.
Кстати, об именах переменных. Переменные – это существительные. Например, my_stop_loss, day_of_week, current_month. Не так страшно назвать переменную длинным именем, гораздо страшнее назвать ее непонятно. Что такое dow, индекс Dow Jones? Нет, это, оказывается, день недели. Конечно, сегодня вам и так понятно, что это за переменная. Но когда вы откроете код советника месяц спустя, все будет уже не так явно. А это время, упущенное на расшифровку посланий из прошлого – оно вам надо?
Специальные символы в наименованиях переменных и функций
Идем дальше. Если наименования переменных или функций содержат специальные символы ($, @, точка):
int $var1; // неправильно int @var2; // неправильно int var.3; // неправильно void f@() // неправильно { return; }
то компилятор выводит сообщения об ошибках:
Для исправления данной ошибки снова нужно скорректировать имена переменных или функций, ну или сразу называть их по-человечески. В идеале код нужно писать так, чтобы даже человек, не знающий программирование, просто его прочел и понял, что там вообще происходит.
Ошибки использования оператора switch
Старая версия компилятора позволяла использовать любые значения в выражениях и константах оператора switch:
void start() { double n=3.14; switch(n) { case 3.14: Print("Pi"); break; case 2.7: Print("E"); break; } }
В новом компиляторе выражения и константы оператора switch должны быть целыми числами, поэтому при использовании подобных конструкций возникают ошибки:
Поэтому, когда вы разбираете код классики, такой, как WallStreet, Ilan и прочей нетленки (что очень полезно для саморазвития), можно натолкнуться на эту ошибку. Лечится она очень просто, например, при использовании такой вот строки:
switch(MathMod(day_48, 10))
Вот так можно запросто решить проблему:
switch((int)MathMod(day_48, 10))
Возвращаемые значений функций
Все функции, кроме void, должны возвращать значение объявленного типа. Например:
При строгом режиме компиляции (strict) возникает ошибка:
В режиме компиляции по умолчанию компилятор выводит предупреждение:
Если возвращаемое значение функции не соответствует объявлению:
Тогда при строгом режиме компиляции возникает ошибка:
В режиме компиляции по умолчанию компилятор выводит предупреждение:
Для исправления таких ошибок в код функции всего-навсего нужно добавить оператор возврата return c возвращаемым значением соответствующего типа.
Массивы в аргументах функций
Массивы в аргументах функций передаются только по ссылке. Раньше это было не так, поэтому в старых советниках можно встретить эту ошибку. Вот пример:
double ArrayAverage(double a[]) { return(0); }
Данный код при строгом режиме компиляции (strict) приведет к ошибке:
В режиме компиляции по умолчанию компилятор выводит предупреждение:
Для исправления таких ошибок нужно явно указать передачу массива по ссылке, добавив префикс & перед именем массива:
double ArrayAverage(double &a[]) { return(0); }
Кстати, константные массивы (Time[], Open[], High[], Low[], Close[], Volume[]) не могут быть переданы по ссылке. Например, вызов:
вне зависимости от режима компиляции приводит к ошибке:
Для устранения подобных ошибок нужно скопировать необходимые данные из константного массива:
//--- массив для хранения значений цен открытия double OpenPrices[]; //--- копируем значения цен открытия в массив OpenPrices[] ArrayCopy(OpenPrices,Open,0,0,WHOLE_ARRAY); //--- вызываем функцию ArrayAverage(OpenPrices);
Одна из самых распространенных ошибок – потеря советником индикатора. В таких случаях обычно пользователи эксперта на форумах гневно пишут: «Советник не работает!» или «Ставлю советник на график и ничего не происходит!». Решение этого вопроса на самом деле очень простое. Как всегда, достаточно просто заглянуть на вкладку «Журнал» терминала и обнаружить там запись вроде:
2018.07.08 09:15:44.957 2016.01.04 00:51 cannot open file 'C:Users1AppDataRoamingMetaQuotesTerminal MQL4indicatorsKELTNER_F12.ex4' [2]
Говорит это нам о том, что индикатор в папку положить забыли, или же он назван по-другому. Если индикатор отсутствует, нужно добавить его в папку с индикаторами. Если он есть, стоит проверить его название в коде советника – скорее всего там он называется по-другому.
Предупреждения компилятора
Предупреждения компилятора носят информационный характер и не являются сообщениями об ошибках, однако они указывают на возможные источники ошибок и лучше их скорректировать. Чистый код не должен содержать предупреждений.
Пересечения имен глобальных и локальных переменных
Если на глобальном и локальном уровнях присутствуют переменные с одинаковыми именами:
int i; // глобальная переменная void OnStart() { int i=0,j=0; // локальные переменные for (i=0; i<5; i++) { j+=i; } PrintFormat("i=%d, j=%d",i,j); }
то компилятор выводит предупреждение и укажет номер строки, на которой объявлена глобальная переменная:
Для исправления таких предупреждений нужно скорректировать имена глобальных переменных.
Несоответствие типов
В следующем примере:
#property strict void OnStart() { double a=7; float b=a; int c=b; string str=c; Print(c); }
при строгом режиме компиляции при несоответствии типов компилятор выводит предупреждения:
В данном примере компилятор предупреждает о возможной потере точности при присвоении различных типов данных и неявном преобразовании типа int в string.
Для исправления нужно использовать явное приведение типов:
#property strict void OnStart() { double a=7; float b=(float)a; int c=(int)b; string str=(string)c; Print(c); }
Неиспользуемые переменные
Наличие переменных, которые не используются в коде программы (лишние сущности) не является хорошим тоном.
void OnStart() { int i,j=10,k,l,m,n2=1; for(i=0; i<5; i++) {j+=i;} }
Сообщения о таких переменных выводятся вне зависимости от режима компиляции:
Для исправления нужно просто убрать неиспользуемые переменные из кода программы.
Диагностика ошибок при компиляции
Часто после написания программы возникают проблемы при компиляции, вызванные ошибками в коде. Это могут быть самые различные ошибки, но в любом случае возникает необходимость оперативного обнаружения участка кода, где допущена ошибка.
Нередко у людей уходит немало времени и масса нервов на поиски какой-нибудь лишней скобки. Однако, есть способ быстрого обнаружения ошибок, который основан на использовании комментирования.
Написать достаточно большой код без единой ошибки – очень приятно. Но, к сожалению, так получается не часто. Я не рассматриваю здесь ошибки, которые приводят к неверному исполнению кода. Здесь пойдёт речь об ошибках, из-за которых становится невозможной компиляция.
Весьма распространённые ошибки – вставка лишней скобки в сложном условии, нехватка скобки, не выставление двоеточия, запятой при объявлении переменных, опечатка в названии переменной и так далее. Часто при компиляции можно сразу увидеть, в какой строке допущена подобная ошибка. Но бывают и случаи, когда найти такую ошибку не так просто. Ни компилятор, ни зоркий глаз нам не могут помочь сразу найти ошибку. В таких случаях, как правило, начинающие программисты начинают “обходить” весь код, пытаясь визуально определить ошибку. И снова, и снова, пока выдерживают нервы.
Однако MQL, как и другие языки программирования, предлагает отличный инструмент – комментирование. Используя его, можно отключать какие-то участки кода. Обычно комментирование используют именно для вставки каких-то комментариев, или же отключения неиспользуемых участков кода. Комментирование можно также успешно применять и при поиске ошибок.
Поиск ошибок обычно сводится к определению участка кода, где допущена ошибка, а затем, в этом участке, визуально находится ошибка. Думаю, вряд ли кто-то будет сомневаться в том, что исследовать “на глаз” 5-10 строчек кода проще и быстрей, чем 100-500, а то и несколько тысяч.
При использовании комментирования задача предельно проста. Сначала нужно закомментировать различные участки кода (иногда чуть ли не весь код), тем самым “отключив” его. Затем, по очереди, комментирование снимается с этих участков кода. После очередного снятия комментирования совершается попытка компиляции. Если компиляция прошла успешно – ошибка не в этом участке кода. Затем открывается следующий участок кода и так далее. Когда находится проблемный участок кода, визуально ищется ошибка, затем устраняется. Опять происходит попытка компиляции. Если всё прошло успешно, ошибка устранена.
Важно правильно определять участки кода, которые необходимо комментировать. Если это условие (или иная логическая конструкция), то оно должно комментироваться полностью. Если комментируется участок кода, где объявляются переменные, важно, чтобы не был открыт участок, где происходит обращение к этим переменным. Иначе говоря – комментирование должно применяться по логике программирования. Несоблюдения такого подхода приводит к возникновению новых, вводящих в заблуждение, ошибок при компиляции.
Вот отличный пример ошибки, когда неясно, где ее искать и нас может выручить комментирование кода.
Ошибки времени выполнения
Ошибки, возникающие в процессе исполнения кода программы, принято называть ошибками времени выполнения (runtime errors). Такие ошибки обычно зависят от состояния программы и связаны с некорректными значениями переменных.
Например, если переменная используется в качестве индекса элементов массива, то ее отрицательные значения неизбежно приведут к выходу за пределы массива.
Выход за пределы массива (Array out of range)
Эта ошибка часто возникает в индикаторах при обращении к индикаторным буферам. Функция IndicatorCounted() возвращает количество баров, не изменившихся после последнего вызова индикатора. Значения индикаторов на уже рассчитанных ранее барах не нуждаются в пересчете, поэтому для ускорения расчетов достаточно обрабатывать только несколько последних баров.
Большинство индикаторов, в которых используется данный способ оптимизации вычислений, имеют такой вид:
//+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { //--- иногда для расчета требуется не менее N баров (например, 100) // если на графике нет такого количества баров (например, на таймфрейме MN) if (Bars<100) { return(-1); // прекращаем расчет и выходим досрочно } //--- количество баров, не изменившихся с момента последнего вызова индикатора int counted_bars=IndicatorCounted(); //--- в случае ошибки выходим if (counted_bars<0) { return(-1); } //--- позиция бара, с которого начинается расчет в цикле int limit=Bars-counted_bars; //--- если counted_bars=0, то начальную позицию в цикле нужно уменьшить на 1, if (counted_bars==0) { limit--; // чтобы не выйти за пределы массива при counted_bars==0 //--- в расчетах используется смещение на 10 баров вглубь //--- истории, поэтому добавим это смещение при первом расчете limit-=10; } else { //--- индикатор уже рассчитывался ранее, counted_bars>0 //--- при повторных вызовах увеличим limit на 1, чтобы //--- гарантированно обновлять значения индикатора для последнего бара limit++; } //--- основной цикл расчета for (int i=limit; i>0; i--) { // используются значения баров, уходящих вглубь истории на 5 и 10 Buff1[i]=0.5*(Open[i+5]+Close[i+10]) } }
Часто встречается некорректная обработка случая counted_bars==0 (начальную позицию limit нужно уменьшить на значение, равное 1 + максимальный индекс относительно переменной цикла).
Также следует помнить о том, что в момент исполнения функции start() мы можем обращаться к элементам массивов индикаторных буферов от 0 до Bars()-1. Если есть необходимость работы с массивами, которые не являются индикаторными буферами, то их размер следует увеличить при помощи функции ArrayResize() в соответствии с текущим размером индикаторных буферов. Максимальный индекс элемента для адресации также можно получить вызовом ArraySize() с одним из индикаторных буферов в качестве аргумента.
Деление на ноль (Zero divide)
Ошибка “Zero divide” возникает в случае, если при выполнении операции деления делитель оказывается равен нулю:
void OnStart() { int a=0, b=0,c; c=a/b; Print("c=",c); }
При выполнении данного скрипта во вкладке “Эксперты” возникает сообщение об ошибке и завершении работы программы:
Обычно такая ошибка возникает в случаях, когда значение делителя определяется значениями каких-либо внешних данных. Например, если анализируются параметры торговли, то величина задействованной маржи оказывается равна 0, если нет открытых ордеров. Другой пример: если анализируемые данные считываются из файла, то в случае его отсутствия нельзя гарантировать корректную работу. По этой причине желательно стараться учитывать подобные случаи и корректно их обрабатывать.
Самый простой способ – проверять делитель перед операцией деления и выводить сообщение о некорректном значении параметра:
void OnStart() { int a=0, b=0,c; if (b!=0) { c=a/b; Print(c); } else { Print("Error: b=0"); return; } }
В результате критической ошибки не возникает, но выводится сообщение о некорректном значении параметра и работа завершается:
Использование 0 вместо NULL для текущего символа
В старой версии компилятора допускалось использование 0 (нуля) в качестве аргумента в функциях, требующих указания финансового инструмента.
Например, значение технического индикатора Moving Average для текущего символа можно было запрашивать следующим образом:
AlligatorJawsBuffer[i]=iMA(0,0,13,8,MODE_SMMA,PRICE_MEDIAN,i); // неправильно
В новом компиляторе для указания текущего символа нужно явно указывать NULL:
AlligatorJawsBuffer[i]=iMA(NULL,0,13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно
Кроме того, текущий символ и период графика можно указать при помощи функций Symbol() и Period().
AlligatorJawsBuffer[i]=iMA(Symbol(),Period(),13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно
Еще лучше, если вы будете использовать предопределенные переменные _Symbol и _Period – они обрабатываются быстрее:
AlligatorJawsBuffer[i]=iMA(_Symbol,_Period,13,8,MODE_SMMA,PRICE_MEDIAN,i); // правильно
Строки в формате Unicodе и их использование в DLL
Строки представляют собой последовательность символов Unicode. Следует учитывать этот факт и использовать соответствующие функции Windows. Например, при использовании функций библиотеки wininet.dll вместо InternetOpenA() и InternetOpenUrlA() следует вызывать InternetOpenW() и InternetOpenUrlW(). При передаче строк в DLL следует использовать структуру MqlString:
#pragma pack(push,1) struct MqlString { int size; // 32-битное целое, содержит размер распределенного для строки буфера LPWSTR buffer; // 32-разрядный адрес буфера, содержащего строку int reserved; // 32-битное целое, зарезервировано, не использовать }; #pragma pack(pop,1)
Совместное использование файлов
При открытии файлов необходимо явно указывать флаги FILE_SHARE_WRITE и FILE_SHARE_READ для совместного использования.
В случае их отсутствия, файл будет открыт в монопольном режиме, что не позволит больше никому его открывать, пока он не будет закрыт монополистом.
Например, при работе с оффлайновыми графиками требуется явно указывать флаги совместного доступа:
// 1-st change - add share flags ExtHandle=FileOpenHistory(c_symbol+i_period+".hst", FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ);
Особенность преобразования datetime
Следует иметь ввиду, что преобразование типа datetime в строку зависит от режима компиляции:
datetime date=D'2014.03.05 15:46:58'; string str="mydate="+date; //--- str="mydate=1394034418" - без директивы #property strict //--- str="mydate=2014.03.05 15:46:58" - с директивой #property strict
Например, попытка работы с файлами, имя которых содержит двоеточие, приведет к ошибке.
Обработка ошибок времени выполнения
Так как без использования встроенных пользовательских функций не сможет обойтись ни один торгующий эксперт, то в первую очередь попытаемся упростить себе жизнь при анализе ошибок, возвращаемых этими функциями.
В наборе “из коробки” доступны некоторые библиотеки для упрощения написания советников, в том числе и для работы с ошибками. Хранятся они в папке MQL4/Include:
Нам понадобятся две библиотеки:
- stderror.mqh – содержит константы для номера каждой ошибки;
- stdlib.mqh – содержит несколько вспомогательных функций, в том числе и функцию возврата описания ошибки в виде строки:
string ErrorDescription(int error_code)
Поэтому подключим в наш проект обе эти библиотеки:
#include <stderror.mqh> #include <stdlib.mqh>
Сами описания ошибок находятся в файле MQL4/Library/stdlib.mql4 и они на английском языке. Поэтому, если вы против иностранных языков, всегда можно переписать описания на свой родной.
Еще одна встроенная необходимая нам функция – GetLastError(). Именно она возвращает коды ошибок в виде целого числа (int), который мы потом будем обрабатывать. Сами коды ошибок и их описания на русском можно посмотреть в руководстве по mql4 от MetaQuotes. Оттуда же можно взять информацию для перевода файла stdlib.mql4 на русский.
Теперь, когда мы подключили необходимые библиотеки, рассмотрим результаты работы функций, непосредственно связанных с торговыми операциями, так как игнорирование сбоев в этих функциях может привести к критическим для бота последствиям.
К сожалению, средствами MQL4 нельзя написать обобщенную библиотеку для обработки всех возможных ошибочных ситуаций. В каждом отдельном случае придется обрабатывать ошибки отдельно. Но не все так плохо, – многие ошибки не нужно обрабатывать, их достаточно исключить на этапе разработки и тестирования эксперта, хотя для этого и нужно вовремя узнать об их наличии.
Рассмотрим для примера две типичные для экспертов на MQL4 ошибки:
- Ошибка 130 – ERR_INVALID_STOPS
- Ошибка 146 – ERR_TRADE_CONTEXT_BUSY
Одним из случаев, когда возникает первая ошибка, является попытка эксперта выставить отложенный ордер слишком близко к рынку. Ее наличие может серьезно ухудшить показатели эксперта в некоторых случаях. Например, допустим эксперт, открыв прибыльную позицию, поджимает прибыль каждые 150 пунктов. Если при очередной такой попытке возникнет ошибка 130, а цена безвозвратно вернется к предыдущему уровню стопа, эксперт может лишить вас законной прибыли. Несмотря на возможность таких последствий, данную ошибку можно исключить в корне, доработав код эксперта так, чтобы он учитывал минимальное допустимое расстояние между ценой и стопами.
Вторую ошибку, связанную с занятостью торгового контекста терминала, полностью исключить не получится. При работе нескольких экспертов в одном терминале всегда возможна ситуация, когда один из экспертов попытается открыть позицию, пока другой все еще делает то же самое. Следовательно, такую ошибку всегда нужно обрабатывать.
Таким образом, мы всегда должны быть в курсе, если какая-то из используемых встроенных функций возвращает ошибку во время работы эксперта. Добиться этого можно, используя следующую нехитрую вспомогательную функцию:
void logError(string functionName, string msg, int errorCode = -1) { Print("ERROR: in " + functionName + "()"); Print("ERROR: " + msg ); int err = GetLastError(); if (errorCode != -1) { err = errorCode; } if (err != ERR_NO_ERROR) { Print("ERROR: code=" + err + " - " + ErrorDescription( err )); } }
Использовать ее мы будем следующим образом:
void openLongTrade() { int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask + 5, 5, 0, 0); if (ticket == -1) { logError("openLongTrade", "could not open order"); } }
Конечно, это упрощенный пример. Для написания более грамотных функций открытия, закрытия и модификации ордеров смотрите этот урок.
Первым параметром в функцию logError() передается имя функции, в которой была обнаружена ошибка, в нашем примере – в функции openLongTrade(). Если наш эксперт вызывает функцию OrderSend() в нескольких местах, это позволит нам точно установить, в каком из них произошла ошибка. Вторым параметром передается описание ошибки, чтобы можно было понять, где именно внутри функции openLongTrade() была обнаружена ошибка. Это может быть как краткое описание ошибки, так и более развернутое, с перечислением значений всех параметров, переданных во встроенную функцию.
Я предпочитаю последний вариант, так как при возникновении ошибки можно сразу получить всю необходимую для анализа информацию. Для примера допустим, что до вызова OrderSend() текущая цена успела сильно отклониться от последней известной нам цены. В результате при выполнении этого примера произойдет ошибка и в протоколе работы эксперта появятся следующие строки:
ERROR: in openLongTrade() ERROR: could not open order ERROR: code=138 - requote
То есть сразу будет видно:
- в какой функции произошла ошибка;
- к чему она относится (в данном случае – к попытке открыть позицию);
- какая именно ошибка возникла (код ошибки и ее описание).
Теперь рассмотрим третий, необязательный, параметр функции logError(). Он необходим в тех случаях, когда мы хотим обработать конкретный вид ошибки, а об остальных будем отчитываться в протоколе работы эксперта, как и прежде:
void updateStopLoss(double newStopLoss) { bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), OrderExpiration()); if (!modified) { int errorCode = GetLastError(); if (errorCode != ERR_NO_RESULT ) { logError("updateStopLoss", "failed to modify order", errorCode); } } }
Здесь в функции updateStopLoss() вызывается встроенная функция OrderModify(). Эта функция несколько отличается в плане обработки ошибок от OrderSend(). Если ни один из параметров изменяемого ордера не отличается от его текущих параметров, то функция вернет ошибку ERR_NO_RESULT. Если в нашем эксперте такая ситуация допустима, то мы должны игнорировать конкретно эту ошибку. Для этого мы анализируем значение, возвращаемое GetLastError(). Если произошла ошибка с кодом ERR_NO_RESULT, то мы ничего не выводим в протокол.
Однако если произошла другая ошибка, то необходимо полностью отрапортовать о ней, как мы делали это раньше. Именно для этого мы сохраняем результат функции GetLastError() в промежуточной переменной и передаем его третьим параметром в функцию logError(). Дело в том, что встроенная функция GetLastError() автоматически обнуляет код последней ошибки после своего вызова. Если бы мы не передали код ошибки явно в logError(), то в протоколе была бы отражена ошибка с кодом 0 и описанием “no error”.
Похожие действия необходимо совершать и при обработке других ошибок, например, реквотов. Основная идея заключается в том, чтобы обрабатывать только ошибки, требующие обработки, а остальные передавать в функцию logError(). Тогда мы всегда будем в курсе, если во время работы эксперта произошла непредвиденная ошибка. Проанализировав логи, мы сможем решить, требует ли данная ошибка отдельной обработки или же ее можно исключить, доработав код эксперта. Такой подход часто заметно упрощает жизнь и сокращает время, уходящее на борьбу с ошибками.
Диагностика логических ошибок
Логические ошибки в коде эксперта могут доставить много проблем. Отсутствие возможности пошаговой отладки экспертов делают борьбу с такими ошибками не очень приятным занятием. Основным средством для диагностики этого на данный момент является встроенная функция Print(). С ее помощью можно выполнять распечатку текущих значений важных переменных, а также протоколировать ход работы эксперта прямо в терминале во время тестирования. При отладке эксперта во время тестирования с визуализацией также может помочь встроенная функция Comment(), которая выводит сообщения на график. Как правило, убедившись, что эксперт работает не так, как было задумано, приходится добавлять временные вызовы функции Print() и протоколировать внутреннее состояние эксперта в предполагаемых местах возникновения ошибки.
Однако, для обнаружения сложных ошибочных ситуаций порой приходится добавлять десятки таких вызовов функции Print(), а после обнаружения и устранения проблемы их приходится удалять или комментировать, чтобы не загромождался код эксперта и не замедлялось его тестирование. Ситуация ухудшается, если в коде эксперта функция Print() уже используется для периодического протоколирования различных состояний. Тогда удаление временных вызовов Print() не удается выполнить путем простого поиска фразы ‘Print’ в коде эксперта. Приходится задумываться, чтобы не удалить еще и полезные вызовы этой функции.
Например, при протоколировании ошибок функций OrderSend(), OrderModify() и OrderClose() полезным бывает печатать в протокол текущее значение переменных Bid и Ask. Это несколько облегчает распознавание причин таких ошибок, как ERR_INVALID_STOPS и ERR_OFF_QUOTES.
Чтобы выделить такие диагностические выводы в протокол, я рекомендую использовать такую вспомогательную функцию:
void logInfo(string msg) { Print("INFO: " + msg); }
Это желательно сделать по нескольким причинам. Во-первых, теперь такие вызовы не будут попадаться при поиске ‘Print’ в коде эксперта, ведь искать мы будем logInfo. Во-вторых, у этой функции есть еще одна полезная особенность, о которой мы поговорим чуть позже.
Добавление и удаление временных диагностических вызовов функции Print() отнимает у нас драгоценное время. Поэтому я предлагаю рассмотреть еще один подход, который эффективен при обнаружении логических ошибок в коде и позволяет немного сэкономить наше время. Рассмотрим следующую несложную функцию:
void openLongTrade(double stopLoss) { int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (ticket == -1) { logError("openLongTrade", "could not open order"); } }
В данном случае, так как мы открываем длинную позицию, совершенно очевидно, что при нормальной работе эксперта значение параметра stopLoss никогда не будет больше или равно текущей цене Bid. То есть, при вызове функции openLongTrade() всегда выполняется условие stopLoss < Bid. Так как мы знаем об этом еще на этапе написания рассматриваемой функции, то мы сразу же можем этим воспользоваться следующим образом:
void openLongTrade( double stopLoss ) { assert("openLongTrade", stopLoss < Bid, "stopLoss < Bid"); int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (ticket == -1) { logError("openLongTrade", "could not open order"); } }
То есть мы логируем наше утверждение в коде при помощи новой вспомогательной функции assert(). Сама функция выглядит довольно просто:
void assert(string functionName, bool assertion, string description = "") { if (!assertion) { Print("ASSERT: in " + functionName + "() - " + description); } }
Первым параметром функции является ее имя, в котором проверяется наше условие (по аналогии с функцией logError()). Вторым параметром передается результат проверки этого условия. И третьим параметром передается его описание. В результате, если ожидаемое условие не выполняется, в протокол будет выведена следующая информация:
- название функции, в которой условие было нарушено;
- описание нарушенного условия.
В качестве описания можно передавать, например, само условие, а можно выводить и более подробное описание, содержащее значения контролируемых переменных на момент проверки условия, если это поможет разобраться в причинах ошибки.
Конечно же, рассмотренный пример максимально упрощен. Но, надеюсь, основную идею отражает достаточно хорошо. В процессе наращивания функциональности эксперта мы отдаем себе отчет в том, как он должен работать и какие состояния и входные параметры функций допустимы, а какие нет. Фиксируя это в коде эксперта при помощи функции assert() мы получаем ценную информацию о месте, в котором нарушается логика работы эксперта. Более того, мы частично избавляем себя от необходимости добавлять и удалять временные вызовы функции Print(), так как функция assert() выдает диагностические сообщения в протокол только в момент обнаружения несоответствий в ожидаемых нами условиях.
Еще одним полезным приемом является использование этой функции перед каждой операцией деления. Дело в том, что иногда в результате той или иной логической ошибки иногда происходит деление на ноль. Работа эксперта в этом случае прекращается, а в протоколе появляется одна лишь строка с печальным диагнозом: ‘zero divide’. Узнать, в каком именно месте произошла эта ошибка, если операция деления используется в коде неоднократно, достаточно сложно. Вот здесь и поможет функция assert(). Вставляем соответствующие проверки перед каждой операцией деления:
assert("buildChannel", distance > 0, "distance > 0"); double slope = delta / distance;
И теперь, в случае деления на ноль, достаточно будет лишь взглянуть в логи, чтобы узнать, в каком именно месте произошла ошибка.
Обработка состояний
Во время работы эксперта на вашем счете могут возникнуть некоторые ситуации, которые не являются ошибками – так называемые состояния эксперта. Такие состояния не являются ошибками, но все же их стоит логировать. В этом помогают специальные функции языка mql4.
Функция IsExpertEnabled() возвращает информацию о возможности запуска экспертов. Функция вернет true, если в клиентском терминале разрешен запуск экспертов, иначе возвращает false. В случае возврата false полезно будет известить об этом пользователя с просьбой включить соответствующую настройку. Пример:
void OnStart() { if (!IsExpertEnabled() { //советникам не разрешено торговать Alert("Attention! Please press the "Expert Advisors" button in MT4"); } //рабочий алгоритм советника return; }
Если эксперт использует внешние библиотеки, пригодится функция IsLibrariesAllowed(). Она возвращает true, если эксперт может вызвать библиотечную функцию, иначе возвращает false.
Если библиотека в виде dll файла, пригодится функция IsDllsAllowed(). Также нелишним будет проверить, есть ли вообще возможность торговать при помощи экспертов с помощью функции IsTradeAllowed().
Если вы хотите узнать, является ли счет демонстрационным, или же реальным, можно использовать функцию IsDemo().
Все вышеперечисленные проверки стоит сделать в функции OnInit().
Конечно же, стоит проверять периодически связь с сервером. В этом поможет функция IsConnected().
Следующие три функции помогут определить, в каком режиме находится советник. Если IsOptimisation() возвращает true, проводится оптимизация, если IsTesting(), то тестирование, IsVisualMode() – тестирование в режиме визуализации. Под каждый из этих вариантов в советнике может быть предусмотрена своя логика. Например, для режима визуализации можно что-то выводить на график (и не выводить в других режимах ради экономии ресурсов). В режиме тестирования можно выводить отладочную информацию, в режиме оптимизации максимально облегчить код, чтобы сэкономить время.
И последняя функция – IsTradeContextBusy(). Она вернет true, если поток для выполнения торговых операций занят. Это бывает полезно при совершении экспертом торговых операций. Можно применить функцию Sleep для ожидания некоторого момента и новой попытки.
Еще одна полезная функция – UninitializeReason()
int deinit() { switch(UninitializeReason()) { case REASON_CHARTCLOSE: case REASON_REMOVE: CleanUp(); break; // очистка и освобождение ресурсов. case REASON_RECOMPILE: case REASON_CHARTCHANGE: case REASON_PARAMETERS: case REASON_ACCOUNT: StoreData(); break; // подготовка к рестарту. } //... }
Можно также логировать причину выхода советника.
Коды самых распространенных ошибок и их вероятное решение
№ ошибки | Значение | Проблема | Решение |
4, 146 | Торговый сервер занят | Советник подал слишком много приказов одновременно или не дождавшись ответа от сервера, при выполнении операции – советник пытается отправить новый приказ | Перезагрузка терминала или оптимизация кода советника с помощью функций обработки ошибок |
8, 141 | Слишком частые запросы | Предыдущие причины ошибки, в сильно частом запросе | Аналогичное решение |
129 | Неправильная цена | Цена по которой Вы пытаетесь открыть позицию (BUY или SELL) неправильная | BUY нужно открывать по Ask а закрывать по BID; SELL нужно открывать по BID а закрывать по ASK |
130, 145 | Неправильные стопы | Стоп лосс, тейк профит или уровень открытия отложки или лимитника неверные. Стопы расположены слишком близко к цене. Ваш счет открыт в группе ECN (ЕЦН) или NDD (НДД), что не дает сразу выставлять стопы |
Проверьте значения Ваших стоп лоссов, тейк профитов, уточните минимальный стоп уровень по Вашему инструменту у брокера, при выставлении стопов – соблюдайте уровень минимальной дистанции. В хорошо написанном советнике должны быть функции работы на счетах ECN и NDD – это происходит путем модификации ордера уже после его открытия |
131 | Неправильный объем | Неправильный лот при открытии сделки, или меньше минимального (больше максимального). Разрядность лота тоже может отличаться от разрядности брокера | Проверьте правильность открытия лота, изучите спецификацию контракта и прочтите условия торговли в Вашем ДЦ, проверьте минимальный и максимальный лот в Вашем ДЦ и на Вашем счете |
132 | Рынок закрыт | Рынок закрыт на выходные дни | Пробуйте связаться с рынком после выходных |
133 | Торговля запрещена | В данный момент торговля запрещена | По данной валютной паре запрещено торговать – в конкретный момент времени или вообще. Часто у брокеров есть перерыв в несколько минут в полночь |
134 | Недостаточно денег для совершения операции | Лот, который Вы пытаетесь открыть, слишком большой, на него не хватает маржи | Проверьте уровень свободных средств и рассчитайте средства, которые Вам нужны для открытия лота, следите за уровнем Ваших свободных средств |
135-138 | Цена изменилась | Реквот, слишком быстрый рынок (новости), Брокер или ДЦ не дает Вам поставить позицию по заявленной цене | Не торгуйте в такие моменты, увеличьте уровень проскальзывания, но помните, что это влечет за собой открытие позиций не по заявленной Вами цене. Предусмотрите в советнике функцию обработки ошибок и количество попыток открытия позиций |
147 | Использование даты истечения ордера запрещено брокером | Ваш советник или Вы пытаетесь установить срок истечения отложенного ордера | В советнике, в функции OrderSend в параметре срок истечения поставьте 0 (ноль). Не устанавливайте срок истечения ордера |
148 | Количество открытых и отложенных ордеров достигло предела, установленного брокером | Максимальное количество открытых ордеров и позиций достигло предела, установленного брокером | Удалите или закройте часть позиций. Остановите процесс открытия новых позиций |
4012, 4013 | Остаток от деления на ноль | Вы пытаетесь поделить число на 0 (ноль) | Проверьте код советника на наличие ошибки, или же проверьте все значения из MarketInfo функций на момент возвращения 0, иногда при MarketInfo(Symbol(),MODE_SPREAD) возвращается не спред, а 0 (у брокеров с плавающим спредом) |
4017 | Вызовы DLL не разрешены | В Вашем терминале запрещен вызов DLL | Разрешите вызов DLL через Меню – сервис – Настройки – Советник – Разрешить вызов DLL |
4018, 4019 | Невозможно загрузить библиотеку | Библиотека повреждена или ее вызов завершается с ошибкой, возможно она вообще отсутствует | Проверьте библиотеку DLL |
4020 | Вызовы внешних библиотечных функций не разрешены | В Вашем терминале запрещен вызов функций из внешних экспертов | Разрешите вызов функций через Меню – сервис – Настройки – Советник – Разрешить вызов внешних экспертов |
4103 | Невозможно открыть файл | Данный файл не существует или заблокирован другим процессом | Проверьте наличие указанного файла. Проверьте, не заблокирован ли файл системой антивируса, разрешен ли режим записи-чтения файла |
4106 | Неизвестный символ | Символа нет в обзоре рынка | В обзоре рынка – правой кнопкой мыши – показать все символы. Проверить названия символа в советнике и наличие его в обзоре рынка. Некоторые советники используют четкие названия без суффиксов, а брокеры намеренно ставят суффиксы, например EURUSDx где х – суффикс |
4108 | Неверный номер тикета | Тикет ордера, который выбирает эксперт – не существует. Эксперт пытается выбрать тикет, но данный ордер был закрыт другим советником или руками. При попытке осуществления приказа над ордером, тикет был исполнен и закрыт брокером | Если данная ошибка появляется очень часто, 100-1000 раз за минуту, проверьте функции Вашего советника. Отключите другие советники или настройте их так, чтобы они не конфликтовали, не закрывайте ордер руками, когда эксперт выполняет операцию. Иногда такое случается, когда несколько советников используют одинаковый MagicNumber |
4109 | Торговля не разрешена | Советнику запрещено торговать, на графике грустный смайл или крестик | Включите галочку «Разрешить советнику торговать» во вкладе при установке советника, либо в меню – сервис – настройки – советники |
4110, 4111 | Длинные/короткие позиции не разрешены | В настройках советника, во вкладке Общие не разрешен тип позиций | Во вкладке Общие, при установке советника, есть выбор позиций, разрешенных к открытию |
Заключение
Рассмотренные вспомогательные функции и несложные приемы позволяют заметно упростить и ускорить процесс обнаружения и исправления ошибок в коде торговых экспертов, написанных на языке программирования MQL4. Грамотное написание кода и функций для логирования и сопровождения работы советника существенно ускоряют процесс его разработки.
Тема на форуме
С уважением, Дмитрий аkа Silentspec
TradeLikeaPro.ru
Я пытаюсь изменить заказ, но все равно не могу изменить порядок! Ошибка № 130. Я использую брокера ECN, поэтому мне нужно изменить ордер, чтобы установить стоп-лосс / тейк-профит. Что я делаю не так?
int digits = MarketInfo( Symbol(), MODE_DIGITS );
if ( digits == 2 || digits == 3 ) pipdigits = 0.01;
else if ( digits == 4 || digits == 5 ) pipdigits = 0.0001;
selltakeprofit = Ask + ( takeprofit * pipdigits );
sellstoploss = Ask - ( stoploss * pipdigits );
ticket = OrderSend( Symbol(), OP_SELL, lotsize, Ask, 100, 0, 0, 0, 0, 0, CLR_NONE );
if ( ticket < 0 )
{
Print( "venda Order send failed with error #", GetLastError() );
Print( "stop loss = ", sellstoploss );
}
else
{
Print( "Order send sucesso!!" );
Print( "Balance = ", AccountBalance() );
Print( "Equity = ", AccountEquity() );
bool res = OrderModify( ticket, 0, sellstoploss, selltakeprofit, 0 );
if ( res == false )
{
Print( "Error modifying order!, error#", GetLastError() );
Print( "sellstoploss ", sellstoploss );
Print( "selltakeprofit ", selltakeprofit );
Print( "StopLevel ", StopLevel );
Print( "Ask ", Ask );
}
else
{
Print( "Order modified successfully" );
}
}
5 ответов
Лучший ответ
Ошибка № 130: ERR_INVALID_STOPS
.
Наиболее вероятная проблема в том, что
а) вводимый вами уровень стоп-лосса слишком близок к цене открытия ордера. Это продиктовано
MarketInfo( Symbol(), MODE_STOPLEVEL ) // returns a min allowed distance [pts]
Еще
б) , потому что вы не нормализовали уровень стоп-лосса с помощью NormalizeDouble()
.
См. Ниже пример заказа на покупку. В вашем примере, то есть для ордера на продажу, обратите внимание, что вы должны открывать ордер по цене Bid, а не Ask, как у вас. Также обратите внимание, что стоп-лосс и тейк-профит обычно рассчитываются относительно цены предложения, так как предложение — это то, что отображается на ваших графиках, к сожалению, вам просто нужно принять убыток от спреда с ходу.
Другая небольшая проблема заключается в том, что вы не вводите цвет для последнего параметра в OrderModify()
. В отличие от OrderSend()
, они не инициализируются по умолчанию в определении функции, поэтому вам действительно следует их передавать.
//--- get minimum stop level
double minstoplevel = MarketInfo( Symbol(), MODE_STOPLEVEL );
Print( "Minimum Stop Level=", minstoplevel, " points" );
double price = Ask;
//--- calculated SL and TP prices must be normalized
double stoploss = NormalizeDouble( Bid - minstoplevel * Point, Digits );
double takeprofit = NormalizeDouble( Bid + minstoplevel * Point, Digits );
//--- place market order to buy 1 lot
int ticket = OrderSend( Symbol(), OP_BUY, 1, price, 3, stoploss, takeprofit, "My order", 16384, 0, clrGreen );
2
user3666197
13 Дек 2014 в 21:31
Вызов OrderModify()
может столкнуться не с одним, а с двумя ограничениями
Первый из них тривиален — нельзя поставить SL / TP ближе, чем позволяет ваш брокер, через определенное расстояние MODE_STOPLEVEL
.
Второй, менее заметный — {SL | TP} в случае, если определенное брокером расстояние замораживания посещается соответствующей ценой XTO (цена eXecute-Trade-Operation, равная { Ask
для Short.SL и Short.TP | Bid
для Long.TP и Long.SL})
MarketInfo( Symbol(), MODE_STOPLEVEL ) // returns a min allowed distance [pts]
MarketInfo( Symbol(), MODE_FREEZELEVEL ) // returns a freezing distance [pts]
OrderSend()
может быть ограничено для некоторых типов учетных записей ECN / STP
Еще одно довольно распространенное условие, установленное в системах STP / ECN (введенное внутренней политикой управления рисками брокера), заключается в том, что нельзя устанавливать TP / SL прямо на OrderSend()
, но необходимо оставьте эти поля пустыми и при положительном подтверждении OrderSend()
отправьте отдельную инструкцию OrderModify()
для данного OrderTicketNumber, чтобы добавить фактический уровень цены TP и / или SL. (s)
A NormalizeDouble()
— по возможности практика здесь отдельно не комментируется, поскольку MetaQuotes Inc. публикует ее как обязательную.
Рекомендуемая практика
Внимательно ознакомьтесь с Положениями и условиями вашего брокера и проконсультируйтесь со своим менеджером по работе с клиентами по поводу полного набора политик на стороне брокера, применимых к вашему типу торгового счета.
3
user3666197
27 Ноя 2020 в 15:20
Когда вы совершаете сделку на покупку, ваша цена — Ask
, ваши стоп-лосс и тейк-профит относятся к противоположной сделке, так как при закрытии вы подвержены Bid
цена.
Используя это простое правило, при покупке stoploss
и takeprofit
будут:
double stoploss = NormalizeDouble( Bid - minstoplevel * Point, Digits );
double takeprofit = NormalizeDouble( Bid + minstoplevel * Point, Digits );
int ticket = OrderSend( Symbol(),
OP_BUY,
lots,
price,
slippage,
stoploss,
takeprofit
);
Наоборот, когда вы продаете:
double stoploss = NormalizeDouble( Ask + minstoplevel * Point, Digits );
double takeprofit = NormalizeDouble( Ask - minstoplevel * Point, Digits );
int ticket = OrderSend( Symbol(),
OP_SELL,
lots,
price,
slippage,
stoploss,
takeprofit
);
1
user3666197
25 Ноя 2016 в 15:07
Здравствуйте, некоторые брокеры ECN не позволяют отправлять ордера с SL и TP, поэтому сначала отправьте ордер без SL и TP, затем измените его и назначьте ему SL и TP.
0
Simo
23 Июл 2018 в 15:15
На самом деле реальная проблема заключается в том, что ваша новая цена стоп-лосса, хотя для стороны покупки больше, чем текущий стоп-лосс, вам все равно нужно проверять, действительно ли ваш новый стоп-лосс меньше текущей цены Bid. В противном случае вы получите ошибку Order Modify 130. Надеюсь, я понимаю. И противоположное относится к стороне продажи.
0
Henri Fanda
29 Июн 2020 в 06:57