403 lines
16 KiB
C#
403 lines
16 KiB
C#
/*
|
|
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
|
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using NodaTime;
|
|
using QuantConnect.Securities;
|
|
|
|
namespace QuantConnect.Scheduling
|
|
{
|
|
/// <summary>
|
|
/// Provides a builder class to allow for fluent syntax when constructing new events
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This builder follows the following steps for event creation:
|
|
///
|
|
/// 1. Specify an event name (optional)
|
|
/// 2. Specify an IDateRule
|
|
/// 3. Specify an ITimeRule
|
|
/// a. repeat 3. to define extra time rules (optional)
|
|
/// 4. Specify additional where clause (optional)
|
|
/// 5. Register event via call to Run
|
|
/// </remarks>
|
|
public class FluentScheduledEventBuilder : IFluentSchedulingDateSpecifier, IFluentSchedulingRunnable
|
|
{
|
|
private IDateRule _dateRule;
|
|
private ITimeRule _timeRule;
|
|
private Func<DateTime, bool> _predicate;
|
|
|
|
private readonly string _name;
|
|
private readonly ScheduleManager _schedule;
|
|
private readonly SecurityManager _securities;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="FluentScheduledEventBuilder"/> class
|
|
/// </summary>
|
|
/// <param name="schedule">The schedule to send created events to</param>
|
|
/// <param name="securities">The algorithm's security manager</param>
|
|
/// <param name="name">A specific name for this event</param>
|
|
public FluentScheduledEventBuilder(ScheduleManager schedule, SecurityManager securities, string name = null)
|
|
{
|
|
_name = name;
|
|
_schedule = schedule;
|
|
_securities = securities;
|
|
}
|
|
|
|
private FluentScheduledEventBuilder SetTimeRule(ITimeRule rule)
|
|
{
|
|
// if it's not set, just set it
|
|
if (_timeRule == null)
|
|
{
|
|
_timeRule = rule;
|
|
return this;
|
|
}
|
|
|
|
// if it's already a composite, open it up and make a new composite
|
|
// prevent nesting composites
|
|
var compositeTimeRule = _timeRule as CompositeTimeRule;
|
|
if (compositeTimeRule != null)
|
|
{
|
|
var rules = compositeTimeRule.Rules;
|
|
_timeRule = new CompositeTimeRule(rules.Concat(new[] { rule }));
|
|
return this;
|
|
}
|
|
|
|
// create a composite from the existing rule and the new rules
|
|
_timeRule = new CompositeTimeRule(_timeRule, rule);
|
|
return this;
|
|
}
|
|
|
|
#region DateRules and TimeRules delegation
|
|
|
|
/// <summary>
|
|
/// Creates events on each of the specified day of week
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingDateSpecifier.Every(params DayOfWeek[] days)
|
|
{
|
|
_dateRule = _schedule.DateRules.Every(days);
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates events on every day of the year
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingDateSpecifier.EveryDay()
|
|
{
|
|
_dateRule = _schedule.DateRules.EveryDay();
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates events on every trading day of the year for the symbol
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingDateSpecifier.EveryDay(Symbol symbol)
|
|
{
|
|
_dateRule = _schedule.DateRules.EveryDay(symbol);
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates events on the first day of the month
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingDateSpecifier.MonthStart()
|
|
{
|
|
_dateRule = _schedule.DateRules.MonthStart();
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates events on the first trading day of the month
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingDateSpecifier.MonthStart(Symbol symbol)
|
|
{
|
|
_dateRule = _schedule.DateRules.MonthStart(symbol);
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filters the event times using the predicate
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingDateSpecifier.Where(Func<DateTime, bool> predicate)
|
|
{
|
|
_predicate = _predicate == null
|
|
? predicate
|
|
: (time => _predicate(time) && predicate(time));
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates events that fire at the specific time of day in the algorithm's time zone
|
|
/// </summary>
|
|
IFluentSchedulingRunnable IFluentSchedulingTimeSpecifier.At(TimeSpan timeOfDay)
|
|
{
|
|
return SetTimeRule(_schedule.TimeRules.At(timeOfDay));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates events that fire a specified number of minutes after market open
|
|
/// </summary>
|
|
IFluentSchedulingRunnable IFluentSchedulingTimeSpecifier.AfterMarketOpen(Symbol symbol, double minutesAfterOpen, bool extendedMarketOpen)
|
|
{
|
|
return SetTimeRule(_schedule.TimeRules.AfterMarketOpen(symbol, minutesAfterOpen, extendedMarketOpen));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates events that fire a specified numer of minutes before market close
|
|
/// </summary>
|
|
IFluentSchedulingRunnable IFluentSchedulingTimeSpecifier.BeforeMarketClose(Symbol symbol, double minuteBeforeClose, bool extendedMarketClose)
|
|
{
|
|
return SetTimeRule(_schedule.TimeRules.BeforeMarketClose(symbol, minuteBeforeClose, extendedMarketClose));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates events that fire on a period define by the specified interval
|
|
/// </summary>
|
|
IFluentSchedulingRunnable IFluentSchedulingTimeSpecifier.Every(TimeSpan interval)
|
|
{
|
|
return SetTimeRule(_schedule.TimeRules.Every(interval));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filters the event times using the predicate
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingTimeSpecifier.Where(Func<DateTime, bool> predicate)
|
|
{
|
|
_predicate = _predicate == null
|
|
? predicate
|
|
: (time => _predicate(time) && predicate(time));
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register the defined event with the callback
|
|
/// </summary>
|
|
ScheduledEvent IFluentSchedulingRunnable.Run(Action callback)
|
|
{
|
|
return ((IFluentSchedulingRunnable)this).Run((name, time) => callback());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register the defined event with the callback
|
|
/// </summary>
|
|
ScheduledEvent IFluentSchedulingRunnable.Run(Action<DateTime> callback)
|
|
{
|
|
return ((IFluentSchedulingRunnable)this).Run((name, time) => callback(time));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register the defined event with the callback
|
|
/// </summary>
|
|
ScheduledEvent IFluentSchedulingRunnable.Run(Action<string, DateTime> callback)
|
|
{
|
|
var name = _name ?? _dateRule.Name + ": " + _timeRule.Name;
|
|
// back the date up to ensure we get all events, the event scheduler will skip past events that whose time has passed
|
|
var dates = ScheduleManager.GetDatesDeferred(_dateRule, _securities);
|
|
var eventTimes = _timeRule.CreateUtcEventTimes(dates);
|
|
if (_predicate != null)
|
|
{
|
|
eventTimes = eventTimes.Where(_predicate);
|
|
}
|
|
var scheduledEvent = new ScheduledEvent(name, eventTimes, callback);
|
|
_schedule.Add(scheduledEvent);
|
|
return scheduledEvent;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filters the event times using the predicate
|
|
/// </summary>
|
|
IFluentSchedulingRunnable IFluentSchedulingRunnable.Where(Func<DateTime, bool> predicate)
|
|
{
|
|
_predicate = _predicate == null
|
|
? predicate
|
|
: (time => _predicate(time) && predicate(time));
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Filters the event times to only include times where the symbol's market is considered open
|
|
/// </summary>
|
|
IFluentSchedulingRunnable IFluentSchedulingRunnable.DuringMarketHours(Symbol symbol, bool extendedMarket)
|
|
{
|
|
var security = GetSecurity(symbol);
|
|
Func<DateTime, bool> predicate = time =>
|
|
{
|
|
var localTime = time.ConvertFromUtc(security.Exchange.TimeZone);
|
|
return security.Exchange.IsOpenDuringBar(localTime, localTime, extendedMarket);
|
|
};
|
|
_predicate = _predicate == null
|
|
? predicate
|
|
: (time => _predicate(time) && predicate(time));
|
|
return this;
|
|
}
|
|
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingDateSpecifier.On(int year, int month, int day)
|
|
{
|
|
_dateRule = _schedule.DateRules.On(year, month, day);
|
|
return this;
|
|
}
|
|
|
|
IFluentSchedulingTimeSpecifier IFluentSchedulingDateSpecifier.On(params DateTime[] dates)
|
|
{
|
|
_dateRule = _schedule.DateRules.On(dates);
|
|
return this;
|
|
}
|
|
|
|
IFluentSchedulingRunnable IFluentSchedulingTimeSpecifier.At(int hour, int minute, int second)
|
|
{
|
|
return SetTimeRule(_schedule.TimeRules.At(hour, minute, second));
|
|
}
|
|
|
|
IFluentSchedulingRunnable IFluentSchedulingTimeSpecifier.At(int hour, int minute, DateTimeZone timeZone)
|
|
{
|
|
return SetTimeRule(_schedule.TimeRules.At(hour, minute, 0, timeZone));
|
|
}
|
|
|
|
IFluentSchedulingRunnable IFluentSchedulingTimeSpecifier.At(int hour, int minute, int second, DateTimeZone timeZone)
|
|
{
|
|
return SetTimeRule(_schedule.TimeRules.At(hour, minute, second, timeZone));
|
|
}
|
|
|
|
IFluentSchedulingRunnable IFluentSchedulingTimeSpecifier.At(TimeSpan timeOfDay, DateTimeZone timeZone)
|
|
{
|
|
return SetTimeRule(_schedule.TimeRules.At(timeOfDay, timeZone));
|
|
}
|
|
|
|
private Security GetSecurity(Symbol symbol)
|
|
{
|
|
Security security;
|
|
if (!_securities.TryGetValue(symbol, out security))
|
|
{
|
|
throw new KeyNotFoundException($"{symbol} not found in portfolio. Request this data when initializing the algorithm.");
|
|
}
|
|
|
|
return security;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies the date rule component of a scheduled event
|
|
/// </summary>
|
|
public interface IFluentSchedulingDateSpecifier
|
|
{
|
|
/// <summary>
|
|
/// Filters the event times using the predicate
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier Where(Func<DateTime, bool> predicate);
|
|
/// <summary>
|
|
/// Creates events only on the specified date
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier On(int year, int month, int day);
|
|
/// <summary>
|
|
/// Creates events only on the specified dates
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier On(params DateTime[] dates);
|
|
/// <summary>
|
|
/// Creates events on each of the specified day of week
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier Every(params DayOfWeek[] days);
|
|
/// <summary>
|
|
/// Creates events on every day of the year
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier EveryDay();
|
|
/// <summary>
|
|
/// Creates events on every trading day of the year for the symbol
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier EveryDay(Symbol symbol);
|
|
/// <summary>
|
|
/// Creates events on the first day of the month
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier MonthStart();
|
|
/// <summary>
|
|
/// Creates events on the first trading day of the month
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier MonthStart(Symbol symbol);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies the time rule component of a scheduled event
|
|
/// </summary>
|
|
public interface IFluentSchedulingTimeSpecifier
|
|
{
|
|
/// <summary>
|
|
/// Filters the event times using the predicate
|
|
/// </summary>
|
|
IFluentSchedulingTimeSpecifier Where(Func<DateTime, bool> predicate);
|
|
/// <summary>
|
|
/// Creates events that fire at the specified time of day in the specified time zone
|
|
/// </summary>
|
|
IFluentSchedulingRunnable At(int hour, int minute, int second = 0);
|
|
/// <summary>
|
|
/// Creates events that fire at the specified time of day in the specified time zone
|
|
/// </summary>
|
|
IFluentSchedulingRunnable At(int hour, int minute, DateTimeZone timeZone);
|
|
/// <summary>
|
|
/// Creates events that fire at the specified time of day in the specified time zone
|
|
/// </summary>
|
|
IFluentSchedulingRunnable At(int hour, int minute, int second, DateTimeZone timeZone);
|
|
/// <summary>
|
|
/// Creates events that fire at the specified time of day in the specified time zone
|
|
/// </summary>
|
|
IFluentSchedulingRunnable At(TimeSpan timeOfDay, DateTimeZone timeZone);
|
|
/// <summary>
|
|
/// Creates events that fire at the specific time of day in the algorithm's time zone
|
|
/// </summary>
|
|
IFluentSchedulingRunnable At(TimeSpan timeOfDay);
|
|
/// <summary>
|
|
/// Creates events that fire on a period define by the specified interval
|
|
/// </summary>
|
|
IFluentSchedulingRunnable Every(TimeSpan interval);
|
|
/// <summary>
|
|
/// Creates events that fire a specified number of minutes after market open
|
|
/// </summary>
|
|
IFluentSchedulingRunnable AfterMarketOpen(Symbol symbol, double minutesAfterOpen = 0, bool extendedMarketOpen = false);
|
|
/// <summary>
|
|
/// Creates events that fire a specified numer of minutes before market close
|
|
/// </summary>
|
|
IFluentSchedulingRunnable BeforeMarketClose(Symbol symbol, double minuteBeforeClose = 0, bool extendedMarketClose = false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Specifies the callback component of a scheduled event, as well as final filters
|
|
/// </summary>
|
|
public interface IFluentSchedulingRunnable : IFluentSchedulingTimeSpecifier
|
|
{
|
|
/// <summary>
|
|
/// Filters the event times using the predicate
|
|
/// </summary>
|
|
new IFluentSchedulingRunnable Where(Func<DateTime, bool> predicate);
|
|
/// <summary>
|
|
/// Filters the event times to only include times where the symbol's market is considered open
|
|
/// </summary>
|
|
IFluentSchedulingRunnable DuringMarketHours(Symbol symbol, bool extendedMarket = false);
|
|
/// <summary>
|
|
/// Register the defined event with the callback
|
|
/// </summary>
|
|
ScheduledEvent Run(Action callback);
|
|
/// <summary>
|
|
/// Register the defined event with the callback
|
|
/// </summary>
|
|
ScheduledEvent Run(Action<DateTime> callback);
|
|
/// <summary>
|
|
/// Register the defined event with the callback
|
|
/// </summary>
|
|
ScheduledEvent Run(Action<string, DateTime> callback);
|
|
}
|
|
}
|