DataServer 1st Version
This commit is contained in:
@@ -35,7 +35,7 @@ type
|
||||
constructor Create(const AChanged: TSignal; const AProc: TFunc<T>);
|
||||
end;
|
||||
|
||||
TMycWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TMutable<T>.IWriteableMutable)
|
||||
TMycWriteableMutable<T> = class(TInterfacedObject, TMutable<T>.IMutable, TMutable<T>.IWriteable)
|
||||
private
|
||||
FValue: T;
|
||||
FChanged: TEvent;
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ type
|
||||
property Value: T read GetValue;
|
||||
end;
|
||||
|
||||
IWriteableMutable = interface(IMutable)
|
||||
IWriteable = interface(IMutable)
|
||||
procedure SetValue(const Value: T);
|
||||
end;
|
||||
|
||||
@@ -42,7 +42,7 @@ type
|
||||
|
||||
class function Construct(const Changing: TSignal; const Proc: TFunc<T>): TMutable<T>; overload; static;
|
||||
|
||||
class function CreateWriteable(const Init: T): IWriteableMutable; overload; static;
|
||||
class function CreateWriteable(const Init: T): IWriteable; overload; static;
|
||||
|
||||
property Changed: TSignal read GetChanged;
|
||||
end;
|
||||
@@ -105,7 +105,7 @@ begin
|
||||
Result := TMycFuncMutable<T>.Create(Changing, Proc);
|
||||
end;
|
||||
|
||||
class function TMutable<T>.CreateWriteable(const Init: T): IWriteableMutable;
|
||||
class function TMutable<T>.CreateWriteable(const Init: T): IWriteable;
|
||||
begin
|
||||
Result := TMycWriteableMutable<T>.Create(Init);
|
||||
end;
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
unit Myc.Trade.DataPoint;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils;
|
||||
|
||||
type
|
||||
IDataPoint<T> = interface
|
||||
['{6A52697A-2868-42A9-982D-993542B7B360}']
|
||||
function GetData: T;
|
||||
function GetTime: TDateTime;
|
||||
function GetVolume: Double;
|
||||
|
||||
property Time: TDateTime read GetTime;
|
||||
property Volume: Double read GetVolume;
|
||||
property Data: T read GetData;
|
||||
end;
|
||||
|
||||
ITick = interface
|
||||
['{B342223B-D299-4A1C-82F3-569F54417A66}']
|
||||
function GetAsk: Double;
|
||||
function GetBid: Double;
|
||||
|
||||
property Ask: Double read GetAsk;
|
||||
property Bid: Double read GetBid;
|
||||
end;
|
||||
|
||||
IOHLC = interface
|
||||
['{05374E3C-731B-44FA-A23E-051F1461B78D}']
|
||||
function GetOpen: Double;
|
||||
function GetHigh: Double;
|
||||
function GetLow: Double;
|
||||
function GetClose: Double;
|
||||
|
||||
property Open: Double read GetOpen;
|
||||
property High: Double read GetHigh;
|
||||
property Low: Double read GetLow;
|
||||
property Close: Double read GetClose;
|
||||
end;
|
||||
|
||||
// Abstract base class for all data points.
|
||||
TDataPoint<T> = class abstract(TInterfacedObject, IDataPoint<T>)
|
||||
protected
|
||||
fTime: TDateTime;
|
||||
fVolume: Double;
|
||||
FData: T;
|
||||
function GetTime: TDateTime;
|
||||
function GetVolume: Double;
|
||||
function GetData: T;
|
||||
public
|
||||
constructor Create(Time: TDateTime; Volume: Double; const AData: T);
|
||||
end;
|
||||
|
||||
TTick = class(TInterfacedObject, ITick)
|
||||
private
|
||||
fAsk: Double;
|
||||
fBid: Double;
|
||||
function GetAsk: Double;
|
||||
function GetBid: Double;
|
||||
public
|
||||
constructor Create(Ask: Double; Bid: Double);
|
||||
end;
|
||||
|
||||
TOHLC = class(TInterfacedObject, IOHLC)
|
||||
private
|
||||
fOpen: Double;
|
||||
fHigh: Double;
|
||||
fLow: Double;
|
||||
fClose: Double;
|
||||
function GetClose: Double;
|
||||
function GetHigh: Double;
|
||||
function GetLow: Double;
|
||||
function GetOpen: Double;
|
||||
public
|
||||
constructor Create(Open, High, Low, Close: Double);
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TDataPoint }
|
||||
|
||||
constructor TDataPoint<T>.Create(Time: TDateTime; Volume: Double; const AData: T);
|
||||
begin
|
||||
fTime := Time;
|
||||
fVolume := Volume;
|
||||
FData := AData;
|
||||
end;
|
||||
|
||||
function TDataPoint<T>.GetData: T;
|
||||
begin
|
||||
Result := FData;
|
||||
end;
|
||||
|
||||
function TDataPoint<T>.GetTime: TDateTime;
|
||||
begin
|
||||
result := fTime;
|
||||
end;
|
||||
|
||||
function TDataPoint<T>.GetVolume: Double;
|
||||
begin
|
||||
result := fVolume;
|
||||
end;
|
||||
|
||||
{ TTick }
|
||||
|
||||
constructor TTick.Create(Ask: Double; Bid: Double);
|
||||
begin
|
||||
inherited Create;
|
||||
fAsk := Ask;
|
||||
fBid := Bid;
|
||||
end;
|
||||
|
||||
function TTick.GetAsk: Double;
|
||||
begin
|
||||
result := fAsk;
|
||||
end;
|
||||
|
||||
function TTick.GetBid: Double;
|
||||
begin
|
||||
result := fBid;
|
||||
end;
|
||||
|
||||
{ TOHLC }
|
||||
|
||||
constructor TOHLC.Create(Open, High, Low, Close: Double);
|
||||
begin
|
||||
inherited Create;
|
||||
fOpen := Open;
|
||||
fHigh := High;
|
||||
fLow := Low;
|
||||
fClose := Close;
|
||||
end;
|
||||
|
||||
function TOHLC.GetClose: Double;
|
||||
begin
|
||||
result := fClose;
|
||||
end;
|
||||
|
||||
function TOHLC.GetHigh: Double;
|
||||
begin
|
||||
result := fHigh;
|
||||
end;
|
||||
|
||||
function TOHLC.GetLow: Double;
|
||||
begin
|
||||
result := fLow;
|
||||
end;
|
||||
|
||||
function TOHLC.GetOpen: Double;
|
||||
begin
|
||||
result := fOpen;
|
||||
end;
|
||||
|
||||
end.
|
||||
@@ -1,39 +1,5 @@
|
||||
unit Myc.Trade.DataSeries;
|
||||
|
||||
(* ------------------------------------------------------------------------------
|
||||
This unit provides functions to load tick data (TTickData) from
|
||||
binary files. The data originates from a C# application
|
||||
and has the structure OADateTime (Double), Ask (Single), and Bid (Single).
|
||||
|
||||
The files follow the naming convention:
|
||||
For .tab files: Symbol_Year_MM.tab OR Symbol_Year_MM.tab_zip
|
||||
For .tab-live files: Symbol_Year_MM.tab-live (NEVER compressed)
|
||||
(MM represents the two-digit month, e.g., 01 for January, 12 for December)
|
||||
|
||||
If both compressed (.tab_zip) and uncompressed (.tab) versions of a .tab
|
||||
file exist, the compressed version is preferred. Files ending with _zip
|
||||
are expected to be ZIP archives containing the actual data file
|
||||
(e.g., Symbol_Year_MM.tab).
|
||||
|
||||
Loading occurs in two phases:
|
||||
1. All .tab files (regular or _zip) are processed chronologically by
|
||||
month and year. Unique ticks are loaded, and the timestamp of the
|
||||
latest tick across all .tab files is determined (overallLastTabTickTime).
|
||||
Assumes timestamps are unique across all .tab files.
|
||||
2. All .tab-live files (which are never compressed), for months/years
|
||||
corresponding to found .tab files, are processed. Ticks from a
|
||||
.tab-live file are only integrated if their timestamp is strictly later
|
||||
than overallLastTabTickTime. Assumes such ticks are globally unique.
|
||||
|
||||
If a .tab-live file results in no new data being added under these rules,
|
||||
it is deleted after processing.
|
||||
|
||||
The loading function automatically detects subsequent monthly/yearly files.
|
||||
|
||||
Main Function:
|
||||
LoadTickDataSeries - Loads a series of tick data files.
|
||||
------------------------------------------------------------------------------ *)
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
@@ -293,9 +259,9 @@ begin
|
||||
|
||||
for var i := 0 to High(fL) do
|
||||
begin
|
||||
FCachedFiles.Remove(fL[i].Name);
|
||||
if not IsMemoryLow then
|
||||
break;
|
||||
FCachedFiles.Remove(fL[i].Name);
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -319,10 +285,6 @@ begin
|
||||
|
||||
if FileName.EndsWith('_zip', True) then
|
||||
begin
|
||||
var zipFileBytes := TFile.ReadAllBytes(FileName); // Read all bytes of the .zip file
|
||||
if Length(zipFileBytes) = 0 then
|
||||
exit;
|
||||
|
||||
var capFileName := FileName;
|
||||
Result :=
|
||||
TFuture<TBytes>
|
||||
@@ -335,7 +297,7 @@ begin
|
||||
.Chain<TArray<TDataPoint>>(
|
||||
function(bytes: TBytes): TArray<TDataPoint>
|
||||
begin
|
||||
var zipMemoryStream := TBytesStream.Create(zipFileBytes); // Create a memory stream to hold the zip file content
|
||||
var zipMemoryStream := TBytesStream.Create(bytes); // Create a memory stream to hold the zip file content
|
||||
try
|
||||
zipMemoryStream.Position := 0;
|
||||
Result := ReadCompressedData(zipMemoryStream);
|
||||
@@ -349,6 +311,7 @@ begin
|
||||
var capFileName := FileName;
|
||||
Result :=
|
||||
TFuture<TArray<TDataPoint>>.Construct(
|
||||
TLatch.Enqueue(LoadGate),
|
||||
function: TArray<TDataPoint>
|
||||
begin
|
||||
if TFile.Exists(capFileName) then
|
||||
@@ -375,7 +338,6 @@ begin
|
||||
begin
|
||||
var cachedFile: TCachedFile;
|
||||
cachedFile.Name := Filename;
|
||||
var age: TDateTime;
|
||||
if FileAge(Filename, cachedFile.Age, true) then
|
||||
begin
|
||||
cachedFile.Data := Result;
|
||||
@@ -418,7 +380,7 @@ begin // Start of LoadDataSeries
|
||||
var maxTabYearFound := -1;
|
||||
var maxTabMonthFound := -1;
|
||||
|
||||
var filesToLoadPhase1 := TList<TPhase1FileEntry>.Create; // Create list with the named record type
|
||||
var filesToLoad := TList<TPhase1FileEntry>.Create; // Create list with the named record type
|
||||
try
|
||||
while True do
|
||||
begin
|
||||
@@ -443,7 +405,7 @@ begin // Start of LoadDataSeries
|
||||
tabFileEntryRecord.Path := actualTabFileToLoad;
|
||||
tabFileEntryRecord.Year := currentTabYear;
|
||||
tabFileEntryRecord.Month := currentTabMonth;
|
||||
filesToLoadPhase1.Add(tabFileEntryRecord);
|
||||
filesToLoad.Add(tabFileEntryRecord);
|
||||
|
||||
// Advance to the next month
|
||||
Inc(currentTabMonth);
|
||||
@@ -460,7 +422,7 @@ begin // Start of LoadDataSeries
|
||||
try
|
||||
var LoadGate: TLatch;
|
||||
|
||||
for var tabFileEntry: TPhase1FileEntry in filesToLoadPhase1 do // Iterate with the correct type
|
||||
for var tabFileEntry: TPhase1FileEntry in filesToLoad do // Iterate with the correct type
|
||||
begin
|
||||
var data := LoadDataFile(LoadGate, tabFileEntry.Path);
|
||||
|
||||
@@ -490,7 +452,7 @@ begin // Start of LoadDataSeries
|
||||
loadedFileList.Free;
|
||||
end;
|
||||
finally
|
||||
filesToLoadPhase1.Free;
|
||||
filesToLoad.Free;
|
||||
end;
|
||||
|
||||
Result :=
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
unit Myc.Trade.DataServer;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Generics.Collections,
|
||||
Myc.Lazy,
|
||||
Myc.Trade.DataPoint,
|
||||
Myc.Trade.DataSeries;
|
||||
|
||||
type
|
||||
IDataProvider = interface
|
||||
['{B2A9996C-724B-4416-A882-595B7E58066D}']
|
||||
procedure Fetch;
|
||||
end;
|
||||
|
||||
IDataServer<T> = interface
|
||||
['{A6E246A2-E84E-49AB-A63E-333E561E488C}']
|
||||
function GetData: TMutable<TArray<T>>;
|
||||
function GetIsLiveData: TMutable<Boolean>;
|
||||
property Data: TMutable<TArray<T>> read GetData;
|
||||
property IsLiveData: TMutable<Boolean> read GetIsLiveData;
|
||||
end;
|
||||
|
||||
TDataServer<T> = class(TInterfacedObject, IDataServer<T>, IDataProvider)
|
||||
protected
|
||||
function GetData: TMutable<TArray<T>>; virtual; abstract;
|
||||
function GetIsLiveData: TMutable<Boolean>; virtual; abstract;
|
||||
procedure Fetch; virtual; abstract;
|
||||
end;
|
||||
|
||||
IDataServerNode<T> = interface
|
||||
['{DA3531F1-158E-4A63-8E5A-34089C537B1B}']
|
||||
function CreateDataServer: IDataServer<T>;
|
||||
end;
|
||||
|
||||
TDataServerNode<T> = class(TInterfacedObject, IDataServerNode<T>)
|
||||
public
|
||||
// Factory method to create the actual data server instance.
|
||||
function CreateDataServer: IDataServer<T>; virtual; abstract;
|
||||
end;
|
||||
|
||||
TFileStreamServerNode<T> = class(TDataServerNode<T>)
|
||||
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
@@ -0,0 +1,48 @@
|
||||
unit Myc.Trade.Node;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils;
|
||||
|
||||
type
|
||||
// Base interface for all objects created by an INode factory.
|
||||
ITradeObject = interface
|
||||
['{B8A29A67-272E-456A-A816-A19A76E43213}']
|
||||
end;
|
||||
|
||||
// Represents a node in the trading graph, acting as a factory for a trade object.
|
||||
INode = interface
|
||||
['{E879B5E4-3A4E-434A-8A4F-A9F71B0B7E1C}']
|
||||
function GetCaption: string;
|
||||
// Factory method to create the runtime object.
|
||||
function CreateObject: ITradeObject;
|
||||
|
||||
property Caption: string read GetCaption;
|
||||
end;
|
||||
|
||||
// Abstract base class for all node implementations.
|
||||
TNodeBase = class abstract(TInterfacedObject, INode)
|
||||
protected
|
||||
fCaption: string;
|
||||
function GetCaption: string;
|
||||
public
|
||||
constructor Create(const Caption: string);
|
||||
function CreateObject: ITradeObject; virtual; abstract;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TNodeBase }
|
||||
|
||||
constructor TNodeBase.Create(const Caption: string);
|
||||
begin
|
||||
fCaption := Caption;
|
||||
end;
|
||||
|
||||
function TNodeBase.GetCaption: string;
|
||||
begin
|
||||
result := fCaption;
|
||||
end;
|
||||
|
||||
end.
|
||||
Reference in New Issue
Block a user