Любой вопрос новичка, чтоб не захламлять форум. Профи, не проходите мимо. Без вас никуда - 6. - страница 641

 
simpleton:

А зачем эмулировать ошибку?

Ошибка - она для сигнализации того, что по каким-то причинам, связанным с ограничениями/отказами системы, не удалось выполнить алгоритм и получить результат с какими-то (естественно, ограниченными, но - ) гарантиями. Функция FillAndPrint() как раз красноречиво и показывает, что значит ошибочная ситуация, а что - нет. Когда возникает ошибка, она даже не пытается выдавать результат. Если же ошибки не возникло, результату можно доверять. Именно таким образом должна строиться логика "ошибка/не ошибка".

Здесь же нужна модификация алгоритма: требуется ещё наложить дополнительный фильтр.

Так и надо сделать:

Сначала "отфильтровали" по типам и параметрам объектов, выбрав из всех имеющихся объектов только нужные нам, а затем наложили дополнительный фильтр. Примерно, как это делал бы человек. Человек, ведь, примерно так и делал бы?

Для каждой такой маленькой подзадачки напрашивается отдельная функция.

Чисел в выражениях не должно быть, кроме очень особых случаев, например, если надо удвоить, и это удвоение - в природе алгоритма. Тогда можно использовать число 2 напрямую в выражениях. И в других подобных очень редких случаях.

В остальных случаях следует использовать мнемоники. Во-первых, они значительно улучшают понимание того, что в данном месте происходит, и поэтому способствуют уменьшению вероятности допустить ошибки. А, во-вторых, само значение задано в одном месте, и его легко при необходимости поменять, причём ошибиться уже будет невозможно по сравнению со случаем, когда число используется в алгоритме неоднократно, и без использования мнемоник приходится править числа в нескольких местах алгоритма.

Результат прогона:

Ни одного объекта не найдено. Увеличим значения обоих мнемоник в 10 раз до 36000 (10 часов) и прогоним ещё раз:

Одна трендовая уже "прошла" фильтрацию. Теперь восстановим значение первой мнемоники до 3600 и прогоним:

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

Чтобы помочь как-то формализовывать, попробую так объяснить. Программа, видимо, подобна плану.

Каждый крупный пункт плана может быть разбит на пункты более мелкого подплана. Мелкий - на ещё более мелкий. Пункты самых мелких подпланов исполняются непосредственно.

Каждый план, подплан и даже пункты самых мелких подпланов соответствует функциям в программе. Пункты самых мелких подпланов соответствуют "концевым" функциям, которые вызывают только системные функции или даже их не вызывают, например, в обсуждаемых выше в качестве примера можно привести AddValue() или DiffInSecs(). Пункты подпланов, стоящих выше, соответствуют функциям, которые вызывают функции, реализующие пункты подпланов, стоящих ниже. В обсуждаемых выше это - MassTrendNumber(), AddValueIfFound(), AddValueIfFiltered(). "Низкоуровневые" функции не должны вызывать "высокоуровневые", а "высокоуровневые", в основном, не должны перескакивать на несколько уровней вниз, то есть, должны вызывать функции, в основном, только на уровень ниже. Для "низкоуровневых" это правило намного строже, чем для "высокоуровневых".

Попробуйте строить свои программы, организуя действия в них в виде (коротких) функций, связанных такой вот древовидной структурой, в смысле, кто кого вызывает.

В данной программе получилось вырожденное дерево: одна несколько раз "ветвящаяся" ветвь. И "ветвится" она не на две маленьких ветви, а на одну. Но суть, что "высокоуровневые" функции последовательно вызывают "низкоурвневые", прослеживается. В данной модификации я вставил в эту структуру ещё один уровень, ещё одну "неразветвлённую ветвь" - AddValueIfFiltered().

Выкладываю готовый код. 

Задача: Поиск линий тренда (OBJ_TREND), запись значений цены относительно текущего бара в массив. С фильтрацией относительно существования параметров времени объекта (OBJ_TREND).

 

