Implementing first "strategy" for proof of concept
This commit is contained in:
+105
-19
@@ -8,18 +8,18 @@ uses
|
||||
type
|
||||
// A data record for an Ask/Bid price pair.
|
||||
TAskBidItem = packed record
|
||||
Ask: Single;
|
||||
Bid: Single;
|
||||
constructor Create(AAsk, ABid: Single);
|
||||
Ask: Double;
|
||||
Bid: Double;
|
||||
constructor Create(AAsk, ABid: Double);
|
||||
end;
|
||||
|
||||
TOhlcItem = record
|
||||
Open: Single;
|
||||
High: Single;
|
||||
Low: Single;
|
||||
Close: Single;
|
||||
Volume: Single;
|
||||
constructor Create(AOpen, AHigh, ALow, AClose, AVolume: Single);
|
||||
Open: Double;
|
||||
High: Double;
|
||||
Low: Double;
|
||||
Close: Double;
|
||||
Volume: Double;
|
||||
constructor Create(AOpen, AHigh, ALow, AClose, AVolume: Double);
|
||||
end;
|
||||
|
||||
// Represents a time-stamped data point in a series.
|
||||
@@ -29,13 +29,38 @@ type
|
||||
constructor Create(ATime: TDateTime; const AData: T);
|
||||
end;
|
||||
|
||||
// A time-ordered series of data points, optimized for chronological additions.
|
||||
// The most recently added element has the logical index 0.
|
||||
IMycProcessor<T> = interface
|
||||
procedure ProcessData(const Value: T);
|
||||
end;
|
||||
|
||||
TMycGenericProcessor<T> = class(TInterfacedObject, IMycProcessor<T>)
|
||||
type
|
||||
TProc = reference to procedure(const Value: T);
|
||||
private
|
||||
FProc: TProc;
|
||||
procedure ProcessData(const Value: T);
|
||||
public
|
||||
constructor Create(const AProc: TProc);
|
||||
end;
|
||||
|
||||
TMycContainedProcessor<T> = class(TContainedObject, IMycProcessor<T>)
|
||||
type
|
||||
TProc = procedure(const Value: T) of object;
|
||||
private
|
||||
FProc: TProc;
|
||||
procedure ProcessData(const Value: T);
|
||||
public
|
||||
constructor Create(const Controller: IInterface; const AProc: TProc);
|
||||
end;
|
||||
|
||||
// An immutable time-ordered series of data points.
|
||||
// The most recent element has the logical index 0.
|
||||
IDataSeries<T> = interface
|
||||
function GetCount: Int64;
|
||||
function GetItems(Idx: Int64): TDataPoint<T>;
|
||||
function GetTotalCount: Int64;
|
||||
function GetLookback: Int64;
|
||||
// Add data and result the new series.
|
||||
function Add(const Data: TArray<TDataPoint<T>>; First, Count: Integer): IDataSeries<T>;
|
||||
property Count: Int64 read GetCount;
|
||||
// Accesses data points by their logical index.
|
||||
@@ -74,7 +99,6 @@ type
|
||||
|
||||
function Add(const Data: TArray<TDataPoint<T>>): TDataSeries<T>; overload;
|
||||
function Add(const Data: TArray<TDataPoint<T>>; First, Count: Integer): TDataSeries<T>; overload;
|
||||
|
||||
function Convert<S>(const Func: TConvertFunc<S>): TDataSeries<S>;
|
||||
|
||||
// Searches for a data point by its timestamp.
|
||||
@@ -99,12 +123,21 @@ type
|
||||
function ToOhlc(TimeFrame: TTimeSpan): TDataSeries<TOhlcItem>;
|
||||
end;
|
||||
|
||||
TDataSeriesOhlcHelper = record helper for TDataSeries<TOhlcItem>
|
||||
function ToOpen: TDataSeries<Single>;
|
||||
function ToClose: TDataSeries<Single>;
|
||||
function ToHigh: TDataSeries<Single>;
|
||||
function ToLow: TDataSeries<Single>;
|
||||
function ToVolume: TDataSeries<Single>;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Math,
|
||||
System.Generics.Collections,
|
||||
Myc.Trade.DataArray,
|
||||
Myc.Trade.Core.DataPoint;
|
||||
|
||||
// Optimized helper function using direct TTimeSpan features and integer arithmetic.
|
||||
@@ -180,17 +213,40 @@ begin
|
||||
if not firstPointInBar then
|
||||
ohlcPoints.Add(TDataPoint<TOhlcItem>.Create(windowEndTime, currentBar));
|
||||
|
||||
var dataArray := TMycDataArray<TOhlcItem>.CreateFromArray(ohlcPoints.ToArray, 0, ohlcPoints.Count);
|
||||
var seriesImpl := TMycDataSeries<TOhlcItem>.Create(ohlcPoints.Count, dataArray, ohlcPoints.Count);
|
||||
Result := TDataSeries<TOhlcItem>.Create(seriesImpl);
|
||||
Result := TDataSeries<TOhlcItem>.CreateDataSeries(ohlcPoints.Count, ohlcPoints.ToArray);
|
||||
finally
|
||||
ohlcPoints.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDataSeriesOhlcHelper.ToClose: TDataSeries<Single>;
|
||||
begin
|
||||
Result := Self.Convert<Single>(function(const Ohlc: TDataPoint<TOhlcItem>): Single begin Result := Ohlc.Data.Close; end);
|
||||
end;
|
||||
|
||||
function TDataSeriesOhlcHelper.ToHigh: TDataSeries<Single>;
|
||||
begin
|
||||
Result := Self.Convert<Single>(function(const Ohlc: TDataPoint<TOhlcItem>): Single begin Result := Ohlc.Data.High; end);
|
||||
end;
|
||||
|
||||
function TDataSeriesOhlcHelper.ToLow: TDataSeries<Single>;
|
||||
begin
|
||||
Result := Self.Convert<Single>(function(const Ohlc: TDataPoint<TOhlcItem>): Single begin Result := Ohlc.Data.Low; end);
|
||||
end;
|
||||
|
||||
function TDataSeriesOhlcHelper.ToOpen: TDataSeries<Single>;
|
||||
begin
|
||||
Result := Self.Convert<Single>(function(const Ohlc: TDataPoint<TOhlcItem>): Single begin Result := Ohlc.Data.Open; end);
|
||||
end;
|
||||
|
||||
function TDataSeriesOhlcHelper.ToVolume: TDataSeries<Single>;
|
||||
begin
|
||||
Result := Self.Convert<Single>(function(const Ohlc: TDataPoint<TOhlcItem>): Single begin Result := Ohlc.Data.Volume; end);
|
||||
end;
|
||||
|
||||
{ TAskBidItem }
|
||||
|
||||
constructor TAskBidItem.Create(AAsk, ABid: Single);
|
||||
constructor TAskBidItem.Create(AAsk, ABid: Double);
|
||||
begin
|
||||
Ask := AAsk;
|
||||
Bid := ABid;
|
||||
@@ -198,7 +254,7 @@ end;
|
||||
|
||||
{ TOhlcItem }
|
||||
|
||||
constructor TOhlcItem.Create(AOpen, AHigh, ALow, AClose, AVolume: Single);
|
||||
constructor TOhlcItem.Create(AOpen, AHigh, ALow, AClose, AVolume: Double);
|
||||
begin
|
||||
Open := AOpen;
|
||||
High := AHigh;
|
||||
@@ -225,12 +281,19 @@ end;
|
||||
|
||||
function TDataSeries<T>.Add(const Data: TArray<TDataPoint<T>>; First, Count: Integer): TDataSeries<T>;
|
||||
begin
|
||||
{$ifdef DEBUG}
|
||||
for var i := First + 1 to First + Count - 1 do
|
||||
Assert(Data[i].Time >= Data[i - 1].Time, 'Input array for Add is not chronologically sorted');
|
||||
if FDataSeries.Count > 0 then
|
||||
Assert(Data[First].Time >= FDataSeries[0].Time, 'First new item is older than last existing item');
|
||||
{$endif}
|
||||
|
||||
Result := FDataSeries.Add(Data, First, Count);
|
||||
end;
|
||||
|
||||
function TDataSeries<T>.Add(const Data: TArray<TDataPoint<T>>): TDataSeries<T>;
|
||||
begin
|
||||
Result := FDataSeries.Add(Data, 0, Length(Data));
|
||||
Result := Add(Data, 0, Length(Data));
|
||||
end;
|
||||
|
||||
function TDataSeries<T>.Convert<S>(const Func: TConvertFunc<S>): TDataSeries<S>;
|
||||
@@ -240,7 +303,8 @@ end;
|
||||
|
||||
class function TDataSeries<T>.CreateDataSeries(Lookback: Int64; const Data: TArray<TDataPoint<T>> = nil): TDataSeries<T>;
|
||||
begin
|
||||
Result := TMycDataSeries<T>.CreateDataSeries(Lookback, TMycDataArray<T>.CreateFromArray(Data, 0, Length(Data)), Length(Data));
|
||||
Result :=
|
||||
TMycDataSeries<T>.CreateDataSeries(Lookback, TMycDataArray<TDataPoint<T>>.CreateFromArray(Data, 0, Length(Data)), Length(Data));
|
||||
end;
|
||||
|
||||
class operator TDataSeries<T>.Finalize(var Dest: TDataSeries<T>);
|
||||
@@ -350,4 +414,26 @@ begin
|
||||
Result[i] := FDataSeries[n - i].Data;
|
||||
end;
|
||||
|
||||
constructor TMycGenericProcessor<T>.Create(const AProc: TProc);
|
||||
begin
|
||||
inherited Create;
|
||||
FProc := AProc;
|
||||
end;
|
||||
|
||||
procedure TMycGenericProcessor<T>.ProcessData(const Value: T);
|
||||
begin
|
||||
FProc(Value);
|
||||
end;
|
||||
|
||||
constructor TMycContainedProcessor<T>.Create(const Controller: IInterface; const AProc: TProc);
|
||||
begin
|
||||
inherited Create(Controller);
|
||||
FProc := AProc;
|
||||
end;
|
||||
|
||||
procedure TMycContainedProcessor<T>.ProcessData(const Value: T);
|
||||
begin
|
||||
FProc(Value);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user