Какая конструкция правильная? - страница 8

 
valenok2003:

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

тогда еще добавьте строку

int err = GetLastError();

в начало функции - очистить буфер ошибок: иногда можно зачитать "чужую" ошибку, а так при старте функции буфер ошибок будет очищен.

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

Удачи.

 
VladislavVG:

тогда еще добавьте строку

в начало функции - очистить буфер ошибок: иногда можно зачитать "чужую" ошибку, а так при старте функции буфер ошибок будет очищен.

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

Удачи.


Да, спасибо, в реальных прогах я так и делаю.
 
Люди добрые, подскажите, почему функция возвращает 0, хотя открытых ордеров нет. Должна же выдаваться какая-то ошибка?
//+------------------------------------------------------------------+
//| функция закрытия ордеров по символу
//+------------------------------------------------------------------+
int Close_This_Symbol_All(string _Symbol_Name, string _Type_Order, int _Slippage, bool _Alert_ON)
{
  bool _Result;
  ERROR = 0;
//----
  if(OrdersTotal() == 0) return(-1);
  for (int _Cnt = OrdersTotal()-1; _Cnt >= 0; _Cnt--) 
  {
    if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) break;
    if(OrderSymbol() == _Symbol_Name)
    { 
      while (!IsTradeAllowed()) Sleep(1000);
      RefreshRates();
      if(OrderType() == OP_BUY   && _Type_Order == "BUY") 
      {
        _Result = OrderClose(OrderTicket(), OrderLots(), MarketInfo(_Symbol_Name,MODE_BID), _Slippage, CLR_NONE);
        ERROR = GetLastError();
      }
      if(OrderType() == OP_SELL && _Type_Order == "SELL") 
      {
        _Result = OrderClose(OrderTicket(), OrderLots(), MarketInfo(_Symbol_Name,MODE_ASK), _Slippage, CLR_NONE);
        ERROR = GetLastError();
      }
      if(_Result == true) PlaySound(Name_Sound_Close);
      else 
      {
        Error(Name_Expert," Close "+_Type_Order+": ",ERROR,_Alert_ON);
        break;
      }
    }  
  }
//----
  return(ERROR);
}
//+------------------------------------------------------------------+
 
В очередной раз разбираем по косточкам?
 
valenok2003:
Люди добрые, подскажите, почему функция возвращает 0, хотя открытых ордеров нет. Должна же выдаваться какая-то ошибка?
int OrdersTotal( )

Возвращает общее количество открытых и отложенных ордеров.

Всё ещё пишешь на заказ?

 

-- Использовать имена, начинающиеся с подчеркивания и двойного подчеркивания -- плохой тон. Лучше уж тогда подчеркивание в конце.


-- Почему _Type_Order строка? Имхо, нереально неудобно. Тогда приводить бы надо. Т.к. если написать "Sell" или "sell" ничего пахать не будет.


-- Если хотите ошибку, сделайте ошибку:

ERROR = -1;

А лучше так

#define ERROR_NOTHING_TO_CLOSE -1
...

...
ERROR = ERROR_NOTHING_TO_CLOSE;


--

if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) break;

Почему break? Допустим, миллисекунду назад ордер закрылся по ТП -- что из-за этого остальные закрывать не надо? Лучше так:

if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) continue;

--

while (!IsTradeAllowed()) Sleep(1000);

Строка хуже, чем бесполезная -- она вредная. Наверное имелось в виду это?

while (IsTradeContextBusy()) Sleep(1000);


--

else 
      {
        Error(Name_Expert," Close "+_Type_Order+": ",ERROR,_Alert_ON);
        break;
      }

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

Остальные закрывать не надо? Повторно попытаться не надо?


-- К чему здесь вообще возврат ошибки? Гораздо уместнее вернуть к примеру true если все удалось закрыть и false если нет.


Вроде все пока.

 
TheXpert:

-- Использовать имена, начинающиеся с подчеркивания и двойного подчеркивания -- плохой тон. Лучше уж тогда подчеркивание в конце.


  Используя внутри функций имена начинающиеся с подчёркивания я исключаю риск переопределения переменных. Т.о. в start() я спокойно могу использовать теже самые имена, но без подчёркивания. что увеличивает прозрачность кода.  

