.
Пишем класс статистического анализа индикатора (TGauge, virtual, abstract, momentum).
Автор megabax   
12.11.2009 г.
New Page 1

Пишем класс статистического анализа индикатора (TGauge, virtual, abstract, momentum).

Все статьи по данной теме.

В этом уроке вам понадобиться материал (программные коды) предыдущих уроков:

Сегодня мы реализуем класс для статистического анализа индикатора, согласно постановки задачи, поставленной на прошлом уроке. Для начала объявим шаблон класса:

TPASSStatAnalizTemplate=class(TObject)
protected
     FIndicator:TPASSIndicator;
     FProfitChange:double;
     FDrawdownChange:double;
     FLastSignalPrice:double; // Цена открытия свечи сведущей за прошлым сигналом
     FAnalizCandleCount:LongInt; //Количество анализируемых свечей
     FSignalType:TPASSSignalsTypes;
     FParameters:TPASSParameters;
     FStoreData:TPASSStatStoreDataTemplate;
     procedure SaveTestResult;
public
     Gauge:TGauge;
     constructor Create(AIndicator:TPASSIndicator; AAnalizCandleCount:LongInt; AStoreData:TPASSStatStoreDataTemplate);
     function FindSignal:boolean; virtual; abstract;
     function FindSignalRotate:boolean; virtual; abstract;//поиск сигнала, обратного найденному
     procedure GetChange;
     procedure Test;
     Destructor Destroy;
end;
 

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

  • FIndicator - в этом поле у нас храниться ссылка на индикатор. Так как типом является базовый класса TPASSIndicator, то в дальнейшем мы можем хранить в этом поле ссылку на любой индикатор (а не только momentum), примем, как созданный ранее, так и созданный в дальнейшем.
  • FProfitChange - в этом поле мы будем хранить максимальный профит за заданное количество свечей, рассчитанный для текущего сигнала.
  • FDrawdownChange - в этом поле мы будем хранить максимальный убыток за заданное количество свечей, рассчитанный для текущего сигнала.
  • FLastSignalPrice - сигнальная цена текущего сигнала. В качестве сигнальной берем цену открытия интервала, следующего за сигнальным. Иными словами, если у нас интервал равен одному дню, то получив сигнал сегодня вечером мы сделку совершаем завтра утром.
  • FAnalizCandleCount - здесь мы храним то количество свечей, за которое будем анализировать максимальный профит (дродаун).
  • FSignalType - тип сигнала: покупка или продажа. Данный тип у нас объявлен в новой версии модуля PASSBaseObj. Скачать новую версию можно здесь.
  • FParameters - в этом поле храниться список параметров. Каждый параметр это пара имя - значение. Результат работы класса мы помещаем в параметры. Это нужно для того, что бы наша библиотека была более универсальной. Поясню сказанное: при тестировании индикатора у нас результаты вычислений будут передаваться другому объекту для обработки.  Иметь список пар "имя - значение" гораздо универсальнее, чем просто структура с заданными полями.

  • FStoreData - ссылка на класс, который будет обрабатывать результаты вычислений.

Теперь рассмотрим процедуру SaveTestResult. Она то как раз и будет передавать результаты вычисления другому классу. Вот как реализован данный метод:

procedure TPASSStatAnalizTemplate.SaveTestResult;
begin
      FStoreData.AddData(FParameters);
end;

Теперь перейдем к разделу Public:

  • Gauge - ссылка на прогресс бар (TGauge). Если у нас тестирование будет идти долго, то мы сможем видеть прогресс выполнения:

класс статистического анализа индикатора (TGauge, virtual, abstract, momentum)

Сам компонент TGauge находиться на закладке Samples*:

класс статистического анализа индикатора (TGauge, virtual, abstract, momentum)

Следует так же иметь в виду, что коль мы используем в качестве полей объектов класс TGauge, то в разделе uses модуля, где у нас объявлен данный класс, следует добавить Gauges:

uses PASSIndicators, PASSBaseObj, SysUtils, classes, Gauges;

А теперь перейдем к остальным методам класса TPASSStatAnalizTemplate:

  • Create - метод конструктор, создающий объект. Ему мы передаем анализируемый индикатор; количество свечей после сигнала, за которые анализируем индикатор и объект, обрабатывающий результаты вычисления. вот как он реализован:
constructor TPASSStatAnalizTemplate.Create(AIndicator:TPASSIndicator; AAnalizCandleCount:LongInt; AStoreData:TPASSStatStoreDataTemplate);
begin
inherited Create;
    FIndicator:=AIndicator;
    FAnalizCandleCount:=AAnalizCandleCount;
    FStoreData:=AStoreData;
    FParameters:=TPASSParameters.Create;
    FParameters.Add('ProfitChange',0, ptFloat);
    FParameters.Add('DrawdownChange',0, ptFloat);
    FParameters.Add('SignalResult',enBuy, ptSignal);
    FParameters.Add('SignalDate',0, ptData);
    FParameters.Add('ProfitChangeSign',enBuy, ptFloat);
end;

В конструкторе мы инициируем начальные значения полей, которые являются входными параметрами алгоритма. Заполнения начальных значений происходит из переданных параметров. Затем мы создаем объект класса TPASSParameters, где у нас будут храниться результаты вычислений и добавляем туда нужные параметры.

  • FindSignal - данный метод позиционирует указатель на следующий сигнал. Так как мы можем анализировать разные типы сигналов, при чем на одном и том же индикаторе, то данный метод мы пока объявили абстрактным. Его мы реализуем в дочерних классах.
  • FindSignalRotate - указатель позиционируется на сигнал, противоположный только что найденному. Это нужно, так как у нас в постановке задачи есть требование, что нужно подчитать статистку по прибыли (убытку), если мы вошли в позицию по сигналу и вышли по противоположному сигналу.  Данный метод так же реализуем в дочерних класса, здесь он абстрактный.

  • GetChange - этой процедурой мы производим расчет максимальной прибыли и дродауна за указанное количество интервалов FAnalizCandleCount:

procedure TPASSStatAnalizTemplate.GetChange;
var  CurrentItemIndex, I:LongInt; BarData:TBarStructure;
       FMaxPrice, FMinPrice:double;
begin
      CurrentItemIndex:=FIndicator.PriceSource.CurrentItemIndex;
      FLastSignalPrice:=FIndicator.PriceSource.GetDataByFieldNameAndIndex('Open',CurrentItemIndex+1);
      if FLastSignalPrice=0 then raise exception.Create('TPASSStatAnalizTemplate.TPASSStatAnalizTemplate - нулевое значение последней цены. Свеча '+
             DateTimeToStr(FIndicator.PriceSource.GetBarData.DateTime));
      FMinPrice:=FLastSignalPrice;
      FMaxPrice:=FLastSignalPrice;
      for I:=1 to FAnalizCandleCount do
      begin
          if not(FIndicator.Next) then break;
          BarData:=FIndicator.PriceSource.GetBarData;
          if BarData.Hight>FMaxPrice then FMaxPrice:=BarData.Hight;
          if BarData.Low<FMinPrice then FMinPrice:=BarData.Low;
      end;
      if FSignalType=enBuy then
      begin
          FProfitChange:=(FMaxPrice-FLastSignalPrice)/FLastSignalPrice;
          FDrawdownChange:=(FLastSignalPrice-FMinPrice)/FLastSignalPrice;
      end else
      begin
         FProfitChange:=(FLastSignalPrice-FMinPrice)/FLastSignalPrice;
         FDrawdownChange:=(FMaxPrice-FLastSignalPrice)/FLastSignalPrice;
      end;
      FIndicator.PriceSource.CurrentItemIndex:=CurrentItemIndex;
end;

