Странное поведение оператора switch ?

 

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

//==================================================================================================================================================================================
// Отрисовывает wingdings-символ над/под баром с индексом barIndex. ================================================================================================================
void Draw :: wingdings(string objName,                    // Название объекта
                       const ENUM_LOCATION objLocation,   // Расположение wingdings-символа
                       const long wingdingsCode,          // Код wingdings-символа
                       const int wingdingsWidth,          // Ширина wingdings-символа
                       const color wingdingsColor,        // Цвет wingdings-символа
                       const int barIndex,                // Индекса бара, у которого будет отрисован wingdings-символ
                       const ENUM_TIMEFRAMES tf) {        // Таймфрем, на котором будет отрисован wingdings-символ
//---
  Print("tf = PERIOD_H1");
  objName += "_" + TimeToString(barOpenTime(barIndex), TIME_DATE|TIME_MINUTES);
  if (!ObjectCreate(0, objName, OBJ_ARROW, 0, 0, 0)) {
    writeLog(MESSAGE_ERROR, __FUNCTION__ + " { Не удалось создать объект типа 'OBJ_ARROW' }");
    writeLog(MESSAGE_ERROR, __FUNCTION__ + " { _LastError = '" + iToS(_LastError) + "' }");
  }
  ObjectSetInteger(0, objName, OBJPROP_TIME, 0, barOpenTime(barIndex));

  if (objLocation == LOCATION_ABOVE) {
    Print("objLocation == LOCATION_ABOVE");
    ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_TOP);
    ObjectSetDouble(0, objName, OBJPROP_PRICE, barHighPrice(barIndex) + relativeDistance(tf));
  }
  else if (objLocation == LOCATION_BELOW) {
    Print("objLocation == LOCATION_BELOW");
    ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
    ObjectSetDouble(0, objName, OBJPROP_PRICE, barLowPrice(barIndex) - relativeDistance(tf));
  }
  ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, wingdingsCode);
  ObjectSetInteger(0, objName, OBJPROP_WIDTH, wingdingsWidth);
  ObjectSetInteger(0, objName, OBJPROP_COLOR, wingdingsColor);
//---
  ChartRedraw();
}

По сути, я начал писать для неё функцию только что вот эту:

//==================================================================================================================================================================================
// Возвращает расстояние равное запрошенному количеству процентов (percent) от экрана. =============================================================================================
double Draw :: relativeDistance(const ENUM_TIMEFRAMES tf) {
  switch (tf) {
    case PERIOD_M1:
      return (ChartGetDouble(0, CHART_PRICE_MAX) - ChartGetDouble(0, CHART_PRICE_MIN)) / 100 * 5;
      break;
    case PERIOD_H1:
      return (ChartGetDouble(0, CHART_PRICE_MAX) - ChartGetDouble(0, CHART_PRICE_MIN)) / 100 * 19;
      break;
    case PERIOD_D1:
      return (ChartGetDouble(0, CHART_PRICE_MAX) - ChartGetDouble(0, CHART_PRICE_MIN)) / 100 * 2;
      break;
    default:
      return (ChartGetDouble(0, CHART_PRICE_MAX) - ChartGetDouble(0, CHART_PRICE_MIN)) / 100 * 3;
  }
}

Функция relativeDistance() нужна для того, чтобы без каких-либо параметров в зависимости от таймрейма на котором работает индикатор задавать расстояние от бара с заданым индексом до wingdings-символа. А нужно это лишь потому, что если задавать процент это экрана фиксированный то, сменяя таймфреймы графиков wingdings-символ скачет выше и ниже. Т.е. хочу добиться удобства отслеживания некоторых ситуаций, которые я ищу.

Так вот.

Если индикатор работает на графике с периодом PERIOD_Н1 и я вызываю метод wingdings() вот так:

Draw :: wingdings("BullishEngulfing_" + (string)index, LOCATION_BELOW, 51, 2, clrBlue, index, PERIOD_CURRENT);

Т.е. передаю в её параметры PERIOD_CURRENT, то функция wingdings() отрабатывает не так как нужно. Такое ощущение, что косяк в операторе switch, который находится в новой функции relativeDistance(), которую я начал писать. Какое бы я не задавал значение в case PERIOD_H1 (вместо 19), расстояние не изменяется.

case PERIOD_H1:
return (ChartGetDouble(0, CHART_PRICE_MAX) - ChartGetDouble(0, CHART_PRICE_MIN)) / 100 * 19;
break;

Но, если я передаю в функцию wingdings() не PERIOD_CURRENT, а PERIOD_Н1, то всё работает.

Draw :: wingdings("BullishEngulfing_" + (string)index, LOCATION_BELOW, 51, 2, clrBlue, index, PERIOD_H1);

Я вот хочупонять как так получается. Ведь, если открытый график, на котором работает индикатор PERIOD_Н1, то PERIOD_CURRENT = PERIOD_Н1. В чём здесь ошибка может быть?

 
Виктор Демихов:

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

По сути, я начал писать для неё функцию только что вот эту:

Функция relativeDistance() нужна для того, чтобы без каких-либо параметров в зависимости от таймрейма на котором работает индикатор задавать расстояние от бара с заданым индексом до wingdings-символа. А нужно это лишь потому, что если задавать процент это экрана фиксированный то, сменяя таймфреймы графиков wingdings-символ скачет выше и ниже. Т.е. хочу добиться удобства отслеживания некоторых ситуаций, которые я ищу.

