Files
MycLib/Src/Myc.Trade.DataPoint.pas
T
2025-07-15 11:44:44 +02:00

232 lines
6.8 KiB
ObjectPascal

unit Myc.Trade.DataPoint;
interface
uses
Myc.Signals,
Myc.Mutable,
Myc.Trade.Types,
Myc.Trade.DataArray;
type
// A generic interface for components that process data of type T.
IMycProcessor<T> = interface
function ProcessData(const Value: T): TState;
end;
// Interface helper for IDataProvider providing the null object pattern.
TDataProvider<T> = record
public
type
TTag = Pointer;
IDataProvider = interface
function Link(const Receiver: IMycProcessor<T>): TTag;
procedure Unlink(Tag: TTag);
end;
strict private
class var
FNull: IDataProvider;
class constructor CreateClass;
private
FDataProvider: IDataProvider;
public
constructor Create(const ADataProvider: IDataProvider);
// Managed record operators
class operator Initialize(out Dest: TDataProvider<T>);
class operator Implicit(const A: IDataProvider): TDataProvider<T>; overload;
class operator Implicit(const A: TDataProvider<T>): IDataProvider; overload;
// Wrapper for IMycDataProvider methods
function Link(const Receiver: IMycProcessor<T>): TTag; inline;
procedure Unlink(Tag: TTag); inline;
// Provides access to the null object instance.
class property Null: IDataProvider read FNull;
end;
// Interface helper for IConverter<S,T> providing the null object pattern.
TConverter<S, T> = record
public
type
IConverter = interface(IMycProcessor<S>)
{$region 'private'}
function GetSender: TDataProvider<T>.IDataProvider;
{$endregion}
property Sender: TDataProvider<T>.IDataProvider read GetSender;
end;
{$region 'private'}
strict private
class var
FNull: IConverter;
class constructor CreateClass;
private
FConverter: IConverter;
function GetSender: TDataProvider<T>; inline;
{$endregion}
public
constructor Create(const AConverter: IConverter);
// Managed record operators
class operator Initialize(out Dest: TConverter<S, T>);
class operator Implicit(const A: IConverter): TConverter<S, T>; overload;
class operator Implicit(const A: TConverter<S, T>): IConverter; overload;
class function CreateGeneric(const Func: TConstFunc<S, T>): TConverter<S, T>; static;
// Wrapper for IMycProcessor.ProcessData
function ProcessData(const Value: S): TState; inline;
function Chain<R>(const Next: TConverter<T, R>): TConverter<T, R>; overload; inline;
function Chain<R>(const Func: TConstFunc<T, R>): TConverter<T, R>; overload; inline;
// Extracts the field of a record by it's name (using RTTI).
function Field<R>(const FieldName: String): TConverter<T, R>; overload; inline;
// Provides access to the null object instance.
class property Null: IConverter read FNull;
// Wrapper for IConverter.Sender
property Sender: TDataProvider<T> read GetSender;
end;
// Factory for creating specific converter instances.
TConverter = record
class function CreateCounter<T>: TConverter<T, Int64>; static;
class function CreateTicker<T>: TConverter<TArray<T>, T>; static;
class function CreateRecordField<S, T>(const FieldName: String): TConverter<S, T>; static;
class function CreateEndpoint<T>(const DataProvider: TDataProvider<T>; Lookback: Int64): TMutable<TSeries<T>>; static;
end;
implementation
uses
Myc.Trade.DataPoint.Impl;
{ TDataProvider<T> }
class constructor TDataProvider<T>.CreateClass;
begin
// Create the singleton null object instance.
FNull := TNullDataProvider<T>.Create;
end;
constructor TDataProvider<T>.Create(const ADataProvider: IDataProvider);
begin
FDataProvider := ADataProvider;
if not Assigned(FDataProvider) then
FDataProvider := FNull;
end;
class operator TDataProvider<T>.Initialize(out Dest: TDataProvider<T>);
begin
Dest.FDataProvider := FNull;
end;
class operator TDataProvider<T>.Implicit(const A: IDataProvider): TDataProvider<T>;
begin
Result.Create(A);
end;
class operator TDataProvider<T>.Implicit(const A: TDataProvider<T>): IDataProvider;
begin
Result := A.FDataProvider;
end;
function TDataProvider<T>.Link(const Receiver: IMycProcessor<T>): TTag;
begin
Result := FDataProvider.Link(Receiver);
end;
procedure TDataProvider<T>.Unlink(Tag: TTag);
begin
FDataProvider.Unlink(Tag);
end;
{ TConverter<S, T> }
class constructor TConverter<S, T>.CreateClass;
begin
FNull := TNullConverter<S, T>.Create;
end;
constructor TConverter<S, T>.Create(const AConverter: IConverter);
begin
FConverter := AConverter;
if not Assigned(FConverter) then
FConverter := FNull;
end;
function TConverter<S, T>.Chain<R>(const Next: TConverter<T, R>): TConverter<T, R>;
begin
FConverter.Sender.Link(Next);
Result := Next;
end;
function TConverter<S, T>.Chain<R>(const Func: TConstFunc<T, R>): TConverter<T, R>;
begin
Result := Chain<R>(TMycGenericConverter<T, R>.Create(Func));
end;
class function TConverter<S, T>.CreateGeneric(const Func: TConstFunc<S, T>): TConverter<S, T>;
begin
Result := TMycGenericConverter<S, T>.Create(Func);
end;
function TConverter<S, T>.Field<R>(const FieldName: String): TConverter<T, R>;
begin
Result := Chain<R>(TConverter.CreateRecordField<T, R>(FieldName));
end;
function TConverter<S, T>.GetSender: TDataProvider<T>;
begin
Result := FConverter.Sender;
end;
class operator TConverter<S, T>.Initialize(out Dest: TConverter<S, T>);
begin
Dest.FConverter := FNull;
end;
class operator TConverter<S, T>.Implicit(const A: IConverter): TConverter<S, T>;
begin
Result.Create(A);
end;
class operator TConverter<S, T>.Implicit(const A: TConverter<S, T>): IConverter;
begin
Result := A.FConverter;
end;
function TConverter<S, T>.ProcessData(const Value: S): TState;
begin
Result := FConverter.ProcessData(Value);
end;
{ TConverter }
class function TConverter.CreateCounter<T>: TConverter<T, Int64>;
begin
Result := TMycDataCounter<T>.Create;
end;
class function TConverter.CreateEndpoint<T>(const DataProvider: TDataProvider<T>; Lookback: Int64): TMutable<TSeries<T>>;
begin
Result := TMycDataEndpoint<T>.Create(DataProvider, Lookback);
end;
class function TConverter.CreateRecordField<S, T>(const FieldName: String): TConverter<S, T>;
begin
Result := TMycRecordFieldReader<S, T>.Create(FieldName);
end;
class function TConverter.CreateTicker<T>: TConverter<TArray<T>, T>;
begin
Result := TMycTicker<T>.Create;
end;
end.