Пользовательские индикаторы > TFConverter: динамический пересчет в старший таймфрейм

Дополнительные индикаторы от пользователей Альфа-Директ 4. Готовые решения от пользователей.
BugsDigger
Сообщения: 339
Зарегистрирован: 11 ноя 2018, 17:11
Благодарил (а): 21 раз
Поблагодарили: 42 раза

TFConverter: динамический пересчет в старший таймфрейм

Непрочитанное сообщение BugsDigger » 21 апр 2020, 20:42

Одно из неудобств длинных таймфреймов в АД - срабатывание стратегий только в конце свечи (с фичей сработки внутри свечи есть проблемы). А хочется так: поставить короткий ТФ (скажем, минутный), пересчитать от очередного бара набор более длинных баров (скажем получасовых) и на полученные данные напустить индикатор(ы). Получилось в таком духе:

Код: Выделить всё

function Initialize()
{
 IndicatorName = "TFConverter";
 PriceStudy=true;
 AddInput("Input", Inputs.Candle);
 
 // серии объема сделаны невидимыми, т.к. иначе индикаторы, привязанные к сериям цен, рисуются неправильно
 AddSeries("Volume",    DrawAs.Histogram, Color.Green, AxisType.ZeroBased, false, Axes.New);  // true
 AddSeries("AskVolume", DrawAs.Histogram, Color.Green, AxisType.ZeroBased, false, Axes.New);  // намеренно невидимая         
 AddSeries("BidVolume", DrawAs.Histogram, Color.Red,   AxisType.ZeroBased, false, Axes.New);  // true
 
 AddSeries("Open",  DrawAs.Line, Color.Transparent); // исходно невидимы; для визуализации выбрать цвет в окне настройки индикатора
 AddSeries("High",  DrawAs.Line, Color.Transparent);
 AddSeries("Low",   DrawAs.Line, Color.Transparent);
 AddSeries("Close", DrawAs.Line, Color.Transparent); // плохо для визуализации, т.к. скачет за последней ценой закрытия
 AddSeries("Mid",   DrawAs.Line, Color.Transparent); // (H+L)/2 ведет себя более консервативно
     
 AddParameter("OutputTF_sec", 1800);             // взять значение в скобках из таблицы внизу (или любое другое >=1)
 AddParameter("OutputHistory", 50);              // число выходных сконвертированных свечек; выбрать число, достаточне для построения индикаторов по выходным данным

 AddGlobalVariable("InputTF_sec", Types.Int, 1);
 AddGlobalVariable("Period", Types.Int, 0);      // окно во входных барах
}