- Почему _Type_Order строка? Имхо, нереально неудобно. Тогда приводить бы надо. Т.к. если написать "Sell" или "sell" ничего пахать не будет.

Вы, конечно, правы. Однако использование строки увеличивает прозрачность кода и при тех объёмах кода, которые я имею на данный момент нет необходимости в приведении. Когда я столкнусь реально с этой проблемой, то сделаю, а пока в этом нет необходимости. Я просто пишу SELL или BUY.


Почему break? Допустим, миллисекунду назад ордер закрылся по ТП -- что из-за этого остальные закрывать не надо? Лучше так:

if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) continue;

Вы, безусловно правы, спасибо.


Строка хуже, чем бесполезная -- она вредная. Наверное имелось в виду это?

функция IsTradeContextBusy() информирует только о занятости потока, IsTradeAllowed() несколько шире


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


да, на период отладки именно так

К чему здесь вообще возврат ошибки? Гораздо уместнее вернуть к примеру true если все удалось закрыть и false если нет.


Спасибо, отвечая вам я, похоже, понял в чём ошибка. Сейчас проверю и отпишусь.
 

Ошибка была в следующем:

переменная bool _Result не инициализирована, значит там будет false, таким образом, поскольку не выполнилось ни одно из условий мы не изменили переменную  _Result, а в ней уже false. И функция переходит к обработке ошибок, которых реально не было.

Я исправил функцию и выкладываю её здесь, думаю она кому-нибудь может пригодиться.

//+------------------------------------------------------------------+
//| функция закрытия ордеров по символу
//+------------------------------------------------------------------+
int Close_This_Symbol_All(string _Symbol_Name, string _Type_Order, int _Slippage, bool _Alert_ON)
{
int _Cnt_Close_Orders = 0;
//----
  if(OrdersTotal() == 0) return(_Cnt_Close_Orders);
  for (int _Cnt = OrdersTotal()-1; _Cnt >= 0; _Cnt--) 
  {
    if(!OrderSelect(_Cnt, SELECT_BY_POS, MODE_TRADES)) continue;
    if(OrderSymbol() == _Symbol_Name)
    { 
      while (!IsTradeAllowed()) Sleep(1000);
      RefreshRates();
      if(OrderType() == OP_BUY   && _Type_Order == "BUY") 
      {
        if(OrderClose(OrderTicket(), OrderLots(), MarketInfo(_Symbol_Name,MODE_BID), _Slippage, CLR_NONE))
        {
          _Cnt_Close_Orders++;
          PlaySound(Name_Sound_Close);        
        } 
        else 
        {
          Error(Name_Expert," Close "+_Type_Order+": ",GetLastError(),_Alert_ON);
          continue;
        }
      }
      if(OrderType() == OP_SELL && _Type_Order == "SELL") 
      {
        if(OrderClose(OrderTicket(), OrderLots(), MarketInfo(_Symbol_Name,MODE_ASK), _Slippage, CLR_NONE))
        {
          _Cnt_Close_Orders++;
          PlaySound(Name_Sound_Close);        
        } 
        else 
        {
          Error(Name_Expert," Close "+_Type_Order+": ",GetLastError(),_Alert_ON);
          continue;
        }
      }
    }  
  }
//----
  return(_Cnt_Close_Orders);
}
//+------------------------------------------------------------------+

 PS Модераторам. Такая ветка невзначай получилась - готовый самоучитель по правильному закрытию ордеров. Может стоит её переименовать, типа - как правильно закрыть ордера с разбором примеров?

PPS Всем принявшим участие огромное СПАСИБО. Возможно вопросы будут ещё. 

 
valenok2003:

Ошибка была в следующем:

переменная bool _Result не инициализирована, значит там будет false, таким образом, поскольку не выполнилось ни одно из условий мы не изменили переменную _Result, а в ней уже false. И функция переходит к обработке ошибок, которых реально не было.

Я исправил функцию и выкладываю её здесь, думаю она кому-нибудь может пригодиться.

