Введение
При использовании новой версии компилятора языка MQL4 некоторые старые программы могут выдавать ошибки.
В старой версии компилятора во избежание критического завершения программ многие ошибки обрабатывались средой исполнения и не приводили к остановке работы. Например, деление на ноль или выход за пределы массива являются критическими ошибками и обычно приводят к аварийному завершению. Проявляются такие ошибки лишь в некоторых состояниях при определенных значениях переменных, однако о таких ситуациях следует знать и корректно их обрабатывать.
Новый компилятор позволяет обнаружить реальные или потенциальные источники ошибок и повысить качество кода.
В этой статье мы рассмотрим возможные ошибки, возникающие при компиляции старых программ, и методы их устранения.
- Ошибки компиляции
- 1.1. Идентификатор совпадает с зарезервированным словом
- 1.2. Специальные символы в наименованиях переменных и функций
- 1.3. Ошибки использования оператора switch
- 1.4. Возвращаемые значения у функций
- 1.5. Массивы в аргументах функций
- Ошибки времени выполнения
- 2.1. Выход за пределы массива (Array out of range)
- 2.2. Деление на ноль (Zero divide)
- 2.3. Использование 0 вместо NULL для текущего символа
- 2.4. Строки в формате Unicodе и их использование в DLL
- 2.5. Совместное использование файлов
- 2.6. Особенность преобразования datetime
- Предупреждения компилятора
- 3.1. Пересечения имен глобальных и локальных переменных
- 3.2. Несоответствие типов
- 3.3. Неиспользуемые переменные
1. Ошибки компиляции
При наличии ошибок в коде программа не может быть скомпилирована.
Для полного контроля всех ошибок рекомендуется использовать строгий режим компиляции, который устанавливается директивой:
#property strict
Этот режим значительно упрощает поиск ошибок.
1.1. Идентификатор совпадает с зарезервированным словом
Если наименование переменной или функции совпадает с одним из зарезервированных слов:
int char[]; int char1[]; int char() { return(0); }
то компилятор выводит сообщения об ошибках:
Рис.1. Ошибки «unexpected token» и «name expected»
Для исправления данной ошибки нужно исправить имя переменной или функции.
1.2. Специальные символы в наименованиях переменных и функций
Если наименования переменных или функций содержат специальные символы ($, @, точка):
int $var1; int @var2; int var.3; void f@() { return; }
то компилятор выводит сообщения об ошибках:
Рис.2. Ошибки «unknown symbol» и «semicolon expected»
Для исправления данной ошибки нужно скорректировать имена переменных или функций.
1.3. Ошибки использования оператора switch
Старая версия компилятора позволяла использовать любые значения в выражениях и константах оператора switch:
void start() { double n=3.14; switch(n) { case 3.14: Print("Pi");break; case 2.7: Print("E");break; } }
В новом компиляторе выражения и константы оператора switch должны быть целыми числами, поэтому при использовании подобных конструкций возникают ошибки:
Рис.3. Ошибки «illegal switch expression type» и «constant expression is not integral»
В таких случаях можно использовать явные сравнения численных значений, например:
void start() { double n=3.14; if(n==3.14) Print("Pi"); else if(n==2.7) Print("E"); }
1.4. Возвращаемые значений функций
Все функции, кроме void, должны возвращать значение объявленного типа. Например:
int function()
{
}
При строгом режиме компиляции (strict) возникает ошибка:
Рис.4. Ошибка «not all control paths return a value»
В режиме компиляции по умолчанию компилятор выводит предупреждение:
Рис.5. Предупреждение «not all control paths return a value»
Если возвращаемое значение функции не соответствует объявлению:
int init() { return; }
то при строгом режиме компиляции возникает ошибка:
Рис.6. Ошибка «function must return a value»
В режиме компиляции по умолчанию компилятор выводит предупреждение:
Рис.7. Предупреждение ‘return — function must return a value»
Для исправления таких ошибок в код функции нужно добавить оператор возврата return c возвращаемым значением соответствующего типа.
1.5. Массивы в аргументах функций
Массивы в аргументах функций теперь передаются только по ссылке.
double ArrayAverage(double a[]) { return(0); }
Данный код при строгом режиме компиляции (strict) приведет к ошибке:
Рис.8. Ошибка компилятора «arrays passed by reference only»
В режиме компиляции по умолчанию компилятор выводит предупреждение:
Рис.9. Предупреждение компилятора «arrays passed by reference only»
Для исправления таких ошибок нужно явно указать передачу массива по ссылке, добавив префикс & перед именем массива:
double ArrayAverage(double &a[]) { return(0); }
Следует отметить, что теперь константные массивы (Time[], Open[], High[], Low[], Close[], Volume[]) не могут быть переданы по ссылке. Например, вызов:
ArrayAverage(Open);
вне зависимости от режима компиляции приводит к ошибке:
Рис.10. Ошибка ‘Open’ — constant variable cannot be passed as reference
Для устранения подобных ошибок нужно скопировать необходимые данные из константного массива:
double OpenPrices[]; ArrayCopy(OpenPrices,Open,0,0,WHOLE_ARRAY); ArrayAverage(OpenPrices);
2. Ошибки времени выполнения
Ошибки, возникающие в процессе исполнения кода программы принято называть ошибками времени выполнения (runtime errors). Такие ошибки обычно зависят от состояния программы и связаны с некорректными значениями переменных.
Например, если переменная используется в качестве индекса элементов массива, то ее отрицательные значения неизбежно приведут к выходу за пределы массива.
2.1. Выход за пределы массива (Array out of range)
Эта ошибка часто возникает в индикаторах при обращении к индикаторным буферам. Функция IndicatorCounted() возвращает количество баров, неизменившихся после последнего вызова индикатора. Значения индикаторов на уже рассчитанных ранее
барах не нуждаются в пересчете, поэтому для ускорения расчетов
достаточно обрабатывать только несколько последних баров.
Большинство индикаторов, в которых используется данный способ оптимизации вычислений, имеют вид:
int start() { if (Bars<100) return(-1); int counted_bars=IndicatorCounted(); if(counted_bars<0) return(-1); int limit=Bars-counted_bars; if(counted_bars==0) { limit--; limit-=10; } else { limit++; } for (int i=limit; i>0; i--) { Buff1[i]=0.5*(Open[i+5]+Close[i+10]) } }
Часто встречается некорректная обработка случая counted_bars==0 (начальную позицию limit нужно уменьшить на значение, равное 1 + максимальный индекс относительно переменной цикла).
Также следует помнить о том, что в момент исполнения функции start() мы можем обращаться к элементам массивов индикаторных буферов от 0 до Bars()-1. Если есть необходимость работы с массивами, которые не являются индикаторными буферами, то их размер следует увеличить при помощи функции ArrayResize() в соответствии с текущим размером индикаторных буферов. Максимальный индекс элемента для адресации также можно получить вызовом ArraySize() с одним из индикаторных буферов в качестве аргумента.
2.2. Деление на ноль (Zero divide)
Ошибка «Zero divide» возникает в случае, если при выполнении операции деления делитель оказывается равен нулю:
void OnStart() { int a=0, b=0,c; c=a/b; Print("c=",c); }
При выполнении данного скрипта во вкладке «Эксперты» возникает сообщение об ошибке и завершении работы программы:
Рис.11. Сообщение об ошибке «zero divide»
Обычно такая ошибка возникает в случаях, когда значение делителя определяется значениями каких-либо внешних данных. Например, если анализируются параметры торговли, то величина задействованной маржи оказывается равна 0 если нет открытых ордеров. Другой пример: если анализируемые данные считываются из файла, то в случае его отсутствия нельзя гарантировать корректную работу. По этой причине желательно стараться учитывать подобные случаи и корректно их обрабатывать.
Самый простой способ — проверять делитель перед операцией деления и выводить сообщение об некорректном значении параметра:
void OnStart() { int a=0, b=0,c; if(b!=0) {c=a/b; Print(c);} else {Print("Error: b=0"); return; }; }
В результате критической ошибки не возникает, но выводится сообщение о некорректном значении параметра и работа завершается:
Рис. 12. Сообщение о некорректном значении делителя
2.3. Использование 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);
2.4. Строки в формате Unicodе и их использование в DLL
Строки теперь представляют собой последовательность символов Unicode.
Следует учитывать этот факт и использовать соответствующие функции Windows. Например, при использовании функций библиотеки wininet.dll вместо InternetOpenA() и InternetOpenUrlA() следует вызывать InternetOpenW() и InternetOpenUrlW().
В MQL4 изменилась внутренняя структура строк (теперь она занимает 12 байт), поэтому при передаче строк в DLL следует использовать структуру MqlString:
#pragma pack(push,1) struct MqlString { int size; LPWSTR buffer; int reserved; }; #pragma pack(pop,1)
2.5. Совместное использование файлов
В новом MQL4 при открытии файлов необходимо явно указывать флаги FILE_SHARE_WRITE и FILE_SHARE_READ для совместного использования.
В случае их отсутствия файл будет открыт в монопольном режиме, что не позволит больше никому его открывать, пока он не будет закрыт монополистом.
Например, при работе с оффлайновыми графиками требуется явно указывать флаги совместного доступа:
ExtHandle=FileOpenHistory(c_symbol+i_period+".hst",FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ);
Подробности можно найти в статье в статье «Оффлайновые графики и новый MQL4«.
2.6. Особенность преобразования datetime
Следует иметь ввиду, что преобразование типа datetime в строку теперь зависит от режима компиляции:
datetime date=D'2014.03.05 15:46:58'; string str="mydate="+date;
Например, попытка работы с файлами, имя которых содержит двоеточие, приведет к ошибке.
3. Предупреждения компилятора
Предупреждения компилятора носят информационный характер и не являются сообщениями об ошибках, однако они указывают на возможные источники ошибок и лучше их скорректировать.
Чистый код не должен содержать предупреждений.
3.1. Пересечения имен глобальных и локальных переменных
Если на глобальном и локальном уровнях присутствуют переменные с одинаковыми именами:
int i; void OnStart() { int i=0,j=0; for (i=0; i<5; i++) {j+=i;} PrintFormat("i=%d, j=%d",i,j); }
то компилятор выводит предупреждение и укажет номер строки, на которой объявлена глобальная переменная:
Рис.13. Предупреждение «declaration of ‘%’ hides global declaration at line %»
Для исправления таких предупреждений нужно скорректировать имена глобальных переменных.
3.2. Несоответствие типов
В новой версии компилятора введена операция приведения типов.
#property strict void OnStart() { double a=7; float b=a; int c=b; string str=c; Print(c); }
В строгом режиме компиляции при несоответствии типов компилятор выводит предупреждения:
Рис.14. Предупреждения «possible loss of data due to type conversion» и «implicit conversion from ‘number’ to ‘string’
В данном примере компилятор предупреждает о возможной потере точности при присвоении различных типов данных и неявном преобразовании типа int в string.
Для исправления нужно использовать явное приведение типов:
#property strict void OnStart() { double a=7; float b=(float)a; int c=(int)b; string str=(string)c; Print(c); }
3.3. Неиспользуемые переменные
Наличие переменных, которые не используются в коде программы (лишние сущности) не является хорошим тоном.
void OnStart() { int i,j=10,k,l,m,n2=1; for(i=0; i<5; i++) {j+=i;} }
Сообщения о таких переменных выводятся вне зависимости от режима компиляции:
Рис.15. Предупреждения «variable ‘%’ not used’
Для исправления нужно убрать неиспользуемые переменные из кода программы.
Выводы
В статье рассмотрены типичные проблемы, с которыми могут столкнуться программисты при компиляции старых программ, содержащих ошибки.
Во всех случаях при отладке программ рекомендуется использовать строгий режим компиляции.
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
-
#1
Здравствуйте
При компиляции появляется ошибка
possible loss of data due to type conversion
указывающая на то что в этой строке возможна потеря данных при конвертации
NormalizeDouble(Price_Cls, MarketInfo(OrderSymbol(), MODE_DIGITS));
по причине MarketInfo(OrderSymbol(), MODE_DIGITS)
Явное приведение данных не привело к результату
Замена на Digits помогает, но по регламенту исполняемой задачи не подходит.
Буду рад помощи.
Благодарен.
-
#2
Здравствуйте
При компиляции появляется ошибка
possible loss of data due to type conversion
указывающая на то что в этой строке возможна потеря данных при конвертацииNormalizeDouble(Price_Cls, MarketInfo(OrderSymbol(), MODE_DIGITS));
по причине MarketInfo(OrderSymbol(), MODE_DIGITS)
Явное приведение данных не привело к результату
Замена на Digits помогает, но по регламенту исполняемой задачи не подходит.
Буду рад помощи.
Благодарен.
Маркетинфо функция дробная. А там надо целочисленные данные. По мнению компилятора дробные данные будут потеряны.
NormalizeDouble(Price_Cls, (int)MarketInfo(OrderSymbol(), MODE_DIGITS));
-
#3
Доброго времени суток!
Прошу помочь в исправлении предупреждения.
Есть код:
datetime double_in_datatime(double _Use_Time)
{
datetime _Currently = iTime(NULL,1440,0);
double _Hour = MathFloor(_Use_Time);
double _Min = (_Use_Time - MathFloor(_Use_Time))*100;
[U]datetime _Sec_in_Hour = _Hour*3600;[/U]
[U]datetime _Sec_in_Min = _Min*60;[/U]
datetime _Ret = _Currently + _Sec_in_Hour + _Sec_in_Min;
return(_Ret);
}
В подчеркнутых строках выдает предупреждение: «возможна потеря данных из-за преобразования типов»
-
#4
Доброго времени суток!
Прошу помочь в исправлении предупреждения.
Есть код:datetime double_in_datatime(double _Use_Time) { datetime _Currently = iTime(NULL,1440,0); double _Hour = MathFloor(_Use_Time); double _Min = (_Use_Time - MathFloor(_Use_Time))*100; [U]datetime _Sec_in_Hour = _Hour*3600;[/U] [U]datetime _Sec_in_Min = _Min*60;[/U] datetime _Ret = _Currently + _Sec_in_Hour + _Sec_in_Min; return(_Ret); }
В подчеркнутых строках выдает предупреждение: «возможна потеря данных из-за преобразования типов»
Ну а зачем-же ты входящей переменной присваиваешь тип datetime?
Если уж это так необходимо, то тогда пиши
datetime Sec_in_Hour = (datetime) _Houe*3600;
или
datetime Sec_in_Hour = datetime (_Houe*3600);
-
#5
Ну а зачем-же ты входящей переменной присваиваешь тип datetime?
Если уж это так необходимо, то тогда пиши
datetime Sec_in_Hour = (datetime) _Houe*3600;
или
datetime Sec_in_Hour = datetime (_Houe*3600);
Если честно, то я этот код «слизал» на другом сайте. И как на счет присвоенного типа double в верхних строчках?
Здравствуйте. basket=FileReadArray(pairs,Pairs,0,ArraySize(Pairs));
{ |
|
Администратор запретил публиковать записи гостям. |
Vlad023 пишет: Здравствуйте. basket=FileReadArray(pairs,Pairs,0,ArraySize(Pairs));
{
Это не ошибка (error), а предупреждение (warning). Поправьте эту строчку так: basket=(int)FileReadArray(pairs,Pairs,0,ArraySize(Pairs)); а в общем ничего страшного не произойдет и без редактирования — просто исчезнет предупреждение. |
|
Администратор запретил публиковать записи гостям. |
I wrote this sample code for learning purposes but I can’t seem to solve the warning message of «possible loss of data due to type conversion«.
I have tried to search online but I can’t seem to find a solution on how to pass the value of the MQL5 built-in functions without getting this warning.
The iAMA
built-in function of MQL5 returns an integer and this integer is getting assigned to a variable of type integer (as shown in the sample code below). I am not sure why there is a data loss warning if both of them are integers.
Note: The code is compiling and running well but for educational purposes, I would like to understand how to solve this warning message.
Your help will be much appreciated!
Here is the code:
// --- Information Properties
#property description "Adaptive Moving Average Function Test"
//--- Core Properties
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
// --- Styling & Labels Properties
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrBlack
#property indicator_width1 2
#property indicator_label1 "Adaptive Moving Average"
//--- Constant Variables
const int ama_period = 34;
const int ama_fast_ma = 2;
const int ama_slow_ma = 34;
//--- Global Variables
double ama_src = PRICE_MEDIAN;
//--- Buffers
double ama_buffer[];
//--- Handles
int ama_buffer_handle;
//+------------------------------------------------------------------+
//| Indicator Initialization |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Buffers Assignment
SetIndexBuffer(0, ama_buffer, INDICATOR_DATA);
//--- Accuracy Setting
IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
//--- First Bar Setting
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ama_period - 1);
//--- Line Shifts Calculations
PlotIndexSetInteger(0, PLOT_SHIFT, 0);
//--- Labels Calculations
PlotIndexSetString(0, PLOT_LABEL, "AMA");
//--- Handles Calculations
ama_buffer_handle = iAMA(NULL, 0, ama_period, ama_fast_ma, ama_slow_ma, 0, ama_src);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| OnCalculate function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
if(rates_total < ama_period)
{
return(0);
}
//--- Troubleshooting: Data Calculation
int calculated = BarsCalculated(ama_buffer_handle);
if(calculated < rates_total)
{
Print("Not all data of ama_buffer_handle is calculated (", calculated, " bars). Error ", GetLastError());
return(0);
}
//--- Troubleshooting: Data Copying
int to_copy;
if(prev_calculated > rates_total || prev_calculated < 0)
{
to_copy = rates_total;
}
else
{
to_copy = rates_total - prev_calculated;
if(prev_calculated > 0)
{
to_copy++;
}
}
//--- Copy & Validate Buffers
if(CopyBuffer(ama_buffer_handle, 0, 0, to_copy, ama_buffer) <= 0)
{
Print("getting ama_buffer_handle is failed! Error ", GetLastError());
return(0);
}
if(IsStopped())
{
return(0);
}
return(rates_total);
}
//+——————————————————————+
//| Test4.mq4 |
//| Copyright 2018, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+——————————————————————+
#property copyright «Copyright 2018, MetaQuotes Software Corp.»
#property link «https://www.mql5.com»
#property version «1.00»
#property strict
//——————————————————————
extern double Lots = 0.1;
extern int TakeProfit = 300;
extern int StopLoss = 50;
extern int TakeProfitStop = 5;
extern int StopLossStop = 20;
extern int Magic = 111;
extern int MagicStop = 112;
extern int Slippage = 3;
extern bool BorderCloseTrueMediomCloseFalse = True;
extern bool AddStopOrdersFalse = True;
extern int StopOrdersShift = 20;
//——————————————————————
extern string TMA = «Параметры индикатора TMA»;
extern string TimeFrame = «current time frame»;
extern int HalfLength = 56;
extern int Price = PRICE_CLOSE;
extern double ATRMultiplier = 2.0;
extern int ATRPeriod = 100;
extern bool Interpolate = true;
//——————————————————————
double PriceHigh, PriceLow, PriceMedium, SL, TP, BuyStopPrice, SellStopPrice;
int Ticket, Ticket2, Ticket3;
int OnInit()
{
if (Digits == 3 || Digits == 5)
{
TakeProfit *= 10;
StopLoss *= 10;
Slippage *= 10;
TakeProfitStop *= 10;
StopLossStop *= 10;
}
return(INIT_SUCCEEDED);
}
//+——————————————————————+
//| Expert deinitialization function |
//+——————————————————————+
void OnDeinit(const int reason)
{
}
//+——————————————————————+
//| Expert tick function |
//+——————————————————————+
void OnTick()
{
PriceHigh = iCustom(NULL, 0, «TMA_Fair», TimeFrame, HalfLength, Price, ATRMultiplier, ATRPeriod, Interpolate, 1, 0);
PriceLow = iCustom(NULL, 0, «TMA_Fair», TimeFrame, HalfLength, Price, ATRMultiplier, ATRPeriod, Interpolate, 2, 0);
PriceMedium = iCustom(NULL, 0, «TMA_Fair», TimeFrame, HalfLength, Price, ATRMultiplier, ATRPeriod, Interpolate, 0, 0);
Comment(«PriceMedium: » + DoubleToStr(PriceMedium, 5));
if(CountSell() == 0 && Bid >= PriceHigh)
{
Ticket = OrderSend(OrderSymbol(), OP_SELL, Lots, Bid, Slippage, 0, 0, «TMA robot», Magic, 0, Red);
if (Ticket > 0)
{
SL = NormalizeDouble(Bid + StopLoss*Point, Digits);
TP = NormalizeDouble(Bid — TakeProfit*Point, Digits);
if (OrderSelect(Ticket, SELECT_BY_TICKET))
if(!OrderModify(Ticket, OrderOpenPrice(), SL, TP, 0))
Print(«Ошибка модификации ордера на продажу»);
} else Print(«Ошибка открытия ордера на продажу»);
}
if(CountBuy() == 0 && Ask <= PriceLow)
{
Ticket = OrderSend(OrderSymbol(), OP_BUY, Lots, Ask, Slippage, 0, 0, «TMA robot», Magic, 0, Blue);
if (Ticket > 0)
{
TP = NormalizeDouble(Ask + TakeProfit*Point, Digits);
SL = NormalizeDouble(Ask — StopLoss*Point, Digits);
if (OrderSelect(Ticket, SELECT_BY_TICKET))
if(!OrderModify(Ticket, OrderOpenPrice(), SL, TP, 0))
Print(«Ошибка модификации ордера на покупку»);
} else Print(«Ошибка открытия ордера на покупку»);
}
if (Ask <= PriceLow && CountSell() > 0 && BorderCloseTrueMediomCloseFalse == True)
{
for (int i = OrdersTotal() — 1; i>=0; i—)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == Magic && OrderType() == OP_SELL)
if(!OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, Black))
Print(«Ошибка закрытия ордера»);
}
}
}
if (Ask <= PriceMedium && CountSell() > 0 && BorderCloseTrueMediomCloseFalse == False)
{
for (int i = OrdersTotal() — 1; i>=0; i—)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == Magic && OrderType() == OP_SELL)
if(!OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, Black))
Print(«Ошибка закрытия ордера»);
}
}
}
if (Bid >= PriceHigh && CountBuy() > 0 && BorderCloseTrueMediomCloseFalse == True)
{
for (int i = OrdersTotal() — 1; i>=0; i—)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == Magic && OrderType() == OP_BUY)
if(!OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, Black))
Print(«Ошибка закрытия ордера на покупку»);
}
}
}
if (Bid >= PriceMedium && CountBuy() > 0 && BorderCloseTrueMediomCloseFalse == False)
{
for (int i = OrdersTotal() — 1; i>=0; i—)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == Magic && OrderType() == OP_BUY)
if(!OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, Black))
Print(«Ошибка закрытия ордера на покупку»);
}
}
}
if(CountSell() > 0 && BuyStopCount() == 0 && exBuyStopCount() == 0 && AddStopOrdersFalse == False && OrderSelect(Ticket, SELECT_BY_TICKET) == true)
{
BuyStopPrice = NormalizeDouble(OrderOpenPrice() + StopOrdersShift*Point, Digits);
SL = NormalizeDouble(BuyStopPrice — StopLossStop*Point, Digits);
TP = NormalizeDouble(BuyStopPrice + TakeProfitStop*Point, Digits);
Ticket2 = OrderSend(OrderSymbol(), OP_BUYSTOP, Lots, BuyStopPrice, Slippage, SL, TP, «TMA robot stoporder», MagicStop, 0, Blue);
//if(Ticket2 > 0)
//{
// if (OrderSelect(Ticket2, SELECT_BY_TICKET))
//if(!OrderModify(Ticket2, OrderOpenPrice(), SL, TP, 0))
// Print(«Ошибка модификации стопордера на продажу»);
//}else Print(«Ошибка открытия стопордера на продажу»);
}
if(CountBuy() > 0 && SellStopCount() == 0 && exSellStopCount() ==0 && AddStopOrdersFalse == False && OrderSelect(Ticket, SELECT_BY_TICKET) == true)
{
SellStopPrice = NormalizeDouble(OrderOpenPrice() — StopOrdersShift*Point, Digits);
SL = NormalizeDouble(SellStopPrice + StopLossStop*Point, Digits);
TP = NormalizeDouble(SellStopPrice — TakeProfitStop*Point, Digits);
Ticket3 = OrderSend(OrderSymbol(), OP_SELLSTOP, Lots, SellStopPrice, Slippage, SL, TP, «TMA robot stoporder», MagicStop, 0, Red);
//if(Ticket3 > 0)
//{
// if (OrderSelect(Ticket3, SELECT_BY_TICKET))
//if(!OrderModify(Ticket3, OrderOpenPrice(), SL, TP, 0))
// Print(«Ошибка модификации стопордера на продажу»);
//}else Print(«Ошибка открытия стопордера на продажу»);
}
}
//+——————————————————————+
int CountSell()
{
int count = 0;
for (int trade = OrdersTotal()-1; trade>=0; trade—)
{
if(OrderSelect(trade, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == OP_SELL)
count++;
}
}
return(count);
}
//+——————————————————————+
int CountBuy()
{
int count = 0;
for (int trade = OrdersTotal()-1; trade >= 0; trade—)
{
if(OrderSelect(trade, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == Magic && OrderType() == OP_BUY)
count++;
}
}
return(count);
}
//+——————————————————————+
int BuyStopCount()
{
int scount = 0;
for(int i=OrdersTotal()-1; i>=0; i—)
{
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == true &&
OrderMagicNumber() == MagicStop &&
OrderType() == OP_BUYSTOP)
{
scount++;
}
}
return(scount);
}
//+——————————————————————+
int SellStopCount()
{
int scount = 0;
for(int i=OrdersTotal()-1; i>=0; i—)
{
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == true &&
OrderMagicNumber() == MagicStop &&
OrderType() == OP_SELLSTOP)
{
scount++;
}
}
return(scount);
}
//+——————————————————————+
int exSellStopCount()
{
int exscount = 0;
for (int trade = OrdersTotal()-1; trade>=0; trade—)
{
if(OrderSelect(trade, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicStop && OrderType() == OP_SELL)
exscount++;
}
}
return(exscount);
}
//+——————————————————————+
int exBuyStopCount()
{
int exscount = 0;
for (int trade = OrdersTotal()-1; trade >= 0; trade—)
{
if(OrderSelect(trade, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicStop && OrderType() == OP_BUY)
exscount++;
}
}
return(exscount);
}