function Evaluate()
{

 // вычисления можно легко перетащить для счета непосредственно в стратегию
 //========================================================
 int history=(int)OutputHistory;                 // результаты конверсии
 double[] Open_     =new double[history];        // индекс: 0-самая свежая свеча, history-1 - самая старая
 double[] Close_    =new double[history];        // т.е. индекс типа того, что для серий (но без знака!)
 double[] High_     =new double[history];
 double[] Low_      =new double[history];
 double[] Volume_   =new double[history];
 double[] AskVolume_=new double[history];
 double[] BidVolume_=new double[history];
 //========================================================
 Action<int> ConvertTF = (int period) =>
 {
  double high, low, vol, ask;
 
  int index1, index2, ci=CurrentIndex;
  for(int i=0; i<history; ++i)
  {
   index2=-i*period;
   if(index2<=-ci) break;
   index1=index2-period+1;
   if(index1<=-ci) index1=-ci+1;
 
   high=Input.High[index1];
   low =Input.Low [index1];
   vol =Input.Volume[index1];
   ask =Input.VolumeAsk[index1];
   for(int t=index1+1; t<=index2; t++)
   {
    high=Math.Max(high, Input.High[t]);
    low =Math.Min(low,  Input.Low[t]);
    vol+=Input.Volume[t];
    ask+=Input.VolumeAsk[t];
   }

   Open_ [i]=Input.Open[-index1];
   Close_[i]=Input.Close[-index2];
   High_ [i]=high;
   Low_  [i]=low;
   
   Volume_   [i]=vol;
   AskVolume_[i]=ask;
   BidVolume_[i]=vol-ask;
  }
 };
 //========================================================

 if(CurrentIndex==0)
 {
  int tf=Input.Timeframe; 
  switch(tf)
  {
   case -1:    InputTF_sec=1; break;       // 1S  (1 секунда)
   case -2:    InputTF_sec=2; break;       // 2S  (2)
   case -3:    InputTF_sec=3; break;       // 3S  (3)
   case -4:    InputTF_sec=4; break;       // 4S  (4)
   case -5:    InputTF_sec=5; break;       // 5S  (5)
   case -6:    InputTF_sec=6; break;       // 6S  (6)
   case -10:   InputTF_sec=10; break;      // S10 (10)
   case -12:   InputTF_sec=12; break;      // S12 (12)
   case -15:   InputTF_sec=15; break;      // S15 (15)
   case -20:   InputTF_sec=20; break;      // S20 (20)
   case -30:   InputTF_sec=30; break;      // S30 (30)
   case 1:     InputTF_sec=60; break;      // M1  (60)
   case 2:     InputTF_sec=60*2; break;    // M2  (120)
   case 3:     InputTF_sec=60*3; break;    // M3  (180)
   case 4:     InputTF_sec=60*4; break;    // M4  (240)
   case 5:     InputTF_sec=60*5; break;    // M5  (300)
   case 6:     InputTF_sec=60*6; break;    // M6  (360)
   case 10:    InputTF_sec=60*10; break;   // M10 (600)
   case 12:    InputTF_sec=60*12; break;   // M12 (720)
   case 15:    InputTF_sec=60*15; break;   // M15 (900)
   case 20:    InputTF_sec=60*20; break;   // M20 (1200)
   case 30:    InputTF_sec=60*30; break;   // M30 (1800)
   case 60:    InputTF_sec=3600; break;    // H1  (3600)
   case 60*2:  InputTF_sec=3600*2; break;  // H2  (7200)
   case 60*3:  InputTF_sec=3600*3; break;  // H3  (10800)
   case 60*4:  InputTF_sec=3600*4; break;  // H4  (14400)
   case 60*6:  InputTF_sec=3600*6; break;  // H6  (21600)
   case 60*8:  InputTF_sec=3600*8; break;  // H8  (28800)
   case 60*12: InputTF_sec=3600*12; break; // H12 (43200) чисто по времени
// case 60*24: InputTF_sec=3600*24; break; // D1  (86400) чисто по времени, но дневные бары на самом деле считают с учетом длительности дневной сессии
   case 60*24: InputTF_sec=60*(60*8+45); break; // D1 (31500) день с учетом длительности дневной сессии; выходит меньше, чем для TF=12H
   default:    InputTF_sec=0; break;
  }
 
  if(InputTF_sec!=0)
  {
   Period=(int)(OutputTF_sec/InputTF_sec+0.5);
   if(Period<1) Period=1;
  }
  else Period=1;
 }


 // ConvertTF((int)Period); // выходные числовые данные можно использовать в расчетах

 // визуализация; меняет данные в прошлом, серии нельзя использовать при тестировании стратегий!
 if(CurrentIndex==MaxIndex)
 {
  ConvertTF((int)Period);

  double hi, lo; 
  int si;
  for(int t=0; t<history; t++) 
  {
   si=t*Period;
   Open [si]    =Open_ [t];
   Close[si]    =Close_[t];
   High [si]=hi =High_ [t];
   Low  [si]=lo =Low_  [t];
   Mid  [si]=(hi+lo)/2.0;
   Volume[si]   =Volume_[t];
   AskVolume[si]=AskVolume_[t];
   BidVolume[si]=BidVolume_[t];
  }
 }
}

TFConverter.png

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

К сожалению, непосредственно на результаты пересчета можно напустить только "точечные" (Input.Price) индикаторы; "свечные" же (Input.Candle) придется переписывать.

Аватара пользователя
Tyler_Durden
Сообщения: 65
Зарегистрирован: 01 дек 2017, 20:42
Благодарил (а): 6 раз

Re: TFConverter: динамический пересчет в старший таймфрейм

Непрочитанное сообщение Tyler_Durden » 21 апр 2020, 23:33

Визуально похоже на скользящие средние. Какое запаздывание, не смотрели?

BugsDigger
Сообщения: 339
Зарегистрирован: 11 ноя 2018, 17:11
Благодарил (а): 21 раз
Поблагодарили: 42 раза

Re: TFConverter: динамический пересчет в старший таймфрейм

Непрочитанное сообщение BugsDigger » 22 апр 2020, 07:35

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

BugsDigger
Сообщения: 339
Зарегистрирован: 11 ноя 2018, 17:11
Благодарил (а): 21 раз
Поблагодарили: 42 раза

Re: TFConverter: динамический пересчет в старший таймфрейм

Непрочитанное сообщение BugsDigger » 22 апр 2020, 12:27

Ну в общем, как м.б. и следовало ожидать, ход, скажем, EMA от пересчитанного довольно точно повторяет ход EMA эквивалентной длины по исходному, т.е. если первое сглаживается по периоду 10 точек на пересчитанной 15-тиминутке, то второе, сглаженное по 150, - примерно то же самое. Тупиковая ветвь эволюции. :D

P.S.
Стандартный индикатор вроде нормально применяется к "разреженным точкам", которые у меня формируются (я добавляю их в серию с разрывом по индексам). Good to know.


Вернуться в «Пользовательские индикаторы»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя