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 находиться на закладке
Samples*:
Следует так же иметь в виду, что коль мы используем в качестве полей объектов
класс 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".
|