unit MainForm; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, System.DateUtils, System.Generics.Collections, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls, FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base, FMX.ListView, FMX.Memo.Types, FMX.ScrollBox, FMX.Memo, FMX.Objects, Myc.Futures, Myc.Trade.DataStream, Myc.Trade.DataPoint, Myc.Trade.DataProvider, Myc.Signals, Myc.Lazy, Myc.Signals.FMX, Myc.TaskManager, FMX.ListBox, FMX.Layouts, FMX.MultiView, FMX.TreeView; type TForm1 = class(TForm) LogMemo: TMemo; Panel1: TPanel; Layout: TFlowLayout; SymbolsComboBox: TComboBox; RandomBox: TCheckBox; LoadButton: TButton; RandomButton: TButton; ChartButton: TButton; StopButton: TButton; TreeView1: TTreeView; Splitter1: TSplitter; procedure RandomButtonClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure LoadButtonClick(Sender: TObject); procedure ChartButtonClick(Sender: TObject); procedure StopButtonClick(Sender: TObject); procedure LayoutResized(Sender: TObject); private const cnt = 20; type TRndItem = record Stream: IDataStream; Data: TMutable>; Labl: TLabel; end; private FOnEvent: TNotifyEvent; { Private declarations } FServer: IDataServer; FSymbols: TFuture>; FRandom: TList; FTerminate: TEvent; FLoadDone: TState; function SelectedSymbol: String; function SelectedStream: IDataStream; public { Public declarations } published property OnEvent: TNotifyEvent read FOnEvent write FOnEvent; end; var Form1: TForm1; implementation {$R *.fmx} procedure TForm1.StopButtonClick(Sender: TObject); begin FTerminate.Notify; end; procedure TForm1.FormCreate(Sender: TObject); begin FTerminate := TEvent.CreateEvent; FRandom := TList.Create; // 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; FSymbols := FServer.EnumerateSymbols; SymbolsComboBox.ProcessSignal( FSymbols.Done.Signal, procedure begin SymbolsComboBox.BeginUpdate; try SymbolsComboBox.Items.Clear; SymbolsComboBox.Items.AddStrings(FSymbols.WaitFor); if SymbolsComboBox.Items.Count > 0 then 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; end; end ); end; procedure TForm1.FormDestroy(Sender: TObject); begin FSymbols.WaitFor; FTerminate.Notify; TaskManager.WaitFor(FLoadDone); FRandom.Free; end; procedure TForm1.LayoutResized(Sender: TObject); begin LogMemo.Lines.Add('resize'); end; procedure TForm1.LoadButtonClick(Sender: TObject); begin if SymbolsComboBox.ItemIndex < 0 then exit; var Stream := FServer.CreateStream(FSymbols.WaitFor[SymbolsComboBox.ItemIndex]); var Data := TDataStreamProvider.Create(30000, 10000, Stream); var path := TPath.Create(Self); path.Parent := Layout; path.Align := TAlignLayout.None; path.ProcessSignal( Data.Changed, procedure begin var Prices := Data.Value; if Prices.Count > 0 then begin path.BeginUpdate; try path.Data.Clear; path.Data.MoveTo(PointF(path.Width - 1, Prices[0].Data.Ask)); for var i := 1 to Prices.Count - 1 do path.Data.LineTo(PointF(path.Width - i - 1, Prices[i].Data.Ask)); finally path.EndUpdate; end; end; end ); end; procedure TForm1.RandomButtonClick(Sender: TObject); begin var rnd: TRndItem; rnd.Stream := FServer.CreateStream(FSymbols.WaitFor[Random(Length(FSymbols.WaitFor))]); rnd.Data := TDataStreamProvider.Create(3000, 1000, rnd.Stream); rnd.Labl := TLabel.Create(Self); rnd.Labl.Parent := Layout; rnd.Labl.Align := TAlignLayout.None; rnd.Labl.WordWrap := false; rnd.Labl.Width := 300; rnd.Labl.Text := rnd.Stream.Symbol + ' loading...'; FRandom.Add(rnd); var Proc := procedure(idx: Integer) begin FRandom[idx] .Labl .ProcessSignal( FRandom[idx].Data.Changed, procedure begin var data := FRandom[idx].Data.Value; if data.Count > 0 then begin var dp := data[0]; FRandom[idx].Labl.Text := FRandom[idx].Stream.Symbol + ' ' + dp.Time.ToString + ' ' + data.TotalCount.ToString + ' ' + dp.Data.Ask.ToString; end; end); end; Proc(FRandom.Count - 1); end; procedure TForm1.ChartButtonClick(Sender: TObject); begin var Symbol := SelectedSymbol; if Symbol = '' then exit; var currPathData := TWriteable>.CreateWriteable.Protect; var currLog := TWriteable.CreateWriteable.Protect; const width = 300; var done := TaskManager.RunTask( nil, function: TState begin var Prices := TDataSeries.CreateWriteable(width); Result := FServer.ProcessData( Symbol, FTerminate.Signal, procedure(const Values: TArray>; const Terminated: TState) begin Prices.Add(Values); currLog.Value := Prices.TotalCount.ToString; 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)); for var i := n - 1 downto 0 do PathData.LineTo(PointF(n - i - 1, Prices[i].Data.Bid)); end; PathData.ClosePath; currPathData.Value := TObjectRef.Create(PathData); end ); end ); FLoadDone := TState.All([FLoadDone, done]); var path := TPath.Create(Self); path.Parent := Layout; path.Align := TAlignLayout.None; path.ProcessSignal( currPathData.Changed, procedure(out IsDone: Boolean) begin if currPathData.Value <> nil then path.Data.Assign(currPathData.Value.Obj); IsDone := done.IsSet; end ); end; function TForm1.SelectedStream: IDataStream; begin var sym := SelectedSymbol; if sym = '' then exit(nil); Result := FServer.CreateStream(sym); end; function TForm1.SelectedSymbol: String; begin Result := ''; if RandomBox.IsChecked then Result := FSymbols.WaitFor[Random(Length(FSymbols.WaitFor))] else if SymbolsComboBox.ItemIndex >= 0 then Result := FSymbols.WaitFor[SymbolsComboBox.ItemIndex]; end; end.