unit L1PlaybackUnit; { This is a very detailed way to simulate TOS and L1 data. You can download real tick data from a data provider then play it back. You can play it back exactly, or you can modify some attributes, or you can just completely make up the data. The implementation is currently tied to esignal, so it doesn't work. } interface uses DataNodes, GenericTickDataNodes, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls; type TTosL1Playback = class(TForm) Panel1: TPanel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; FirstInListDate: TLabel; LastSentDate: TLabel; NextToSendDate: TLabel; LastInListDate: TLabel; TosDataPanel: TPanel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; PriceValue: TEdit; SizeValue: TEdit; TicksValue: TEdit; ExchangeValue: TEdit; L1DataPanel: TPanel; Label9: TLabel; Label10: TLabel; Label11: TLabel; Label12: TLabel; Label13: TLabel; Label14: TLabel; Label15: TLabel; Label16: TLabel; Label17: TLabel; Label18: TLabel; Label19: TLabel; BidTickValue: TRadioGroup; BidPriceValue: TEdit; BidSizeValue: TEdit; BidExchangeValue: TEdit; AskPriceValue: TEdit; AskSizeValue: TEdit; AskExchangeValue: TEdit; VolumeValue: TEdit; OpenValue: TEdit; HighValue: TEdit; LowValue: TEdit; PreviousCloseValue: TEdit; SendCurrentPanel: TPanel; SendRecord: TButton; UpdateHighAndLow: TCheckBox; AutoLoadNextRecord: TCheckBox; NewTradeValue: TCheckBox; UpdateOtherFields: TCheckBox; SymbolPanel: TPanel; Label20: TLabel; SymbolValue: TEdit; SetSymbolButton: TButton; ReloadFields: TButton; PositionInListTrackBar: TTrackBar; SendMultiplePanel: TPanel; SendMultiple: TButton; SendQuantity: TEdit; CountTicks: TRadioButton; CountPrints: TRadioButton; CountShares: TRadioButton; Label21: TLabel; PositionInListLabel: TLabel; LoadFromFile: TButton; SaveToFile: TButton; SaveDialog1: TSaveDialog; OpenDialog1: TOpenDialog; FormTValue: TCheckBox; procedure UpdateHighAndLowClick(Sender: TObject); procedure UpdateOtherFieldsClick(Sender: TObject); procedure SendRecordClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure SetSymbolButtonClick(Sender: TObject); procedure SymbolValueChange(Sender: TObject); procedure PositionInListTrackBarChange(Sender: TObject); procedure SendMultipleClick(Sender: TObject); procedure SaveToFileClick(Sender: TObject); procedure LoadFromFileClick(Sender: TObject); procedure FormDestroy(Sender: TObject); private FSymbol : String; DeferredUpdate : TDeferredUpdate; DeferredUpdateLink : TDataNodeLink; TickDataNode : TGenericTickDataNode; TickDataNodeLink : TDataNodeLink; TickData : TTickRecordArray; Procedure NewTickData; Procedure ShowNewTickData; Procedure SetIndex(Index : Integer); Procedure SetSymbol(Symbol : String); Procedure SendFromScreen; Procedure AutoUpdateFields; Procedure UpdateEnabledDisabled; Procedure AdvanceRecord; Procedure ReleaseOldDataNodes; public { Public declarations } end; var TosL1Playback: TTosL1Playback; implementation {$R *.dfm} Uses GenericTosDataNode, {EsigDmThread,} TwoDLookup, Math; //////////////////////////////////////////////////////////////////////// // TSimulatedDmInfo //////////////////////////////////////////////////////////////////////// { Type TSimulatedDmInfo = Class(TDmInfo) Private FTime : TDateTime; Protected Procedure BeforeDelivery; Override; Public Property Time : TDateTime Read FTime Write FTime; End; Procedure TSimulatedDmInfo.BeforeDelivery; Begin TDataNode.SetSubmitTime(Time); Inherited End; } //////////////////////////////////////////////////////////////////////// // TTosL1Playback //////////////////////////////////////////////////////////////////////// Procedure TTosL1Playback.SetIndex(Index : Integer); Begin PositionInListTrackBar.Position := Index; If Index = Length(TickData) Then Begin PositionInListLabel.Caption := Format('End of %d', [Length(TickData)]); NextToSendDate.Caption := '' End Else With TickData[Pred(Length(TickData)-Index)] Do Begin PositionInListLabel.Caption := Format('%d of %d', [Succ(Index), Length(TickData)]); NextToSendDate.Caption := DateTimeToStr(Time); NewTradeValue.Checked := Trade; If Trade Then Begin PriceValue.Text := Format('%f', [TradePrice]); SizeValue.Text := Format('%d', [TradeVolume]); If Not UpdateOtherFields.Checked Then VolumeValue.Text := Format('%d', [CumVolume]); ExchangeValue.Text := TradeOrBidExchange; FormTValue.Checked := FormT End Else Begin AskPriceValue.Text := Format('%f', [AskPrice]); AskSizeValue.Text := Format('%d', [AskSize]); AskExchangeValue.Text := AskExchange; BidPriceValue.Text := Format('%f', [BidPrice]); BidSizeValue.Text := Format('%d', [BidSize]); BidExchangeValue.Text := TradeOrBidExchange; End End; If Index > 0 Then LastSentDate.Caption := DateTimeToStr(TickData[Length(TickData)-Index].Time) Else LastSentDate.Caption := '' End; Procedure TTosL1Playback.NewTickData; Begin If Assigned(TickDataNode) Then TickData := TickDataNode.GetRecords Else SetLength(TickData, 0); ShowNewTickData End; Procedure TTosL1Playback.ShowNewTickData; Begin If Length(TickData) > 0 Then Begin FirstInListDate.Caption := DateTimeToStr(TickData[Pred(Length(TickData))].Time); LastInListDate.Caption := DateTimeToStr(TickData[0].Time) End Else Begin FirstInListDate.Caption := ''; LastInListDate.Caption := '' End; PositionInListTrackBar.Max := Length(TickData); If Length(TickData) > 0 Then PositionInListTrackBar.Frequency := Max(1, Round(Power(10, Pred(Round(Log10(Length(TickData))))))) Else PositionInListTrackBar.Frequency := 1; SetIndex(0) End; Procedure TTosL1Playback.ReleaseOldDataNodes; Begin If Assigned(TickDataNodeLink) Then TickDataNodeLink.Release; TickDataNode := Nil; TickDataNodeLink := Nil; End; Procedure TTosL1Playback.SetSymbol(Symbol : String); Begin If Symbol <> FSymbol Then Begin FSymbol := Symbol; ReleaseOldDataNodes; Symbol := UpperCase(Trim(Symbol)); SymbolValue.Text := Symbol; SymbolValue.Color := clWindow; If Symbol <> '' Then Begin TGenericTickDataNode.Find(Symbol, DeferredUpdate.NewData, TickDataNode, TickDataNodeLink); TickDataNodeLink.SetReceiveInput(True) End; DeferredUpdate.NewData End End; Procedure TTosL1Playback.SendFromScreen; { Var Msg : TSimulatedDmInfo; Data : TDmData; Index : Integer; } Begin { AutoUpdateFields; Index := PositionInListTrackBar.Position; Data.LastTos.Price := StrToFloat(PriceValue.Text); Data.LastTos.Size := StrToInt(SizeValue.Text); If Index = Length(TickData) Then Data.LastTos.Time := Now Else Data.LastTos.Time := TickData[Pred(Length(TickData)-Index)].Time; Data.LastTos.Ticks := StrToInt(TicksValue.Text); Data.LastTos.Exchange := ExchangeValue.Text; Data.LastTos.FormT := FormTValue.Checked; Data.LastTos.EventType := etNewPrint; Data.NewTosEvent := NewTradeValue.Checked; Data.L1.BidPrice := StrToFloat(BidPriceValue.Text); Data.L1.BidSize := StrToInt(BidSizeValue.Text); Data.L1.BidExchange := BidExchangeValue.Text; Data.L1.AskPrice := StrToFloat(AskPriceValue.Text); Data.L1.AskSize := StrToInt(AskSizeValue.Text); Data.L1.AskExchange := AskExchangeValue.Text; Data.L1.Volume := StrToInt(VolumeValue.Text); Data.L1.Open := StrToFloat(OpenValue.Text); Data.L1.High := StrToFloat(HighValue.Text); Data.L1.Low := StrToFloat(LowValue.Text); Data.L1.PrevClose := StrToFloat(PreviousCloseValue.Text); Data.TosAndL1Valid := True; Msg := TSimulatedDmInfo.Create; Msg.Time := Data.LastTos.Time; Msg.Symbol := SymbolValue.Text; Msg.Data := Data; Msg.Send(TESignalDm.DataChannel(SymbolValue.Text)) } End; Procedure TTosL1Playback.AutoUpdateFields; Var Price : Double; Begin If UpdateHighAndLow.Checked Then Begin Price := StrToFloat(PriceValue.Text); If HighValue.Text = '' Then HighValue.Text := PriceValue.Text Else HighValue.Text := Format('%f', [Max(Price, StrToFloat(HighValue.Text))]); If LowValue.Text = '' Then LowValue.Text := PriceValue.Text Else LowValue.Text := Format('%f', [Min(Price, StrToFloat(LowValue.Text))]) End; If UpdateOtherFields.Checked Then Begin If TicksValue.Text = '' Then TicksValue.Text := '0' Else If NewTradeValue.Checked Then TicksValue.Text := Format('%d', [Succ(StrToInt(TicksValue.Text)) Mod $10000]); If NewTradeValue.Checked Then If VolumeValue.Text = '' Then VolumeValue.Text := SizeValue.Text Else VolumeValue.Text := Format('%d', [StrToInt(VolumeValue.Text) + StrToInt(SizeValue.Text)]); //Bid Tick! End; End; Procedure TTosL1Playback.UpdateEnabledDisabled; Begin HighValue.Enabled := Not UpdateHighAndLow.Checked; LowValue.Enabled := Not UpdateHighAndLow.Checked; TicksValue.Enabled := Not UpdateOtherFields.Checked; VolumeValue.Enabled := Not UpdateOtherFields.Checked; End; procedure TTosL1Playback.UpdateHighAndLowClick(Sender: TObject); begin UpdateEnabledDisabled end; procedure TTosL1Playback.UpdateOtherFieldsClick(Sender: TObject); begin UpdateEnabledDisabled end; Procedure TTosL1Playback.AdvanceRecord; Begin If PositionInListTrackBar.Position < PositionInListTrackBar.Max Then SetIndex(Succ(PositionInListTrackBar.Position)) End; procedure TTosL1Playback.SendRecordClick(Sender: TObject); begin SendFromScreen; If AutoLoadNextRecord.Checked Then AdvanceRecord end; procedure TTosL1Playback.FormCreate(Sender: TObject); begin TDeferredUpdate.Find(NewTickData, DeferredUpdate, DeferredUpdateLink); DeferredUpdateLink.SetReceiveInput(True); NewTickData; UpdateEnabledDisabled end; procedure TTosL1Playback.SetSymbolButtonClick(Sender: TObject); begin SetSymbol(SymbolValue.Text); end; procedure TTosL1Playback.SymbolValueChange(Sender: TObject); begin If SymbolValue.Text = FSymbol Then SymbolValue.Color := clWindow Else SymbolValue.Color := clYellow end; procedure TTosL1Playback.PositionInListTrackBarChange(Sender: TObject); begin SetIndex(PositionInListTrackBar.Position) end; Procedure TTosL1Playback.SendMultipleClick(Sender: TObject); Function EndOfFile : Boolean; Begin Result := PositionInListTrackBar.Position = PositionInListTrackBar.Max End; Procedure Advance; Begin SetIndex(Succ(PositionInListTrackBar.Position)) End; Var TotalQuantity, Remaining, TradeSize : Integer; Begin TotalQuantity := StrToInt(SendQuantity.Text); Remaining := TotalQuantity; If CountTicks.Checked Then While (Not EndOfFile) And (Remaining > 0) Do Begin SendFromScreen; Dec(Remaining); Advance End Else If CountPrints.Checked Then While (Not EndOfFile) And (Remaining > 0) Do Begin SendFromScreen; If NewTradeValue.Checked Then Dec(Remaining); Advance End Else While Not EndOfFile Do Begin If NewTradeValue.Checked Then Begin TradeSize := StrToInt(SizeValue.Text); If TradeSize > Remaining Then Break; Dec(Remaining, TradeSize) End; SendFromScreen; Advance End End; procedure TTosL1Playback.SaveToFileClick(Sender: TObject); Var Table : TTwoDArray; I : Integer; RowName : String; begin If SaveDialog1.Execute Then Begin OpenDialog1.FileName := SaveDialog1.FileName; Table := TTwoDArray.Create; Try For I := 0 To Pred(Length(TickData)) Do With TickData[I] Do Begin RowName := Format('%d', [I]); Table.Add('Date', RowName, DateToStr(Time)); Table.Add('Time', RowName, TimeToStr(Time)); If Trade Then Begin Table.Add('Trade', RowName, 'T'); Table.Add('Trade Price', RowName, Format('%f', [TradePrice])); Table.Add('Trade Volume', RowName, Format('%d', [TradeVolume])); Table.Add('Cum Volume', RowName, Format('%d', [CumVolume])); Table.Add('Trade Exchange', RowName, TradeOrBidExchange); If FormT Then Table.Add('FormT', RowName, 'T') End Else Begin Table.Add('Bid Price', RowName, Format('%f', [BidPrice])); Table.Add('Bid Size', RowName, Format('%d', [BidSize])); Table.Add('Bid Exchange', RowName, TradeOrBidExchange); Table.Add('Ask Price', RowName, Format('%f', [AskPrice])); Table.Add('Ask Size', RowName, Format('%d', [AskSize])); Table.Add('Ask Exchange', RowName, AskExchange) End End; Table.WriteToCSV(SaveDialog1.FileName) Finally Table.Free End End; end; procedure TTosL1Playback.LoadFromFileClick(Sender: TObject); Var Table : TTwoDArray; RowNumber : Integer; RowName : String; begin If OpenDialog1.Execute Then Begin ReleaseOldDataNodes; SetLength(TickData, 0); SaveDialog1.FileName := OpenDialog1.FileName; Table := TTwoDArray.Create; Table.LoadFromCSV(OpenDialog1.FileName); Try RowNumber := -1; Repeat Inc(RowNumber); RowName := Format('%d', [RowNumber]); Until Table.Get('Date', RowName) = ''; SetLength(TickData, RowNumber); For RowNumber := 0 To Pred(RowNumber) Do With TickData[RowNumber] Do Begin RowName := Format('%d', [RowNumber]); Time := StrToDate(Table.Get('Date', RowName)) + StrToTime(Table.Get('Time', RowName)); Trade := Table.Get('Trade', RowName) = 'T'; If Trade Then Begin TradePrice := StrToFloat(Table.Get('Trade Price', RowName)); TradeVolume := StrToInt(Table.Get('Trade Volume', RowName)); CumVolume := StrToInt(Table.Get('Cum Volume', RowName)); TradeOrBidExchange := Table.Get('Trade Exchange', RowName); FormT := Table.Get('FormT', RowName) = 'T' End Else Begin BidPrice := StrToFloat(Table.Get('Bid Price', RowName)); BidSize := StrToInt(Table.Get('Bid Size', RowName)); TradeOrBidExchange := Table.Get('Bid Exchange', RowName); AskPrice := StrToFloat(Table.Get('Ask Price', RowName)); AskSize := StrToInt(Table.Get('Ask Size', RowName)); AskExchange := Table.Get('Ask Exchange', RowName) End End; ShowNewTickData Finally Table.Free End End end; procedure TTosL1Playback.FormDestroy(Sender: TObject); begin DeferredUpdateLink.Release end; end.