Реализуем класс для расчета индикатора momentum (используем библиотеки и AfterConstruction, наследуемый от TObject)
Сегодня мы займемся реализацией биржевого робота. Точнее будем выполнять задачу, поставленную на уроке "Постановка задачи". Для начала нужно скачать с сайта www.easyprog.ru нужные библиотеки (PASSBaseObj и PASSIndicators). Теперь создадим в Delphi новый проект, скопируем туда закаченные библиотеки и добавим их в проект*:
В раздел uses добавим подключенные к проекту модули PASSIndicators, PASSBaseObj:
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, PASSIndicators, PASSBaseObj; |
TPASSMomentum=class(TPASSIndicator) private FDT:integer; // длительность периода в интервалах FPriceFieldType:string; //тип ценового поля (Open, High, Low, Close); procedure UpdateParameters; virtual; procedure AfterConstruction; override; protected FParameters:TPASSParameters; // значения параметров индикатора. FPriceSource:TPASSPriceSource; // источник котировок. public constructor Create(ADT:integer; APriceFieldType:string); function GetResultByFieldName(AFieldName:string):double; override; function GetResultByFieldNameAndIndex(AFieldName:string; Index:LongInt):double; override; function GetResultByFieldNum(AFieldNum:integer):double; override; function GetResultByFieldNumAndIndex(AFieldNum:integer; Index:LongInt):double; override; procedure First; override; procedure Last; override; function Next:boolean; override; function Prev:boolean; override; function GetIndicatorName:string; override; end; |
Данный класс мы объявили как дочерний от класса TPASSIndicator - это базовый класс индикатора. В модуле PASSIndicators есть еще класса TPASSAverageIndicator, объявленный как дочерний от PASSIndicators, он служит родительским классом для TPASSMASimple и TPASSADX, которые реализует индикаторы Moving Average. ADX соответственно. Но индикатор momentum, не является индикатором скользящего среднего и для своего расчета не требует буфера расчета среднего значений котировок, поэтому мы используем в качестве родительского класса TPASSIndicator.
Класс TPASSIndicator имеет абстрактный метод UpdateParameters, поэтому мы обязаны переопределить его в нашем классе. Это мы делаем в секции private, так как данная процедура вызывается только из методов класса индикатора и предназначена для переписывания значений параметров из списка параметров в приватные поля класса. Почему именно так? Дело в том, что при создании библиотек PASSBaseObj и PASSIndicators предполагалось, что они будут использованы для серьезного приложения, похожего на Metatrader или Metastock. А приватные поля используются только главным образом для быстродействия, так как если обращаться через имя параметра, то нужно будет искать его в списке, что замедлит работу программы. Это замедление почувствуется, когда нужно будет делать много расчетов во вложенных циклах.
В процедуре AfterConstruction, которая наследуется от TObject, являющийся предком всех классов в библиотеках, будет просто вызвана процедура UpdateParameters, поскольку в TPASSIndicator это не сделано. Конечно, правильнее было бы переопределить AfterConstruction непосредственно в TPASSIndicator, но рефреймингом кода мы займемся потом, а сейчас наша задача поскорее создать индикатор и исследовать его.
Так мы же определяем конструктор класса, что бы создать объект класса на основании параметров. И переопределяем все абстрактные методы класса TPASSIndicator . Кроме того, мы поля FParameters и FPriceSource из секции private переносим в секцию protected, просто объявив их как protected в дочернем классе. Это нужно для того, что бы эти поля стали доступные в дочернем классе но были по прежнему недоступные извне.
А теперь займемся реализацией. Начнем с UpdateParameters
procedure TPASSMomentum.UpdateParameters; var i,cn:integer; begin cn:=FParameters.Count-1; for i:=0 to cn do begin if UpperCase(FParameters[i].Name)='DT' then FDT:=FParameters[i].Value else begin if UpperCase(FParameters[i].Name)='PRICEFIELDTYPE' then FPriceFieldType:=FParameters[i].Value else raise Exception.Create('No correct parameter name '+FParameters[i].Name); end; end; end; |
Здесь мы просто тупым перебором перебираем параметры и устанавливаем соответствующие приватные поля. В списке есть параметр, которое не соответствует ни одному приватному полю, то это нонсенс. Такого быть не должно. Сразу вызываем исключение.
Далее реализуем метод AfterConstruction и сам конструктор:
procedure TPASSMomentum.AfterConstruction; begin UpdateParameters; end; constructor TPASSMomentum.Create(ADT:integer; APriceFieldType:string); begin inherited Create; FParameters.Add('DT',ADT); FParameters.Add('PriceFieldType',APriceFieldType); end; |
Методы GetResultByFieldName и GetResultByFieldNameAndIndex предназначены для получение значения индикатора по имени функции (у индикаторов может быть несколько функций, например у ADX есть функции DI+, DI- и само ADX). У нашего же индикатора только одна функция - Value. Реализуем получение значения по имени этой функции:
function TPASSMomentum.GetResultByFieldName(AFieldName:string):double; begin if UpperCase(AFieldName)<>'VALUE' then Raise Exception.Create('TPASSMomentum.GetResultByFieldName: Неверное имя поля - '+AFieldName); Result:=GetResultByFieldNum(0); end; function TPASSMomentum.GetResultByFieldNameAndIndex(AFieldName:string; Index:LongInt):double; begin if UpperCase(AFieldName)<>'VALUE' then Raise Exception.Create('TPASSMomentum.GetResultByFieldNameAndIndex: Неверное имя поля - '+AFieldName); Result:=GetResultByFieldNumAndIndex(0,index); end; |
function TPASSMomentum.GetResultByFieldNum(AFieldNum:integer):double; var Pend,Pbeg:double; begin if FDT=0 then Raise Exception.Create('TPASSMomentum.GetResultByFieldNum: нулевое значение параметра DT'); if FPriceSource.CurrentItemIndex<=FDT then raise Exception.Create('TPASSMomentum.GetResultByFieldNum: ошибка выхода за диапазон'); if AFieldNum<>0 then Raise Exception.Create('TPASSMomentum.GetResultByFieldNum: Неверный номер поля - '+IntToStr(AFieldNum)); Pend:=FPriceSource.GetDataByFieldName(FPriceFieldType); Pbeg:=FPriceSource.GetDataByFieldNameAndIndex('PriceFieldType',FPriceSource.CurrentItemIndex-FDT); if Pbeg=0 then raise Exception.Create('TPASSMomentum.GetResultByFieldNum: Обнаружена нулевая котировка по полю '+ FPriceFieldType+' номер свечи '+IntToStr(FPriceSource.CurrentItemIndex-FDT)+' дата и время свечи '+ DateTimeToStr(FPriceSource.GetDataByFieldNameAndIndex('DateTime',FPriceSource.CurrentItemIndex-FDT))); Result:=(Pend-Pbeg)/Pbeg*100/FDT; end; function TPASSMomentum.GetResultByFieldNumAndIndex(AFieldNum:integer; Index:LongInt):double; var Pend,Pbeg:double; begin if AFieldNum<>0 then Raise Exception.Create('TPASSMomentum.GetResultByFieldNumAndIndex: Неверный номер поля - '+IntToStr(AFieldNum)); if FDT=0 then raise Exception.Create('TPASSMomentum.GetResultByFieldNumAndIndex: нулевое значение параметра DT'); if index<=FDT then Raise Exception.Create('TPASSMomentum.GetResultByFieldNumAndIndex: ошибка выхода за диапазон'); Pend:=FPriceSource.GetDataByFieldNameAndIndex(FPriceFieldType,Index); Pbeg:=FPriceSource.GetDataByFieldNameAndIndex(FPriceFieldType,Index-FDT); if Pbeg=0 then raise Exception.Create('TPASSMomentum.GetResultByFieldNumAndIndex: Обнаружена нулевая котировка по полю '+ FPriceFieldType+' номер свечи '+IntToStr(index-FDT)+' дата и время свечи '+ DateTimeToStr(FPriceSource.GetDataByFieldNameAndIndex('DateTime',index-FDT))); Result:=(Pend-Pbeg)/Pbeg*100/FDT; end; |
Теперь реализуем оставшиеся методы:
procedure TPASSMomentum.Last;
begin
FPriceSource.Last;
end;
procedure TPASSMomentum.First;
begin
FPriceSource.CurrentItemIndex:=FDT+1;
end;
function TPASSMomentum.Next:boolean;
begin
Result:=FPriceSource.NextItem;
end;
function TPASSMomentum.Prev:boolean;
begin
Result:=FPriceSource.PrevItem;
end;
function TPASSMomentum.GetIndicatorName:string;
begin
Result:='Momentum';
end; |
Скриншоты, помеченные знаком * , являются цитатами и иллюстрациями в соответствии со ст. 1274 ГК РФ программного продукта "Delphi", авторское право на который принадлежит "Borland Software Corporation"
Источник : http://easyprog.ru/index.php?option=com_content&task=view&id=61&Itemid=44
Хвала и уважение автору МегаБаксу.