PS Модераторам. Такая ветка невзначай получилась - готовый самоучитель по правильному закрытию ордеров. Может стоит её переименовать, типа - как правильно закрыть ордера с разбором примеров?

PPS Всем принявшим участие огромное СПАСИБО. Возможно вопросы будут ещё.


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

Ошибка была в следующем:

переменная bool _Result не инициализирована, значит там будет false, таким образом, поскольку не выполнилось ни одно из условий мы не изменили переменную _Result, а в ней уже false. И функция переходит к обработке ошибок, которых реально не было.

Я исправил функцию и выкладываю её здесь, думаю она кому-нибудь может пригодиться.

PS Модераторам. Такая ветка невзначай получилась - готовый самоучитель по правильному закрытию ордеров. Может стоит её переименовать, типа - как правильно закрыть ордера с разбором примеров?

PPS Всем принявшим участие огромное СПАСИБО. Возможно вопросы будут ещё.

ИМХО : Функция получилась непонятная по самой логике. Если для тестера, то много лишнего, если для реала, то стоит обрабатывать ошибки. Возвращаемое значение вообще смысла не имеет - Вы сообщаете на внешний уровень (на уровень вызова), что вызов завершился ошибкой, саму ошибку при этом теряете, ну написали в журнал - как эксперт это считает ?

Как бы было правильней: (опять ИМХО)

1. Считывать и сохранять номер ошибки.

2. Разделять ошибки на устранимые и неустранимые. Для этого сделать обработчик - те ошибки при возникновении которых ордер все-таки можно закрыть (занят поток, обрыв связи ... и т.д.) обрабатывать прямо на месте. У меня так сделано (сначала неустранимые, потом то, что можно "исправить"):

#define MAXCYKLESCNT 20

int ErrReaction(int err)
{
    switch(err)
    {
        case ERR_TRADE_NOT_ALLOWED    :
                 Print("TRADE NOT ALLOWED ! SWITCH ON option \' Allow live trading\' (Необходимо включить опцию \'Разрешить советнику торговать\')");
        case ERR_INVALID_FUNCTION_PARAMSCNT :    
        case ERR_INVALID_FUNCTION_PARAMVALUE :    
        case ERR_INVALID_STOPS        : 
        case ERR_INVALID_TRADE_VOLUME : 
        case ERR_MARKET_CLOSED        : 
        case ERR_TRADE_DISABLED       : 
        case ERR_NOT_ENOUGH_MONEY     : 
                 return(-err);
        case ERR_NO_CONNECTION        :
                 ReScanServers();
        case ERR_BROKER_BUSY          : 
        case ERR_TRADE_CONTEXT_BUSY   : 
        case ERR_ORDER_LOCKED         :
                 int n=0;
                 while((!IsTradeAllowed())&&(n<20)){ Sleep(500);n++;}
        case ERR_PRICE_CHANGED : 
        case ERR_OFF_QUOTES    : 
        case ERR_REQUOTE       : 
                 RefreshRates();
                 break;
        default: break;
    }//switch(err)
    return(0);
}//int ErrReaction(int err)

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

bool res    = false;
int  ncykls =     0;

    while((!res)&&(ncykls<MAXCYKLESCNT))
    {
        res = ...............
        if(!res)
        { 
            ncykls++;
            err=GetLastError();
            Print(ncykls," Err(",err,") : ",ErrorDescription(err)); 
            err_res = ErrReaction(err); 
            if(err_res<0) return(err_res);
        } 
    }//while((!res)&&(ncykls<MAXCYKLESCNT))

Удачи.

ЗЫ по поводу break/continue

if( !OrderSelect(i,SELECT_BY_POS,MODE_TRADES) ) break;    // No more Orders
вопрос спорный. Если ордера еще есть, то при срабатывании тейка/стопа изменится нумерация ордеров - то есть ордер все равно будет выбран: Вы же выбираете по порядковому номеру, а не по тикету. Если ордер не выбран - это значит, что ордеров нет. Поскольку Вы не проверяете каждый раз количество ордеров, то прогоните цикл в холостую некоторое количество раз.
Причина обращения: