Unit TalRegionals; Interface Uses DataNodes, TalMsgListeners, GenericDataNodes, Classes; Type TTalRegionalBidAsk = Class(TDataNodeWithStringKey) Private FValid : Boolean; FBid, FAsk : Double; Data : TTalMsgListenerDataNode; Constructor Create(Symbol : String); Procedure NewData; Protected Class Function CreateNew(Data : String) : TDataNodeWithStringKey; Override; Public // This is currently hard coded to the NYSE. We could add other markets. Class Procedure Find(Symbol : String; OnChange : TThreadMethod; Out Node : TTalRegionalBidAsk; Out Link : TDataNodeLink); Property Valid : Boolean Read FValid; Property Bid : Double Read FBid; Property Ask : Double Read FAsk; End; // These are strictly for debugging. TTalRegionalBidOrAsk = Class(TGenericDataNode) Public Function IsValid : Boolean; Override; Protected Data : TTalRegionalBidAsk; Constructor Create(Params : TParamList); Override; End; TTalRegionalBid = Class(TTalRegionalBidOrAsk) Published Function GetDouble : Double; Override; End; TTalRegionalAsk = Class(TTalRegionalBidOrAsk) Published Function GetDouble : Double; Override; End; Implementation Uses TalBase, TalCommon; //////////////////////////////////////////////////////////////////////// // TTalRegionalBidAsk //////////////////////////////////////////////////////////////////////// { Assumptions: 1) The data is very noisy. A change in bid size often causes TAL to send us the same price data again, even though we don't care about size. 2) The market is always two sided. We know that sometimes we get both values even when the don't both change, and sometimes we don't. 3) It does not make sense for the bid or ask or both to disappear. (Except when we hide it because of data problems.) Waring: Joe G. says that old versions of TAL don't do the filtering right. We have to upgrade or do it ourselved. This code doesn't check for that and would presumably give garbage results in that case. Must check for that externally, or just always use a new version of TAL. } Constructor TTalRegionalBidAsk.Create(Symbol : String); Var Link : TDataNodeLink; Begin Inherited Create; TTalMsgListenerDataNode.Find( '6053,6057;6074=''N'',', ttRegional, Symbol, False, NewData, Data, Link); AddAutoLink(Link) End; Procedure TTalRegionalBidAsk.NewData; Procedure UpdateField(Var SavedValue : Double; NewValue : Double; Var Changed : Boolean); Begin { UpdateField } If SavedValue <> NewValue Then Begin SavedValue := NewValue; Changed := True End End; { UpdateField } Var FieldStatus : TTal4Status; Field : PTal4FieldData; Tal4Handle : PTal4Handle; NewPrice : Double; Changed : Boolean; FieldId : Word; Begin { TTalRegionalBidAsk.NewData } Changed := False; Tal4Handle := Data.GetRecord; If Data.MessageStatus = tmsDown Then Begin UpdateField(FBid, 0.0, Changed); UpdateField(FAsk, 0.0, Changed) End Else If Assigned(Tal4Handle) Then Begin Repeat FieldStatus := TAL4_GetField(Tal4Handle^, Field); If FieldStatus <> TAL4_SUCCESS Then Break; FieldId := Field^.wFieldId; If Not ((FieldId = fid_REGIONAL_BID) Or (FieldId = fid_REGIONAL_ASK)) Then Continue; If FieldIsPresent(Field) Then NewPrice := FieldAsPrice(Field) Else NewPrice := 0; If FieldId = fid_REGIONAL_BID Then UpdateField(FBid, NewPrice, Changed) Else UpdateField(FAsk, NewPrice, Changed) Until False End; If Changed Then Begin FValid := (FBid > 0) And (FAsk > 0); NotifyListeners End End; { TTalRegionalBidAsk.NewData } Class Function TTalRegionalBidAsk.CreateNew(Data : String) : TDataNodeWithStringKey; Begin Result := Create(Data) End; Class Procedure TTalRegionalBidAsk.Find(Symbol : String; OnChange : TThreadMethod; Out Node : TTalRegionalBidAsk; Out Link : TDataNodeLink); Var TempNode : TDataNodeWithStringKey; Begin FindCommon(TTalRegionalBidAsk, Symbol, OnChange, TempNode, Link); Node := TempNode As TTalRegionalBidAsk End; //////////////////////////////////////////////////////////////////////// // TTalRegionalBidOrAsk //////////////////////////////////////////////////////////////////////// Function TTalRegionalBidOrAsk.IsValid : Boolean; Begin Result := Data.Valid End; Constructor TTalRegionalBidOrAsk.Create(Params : TParamList); Var Symbol : String; Link : TDataNodeLink; Begin Assert(Length(Params) = 1, 'Expecting (Symbol)'); Symbol := Params[0]; Inherited Create; TTalRegionalBidAsk.Find(Symbol, NotifyListeners, Data, Link); AddAutoLink(Link) End; //////////////////////////////////////////////////////////////////////// // TTalRegionalBid //////////////////////////////////////////////////////////////////////// Function TTalRegionalBid.GetDouble : Double; Begin Result := Data.Bid End; //////////////////////////////////////////////////////////////////////// // TTalRegionalAsk //////////////////////////////////////////////////////////////////////// Function TTalRegionalAsk.GetDouble : Double; Begin Result := Data.Ask End; //////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////// Initialization TGenericDataNodeFactory.StoreStandardFactory('NyseBidPrice', TTalRegionalBid); TGenericDataNodeFactory.StoreStandardFactory('NyseAskPrice', TTalRegionalAsk); End.