Implementing first "strategy" for proof of concept

This commit is contained in:
Michael Schimmel
2025-07-11 11:06:18 +02:00
parent 644b6074d6
commit 487169afe0
20 changed files with 1761 additions and 274 deletions
+145 -48
View File
@@ -44,7 +44,9 @@ uses
FMX.ImgList,
System.Actions,
FMX.ActnList,
TestChartControl;
DynamicFMXControl,
FirstStrategy,
Myc.FMX.Chart;
type
TForm1 = class(TForm)
@@ -69,9 +71,9 @@ type
TreeView: TTreeView;
TestButton: TSpeedButton;
TestAction: TAction;
SpeedButton1: TSpeedButton;
TestPopup: TPopup;
FlowLayout1: TFlowLayout;
FlowLayout: TFlowLayout;
StrategyButton: TSpeedButton;
procedure RandomButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
@@ -82,31 +84,33 @@ type
procedure TreeViewDblClick(Sender: TObject);
procedure AddWorkspaceActionExecute(Sender: TObject);
procedure TestActionExecute(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure StrategyButtonClick(Sender: TObject);
private
const
cnt = 20;
type
TRndItem = record
Stream: IDataStream<TAskBidItem>;
Data: TMutable<TDataSeries<TAskBidItem>>;
Stream: IDataStream<TAuraAskBidFileItem>;
Data: TMutable<TDataSeries<TAuraAskBidFileItem>>;
Labl: TLabel;
end;
private
FOnEvent: TNotifyEvent;
{ Private declarations }
FServer: IDataServer<TAskBidItem>;
FServer: IDataServer<TAuraAskBidFileItem>;
FSymbols: TFuture<TArray<String>>;
FRandom: TList<TRndItem>;
FTerminate: TEvent;
FLoadDone: TState;
FProcessDone: TState;
FApplication: IAuraApplication;
FModulesItem: TTreeViewItem;
function SelectedSymbol: String;
function ExecuteStrategy(const Symbol: String; const Processor: IMycProcessor<TArray<TDataPoint<TAskBidItem>>>): TState;
public
procedure NewWorkspace;
function CurrLayout: TFlowLayout;
function CurrLayout<T: TControl>: T;
procedure AlignControl(Control: TControl);
published
property OnEvent: TNotifyEvent read FOnEvent write FOnEvent;
end;
@@ -134,10 +138,6 @@ begin
scrollbox.Parent := tab;
scrollbox.Align := TAlignLayout.Client;
var flow := TFlowLayout.Create(Self);
flow.Parent := tab;
flow.Align := TAlignLayout.Client;
tab.ProcessSignal(ws.Name.Changed, procedure begin tab.Text := ws.Caption; end);
end;
@@ -146,6 +146,68 @@ begin
FTerminate.Notify;
end;
procedure TForm1.StrategyButtonClick(Sender: TObject);
begin
var Layout := CurrLayout<TVertScrollBox>;
if Layout = nil then
exit;
var Symbol := SelectedSymbol;
if Symbol = '' then
exit;
var stateText := TWriteable<String>.CreateWriteable.Protect;
var stateLabel := TLabel.Create(Self);
AlignControl( stateLabel );
stateLabel.Text := 'Initializing...';
var chart := TMycChart.Create(Self);
AlignControl( chart );
chart.Height := Layout.ChildrenRect.Width*9/16;
/////
var strategy: ITicksToTimeframe := TTicksToTimeframe.Create( D, stateText );
var Ohlc: IMycIndicator<TDataPoint<TOhlcItem>, TOhlcItem> := TMycGenericIndicator<TDataPoint<TOhlcItem>, TOhlcItem>.Create( 0,
function( const Ohlc: TDataPoint<TOhlcItem> ): TOhlcItem
begin
Result := Ohlc.Data;
end );
strategy.Observers.Link(Ohlc);
var Closes: IMycIndicator<TOhlcItem, Double> := TMycGenericIndicator<TOhlcItem, Double>.Create( 0,
function( const Ohlc: TOhlcItem ): Double
begin
Result := Ohlc.Close;
end );
Ohlc.Observers.Link( Closes );
var Hull: IMycIndicator<Double, Double> := THullMovingAverage.Create( 50 );
Closes.Observers.Link( Hull );
Hull.Observers.Link(chart.CreateDoubleListener);
var done := ExecuteStrategy( Symbol, strategy );
/////
stateLabel.ProcessSignal(
stateText.Changed, done,
procedure
begin
stateLabel.Text := stateText.Value;
end );
FProcessDone := TState.All([FProcessDone, done]);
strategy.Observers.Link(chart.CreateOhlcListener);
end;
procedure TForm1.TreeViewDblClick(Sender: TObject);
begin
var sel := TreeView.Selected as TTreeViewItem;
@@ -209,6 +271,7 @@ begin
// Create an instance of the TAuraTABFileServer. The server can be reused for multiple stream creations. [364]
FServer := TAuraTABFileServer.Create('\\COFFEE\TickData\Pepperstone');
SymbolsComboBox.Enabled := false;
ChartButton.Enabled := false;
LoadButton.Enabled := false;
@@ -244,7 +307,7 @@ procedure TForm1.FormDestroy(Sender: TObject);
begin
FSymbols.WaitFor;
FTerminate.Notify;
TaskManager.WaitFor(FLoadDone);
TaskManager.WaitFor(FProcessDone);
FRandom.Free;
end;
@@ -257,12 +320,12 @@ procedure TForm1.LoadButtonClick(Sender: TObject);
begin
if SymbolsComboBox.ItemIndex < 0 then
exit;
var Layout := CurrLayout;
var Layout := CurrLayout<TVertScrollBox>;
if Layout = nil then
exit;
var Stream := FServer.CreateStream(FSymbols.WaitFor[SymbolsComboBox.ItemIndex]);
var Data := TDataStreamProvider.Create<TAskBidItem>(30000, 10000, Stream);
var Data := TDataStreamProvider.Create<TAuraAskBidFileItem>(30000, 10000, Stream);
var path := TPath.Create(Self);
path.Parent := Layout;
@@ -292,14 +355,14 @@ end;
procedure TForm1.RandomButtonClick(Sender: TObject);
begin
var Layout := CurrLayout;
var Layout := CurrLayout<TVertScrollBox>;
if Layout = nil then
exit;
var rnd: TRndItem;
rnd.Stream := FServer.CreateStream(FSymbols.WaitFor[Random(Length(FSymbols.WaitFor))]);
rnd.Data := TDataStreamProvider.Create<TAskBidItem>(3000, 1000, rnd.Stream);
rnd.Data := TDataStreamProvider.Create<TAuraAskBidFileItem>(3000, 1000, rnd.Stream);
rnd.Labl := TLabel.Create(Self);
rnd.Labl.Parent := Layout;
@@ -346,9 +409,22 @@ begin
NewWorkspace;
end;
procedure TForm1.AlignControl(Control: TControl);
begin
var Layout := CurrLayout<TVertScrollBox>;
if Layout = nil then
exit;
Control.Parent := Layout;
Control.Width := Layout.Width;
Control.Position.Y := Layout.ChildrenRect.Bottom+1;
Control.Anchors := [TAnchorKind.akLeft, TAnchorKind.akRight];
Control.Align := TAlignLayout.Top;
end;
procedure TForm1.ChartButtonClick(Sender: TObject);
begin
var Layout := CurrLayout;
var Layout := CurrLayout<TVertScrollBox>;
if Layout = nil then
exit;
@@ -361,41 +437,44 @@ begin
const width = 300;
var terminated := TFlag.CreateObserver(FTerminate.Signal).State;
var done :=
TaskManager.RunTask(
nil,
function: TState
begin
var Prices := TDataSeries<TAskBidItem>.CreateDataSeries(width);
var Prices := TDataSeries<TAuraAskBidFileItem>.CreateDataSeries(width);
Result :=
FServer.ProcessData(
Symbol,
FTerminate.Signal,
procedure(const Values: TArray<TDataPoint<TAskBidItem>>; const Terminated: TState)
begin
Prices := Prices.Add(Values);
currLog.Value := Prices.TotalCount.ToString;
var PathData := TPathData.Create;
if Prices.Count > 0 then
terminated,
TMycGenericProcessor<TArray<TDataPoint<TAuraAskBidFileItem>>>.Create(
procedure(const Values: TArray<TDataPoint<TAuraAskBidFileItem>>)
begin
var n := Prices.Count;
PathData.MoveTo(PointF(n - 1, Prices[0].Data.Ask));
for var i := 1 to n - 1 do
PathData.LineTo(PointF(n - i - 1, Prices[i].Data.Ask));
Prices := Prices.Add(Values);
currLog.Value := Prices.TotalCount.ToString;
for var i := n - 1 downto 0 do
PathData.LineTo(PointF(n - i - 1, Prices[i].Data.Bid));
end;
PathData.ClosePath;
var PathData := TPathData.Create;
if Prices.Count > 0 then
begin
var n := Prices.Count;
PathData.MoveTo(PointF(n - 1, Prices[0].Data.Ask));
for var i := 1 to n - 1 do
PathData.LineTo(PointF(n - i - 1, Prices[i].Data.Ask));
currPathData.Value := TObjectRef<TPathData>.Create(PathData);
end
for var i := n - 1 downto 0 do
PathData.LineTo(PointF(n - i - 1, Prices[i].Data.Bid));
end;
PathData.ClosePath;
currPathData.Value := TObjectRef<TPathData>.Create(PathData);
end )
);
end
);
FLoadDone := TState.All([FLoadDone, done]);
FProcessDone := TState.All([FProcessDone, done]);
var path := TPath.Create(Self);
path.Parent := Layout;
@@ -412,19 +491,19 @@ begin
);
end;
function TForm1.CurrLayout: TFlowLayout;
function TForm1.CurrLayout<T>: T;
begin
if TabControl.ActiveTab = nil then
exit(nil);
var Res: TFlowLayout := nil;
var Res: T := nil;
TabControl.ActiveTab.EnumControls(
function(Control: TControl): TEnumControlsResult
begin
Result := TEnumControlsResult.Continue;
if Control is TFlowLayout then
if Control is T then
begin
Res := Control as TFlowLayout;
Res := Control as T;
Result := TEnumControlsResult.Stop;
end;
end
@@ -433,6 +512,29 @@ begin
Result := Res;
end;
function TForm1.ExecuteStrategy(const Symbol: String; const Processor: IMycProcessor<TArray<TDataPoint<TAskBidItem>>>): TState;
var
dataProvider: IMycConverter<TArray<TDataPoint<TAuraAskBidFileItem>>, TArray<TDataPoint<TAskBidItem>>>;
begin
var terminated := TFlag.CreateObserver(FTerminate.Signal).State;
dataProvider := TMycGenericConverter<TArray<TDataPoint<TAuraAskBidFileItem>>, TArray<TDataPoint<TAskBidItem>>>.Create(
function( const Values: TArray<TDataPoint<TAuraAskBidFileItem>> ): TArray<TDataPoint<TAskBidItem>>
begin
SetLength( Result, Length( Values ) );
for var i:=0 to High(Result) do
begin
Result[i].Time := Values[i].Time;
Result[i].Data.Ask := Values[i].Data.Ask;
Result[i].Data.Bid := Values[i].Data.Bid;
end;
end );
dataProvider.Observers.Link( Processor );
Result := FServer.ProcessData( Symbol, terminated, dataProvider );
end;
function TForm1.SelectedSymbol: String;
begin
Result := '';
@@ -442,9 +544,4 @@ begin
Result := FSymbols.WaitFor[SymbolsComboBox.ItemIndex];
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
TestChartForm.Visible := true;
end;
end.