unit MonitorRealtickUnit; interface uses DataNodes, GenericTosDataNode, WakeMeSoon, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls; type TRealtickMonitor = class(TForm) MonitorCheckBox: TCheckBox; ReportCheckBox: TCheckBox; ReportAsEdit: TEdit; Label3: TLabel; DelayLabel: TLabel; WorstDelayLabel: TLabel; OverdueLabel: TLabel; WorstOverdueLabel: TLabel; Timer1: TTimer; procedure MonitorCheckBoxClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Timer1Timer(Sender: TObject); private Procedure AddToLog(Msg : String); private FLastUpdateTime : TDateTime; // This is a cached, thread safe copy of the data. FDMNextExpected : TDateTime; FDMDelay : Double; FDMWorstDelay : Double; FDMOverdue : Double; FDMWorstOverdue : Double; FDMTosData : TGenericTosDataNode; FDMTosLink : TDataNodeLink; FTimeDataPush : TWakeMeSoon; Procedure UpdateDataMonitorGui; Procedure UpdateOverdue; Procedure RequestTimeData; Procedure ReleaseTimeData; Procedure ReadTimeData; Procedure NewTimeData; Procedure NewTimeDataInGuiThread; public Procedure UpdateReportAsName; //Procedure RunInAutoMode(FileName, ServerName : String); end; var RealtickMonitor: TRealtickMonitor; implementation {$R *.dfm} Uses SimpleMarketData, DebugOutput, MonitorAlive, DateUtils, StrUtils, Math, HashSelector; Procedure TRealtickMonitor.UpdateDataMonitorGui; Begin { The data monitor has a simple puprose and idea. There is some additional info on the screen, for the purpose of debugging, but it is not essential. Sometimes, we don't get any data from TAL, and we don't get any error messages. I've only seen this happen all at once; we get no data at all. To look for this, we request data for the special symbol "$TIME". We expect to get this once per minute. Every time we get a new value for $TIME, we report it out to the database. An external process looks for these values, and accumulates these, and complains when it has not heard from us in too long. } ReportCheckBox.Enabled := MonitorCheckBox.Checked; If MonitorCheckBox.Checked Then Begin RequestTimeData; UpdateOverdue; OverdueLabel.Caption := Format('Overdue: %.0f seconds', [FDMOverdue]); DelayLabel.Caption := Format('Delay: %.4f seconds', [FDMDelay]) End Else Begin ReleaseTimeData; OverdueLabel.Caption := 'Overdue:'; DelayLabel.Caption := 'Delay:' End; WorstOverdueLabel.Caption := Format('Worst overdue: %.4f seconds', [FDMWorstOverdue]); WorstDelayLabel.Caption := Format('Worst delay: %.4f seconds', [FDMWorstDelay]) End; Procedure TRealtickMonitor.UpdateOverdue; Begin FDMOverdue := Max(0.0, (Now - FDMNextExpected) * 24.0 * 60.0 * 60.0); FDMWorstOverdue := Max(FDMWorstOverdue, FDMOverdue); End; Procedure TRealtickMonitor.RequestTimeData; Begin Exit; If Not Assigned(FDMTosData) Then Begin Assert(Not Assigned(FDMTosLink)); TGenericTosDataNode.Find('$TIME', NewTimeData, FDMTosData, FDMTosLink); FDMTosLink.SetReceiveInput(True); FDMNextExpected := Now + 1.0 / 24.0 / 60.0; ReadTimeData End End; Procedure TRealtickMonitor.ReleaseTimeData; Begin If Assigned(FDMTosLink) Then Begin FDMTosLink.Release; FLastUpdateTime := 0; Assert(Assigned(FDMTosData)); FDMTosData := Nil; FDMTosLink := Nil End End; Procedure TRealtickMonitor.ReadTimeData; Begin If FLastUpdateTime <> 0 Then Begin UpdateOverdue; // This is vital because it is our last chance // to update WorseOverdue. FDMDelay := (Now - FLastUpdateTime) * 24.0 * 60.0 * 60.0; FDMWorstDelay := Max(FDMWorstDelay, FDMDelay); FDMNextExpected := Now + 1.0 / 24.0 / 60.0 End End; Procedure TRealtickMonitor.NewTimeData; Begin If Not FDMTosData.IsValid Then FLastUpdateTime := 0 Else FLastUpdateTime := FDMTosData.GetLast.Time; FTimeDataPush.RequestWakeup End; Procedure TRealtickMonitor.NewTimeDataInGuiThread; Begin ReadTimeData; UpdateDataMonitorGui; If ReportCheckBox.Checked And (FDMOverdue < 60.0) Then // If the data is more than a minute behind, we'll call that a failure. SendKeepAlive(ReportAsEdit.Text) End; Procedure TRealtickMonitor.AddToLog(Msg : String); Begin DebugOutputWindow.AddMessage(Msg) End; {Procedure TAutoAlertMonitor.RunInAutoMode(FileName, ServerName : String); Var ColonPos : Integer; Begin ConfigureAlertsPush.EnablePush.Checked := True; ConfigureAlertsPush.EnablePushClick(Nil); If ServerName <> '' Then Begin ColonPos := Pos(':', ServerName); If ColonPos < 1 Then ConfigureAlertsPush.HostText.Text := ServerName Else With ConfigureAlertsPush Do Begin HostText.Text := LeftStr(ServerName, Pred(ColonPos)); PortText.Text := MidStr(ServerName, Succ(ColonPos), MaxInt) End End; SymbolFileEdit.Text := FileName; AutoStartCheckBox.Checked := True; AutoStopRadioGroup.ItemIndex := 2; PreviousTimerReading := 0; MonitorCheckBox.Checked := True; ReportCheckBox.Checked := True; UpdateDataMonitorGui; Show End; } Procedure TRealtickMonitor.FormCreate(Sender: TObject); Begin { TAutoAlertMonitor.FormCreate } FTimeDataPush := TWakeMeSoon.Create; FTimeDataPush.OnWakeUp := NewTimeDataInGuiThread; UpdateReportAsName; UpdateDataMonitorGui End; { TAutoAlertMonitor.FormCreate } Procedure TRealtickMonitor.UpdateReportAsName; Begin ReportAsEdit.Text := TConfigureMonitorAlive.DataName(HashSelectorForm.HashFirst, HashSelectorForm.HashCount); AddToLog('Monitor alive as: ' + ReportAsEdit.Text); End; procedure TRealtickMonitor.FormDestroy(Sender: TObject); begin ReleaseTimeData; end; Procedure TRealtickMonitor.MonitorCheckBoxClick(Sender: TObject); Begin UpdateDataMonitorGui End; Procedure TRealtickMonitor.Timer1Timer(Sender: TObject); Begin UpdateDataMonitorGui {If Not Assigned(FDMTosData) Then TimerDebugLabel.Caption := 'Not Assigned' Else If Not FDMTosData.IsValid Then TimerDebugLabel.Caption := 'Not Valid' Else Begin TimerDebugLabel.Caption := DateTimeToStr(FDMTosData.GetLast.Time); PriceDebugLabel.Caption := Format('%.4f', [FDMTosData.GetLast.Price]) End} End; End.