#property strict

/******************************************************************************/
bool AddValue(double &array[], const double value) {
  const int size = ArraySize(array);

  if (ArrayResize(array, size + 1) != size + 1) {
    return false; // Ошибка, значение не может быть добавлено к массиву
  }

  array[size] = value; //записываем
  return true; // Нет ошибки, значение добавлено к массиву
}

/******************************************************************************/
bool AddValueIfFound(double &array[], const string name) {
  const int type = ObjectType(name);

  if (type == OBJ_TREND) {
    switch ((color)ObjectGet(name, OBJPROP_COLOR)) { // Тип color допустимо использовать в switch
    case Goldenrod:
    case Gainsboro:
    case White:
      if (!AddValueIfFiltered(array, name)) { // Пропускаем через фильтр
        return false;
      }
    }
  }

  return true; // Нет ошибки, значение, если найдено, добавлено к массиву
}
/******************************************************************************/
bool MassTrendNumber(double &array[], const bool buy) { // Поиск значения цены трендовой линии, текущего бара, запись в массив. Два массива: masS и masB
  const string subname = (buy ? "uptrendline" : "downtrendline"); // существует два названия трендовых линий, первое и второе

  if (ArrayResize(array, 0) != 0) {
    return false; // Ошибка, массив не может быть заполнен достоверно
  }

  for (int i = 0, limit = ObjectsTotal(OBJ_TREND); i < limit+2; i++) {
    if (!AddValueIfFound(array, subname + IntegerToString(i))) {
      return false; // Ошибка, массив, если и заполнен, то недостоверно
    }
  }
 
  return true; // Нет ошибки, массив заполнен достоверно
}
/******************************************************************************/
long DiffInSecs(const datetime dt1, const datetime dt2) {
  return dt1 - dt2;
}
/******************************************************************************/
bool AddValueIfFiltered(double &array[], const string name) {
#define MIN_SECS_BETWEEN_PRICE1_AND_PRICE2 3600
#define MAX_SECS_AFTER_PRICE2              3600

  const datetime dt1 = (datetime)ObjectGet(name, OBJPROP_TIME1);
  const datetime dt2 = (datetime)ObjectGet(name, OBJPROP_TIME2);
  const datetime dt = TimeCurrent();
  
  Print("name = ", name,// ", dt = ", dt, ", dt1 = ", dt1,"\n", 
  " DiffInSecs = ", DiffInSecs(dt,dt2)," DiffInSecs = ", DiffInSecs(dt2,dt1));

   if( DiffInSecs(dt,dt2)>MAX_SECS_AFTER_PRICE2 && DiffInSecs(dt2,dt1)> MIN_SECS_BETWEEN_PRICE1_AND_PRICE2){
    if (!AddValue(array, ObjectGetValueByShift(name, 1))) { // Пытаемся добавить
      return false; // Ошибка, значение не добавлено
    }
  }

  return true; // Нет ошибки, значение, если удовлетворило условию фильтра, добавлено к массиву
}

/******************************************************************************/
void FillAndPrint(double &array[], const bool buy) {
  if (MassTrendNumber(array, buy)) {
    const int limit = ArraySize(array);

    Print("Найдено объектов: ", limit);

    for (int i = 0; i < limit; i++) {
      Print("Price[", i, "] = ", DoubleToStr(array[i], Digits));
    }
  } else {
    Print("Чёрт!");
  }
}

/******************************************************************************/
void OnTick()

//=============================================================================================
//====================================== Линии тренда =========================================
//=============================================================================================
 double masS[]; double masB[];

  Print("Sell:");
  FillAndPrint(masS, false);

  Print("Buy:");
  FillAndPrint(masB, true);
 simpletonСпасибо вам большое, вы за пестовали меня на ощущения правильного кода!) (Правда я немногое понял))))
 
evillive:

У меня сейчас 4-знак, на евордолларе при 1 лоте 1 пункт стоит 10 долларов и всегда так было. Для кроссов  стоимость будет от 8 до 16, там формула сложнее немного.