Эта процедура будет у нас вызываться из алгоритма тестирования в тот момент, когда найден очередной сигнал. Сперва идет поиск минимальной и максимальной котировки в цикле с заданным количество повторений:

      for I:=1 to FAnalizCandleCount do
      begin
          if not(FIndicator.Next) then break;
          BarData:=FIndicator.PriceSource.GetBarData;
          if BarData.Hight>FMaxPrice then FMaxPrice:=BarData.Hight;
          if BarData.Low<FMinPrice then FMinPrice:=BarData.Low;
      end;

Затем, в зависимости от того, какой был сигнал, на покупку или на продажу, вычисляем максимальную прибыль и дродаун. Если у нас был сигнал на покупку, то максимальная прибыль это разница между максимальной и сигнальной ценой, а дродаун - разница между сигнальной и минимальной. При сигнале на продажу наоборот.

  • Test - а это, у нас, собственно говоря, процедура, производящая расчеты для тестирования  сигналов индикатора:

procedure TPASSStatAnalizTemplate.Test;
var CurrentItemIndex:integer; LastSignalPrice:double; SignalType: TPASSSignalsTypes;
       SignalPrice:double;
begin
    while FindSignal do
    begin
       if FAnalizCandleCount+FIndicator.PriceSource.CurrentItemIndex>FIndicator.PriceSource.CountLoadedBars then exit;
      GetChange; //узнаем изменения на заданный диапазон времени
      Gauge.Progress:=FIndicator.PriceSource.CurrentItemIndex;
      FParameters.SetParameterByName('ProfitChange',FProfitChange);
      FParameters.SetParameterByName('DrawdownChange',FDrawdownChange);
      FParameters.SetParameterByName('SignalResult',FSignalType);
      FParameters.SetParameterByName('SignalDate',FIndicator.PriceSource.GetBarData.DateTime);
      SignalType:=FSignalType;
      CurrentItemIndex:=FIndicator.PriceSource.CurrentItemIndex;
      LastSignalPrice:=FLastSignalPrice;
      if not(FindSignalRotate) then exit;
      if FLastSignalPrice=0 then raise Exception.Create('TPASSStatAnalizTemplate.Test - нулевая цена сигнала');
      FIndicator.PriceSource.NextItem;
      SignalPrice:=FIndicator.PriceSource.GetBarData.Open;
      if SignalType=enBuy then
           FParameters.SetParameterByName('ProfitChangeSign',(SignalPrice-FLastSignalPrice)/FLastSignalPrice)
      else
           FParameters.SetParameterByName('ProfitChangeSign',(FLastSignalPrice-SignalPrice)/FLastSignalPrice);
      FIndicator.PriceSource.CurrentItemIndex:=CurrentItemIndex+1;
      SaveTestResult();
   end;
end;

в данной процедуре мы в цикле перебираем все сигналы и вычисляем результаты тестирования, а потом передаем их объекту FStoreData для обработки.

  • Нам осталось рассмотреть деструктор:
Destructor TPASSStatAnalizTemplate.Destroy;
begin
    FParameters.Free;
    inherited Destroy;
end;

В данном деструкторе мы очищаем объект FParameters - мы его создали, мы его и удалим. А вот что касается FStoreData - то это объект переданный извне, в данном деструкторе его уничтожать не нужно.

Перейдем к следующему классу TPASSStatStoreDataTemplate (его нужно разместить впереди объявления класса TPASSStatAnalizTemplate)- это у нас тоже класс-шаблон:

TPASSStatStoreDataTemplate=class(TObject)
public
     procedure AddData(AParameters:TPASSParameters); virtual; abstract;
end;

Как видим, у него всего лишь один метод, да и тот абстрактный.

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


Скриншоты, помеченные знаком * , являются цитатами и иллюстрациями  в соответствии со ст. 1274 ГК РФ программного продукта "Delphi", авторское право на который принадлежит "Borland Software Corporation".

 

Последнее обновление ( 27.07.2013 г. )