Так вот.

Если индикатор работает на графике с периодом PERIOD_Н1 и я вызываю метод wingdings() вот так:

Т.е. передаю в её параметры PERIOD_CURRENT, то функция wingdings() отрабатывает не так как нужно. Такое ощущение, что косяк в операторе switch, который находится в новой функции relativeDistance(), которую я начал писать. Какое бы я не задавал значение в case PERIOD_H1 (вместо 19), расстояние не изменяется.

Но, если я передаю в функцию wingdings() не PERIOD_CURRENT, а PERIOD_Н1, то всё работает.

Я вот хочупонять как так получается. Ведь, если открытый график, на котором работает индикатор PERIOD_Н1, то PERIOD_CURRENT = PERIOD_Н1. В чём здесь ошибка может быть?

НЕТ. Это равенство не соответствует действительности.

 
Alexey Viktorov:

НЕТ. Это равенство не соответствует действительности.

Всмысле нет? Я прикрепил скрин.

Видно же, что на скрине таймфрейм H1 т.е. PERIOD_Н1. А PERIOD_CURRENT период открытого графика. В моём случае период открытого графика т.е. согласно справке текущий период и есть H1.

Что не так?

Файлы:
Screen.png  24 kb
 

PERIOD_CURRENT это всегда 0 , для него в switch варианта не нашлось.

для некоторых (не для всех)случаев можно пролечить:

switch(PeriodSeconds(tf)) {

}

 
Maxim Kuznetsov:

PERIOD_CURRENT это всегда 0 , для него в switch варианта не нашлось.

Судя по всему, этот косяк тянется ещё с mql4. Ведь нет резона в фиксированном значении.

 
Maxim Kuznetsov:

для некоторых (не для всех)случаев можно пролечить:

switch(PeriodSeconds(tf)) {

}

Я тоже об этом изначально подумал. Но хотелось более читабельного варианта что-ли.. А так все эти enum's получается словон балласт. Вроде как они придуманы, но не выполняются свою функцию полностью.

 
Виктор Демихов:

Всмысле нет? Я прикрепил скрин.

Видно же, что на скрине таймфрейм H1 т.е. PERIOD_Н1. А PERIOD_CURRENT период открытого графика. В моём случае период открытого графика т.е. согласно справке текущий период и есть H1.

Что не так?

Вместо PERIOD_CURRENT используйте _Period или Period()

 
Виктор Демихов:

Я тоже об этом изначально подумал. Но хотелось более читабельного варианта что-ли.. А так все эти enum's получается словон балласт. Вроде как они придуманы, но не выполняются свою функцию полностью.

может не выполняют полностью функцию руки или голова?..

AnyFunc (ENUM_TIMEFRAMES tf)
{
        if(tf==PERIOD_CURRENT)
                tf=Period();
...
 
Виктор Демихов:

Судя по всему, этот косяк тянется ещё с mql4. Ведь нет резона в фиксированном значении.

"Косяк" у вас в понимании. А с PERIOD_CURRENT всё верно. Это КОНСТАНТА. И она сообщает функции, в которую её передают в качестве входного параметра периода графика, чтобы функция использовала текущий период (а уж какой он там - зависит от того, на каком таймфрейме графика запущена программа). Но это ни как не обязывает эту КОНСТАНТУ подстраивать своё значение под значение текущего графика.

 
Aleksey Mavrin:

может не выполняют полностью функцию руки или голова?..

AnyFunc (ENUM_TIMEFRAMES tf)
{
        if(tf==PERIOD_CURRENT)
                tf=Period();
...

это правильно, PERIOD_CURRENT это константа и если надо в switch ее обработать, то нужно добавить определение текущего ТФ.

 
Виктор Демихов:

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

По сути, я начал писать для неё функцию только что вот эту:

Функция relativeDistance() нужна для того, чтобы без каких-либо параметров в зависимости от таймрейма на котором работает индикатор задавать расстояние от бара с заданым индексом до wingdings-символа. А нужно это лишь потому, что если задавать процент это экрана фиксированный то, сменяя таймфреймы графиков wingdings-символ скачет выше и ниже. Т.е. хочу добиться удобства отслеживания некоторых ситуаций, которые я ищу.

Так вот.

Если индикатор работает на графике с периодом PERIOD_Н1 и я вызываю метод wingdings() вот так:

Т.е. передаю в её параметры PERIOD_CURRENT, то функция wingdings() отрабатывает не так как нужно. Такое ощущение, что косяк в операторе switch, который находится в новой функции relativeDistance(), которую я начал писать. Какое бы я не задавал значение в case PERIOD_H1 (вместо 19), расстояние не изменяется.

Но, если я передаю в функцию wingdings() не PERIOD_CURRENT, а PERIOD_Н1, то всё работает.

Я вот хочупонять как так получается. Ведь, если открытый график, на котором работает индикатор PERIOD_Н1, то PERIOD_CURRENT = PERIOD_Н1. В чём здесь ошибка может быть?

Почему-то вы заострили внимание на проблеме с PERIOD_CURRENT а вся проблема в не очень правильном подходе к проблеме. Зачем вам ТФ? Для регулирования расстояния от high и low бара достаточно цену перевести в пиксели, прибавить или вычесть N пикселей и полученное значение опять перевести в цену на которую и поставить метку.
Причина обращения: