Мультивалютный индикатор Relations

 

Только осваиваю написания индикаторов и заодно еще ООП изучаю. Подскажите, где ошибки и как лучше реализовывать индикатор. Сдуру написал такой код:

#property strict

#define MAX_BUFFERS 7

#property indicator_separate_window_window
#property indicator_buffers MAX_BUFFERS

sinput int MaxCalcBars = PERIOD_D1 * 10; // Max Calculate Bars

class INDICATOR
{
private:
  struct BUFFER
  {
    double Buffer[];
  };

  void Init( void )
  {
    ArrayResize(Buffers, Size);

    for (int i = 0; i < Size; i++)
      SetIndexBuffer(i, Buffers[i].Buffer);

    return;
  }

protected:
  BUFFER Buffers[];
  int Size;

public:

  INDICATOR( const int &Colors[] )
  {
    Size = MathMin(ArraySize(Colors), MAX_BUFFERS);

    Init();
  }

  void BuffersSetAsSeries( const bool Flag )
  {
    for (int i = 0; i < Size; i++)
      ArraySetAsSeries(Buffers[i].Buffer, Flag);

    return;
  }


  virtual int Calculate(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[])
  {
    return(rates_total);
  }
};

/*--------------------------------------------------------*/

input int period = PERIOD_H1; // Period in bars

#define EMPTY_CURRENCY ""
#define MAX_DIGITS 8

class RELATION : INDICATOR
{
private:
  struct SYMBOL
  {
    string Name;
    bool Direction;

    void SetSymbol( const string Symb, const string BaseCurrency )
    {
      Name = Symb;

      Direction = (StringSubstr(Symb, 0, 3) == BaseCurrency);

      return;
    }

    double GetLogPrice( const datetime time )
    {
      return(MathLog(iClose(Name, Period(), iBarShift(Name, Period(), time))));
    }

    double GetRelation( const datetime TimeLeft, const datetime TimeRight )
    {
      double Res = GetLogPrice(TimeRight) - GetLogPrice(TimeLeft);

      if (Direction)
        Res = -Res;

      return(Res);
    }
  };

  SYMBOL Symbols[];

  string GetBaseCurrency( const string Symbol1, const string Symbol2 )
  {
    string Currency = StringSubstr(Symbol1, 0, 3);

    if (StringFind(Symbol2, Currency) >= 0)
      return(Currency);

    Currency = StringSubstr(Symbol1, 3, 3);

    if (StringFind(Symbol2, Currency) >= 0)
      return(Currency);

    return(EMPTY_CURRENCY);
  }

public:
  RELATION( const string &SymbolList[], const int &Colors[] ) : INDICATOR(Colors)
  {
    string Currency1 = StringSubstr(Symbol(), 0, 3);
    string Currency2 = StringSubstr(Symbol(), 3, 3);

    string BaseCurrency = EMPTY_CURRENCY;

    if (Size > ArraySize(SymbolList))
    {
      Size = ArraySize(SymbolList);

      ArrayResize(Buffers, Size);
    }

    ArrayResize(Symbols, Size);

    if (Size > 1)
      BaseCurrency = GetBaseCurrency(SymbolList[0], SymbolList[1]);

    if (Currency1 == BaseCurrency)
      Currency1 = EMPTY_CURRENCY;
    else if (Currency2 == BaseCurrency)
      Currency2 = EMPTY_CURRENCY;

    IndicatorDigits(MAX_DIGITS);

    for (int i = 0; i < Size; i++)
    {
      if ((StringFind(SymbolList[i], Currency1) >= 0) || (StringFind(SymbolList[i], Currency2) >= 0))
        SetIndexStyle(i, DRAW_LINE, EMPTY, 2, Colors[i]);
      else
        SetIndexStyle(i, DRAW_LINE, EMPTY, 1, Colors[i]);

      SetIndexLabel(i, SymbolList[i]);

      Symbols[i].SetSymbol(SymbolList[i], BaseCurrency);
    }

    BuffersSetAsSeries(FALSE);

    return;
  }

  virtual int Calculate(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[])
  {
    ArraySetAsSeries(time, FALSE);

    const int Begin = MathMax(MathMax(prev_calculated - 1, rates_total - MaxCalcBars), period);
    const int SymbolsSize = ArraySize(Symbols);

    for (int i = Begin; i < rates_total; i++)
      for (int j = 0; j < SymbolsSize; j++)
        Buffers[j].Buffer[i] = Symbols[j].GetRelation(time[i - period], time[i]);

    return(rates_total);
  }
};

/*--------------------------------------------------------*/

INDICATOR* Relation;

void OnInit( void )
{
  const int Colors[] = {clrRed, clrBlue, clrSandyBrown, clrThistle, clrLime, clrSandyBrown, clrMagenta};
  const string SymbolList[] = {"EURUSD", "GBPUSD", "AUDUSD", "NZDUSD", "USDJPY", "USDCHF", "USDCAD"};

  Relation = new RELATION(SymbolList, Colors);

  return;
}

void OnDeinit( const int reason )
{
  delete Relation;

  return;
}

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[])
{
  return(Relation.Calculate(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread));
}

С помощью индикатора хотелось понять, как идет изменение каждой из валют. Вся суть индикатора в этих строках:

    double GetLogPrice( const datetime time )
    {
      return(MathLog(iClose(Name, Period(), iBarShift(Name, Period(), time))));
    }

    double GetRelation( const datetime TimeLeft, const datetime TimeRight )
    {
      double Res = GetLogPrice(TimeRight) - GetLogPrice(TimeLeft);

      if (Direction)
        Res = -Res;

      return(Res);
    }

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

Вот скрин на сегодняшнем основном новостном движении:

 

Можно видеть, что NZD сильнее всех реагировал на новость. Интересно, что по анализу показателей этого индикатора, именно NZD скачет сильнее остальных вот уже несколько крайних недель к ряду.


Можно обсудить и сам индикатор, но лично меня больше интересует, как лучше было бы написать его, с учетом возможных усложнений, внесении универсальности и мощных средств MQL. 

Файлы:
relations.mq4  6 kb
 
kbw74614:

... как лучше было бы написать его, с учетом возможных усложнений ...

За хороший зрения - сто рублей премия )))
 
artikul:
За хороший зрения - сто рублей премия )))
Ишь, медаль!.. Большая честь!..
У меня наград не счесть:
Весь обвешанный, как елка,
На спине -- и то их шесть!..
 
Переформулирую просьбу. Но сначала преамбула.

В кои то веки захотелось написать индикатор (идея этого самого Relations). Поскольку не умею этого делать совсем, да еще и ООП только начал изучать, решил подсмотреть в исходники стандартных индикаторов.

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

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

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

Сам я сделал просто класс INDICATOR с виртуальным методом Calculation. Получилось явно удобнее, чем лобовой подход. Но, очевидно, есть решения гораздо красивее.

Здесь есть представители джоба, которые клепают индикаторы почти ежедневно. Наверняка, имеются отлично зарекомендавшие себя ООП-шаблоны, которыми не стыдно и не западло поделиться с общественности. Короче, покажите, как надо писать на MQL. Как не надо - увидел в стандартных индикаторах.
 
kbw74614:

Можно видеть, что NZD сильнее всех реагировал на новость. 

а в чем, как говорят, физический смысл разности логарифмов цен ?

например, взять изменение цен EURUSD и NZDUSD в обоих случаях в 100 пунктов

double a =MathLog(1.2600) - MathLog(1.2500);

double b =MathLog(0.7700) - MathLog(0.7600);Print(DoubleToStr(a,8)," ",DoubleToStr(b,8)," ",DoubleToStr(a-b,8)); 

имеет 0.00796817 0.01307208 -0.00510391 

и что это значит, что  NZDUSD было более подвижно (а если сравнить графики EURUSD и NZDUSD) ? 

 
keekkenen:

и что это значит, что  NZDUSD было более подвижно (а если сравнить графики EURUSD и NZDUSD) ? 

Да, в вашем примере NZDUSD гораздо подвижнее EURUSD. Relations как раз и показывает, кто как реагирует на возмущения. При этом самое сильная рекция - это ширина канала Relations. Например, если на самом верху EURUSD, а в самом низу NZDUSD в показаниях Relations, то EURNZD круче (всех) реагировал. Если же USDCAD и USDJPY ближе всего друг к другу - CADJPY слабее всего реагировал на возмущение.

В общем, хотелось увидеть картину рынка более наглядно.
 

Вот такой есть вариат:

http://procapital.ru/showthread.php?t=28081&page=263&p=1838329&viewfull=1#post1838329 

 

Если не ошибаюсь - каждая линия вычисляется как разность двух МА (медл. и быстрой), периоды которых можно задать в "свойствах", по умолч.  21 и 8

 
kbw74614:
Да, в вашем примере NZDUSD гораздо подвижнее EURUSD. Relations как раз и показывает, кто как реагирует на возмущения. При этом самое сильная рекция - это ширина канала Relations. Например, если на самом верху EURUSD, а в самом низу NZDUSD в показаниях Relations, то EURNZD круче (всех) реагировал. Если же USDCAD и USDJPY ближе всего друг к другу - CADJPY слабее всего реагировал на возмущение.

В общем, хотелось увидеть картину рынка более наглядно.

NZDUSD гораздо подвижнее EURUSD..

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

 
kbw74614:

Только осваиваю написания индикаторов и заодно еще ООП изучаю. Подскажите, где ошибки и как лучше реализовывать индикатор. Сдуру написал такой код:

.....................

симпатично смотрится. почему используется логарифм?

 
_new-rena:

симпатично смотрится. почему используется логарифм?

Я тоже в подобных ситуациях использую логарифм. Разность логарифмов - это логарифм отношения. Т.е., мы смотрим на относительное изменение цены (можно в процентах). А, если автор зафиксирует время TimeLeft, тогда индикатор будет обладать свойством аддитивности:

I( t0, t1) + I( t1,t2 ) = I( t0, t2), где I() - значение индикатора для пары; t0 < t1 < t2 - моменты времени.
 
Mislaid:

Я тоже в подобных ситуациях использую логарифм. Разность логарифмов - это логарифм отношения. Т.е., мы смотрим на относительное изменение цены изменение цены (можно в процентах). А, если автор зафиксирует время TimeLeft, тогда индикатор будет обладать свойством аддитивности:

I( t0, t1) + I( t1,t2 ) = I( t0, t2), где I() - значение индикатора для пары; t0 < t1 < t2 - моменты времени.

 

да тут интереснее всего выделенное. я и без логарифмов от души навычитался ужо и понять не могу - почему сходится???. фиксация времени нужна - это факт, но это уже технический момент. буду пробовать логари. сенкс!