public virtual void Timer_Elapsed(object?state) // Timer is coming on a ThreadPool thread { Utils.Logger.Info("Trigger.Timer_Elapsed() "); NextScheduleTimeUtc = null; bool isMarketTradingDay; DateTime marketOpenTimeUtc, marketCloseTimeUtc; bool isMarketHoursValid = Utils.DetermineUsaMarketTradingHours(DateTime.UtcNow, out isMarketTradingDay, out marketOpenTimeUtc, out marketCloseTimeUtc, TimeSpan.FromDays(3)); if (!isMarketHoursValid) { Utils.Logger.Error("DetermineUsaMarketTradingHours() was not ok."); } SqTaskScheduler.gTaskScheduler.ScheduleTrigger(this, isMarketHoursValid, isMarketTradingDay, marketOpenTimeUtc, marketCloseTimeUtc); try { if (SqTask != null) { SqExecution sqExecution = ((SqTask)SqTask).ExecutionFactory(); sqExecution.SqTask = (SqTask)SqTask; sqExecution.Trigger = this; sqExecution.Run(); } } catch (Exception e) { Utils.Logger.Error(e, "Trigger.Timer_Elapsed() Exception"); HealthMonitorMessage.SendAsync($"Exception in BrokerTaskExecutionThreadRun(). Exception: '{ e.ToStringWithShortenedStackTrace(1600)}'", HealthMonitorMessageID.SqCoreWebCsError).TurnAsyncToSyncTask(); } }
public static bool IsCriticalTradingTime(GatewayId p_gatewayId, DateTime p_timeUtc) { DateTime timeEt = Utils.ConvertTimeFromUtcToEt(p_timeUtc); if (timeEt.DayOfWeek == DayOfWeek.Saturday || timeEt.DayOfWeek == DayOfWeek.Sunday) // quick check: if it is the weekend => not critical time. { return(false); } bool isMarketHoursValid = Utils.DetermineUsaMarketTradingHours(p_timeUtc, out bool isMarketTradingDay, out DateTime marketOpenTimeUtc, out DateTime marketCloseTimeUtc, TimeSpan.FromDays(3)); if (isMarketHoursValid && !isMarketTradingDay) { return(false); } foreach (var critTradingRange in GatewayExtensions.CriticalTradingPeriods) { if (critTradingRange.GatewayId != p_gatewayId) { continue; } if (!isMarketHoursValid) { return(true); // Caution: if DetermineUsaMarketTradingHours() failed, better to report that we are in a critical period. } DateTime critPeriodStartUtc = DateTime.MinValue; // Caution: if (critTradingRange.RelativeTimePeriod.Start.Base == RelativeTimeBase.BaseOnUsaMarketOpen) { critPeriodStartUtc = marketOpenTimeUtc + critTradingRange.RelativeTimePeriod.Start.TimeOffset; } else if (critTradingRange.RelativeTimePeriod.Start.Base == RelativeTimeBase.BaseOnUsaMarketClose) { critPeriodStartUtc = marketCloseTimeUtc + critTradingRange.RelativeTimePeriod.Start.TimeOffset; } DateTime critPeriodEndUtc = DateTime.MaxValue; if (critTradingRange.RelativeTimePeriod.End.Base == RelativeTimeBase.BaseOnUsaMarketOpen) { critPeriodEndUtc = marketOpenTimeUtc + critTradingRange.RelativeTimePeriod.End.TimeOffset; } else if (critTradingRange.RelativeTimePeriod.End.Base == RelativeTimeBase.BaseOnUsaMarketClose) { critPeriodEndUtc = marketCloseTimeUtc + critTradingRange.RelativeTimePeriod.End.TimeOffset; } if (critPeriodStartUtc <= p_timeUtc && p_timeUtc <= critPeriodEndUtc) // if p_timeUtc is between [Start, End] { return(true); } } return(false); }
public static bool IsInRegularUsaTradingHoursNow(TimeSpan p_maxAllowedStaleness) { DateTime utcNow = DateTime.UtcNow; // 1. quick response for trivial case that works most of the time, that don't need DetermineUsaMarketTradingHours() DateTime utcNowET = Utils.ConvertTimeFromUtcToEt(utcNow).Date; if (utcNowET.DayOfWeek == DayOfWeek.Saturday || utcNowET.DayOfWeek == DayOfWeek.Sunday) { return(false); } DateTime openInET = new DateTime(utcNowET.Year, utcNowET.Month, utcNowET.Day, 9, 30, 0); if (utcNowET < openInET) { return(false); } DateTime maxPossibleCloseInET = new DateTime(utcNowET.Year, utcNowET.Month, utcNowET.Day, 16, 0, 0); // usually it is 16:00, but when half-day trading, then it is 13:00 if (utcNowET > openInET) { return(false); } // 2. During RTH on weekdays, we have to be more thorough. bool isMarketTradingDay; DateTime openTimeUtc, closeTimeUtc; bool isTradingHoursOK = Utils.DetermineUsaMarketTradingHours(utcNow, out isMarketTradingDay, out openTimeUtc, out closeTimeUtc, p_maxAllowedStaleness); if (!isTradingHoursOK) { Utils.Logger.Error("DetermineUsaMarketTradingHours() was not OK."); return(false); } else { if (!isMarketTradingDay) { return(false); } if (utcNow < openTimeUtc) { return(false); } if (utcNow > closeTimeUtc) { return(false); } return(true); } }
private void SchedulerThreadRun() { try { Thread.CurrentThread.Name = "VBroker scheduler"; Thread.Sleep(TimeSpan.FromSeconds(5)); // wait 5 seconds, so that IBGateways can connect first m_schedulerStartupTime = DateTime.UtcNow; // maybe loop is not required. // in the past we try to get UsaMarketOpenOrCloseTime() every 30 minutes. It was determined from YFinance intrady. "sleep 30 min for DetermineUsaMarketOpenOrCloseTime()" // however, it may be a good idea that the Scheduler periodically wakes up and check Tasks while (true) { Utils.Logger.Info($"SchedulerThreadRun() loop BEGIN. Awake at every {cVbSchedulerSleepMinutes}min."); bool isMarketTradingDay; DateTime marketOpenTimeUtc, marketCloseTimeUtc; // Utils.DetermineUsaMarketTradingHours(): may throw an exception once per year, when Nasdaq page changes. BrokerScheduler.SchedulerThreadRun() catches it and HealthMonitor notified in VBroker. bool isMarketHoursValid = Utils.DetermineUsaMarketTradingHours(DateTime.UtcNow, out isMarketTradingDay, out marketOpenTimeUtc, out marketCloseTimeUtc, TimeSpan.FromDays(3)); if (!isMarketHoursValid) { Utils.Logger.Error("DetermineUsaMarketTradingHours() was not ok."); // but we should continue and schedule Daily tasks not related to MarketTradingHours } foreach (SqTask sqTask in gSqTasks) { foreach (SqTrigger trigger in sqTask.Triggers) { ScheduleTrigger(trigger, isMarketHoursValid, isMarketTradingDay, marketOpenTimeUtc, marketCloseTimeUtc); } } Thread.Sleep(TimeSpan.FromMinutes(cVbSchedulerSleepMinutes)); // try reschedulement in 30 minutes } } catch (Exception e) { // Utils.DetermineUsaMarketTradingHours(): may throw an exception once per year, when Nasdaq page changes. BrokerScheduler.SchedulerThreadRun() catches it and HealthMonitor notified in VBroker. HealthMonitorMessage.SendAsync($"Exception in Scheduler.RecreateTasksAndLoopThread. Exception: '{ e.ToStringWithShortenedStackTrace(1600)}'", HealthMonitorMessageID.SqCoreWebCsError).TurnAsyncToSyncTask(); } }