diff --git a/AuraTrader/AuraTrader.dproj b/AuraTrader/AuraTrader.dproj
index e0cbb98..78cf432 100644
--- a/AuraTrader/AuraTrader.dproj
+++ b/AuraTrader/AuraTrader.dproj
@@ -4,7 +4,7 @@
20.3
FMX
True
- Debug
+ Release
Win64
AuraTrader
3
diff --git a/AuraTrader/MainForm.fmx b/AuraTrader/MainForm.fmx
index 2606846..cbf3bbe 100644
--- a/AuraTrader/MainForm.fmx
+++ b/AuraTrader/MainForm.fmx
@@ -64,21 +64,21 @@ object Form1: TForm1
JustifyLastLine = Left
FlowDirection = LeftToRight
end
- object Button1: TButton
+ object ChartButton: TButton
Position.X = 712.00000000000000000
Position.Y = 72.00000000000000000
TabOrder = 6
- Text = 'Button1'
+ Text = 'ChartButton'
TextSettings.Trimming = None
- OnClick = Button1Click
+ OnClick = ChartButtonClick
end
- object Button2: TButton
+ object StopButton: TButton
Position.X = 720.00000000000000000
Position.Y = 96.00000000000000000
TabOrder = 8
- Text = 'Button2'
+ Text = 'StopButton'
TextSettings.Trimming = None
- OnClick = Button2Click
+ OnClick = StopButtonClick
end
end
object LogMemo: TMemo
diff --git a/AuraTrader/MainForm.pas b/AuraTrader/MainForm.pas
index 5199b31..dd6fd7b 100644
--- a/AuraTrader/MainForm.pas
+++ b/AuraTrader/MainForm.pas
@@ -45,14 +45,14 @@ type
SymbolsComboBox: TComboBox;
LoadButton: TButton;
FlowLayout: TFlowLayout;
- Button1: TButton;
- Button2: TButton;
+ ChartButton: TButton;
+ StopButton: TButton;
procedure RandomButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure LoadButtonClick(Sender: TObject);
- procedure Button1Click(Sender: TObject);
- procedure Button2Click(Sender: TObject);
+ procedure ChartButtonClick(Sender: TObject);
+ procedure StopButtonClick(Sender: TObject);
private
const
cnt = 20;
@@ -83,84 +83,7 @@ implementation
{$R *.fmx}
-procedure TForm1.Button1Click(Sender: TObject);
-begin
- if SymbolsComboBox.ItemIndex < 0 then
- exit;
-
- var curr := TWriteable>.CreateProtected;
- var Symbol := FSymbols.WaitFor[SymbolsComboBox.ItemIndex];
-
- var currPathData := TWriteable>.CreateProtected;
-
- LogMemo.AddIdleHandler(curr.Changed, procedure begin LogMemo.Lines.Add(Symbol + ': ' + curr.Value.TotalCount.ToString); end);
-
- var arr := TDataSeries.CreateArray(3000);
- var done :=
- FServer.ProcessData(
- Symbol,
- FTerminate.Signal,
- procedure(const Values: TArray>; const Terminated: TState)
- begin
- arr.Add(Values);
- curr.Value := arr.Copy;
-
- var PathData := TPathData.Create;
- var Prices := arr;
- if Prices.Count > 0 then
- begin
- PathData.MoveTo(PointF(Prices.Count - 1, Prices[0].Data.Ask));
- for var i := 1 to Prices.Count - 1 do
- PathData.LineTo(PointF(Prices.Count - i - 1, Prices[i].Data.Ask));
- end;
-
- currPathData.Value := TObjectRef.Create(PathData);
- end
- );
-
- FLoadDone := TState.All([FLoadDone, done]);
-
- Path1.AddIdleHandler(
- currPathData.Changed,
- procedure
- begin
- if currPathData.Value<>nil then
- begin
- Path1.Data.Assign( currPathData.Value.Obj );
- currPathData.Value := nil;
- end;
- end );
-
-
-(*
- FLoadDone := TState.All([FLoadDone, done]);
-
- Path1.AddIdleHandler(
- curr.Changed,
- procedure
- begin
- var Prices := curr.Value;
-
- if Prices.Count > 0 then
- begin
- Path1.BeginUpdate;
- try
- Path1.Data.Clear;
- Path1.Data.MoveTo(PointF(Path1.Width - 1, Prices[0].Data.Ask));
- for var i := 1 to Prices.Count - 1 do
- begin
- Path1.Data.LineTo(PointF(Path1.Width - i - 1, Prices[i].Data.Ask));
- end;
- finally
- Path1.EndUpdate;
- end;
- end;
- end
- );
-*)
-end;
-
-procedure TForm1.Button2Click(Sender: TObject);
+procedure TForm1.StopButtonClick(Sender: TObject);
begin
FTerminate.Notify;
end;
@@ -174,6 +97,8 @@ begin
FServer := TAuraTABFileServer.Create('\\COFFEE\TickData\Pepperstone');
SymbolsComboBox.Enabled := false;
+ ChartButton.Enabled := false;
+ LoadButton.Enabled := false;
FSymbols := FServer.EnumerateSymbols;
@@ -190,6 +115,8 @@ begin
if SymbolsComboBox.ItemIndex < 0 then
SymbolsComboBox.ItemIndex := SymbolsComboBox.Items.IndexOf('GER40');
SymbolsComboBox.Enabled := true;
+ ChartButton.Enabled := true;
+ LoadButton.Enabled := true;
end;
finally
SymbolsComboBox.EndUpdate;
@@ -200,6 +127,7 @@ end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
+ FSymbols.WaitFor;
FTerminate.Notify;
TaskManager.WaitFor(FLoadDone);
Application.OnIdle := nil;
@@ -279,4 +207,83 @@ begin
Proc(FRandom.Count - 1);
end;
+procedure TForm1.ChartButtonClick(Sender: TObject);
+begin
+ if SymbolsComboBox.ItemIndex < 0 then
+ exit;
+
+ var Symbol := FSymbols.WaitFor[SymbolsComboBox.ItemIndex];
+
+ var currPathData := TMutable>.CreateProtected;
+ var currLog := TMutable.CreateProtected;
+
+ const width = 1000;
+ const incsize = 100;
+ begin
+ var arr := TDataSeries.CreateWriteable(width);
+ var done :=
+ FServer.ProcessData(
+ Symbol,
+ FTerminate.Signal,
+ procedure(const Values: TArray>; const Terminated: TState)
+ begin
+ arr.Add(Values);
+ currLog.Value := arr.TotalCount.ToString;
+
+ var PathData := TPathData.Create;
+ var Prices := arr;
+ if Prices.Count > 0 then
+ begin
+ PathData.MoveTo(PointF(Prices.Count - 1, Prices[0].Data.Ask));
+ for var i := 1 to Prices.Count - 1 do
+ PathData.LineTo(PointF(Prices.Count - i - 1, Prices[i].Data.Ask));
+ end;
+
+ currPathData.Value := TObjectRef.Create(PathData);
+ end
+ );
+ FLoadDone := TState.All([FLoadDone, done]);
+ end;
+
+ LogMemo.AddIdleHandler(currLog.Changed, procedure begin LogMemo.Lines.Add(Symbol + ': ' + currLog.Value); end);
+
+ Path1.AddIdleHandler(
+ currPathData.Changed,
+ procedure
+ begin
+ if currPathData.Value<>nil then
+ begin
+ Path1.Data.Assign( currPathData.Value.Obj );
+ end;
+ end );
+
+
+(*
+ FLoadDone := TState.All([FLoadDone, done]);
+
+ Path1.AddIdleHandler(
+ curr.Changed,
+ procedure
+ begin
+ var Prices := curr.Value;
+
+ if Prices.Count > 0 then
+ begin
+ Path1.BeginUpdate;
+ try
+ Path1.Data.Clear;
+ Path1.Data.MoveTo(PointF(Path1.Width - 1, Prices[0].Data.Ask));
+ for var i := 1 to Prices.Count - 1 do
+ begin
+ Path1.Data.LineTo(PointF(Path1.Width - i - 1, Prices[i].Data.Ask));
+ end;
+ finally
+ Path1.EndUpdate;
+ end;
+ end;
+ end
+ );
+*)
+end;
+
end.
diff --git a/Src/Myc.Core.Lazy.pas b/Src/Myc.Core.Lazy.pas
index e93d468..8706a5e 100644
--- a/Src/Myc.Core.Lazy.pas
+++ b/Src/Myc.Core.Lazy.pas
@@ -10,9 +10,10 @@ uses
type
TMycNullMutable = class(TInterfacedObject, TMutable.IMutable)
- protected
+ private
function GetChanged: TSignal;
function GetValue: T;
+ function GetWriter: TMutable.IWriter;
end;
TMycMutableBase = class(TInterfacedObject, TMutable.IMutable)
@@ -20,6 +21,7 @@ type
FChanged: TEvent;
FChangeState: TSignal.TSubscription;
function GetChanged: TSignal;
+ function GetWriter: TMutable.IWriter;
protected
function GetValue: T; virtual; abstract;
public
@@ -36,13 +38,14 @@ type
constructor Create(const AChanged: TSignal; const AProc: TFunc);
end;
- TMycWriteableMutable = class(TInterfacedObject, TMutable.IMutable, TWriteable.IWriteable)
+ TMycWriteableMutable = class(TInterfacedObject, TMutable.IMutable, TMutable.IWriter)
private
FValue: T;
FChanged: TEvent;
protected
function GetChanged: TSignal;
function GetValue: T;
+ function GetWriter: TMutable.IWriter;
public
constructor Create(const AValue: T);
procedure SetValue(const Value: T);
@@ -77,7 +80,7 @@ type
constructor Create(const AChanged: TSignal.ISignal; const AProc: TFunc);
end;
- TMycProtectedWriteableMutable = class(TInterfacedObject, TMutable.IMutable, TWriteable.IWriteable)
+ TMycProtectedWriteableMutable = class(TInterfacedObject, TMutable.IMutable, TMutable.IWriter)
private
FValue: T;
FChanged: TEvent;
@@ -85,6 +88,7 @@ type
protected
function GetChanged: TSignal;
function GetValue: T;
+ function GetWriter: TMutable.IWriter;
procedure Lock; inline;
procedure Release; inline;
public
@@ -106,6 +110,11 @@ begin
Result := Default(T);
end;
+function TMycNullMutable.GetWriter: TMutable.IWriter;
+begin
+ Result := nil;
+end;
+
{ TMycMutableBase }
constructor TMycMutableBase.Create(const AChanged: TSignal);
@@ -126,6 +135,11 @@ begin
Result := FChanged.Signal;
end;
+function TMycMutableBase.GetWriter: TMutable.IWriter;
+begin
+ Result := nil;
+end;
+
{ TMycWriteableMutable }
constructor TMycWriteableMutable.Create(const AValue: T);
@@ -145,6 +159,11 @@ begin
Result := FValue;
end;
+function TMycWriteableMutable.GetWriter: TMutable.IWriter;
+begin
+ Result := Self;
+end;
+
procedure TMycWriteableMutable.SetValue(const Value: T);
begin
FValue := Value;
@@ -244,6 +263,11 @@ begin
end;
end;
+function TMycProtectedWriteableMutable.GetWriter: TMutable.IWriter;
+begin
+ Result := Self;
+end;
+
procedure TMycProtectedWriteableMutable.Lock;
begin
while AtomicExchange(FLock, 1) = 1 do
diff --git a/Src/Myc.Lazy.pas b/Src/Myc.Lazy.pas
index 55a2cfe..862c954 100644
--- a/Src/Myc.Lazy.pas
+++ b/Src/Myc.Lazy.pas
@@ -9,13 +9,19 @@ uses
type
TMutable = record
type
+ IWriter = interface
+ procedure SetValue(const Value: T);
+ end;
+
IMutable = interface
{$REGION 'property access'}
function GetChanged: TSignal;
function GetValue: T;
+ function GetWriter: IWriter;
{$ENDREGION}
property Changed: TSignal read GetChanged;
property Value: T read GetValue;
+ property Writer: IWriter read GetWriter;
end;
{$REGION 'private'}
@@ -27,7 +33,9 @@ type
private
FMutable: IMutable;
function GetChanged: TSignal; inline;
+ function GetIsWriteable: Boolean;
function GetValue: T; inline;
+ procedure SetValue(const Value: T);
{$ENDREGION}
public
constructor Create(const AMutable: IMutable);
@@ -38,35 +46,12 @@ type
class property Null: IMutable read FNull;
class function Construct(const Changing: TSignal; const Proc: TFunc): TMutable; overload; static;
-
- property Value: T read GetValue;
- property Changed: TSignal read GetChanged;
- end;
-
- TWriteable = record
- type
- IWriteable = interface(TMutable.IMutable)
- procedure SetValue(const Value: T);
- property Value: T read GetValue write SetValue;
- end;
-
- private
- FWriteable: IWriteable;
- function GetChanged: TSignal; inline;
- function GetValue: T; inline;
- procedure SetValue(const Value: T); inline;
-
- public
- constructor Create(const AWriteable: IWriteable);
-
- class function CreateProtected: TWriteable; overload; static;
- class function CreateWriteable: TWriteable; overload; static;
-
- class operator Implicit(const A: IWriteable): TWriteable; overload;
- class operator Implicit(const A: TWriteable): IWriteable; overload;
+ class function CreateProtected: TMutable; overload; static;
+ class function CreateWriteable: TMutable; overload; static;
property Value: T read GetValue write SetValue;
property Changed: TSignal read GetChanged;
+ property IsWriteable: Boolean read GetIsWriteable;
end;
TLazy = record
@@ -127,16 +112,37 @@ begin
Result := TMycFuncMutable.Create(Changing, Proc);
end;
+class function TMutable.CreateProtected: TMutable;
+begin
+ Result := TMycProtectedWriteableMutable.Create(Default(T));
+end;
+
+class function TMutable.CreateWriteable: TMutable;
+begin
+ Result := TMycWriteableMutable.Create(Default(T));
+end;
+
function TMutable.GetChanged: TSignal;
begin
Result := FMutable.Changed;
end;
+function TMutable.GetIsWriteable: Boolean;
+begin
+ Result := Assigned( FMutable.Writer );
+end;
+
function TMutable.GetValue: T;
begin
Result := FMutable.Value;
end;
+procedure TMutable.SetValue(const Value: T);
+begin
+ Assert( IsWriteable );
+ FMutable.Writer.SetValue( Value );
+end;
+
class operator TMutable.Implicit(const A: TMutable): IMutable;
begin
Result := A.FMutable;
@@ -201,46 +207,4 @@ begin
Dest.FLazy := FNull;
end;
-{ TWriteable }
-
-constructor TWriteable.Create(const AWriteable: IWriteable);
-begin
- FWriteable := AWriteable;
-end;
-
-class function TWriteable.CreateProtected: TWriteable;
-begin
- Result := TMycProtectedWriteableMutable.Create(Default(T));
-end;
-
-class function TWriteable.CreateWriteable: TWriteable;
-begin
- Result := TMycWriteableMutable.Create(Default(T));
-end;
-
-function TWriteable.GetChanged: TSignal;
-begin
- Result := FWriteable.Changed;
-end;
-
-function TWriteable.GetValue: T;
-begin
- Result := FWriteable.Value;
-end;
-
-procedure TWriteable.SetValue(const Value: T);
-begin
- FWriteable.Value := Value;
-end;
-
-class operator TWriteable.Implicit(const A: IWriteable): TWriteable;
-begin
- Result.Create(A);
-end;
-
-class operator TWriteable.Implicit(const A: TWriteable): IWriteable;
-begin
- Result := A.FWriteable;
-end;
-
end.
diff --git a/Src/Myc.Trade.Core.DataPoint.pas b/Src/Myc.Trade.Core.DataPoint.pas
index 848e499..0c590ae 100644
--- a/Src/Myc.Trade.Core.DataPoint.pas
+++ b/Src/Myc.Trade.Core.DataPoint.pas
@@ -7,7 +7,7 @@ uses
type
// The implementation class for IDataSeries.
- TDataArray = class(TInterfacedObject, IDataSeries, IDataArray)
+ TDataArray = class(TInterfacedObject, IDataSeries, IDataSeriesWriter)
const
ChunkSize = 1024;
type
@@ -15,7 +15,7 @@ type
private
FChunks: TArray;
FCount: Int64;
- FMaxLookback: Int64;
+ FLookback: Int64;
FTotalCount: Int64;
function LogicalToPhysicalIndex(LogicalIndex: Int64): Int64; inline;
@@ -25,15 +25,16 @@ type
// IDataSeries implementation
function GetCount: Int64;
function GetItems(Idx: Int64): TDataPoint;
- function GetMaxLookback: Int64;
+ function GetLookback: Int64;
function GetTotalCount: Int64;
+ function GetWriter: IDataSeriesWriter;
public
- constructor Create(AMaxLookback: Int64);
+ constructor Create(ALookback: Int64);
procedure Add(const Data: TDataPoint); overload;
procedure Add(const Data: array of TDataPoint; NumToAdd: Integer = -1); overload;
procedure Clear;
- function Copy: IDataSeries;
- property MaxLookback: Int64 read GetMaxLookback;
+ function Immutable: IDataSeries;
+ property Lookback: Int64 read GetLookback;
end;
// Null object implementation for IDataSeries
@@ -43,12 +44,13 @@ type
FNull: IDataSeries;
private
class constructor CreateClass;
+ function GetWriter: IDataSeriesWriter;
public
function GetCount: Int64;
function GetItems(Idx: Int64): TDataPoint;
function GetTotalCount: Int64;
function IndexOf(TimeStamp: TDateTime): Int64;
- function Copy: IDataSeries;
+ function Immutable: IDataSeries;
class property Null: IDataSeries read FNull;
end;
@@ -57,7 +59,7 @@ type
private
FChunks: TArray.TChunk>;
FCount: Int64;
- FMaxLookback: Int64;
+ FLookback: Int64;
FTotalCount: Int64;
function LogicalToPhysicalIndex(LogicalIndex: Int64): Int64; inline;
@@ -66,23 +68,24 @@ type
// IDataSeries implementation
function GetCount: Int64;
function GetItems(Idx: Int64): TDataPoint;
- function GetMaxLookback: Int64;
+ function GetLookback: Int64;
function GetTotalCount: Int64;
+ function GetWriter: IDataSeriesWriter;
public
- constructor Create(const AChunks: TArray.TChunk>; ACount, AMaxLookback, ATotalCount: Int64);
- function Copy: IDataSeries;
- property MaxLookback: Int64 read GetMaxLookback;
+ constructor Create(const AChunks: TArray.TChunk>; ACount, ALookback, ATotalCount: Int64);
+ function Immutable: IDataSeries;
+ property Lookback: Int64 read GetLookback;
end;
implementation
{ TDataArray }
-constructor TDataArray.Create(AMaxLookback: Int64);
+constructor TDataArray.Create(ALookback: Int64);
begin
inherited Create;
- FMaxLookback := AMaxLookback;
+ FLookback := ALookback;
FCount := 0;
FTotalCount := 0;
FChunks := nil;
@@ -170,16 +173,16 @@ begin
FTotalCount := 0;
end;
-function TDataArray.Copy: IDataSeries;
+function TDataArray.Immutable: IDataSeries;
begin
- Result := TStaticDataSeries.Create(FChunks, FCount, FMaxLookback, FTotalCount);
+ Result := TStaticDataSeries.Create(FChunks, FCount, FLookback, FTotalCount);
end;
function TDataArray.GetCount: Int64;
begin
Result := FCount;
- if (FMaxLookback > 0) and (Result > FMaxLookback) then
- Result := FMaxLookback;
+ if (FLookback > 0) and (Result > FLookback) then
+ Result := FLookback;
end;
function TDataArray.GetItems(Idx: Int64): TDataPoint;
@@ -191,9 +194,9 @@ begin
Result := FChunks[physicalIndex div ChunkSize][physicalIndex mod ChunkSize];
end;
-function TDataArray.GetMaxLookback: Int64;
+function TDataArray.GetLookback: Int64;
begin
- Result := FMaxLookback;
+ Result := FLookback;
end;
function TDataArray.GetTotalCount: Int64;
@@ -201,9 +204,14 @@ begin
Result := FTotalCount;
end;
+function TDataArray.GetWriter: IDataSeriesWriter;
+begin
+ Result := Self;
+end;
+
function TDataArray.IsIndexInLimits(LogicalIndex: Int64): Boolean;
begin
- Result := (FMaxLookback <= 0) or (LogicalIndex < FMaxLookback);
+ Result := (FLookback <= 0) or (LogicalIndex < FLookback);
end;
function TDataArray.LogicalToPhysicalIndex(LogicalIndex: Int64): Int64;
@@ -216,12 +224,12 @@ procedure TDataArray.Trim;
var
itemsToRemove, chunksToRemove: Int64;
begin
- if (FCount = 0) or (FMaxLookback <= 0) then
+ if (FCount = 0) or (FLookback <= 0) then
Exit;
itemsToRemove := 0;
- if FCount > FMaxLookback then
- itemsToRemove := FCount - FMaxLookback;
+ if FCount > FLookback then
+ itemsToRemove := FCount - FLookback;
if itemsToRemove <= 0 then
Exit;
@@ -231,7 +239,7 @@ begin
if chunksToRemove > 0 then
begin
var itemsInFreedChunks := chunksToRemove * ChunkSize;
- FChunks := System.Copy(FChunks, chunksToRemove, Length(FChunks) - chunksToRemove);
+ FChunks := Copy(FChunks, chunksToRemove, Length(FChunks) - chunksToRemove);
FCount := FCount - itemsInFreedChunks;
end;
end;
@@ -243,7 +251,7 @@ begin
FNull := TNullDataSeries.Create;
end;
-function TNullDataSeries.Copy: IDataSeries;
+function TNullDataSeries.Immutable: IDataSeries;
begin
Result := FNull;
end;
@@ -264,6 +272,11 @@ begin
Result := 0;
end;
+function TNullDataSeries.GetWriter: IDataSeriesWriter;
+begin
+ Result := nil;
+end;
+
function TNullDataSeries.IndexOf(TimeStamp: TDateTime): Int64;
begin
Result := -1;
@@ -271,16 +284,16 @@ end;
{ TStaticDataSeries }
-constructor TStaticDataSeries.Create(const AChunks: TArray.TChunk>; ACount, AMaxLookback, ATotalCount: Int64);
+constructor TStaticDataSeries.Create(const AChunks: TArray.TChunk>; ACount, ALookback, ATotalCount: Int64);
begin
inherited Create;
FChunks := AChunks;
FCount := ACount;
- FMaxLookback := AMaxLookback;
+ FLookback := ALookback;
FTotalCount := ATotalCount;
end;
-function TStaticDataSeries.Copy: IDataSeries;
+function TStaticDataSeries.Immutable: IDataSeries;
begin
Result := Self;
end;
@@ -288,8 +301,8 @@ end;
function TStaticDataSeries.GetCount: Int64;
begin
Result := FCount;
- if (FMaxLookback > 0) and (Result > FMaxLookback) then
- Result := FMaxLookback;
+ if (FLookback > 0) and (Result > FLookback) then
+ Result := FLookback;
end;
function TStaticDataSeries.GetItems(Idx: Int64): TDataPoint;
@@ -301,9 +314,9 @@ begin
Result := FChunks[physicalIndex div TDataArray.ChunkSize][physicalIndex mod TDataArray.ChunkSize];
end;
-function TStaticDataSeries.GetMaxLookback: Int64;
+function TStaticDataSeries.GetLookback: Int64;
begin
- Result := FMaxLookback;
+ Result := FLookback;
end;
function TStaticDataSeries.GetTotalCount: Int64;
@@ -311,9 +324,14 @@ begin
Result := FTotalCount;
end;
+function TStaticDataSeries.GetWriter: IDataSeriesWriter;
+begin
+ Result := nil;
+end;
+
function TStaticDataSeries.IsIndexInLimits(LogicalIndex: Int64): Boolean;
begin
- Result := (FMaxLookback <= 0) or (LogicalIndex < FMaxLookback);
+ Result := (FLookback <= 0) or (LogicalIndex < FLookback);
end;
function TStaticDataSeries.LogicalToPhysicalIndex(LogicalIndex: Int64): Int64;
diff --git a/Src/Myc.Trade.DataPoint.pas b/Src/Myc.Trade.DataPoint.pas
index cf09b02..48ddc62 100644
--- a/Src/Myc.Trade.DataPoint.pas
+++ b/Src/Myc.Trade.DataPoint.pas
@@ -17,25 +17,27 @@ type
constructor Create(ATime: TDateTime; const AData: T);
end;
+ IDataSeriesWriter = interface
+ procedure Add(const Data: TDataPoint); overload;
+ procedure Add(const Data: array of TDataPoint; NumToAdd: Integer = -1); overload;
+ procedure Clear;
+ end;
+
// A time-ordered series of data points, optimized for chronological additions.
// The most recently added element has the logical index 0.
IDataSeries = interface
function GetCount: Int64;
function GetItems(Idx: Int64): TDataPoint;
function GetTotalCount: Int64;
- function Copy: IDataSeries;
+ function Immutable: IDataSeries;
+ function GetWriter: IDataSeriesWriter;
property Count: Int64 read GetCount;
// Accesses data points by their logical index.
// Index 0 is the newest element, Index (Count - 1) is the oldest.
property Items[Idx: Int64]: TDataPoint read GetItems; default;
// The total number of items ever added to the series.
property TotalCount: Int64 read GetTotalCount;
- end;
-
- IDataArray = interface(IDataSeries)
- procedure Add(const Data: TDataPoint); overload;
- procedure Add(const Data: array of TDataPoint; NumToAdd: Integer = -1); overload;
- procedure Clear;
+ property Writer: IDataSeriesWriter read GetWriter;
end;
// Interface Helper for IDataSeries.
@@ -43,12 +45,11 @@ type
TDataSeries = record
private
FDataSeries: IDataSeries;
- FMaxLookback: Int64;
function GetCount: Int64;
function GetItems(Idx: Int64): TDataPoint;
function GetData(Idx: Int64): T;
+ function GetIsWriteable: Boolean;
function GetTime(Idx: Int64): TDateTime;
- function GetMaxLookback: Int64;
class function GetNull: IDataSeries; static;
function GetTotalCount: Int64;
public
@@ -60,10 +61,14 @@ type
class operator Implicit(const A: TDataSeries): IDataSeries;
class operator Implicit(const A: IDataSeries): TDataSeries;
- class function CreateArray(MaxLookback: Int64): IDataArray; static;
+ class function CreateWriteable(MaxLookback: Int64): TDataSeries; static;
- // Create a guaranteed immutable version of the given series.
- function Copy: TDataSeries;
+ // Create an immutable version of the given series.
+ function Immutable: TDataSeries;
+
+ // Writing (only if IsWriteable=true)
+ procedure Add(const Data: array of TDataPoint; NumToAdd: Integer = -1);
+ procedure Clear;
// Searches for a data point by its timestamp.
// Returns the logical index of the matching item.
@@ -75,8 +80,8 @@ type
property Count: Int64 read GetCount;
property Items[Idx: Int64]: TDataPoint read GetItems; default;
property Data[Idx: Int64]: T read GetData;
+ property IsWriteable: Boolean read GetIsWriteable;
property Time[Idx: Int64]: TDateTime read GetTime;
- property MaxLookback: Int64 read GetMaxLookback;
property TotalCount: Int64 read GetTotalCount;
end;
@@ -109,12 +114,24 @@ begin
FDataSeries := Null;
end;
-function TDataSeries.Copy: TDataSeries;
+procedure TDataSeries.Add(const Data: array of TDataPoint; NumToAdd: Integer = -1);
begin
- Result := FDataSeries.Copy;
+ Assert( IsWriteable );
+ FDataSeries.Writer.Add( Data, NumToAdd );
end;
-class function TDataSeries.CreateArray(MaxLookback: Int64): IDataArray;
+procedure TDataSeries.Clear;
+begin
+ Assert( IsWriteable );
+ FDataSeries.Writer.Clear;
+end;
+
+function TDataSeries.Immutable: TDataSeries;
+begin
+ Result := FDataSeries.Immutable;
+end;
+
+class function TDataSeries.CreateWriteable(MaxLookback: Int64): TDataSeries;
begin
Result := TDataArray.Create(MaxLookback);
end;
@@ -154,16 +171,16 @@ begin
Result := FDataSeries[Idx].Data;
end;
+function TDataSeries.GetIsWriteable: Boolean;
+begin
+ Result := Assigned( FDataSeries.Writer );
+end;
+
function TDataSeries.GetTime(Idx: Int64): TDateTime;
begin
Result := FDataSeries[Idx].Time;
end;
-function TDataSeries.GetMaxLookback: Int64;
-begin
- Result := FMaxLookback;
-end;
-
class function TDataSeries.GetNull: IDataSeries;
begin
Result := TNullDataSeries.Null;
diff --git a/Src/Myc.Trade.DataProvider.pas b/Src/Myc.Trade.DataProvider.pas
index 4fe60dc..ccf8fcc 100644
--- a/Src/Myc.Trade.DataProvider.pas
+++ b/Src/Myc.Trade.DataProvider.pas
@@ -12,12 +12,13 @@ type
TDataStreamProvider = class(TInterfacedObject, TMutable>.IMutable)
private
FStream: IDataStream;
- FDataArray: IDataArray;
+ FDataSeries: TDataSeries;
FNewDataAvailable: TFlag;
FChunk: TArray>;
FLookback: Int64;
function GetChanged: TSignal;
function GetValue: TDataSeries;
+ function GetWriter: TMutable>.IWriter;
public
constructor Create(ALookback, AMaxChunkSize: Int64; const AStream: IDataStream);
destructor Destroy; override;
@@ -38,7 +39,7 @@ begin
SetLength(FChunk, AMaxChunkSize);
FStream := AStream;
FNewDataAvailable := TFlag.CreateObserver(FStream.HasData);
- FDataArray := TDataSeries.CreateArray(ALookback);
+ FDataSeries := TDataSeries.CreateWriteable(ALookback);
end;
destructor TDataStreamProvider.Destroy;
@@ -57,9 +58,14 @@ begin
begin
var cnt := FStream.GetChunk(FChunk);
if cnt > 0 then
- FDataArray.Add(FChunk, cnt);
+ FDataSeries.Add(FChunk, cnt);
end;
- Result := FDataArray;
+ Result := FDataSeries;
+end;
+
+function TDataStreamProvider.GetWriter: TMutable>.IWriter;
+begin
+ Result := nil;
end;
{ TDataStreamProvider }
diff --git a/Src/Myc.Trade.DataStream.pas b/Src/Myc.Trade.DataStream.pas
index 21579e2..049219a 100644
--- a/Src/Myc.Trade.DataStream.pas
+++ b/Src/Myc.Trade.DataStream.pas
@@ -101,7 +101,8 @@ type
// Used by cache to actually load an uncached file.
function DoLoad(const FileName: string): TFuture>>;
- function LoadFile(DataFile: TAuraDataFile; Terminated: TState; Proc: TDataProc): TState;
+ function ProcessFile(FileInfo: TAuraDataFile; const DataFile: TFuture>>; Terminated: TState; Proc: TDataProc):
+ TState;
strict private
class var
@@ -392,27 +393,35 @@ begin
Result :=
FindFirstFile(Symbol)
- .Chain(function(const FirstFile: TAuraDataFile): TState begin Result := LoadFile(FirstFile, terminated, capProc); end);
+ .Chain(
+ function(const FirstFileInfo: TAuraDataFile): TState
+ begin
+ Result := ProcessFile(FirstFileInfo, LoadDataFile(FirstFileInfo), terminated, capProc);
+ end);
end;
function TAuraDataServer.LoadDataFile(const DataFile: TAuraDataFile): TFuture>>;
begin
- Result := FCachedFiles.GetOrAdd(DataFile.GetFullFileName);
+ if DataFile.IsValid then
+ Result := FCachedFiles.GetOrAdd(DataFile.GetFullFileName);
end;
-function TAuraDataServer.LoadFile(DataFile: TAuraDataFile; Terminated: TState; Proc: TDataProc): TState;
+function TAuraDataServer.ProcessFile(FileInfo: TAuraDataFile; const DataFile: TFuture>>; Terminated: TState; Proc:
+ TDataProc): TState;
begin
- if not DataFile.IsValid or Terminated.IsSet then
+ if not FileInfo.IsValid or Terminated.IsSet then
exit(TState.Null);
- var data := FCachedFiles.GetOrAdd(DataFile.GetFullFileName);
+ // Read ahead the next file, while processing the current one
+ var nextFileInfo := FileInfo.GetNextFile;
+ var nextFile := LoadDataFile( nextFileInfo );
Result :=
- data.Chain(
+ DataFile.Chain(
function(const Data: TArray>): TState
begin
Proc(Data, Terminated);
- Result := LoadFile(DataFile.GetNextFile, Terminated, Proc);
+ Result := ProcessFile(nextFileInfo, nextFile, Terminated, Proc);
end
);
end;