Вот, например, маркетинфо для еврофунта вернул 16,984,  курс фунта к доллару = 1,6984, то есть 1 пункт еврофунта стоит 1 фунтдоллар умноженный на стоимость пункта фунтодоллара, которая равна всегда 10,0 (100000*0,0001=10,0 или 100000*0,00010=10,0 - кому как нравится).


Все эти вычисления верны только при условии что счёт ваш в долларах:

В таком случае, для хUSD (EURUSD, GBPUSD etc) tickvalue = lot*point = 100000*0.0001 = 10,0

для USDх (USDCHF, USDJPY etc) tickvalue = lot*point/Bid = 100000*0.01/101.93=9,8107

для кросс-курсов xUSD/yUSD (EURGBP) tickvalue = Bid(yUSD)*lot*point = 1.6980*100000*0.0001 = 16,98

для кроссов xUSD/USDy (EURJPY) tickvalue = lot*point/Bid(USDy) = 100000*0.01/101.91=9,8126


Что-то вы напутали! Нашёл время заглянуть в код, выбрал выражения, и смотрите: 

  double TV = MarketInfo(Symbol(),MODE_TICKVALUE); 
  string sTV = DoubleToStr(TV,4); 
  Comment("TV ",sTV); //sTV = 1.0/Bid

Проще не может быть! Никаких 10, 16 и т.д. 

 
evillive:

У меня сейчас 4-знак, на евордолларе при 1 лоте 1 пункт стоит 10 долларов и всегда так было. Для кроссов  стоимость будет от 8 до 16, там формула сложнее немного.

Вот, например, маркетинфо для еврофунта вернул 16,984,  курс фунта к доллару = 1,6984, то есть 1 пункт еврофунта стоит 1 фунтдоллар умноженный на стоимость пункта фунтодоллара, которая равна всегда 10,0 (100000*0,0001=10,0 или 100000*0,00010=10,0 - кому как нравится).


Все эти вычисления верны только при условии что счёт ваш в долларах:

В таком случае, для хUSD (EURUSD, GBPUSD etc) tickvalue = lot*point = 100000*0.0001 = 10,0

для USDх (USDCHF, USDJPY etc) tickvalue = lot*point/Bid = 100000*0.01/101.93=9,8107

для кросс-курсов xUSD/yUSD (EURGBP) tickvalue = Bid(yUSD)*lot*point = 1.6980*100000*0.0001 = 16,98

для кроссов xUSD/USDy (EURJPY) tickvalue = lot*point/Bid(USDy) = 100000*0.01/101.91=9,8126


borilunad:

Это неправильно! Значность котировки не имеет значения! А стоимость мин.тика нужно вычислять от текущей цены! Что равно TICK_VALUE! Выше привёл пример из моего кода.
 
borilunad:

borilunad:

Это неправильно! Значность котировки не имеет значения! А стоимость мин.тика нужно вычислять от текущей цены! Что равно TICK_VALUE! Выше привёл пример из моего кода.

И чем же неправильно? Маркетинфо возвращает те же значения что получаются по приведённым мной выше формулам. Эти формулы не я придумал, они используются терминалом для вычисления TickValue )))

Понятно, что удобнее получать значение из маркетинфо, но человек спрашивал именно формулы или метод расчёта, так вот они выше.

А про значность я так и писал раньше, что не имеет значения, потому что на пятизнаке считается пункт = 10пипс, а это тот же пункт из 4-знака.

 
evillive:

И чем же неправильно? Маркетинфо возвращает те же значения что получаются по приведённым мной выше формулам. Эти формулы не я придумал, они используются терминалом для вычисления TickValue )))

Понятно, что удобнее получать значение из маркетинфо, но человек спрашивал именно формулы или метод расчёта, так вот они выше.

А про значность я так и писал раньше, что не имеет значения, потому что на пятизнаке считается пункт = 10пипс, а это тот же пункт из 4-знака.


