267 lines
7.1 KiB
ObjectPascal
267 lines
7.1 KiB
ObjectPascal
unit Myc.Trade.DataPoint;
|
|
|
|
interface
|
|
|
|
uses
|
|
Myc.Signals,
|
|
Myc.Core.Notifier;
|
|
|
|
type
|
|
// Represents a time-stamped data point in a series.
|
|
TDataPoint<T> = record
|
|
Time: TDateTime;
|
|
Data: T;
|
|
constructor Create(ATime: TDateTime; const AData: T);
|
|
end;
|
|
|
|
IMycProcessor<T> = interface
|
|
function ProcessData(const Value: T): TState;
|
|
end;
|
|
|
|
TMycProcessor<T> = class abstract(TInterfacedObject, IMycProcessor<T>)
|
|
protected
|
|
function ProcessData(const Value: T): TState; virtual; abstract;
|
|
end;
|
|
|
|
TDataProvider<T> = record
|
|
type
|
|
TTag = Pointer;
|
|
IDataProvider = interface
|
|
function Link(const Receiver: IMycProcessor<T>): TTag;
|
|
procedure Unlink(Tag: TTag);
|
|
end;
|
|
|
|
{$REGION 'private'}
|
|
strict private
|
|
class var
|
|
FNull: IDataProvider;
|
|
class constructor CreateClass;
|
|
private
|
|
FDataProvider: IDataProvider;
|
|
{$ENDREGION}
|
|
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;
|
|
|
|
TMycDataProvider<T> = class abstract(TContainedObject, TDataProvider<T>.IDataProvider)
|
|
private
|
|
FListeners: TMycNotifyList<IMycProcessor<T>>;
|
|
public
|
|
constructor Create(const Controller: IInterface);
|
|
destructor Destroy; override;
|
|
// Notifies all linked processors.
|
|
function Broadcast(const Value: T): TState;
|
|
procedure Notify(const Func: TMycNotifyList<IMycProcessor<T>>.TNotifyProc);
|
|
// Link a Processor
|
|
function Link(const Processor: IMycProcessor<T>): TDataProvider<T>.TTag;
|
|
// Unlink a linked strategy
|
|
procedure Unlink(Tag: TDataProvider<T>.TTag);
|
|
end;
|
|
|
|
TMycGenericProcessor<T> = class(TMycProcessor<T>)
|
|
type
|
|
TProc = reference to function(const Value: T): TState;
|
|
private
|
|
FProc: TProc;
|
|
protected
|
|
function ProcessData(const Value: T): TState; override; final;
|
|
public
|
|
constructor Create(const AProc: TProc);
|
|
end;
|
|
|
|
TMycContainedProcessor<T> = class(TContainedObject, IMycProcessor<T>)
|
|
type
|
|
TProc = function(const Value: T): TState of object;
|
|
private
|
|
FProc: TProc;
|
|
function ProcessData(const Value: T): TState;
|
|
public
|
|
constructor Create(const Controller: IInterface; const AProc: TProc);
|
|
end;
|
|
|
|
TNullDataProvider<T> = class(TInterfacedObject, TDataProvider<T>.IDataProvider)
|
|
public
|
|
function Link(const Receiver: IMycProcessor<T>): TDataProvider<T>.TTag;
|
|
procedure Unlink(Tag: TDataProvider<T>.TTag);
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TNullDataProvider }
|
|
|
|
function TNullDataProvider<T>.Link(const Receiver: IMycProcessor<T>): TDataProvider<T>.TTag;
|
|
begin
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TNullDataProvider<T>.Unlink(Tag: TDataProvider<T>.TTag);
|
|
begin
|
|
// Do nothing in the null implementation.
|
|
end;
|
|
|
|
{ TDataPoint<T> }
|
|
|
|
constructor TDataPoint<T>.Create(ATime: TDateTime; const AData: T);
|
|
begin
|
|
Time := ATime;
|
|
Data := AData;
|
|
end;
|
|
|
|
{ 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;
|
|
// Ensure that the internal interface is never nil.
|
|
if not Assigned(FDataProvider) then
|
|
FDataProvider := FNull;
|
|
end;
|
|
|
|
class operator TDataProvider<T>.Initialize(out Dest: TDataProvider<T>);
|
|
begin
|
|
// Initialize new record instances with the null object.
|
|
Dest.FDataProvider := FNull;
|
|
end;
|
|
|
|
class operator TDataProvider<T>.Implicit(const A: IDataProvider): TDataProvider<T>;
|
|
begin
|
|
// Allow implicit conversion from the interface to the helper.
|
|
Result.Create(A);
|
|
end;
|
|
|
|
class operator TDataProvider<T>.Implicit(const A: TDataProvider<T>): IDataProvider;
|
|
begin
|
|
// Allow implicit conversion from the helper to the interface.
|
|
Result := A.FDataProvider;
|
|
end;
|
|
|
|
function TDataProvider<T>.Link(const Receiver: IMycProcessor<T>): TTag;
|
|
begin
|
|
// Forward the call to the wrapped interface.
|
|
Result := FDataProvider.Link(Receiver);
|
|
end;
|
|
|
|
procedure TDataProvider<T>.Unlink(Tag: TTag);
|
|
begin
|
|
// Forward the call to the wrapped interface.
|
|
FDataProvider.Unlink(Tag);
|
|
end;
|
|
|
|
{ TMycGenericProcessor<T> }
|
|
|
|
constructor TMycGenericProcessor<T>.Create(const AProc: TProc);
|
|
begin
|
|
inherited Create;
|
|
FProc := AProc;
|
|
end;
|
|
|
|
function TMycGenericProcessor<T>.ProcessData(const Value: T): TState;
|
|
begin
|
|
Result := FProc(Value);
|
|
end;
|
|
|
|
{ TMycContainedProcessor<T> }
|
|
|
|
constructor TMycContainedProcessor<T>.Create(const Controller: IInterface; const AProc: TProc);
|
|
begin
|
|
inherited Create(Controller);
|
|
FProc := AProc;
|
|
end;
|
|
|
|
function TMycContainedProcessor<T>.ProcessData(const Value: T): TState;
|
|
begin
|
|
Result := FProc(Value);
|
|
end;
|
|
|
|
{ TMycDataProvider<T> }
|
|
|
|
constructor TMycDataProvider<T>.Create(const Controller: IInterface);
|
|
begin
|
|
inherited Create(Controller);
|
|
end;
|
|
|
|
destructor TMycDataProvider<T>.Destroy;
|
|
begin
|
|
FListeners.Finalize;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TMycDataProvider<T>.Broadcast(const Value: T): TState;
|
|
begin
|
|
FListeners.Lock;
|
|
try
|
|
var item := FListeners.First;
|
|
if item = nil then
|
|
exit(TState.Null);
|
|
|
|
var i := 1;
|
|
while item.Next <> nil do
|
|
begin
|
|
inc(i);
|
|
item := item.Next;
|
|
end;
|
|
|
|
var done := TLatch.CreateLatch(i);
|
|
while item <> nil do
|
|
begin
|
|
item.Receiver.ProcessData(Value).Signal.Subscribe(done);
|
|
item := item.Prev;
|
|
end;
|
|
|
|
Result := done.State;
|
|
finally
|
|
FListeners.Release;
|
|
end;
|
|
end;
|
|
|
|
procedure TMycDataProvider<T>.Notify(const Func: TMycNotifyList<IMycProcessor<T>>.TNotifyProc);
|
|
begin
|
|
FListeners.Lock;
|
|
try
|
|
FListeners.Notify(Func);
|
|
finally
|
|
FListeners.Release;
|
|
end;
|
|
end;
|
|
|
|
function TMycDataProvider<T>.Link(const Processor: IMycProcessor<T>): TDataProvider<T>.TTag;
|
|
begin
|
|
// Add the Processor to the notification list
|
|
FListeners.Lock;
|
|
try
|
|
Result := FListeners.Advise(Processor);
|
|
finally
|
|
FListeners.Release;
|
|
end;
|
|
end;
|
|
|
|
procedure TMycDataProvider<T>.Unlink(Tag: TDataProvider<T>.TTag);
|
|
begin
|
|
FListeners.Lock;
|
|
try
|
|
FListeners.Unadvise(Tag);
|
|
finally
|
|
FListeners.Release;
|
|
end;
|
|
end;
|
|
|
|
end.
|