Да я о том же, что MarketInfo(Symbol(),MODE_TICKVALUE) 1.0/Bid; Может, только для евродоллара, на другие не распыляюсь!
 
borilunad:

Да я о том же, что MarketInfo(Symbol(),MODE_TICKVALUE) 1.0/Bid; Может, только для евродоллара, на другие не распыляюсь!

Вот это-то как раз для евродоллара неправильно, исходя из данного в справке определения

MODE_TICKVALUE

16

Размер минимального изменения цены инструмента в валюте депозита


А это значит надо умножить

MODE_POINT

11

Размер пункта в валюте котировки. Для текущего инструмента хранится в предопределенной переменной Point


на

MODE_LOTSIZE

15

Размер контракта в базовой валюте инструмента


Ну конечно, если у вас счёт в евро, тогда плясать надо от евро, но для трейдеров, у кого счёт всё же в долларах (а таких большинство), приведённые выше формулы действительны. А так как главные и самые торгуемые пары на основе доллара США, то данные формулы чаще всего и используются.

 
evillive:

Вот это-то как раз неправильно, исходя из данного в справке определения

MODE_TICKVALUE

16

Размер минимального изменения цены инструмента в валюте депозита


А это значит надо умножить

MODE_POINT

11

Размер пункта в валюте котировки. Для текущего инструмента хранится в предопределенной переменной Point


на

MODE_LOTSIZE

15

Размер контракта в базовой валюте инструмента


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


Ну тогда, у меня частный случай, но для меня, живущего в еврозоне, удобнее все расчёты вести в евро! 
 

Господа, подскажите пример кода для следующиего индикатора. Никак не разберусь сколько буферов нужно, какой тип отображения и где и какие свойства им нужно прописать.

Индикатор такой: 

1 Отрезками соединяются минимум каждого третьего бара и соседнего. Линяя красная.

2 Отрезками соединяются максимумы каждого 5го бара и соседнего. Линяя синяя.

Главное: отрезки никак не пересекаются. Начало и конец каждого отрезка независим от остальных отрезков.

 

Индикатор рассчитывает значения  начала и конца каждого отрезка. В зависимости от условий они должны окрашивать в разные цвета.

Примерно как это должно выглядить


 

И еще вопрос.

Нормально ли, что не получается с индикатором работать в режиме Отладки.

Когда программа доходит до точки остановки, терминал МТ4 подвисает и окно становится белым (в вин ХР) так что не возможно увидеть что нарисовано на графике 

 
Top2n:

Выкладываю готовый код. 

Задача: Поиск линий тренда (OBJ_TREND), запись значений цены относительно текущего бара в массив. С фильтрацией относительно существования параметров времени объекта (OBJ_TREND).

 simpletonСпасибо вам большое, вы за пестовали меня на ощущения правильного кода!) (Правда я немногое понял))))

Если тренироваться, понимание будет приходить, всё больше и больше. Нужно сосредоточение и внимательность. Когда алгоритм программы размазан по одной большой функции, сосредоточенно и внимательно его реализовать затруднительно - слишком много образуется связей. Если же программа разбита на функционально законченные части (небольшие функции), то для каждой отдельной небольшой функции сделать это уже значительно проще. И так на каждом уровне функций. Кстати:

   if( DiffInSecs(dt,dt2)>MAX_SECS_AFTER_PRICE2 && DiffInSecs(dt2,dt1)> MIN_SECS_BETWEEN_PRICE1_AND_PRICE2){
    if (!AddValue(array, ObjectGetValueByShift(name, 1))) { // Пытаемся добавить
      return false; // Ошибка, значение не добавлено
    }
  }
Наверное, я неудачно назвал мнемонику MAX_SECS_AFTER_PRICE2 (потому что сначала я так понял, что условие должно быть обратным), по смыслу, наверное, должно быть MIN_SECS_AFTER_PRICE2, то есть, минимально допустимое, а не максимально.
Причина обращения: