Overall Statistics |
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
namespace QuantConnect { /// <summary> /// Provides a base class for consolidators that emit data based on the passing /// of a specified time of day (in the data time zone. /// </summary> /// <typeparam name="T">The input type of the consolidator</typeparam> /// <typeparam name="TConsolidated">The output type of the consolidator</typeparam> public abstract class TimeOfDayConsolidatorBase<T, TConsolidated> : DataConsolidator<T> where T : IBaseData where TConsolidated : BaseData { // The time of day to emit the consolidated bar. private readonly TimeSpan _dailyOpenTime; // The working bar used for aggregating the data. private TConsolidated _workingBar; // The last time we emitted a consolidated bar. private DateTime _lastEmit; /// <summary> /// Creates a consolidator to produce a new <typeparamref name="TConsolidated"/> instance /// representing a day starting at the specified time. /// </summary> /// <param name="dailyOpenTime">The time of day to emit a consolidated bar.</param> protected TimeOfDayConsolidatorBase(TimeSpan dailyOpenTime) { _dailyOpenTime = dailyOpenTime; _lastEmit = DateTime.MinValue; } /// <summary> /// Gets the type produced by this consolidator. /// </summary> public override Type OutputType { get { return typeof(TConsolidated); } } /// <summary> /// Gets a clone of the data being currently consolidated. /// </summary> public override IBaseData WorkingData { get { return _workingBar != null ? _workingBar.Clone() : null; } } /// <summary> /// Event handler that fires when a new piece of data is produced. We define this as a 'new' /// event so we can expose it as a <typeparamref name="TConsolidated"/> instead of a <see cref="BaseData"/> instance. /// </summary> public new event EventHandler<TConsolidated> DataConsolidated; /// <summary> /// Updates this consolidator with the specified data. This method is /// responsible for raising the DataConsolidated event. /// The bar range is closed on the left and open on the right: [dailyOpenTime, dailyOpenTime+1day). /// For example, if time of day is 17:00, we have [17:00, next day 17:00): so /// data at 17:00 next day is not included in the bar. /// </summary> /// <param name="data">The new data for the consolidator.</param> public override void Update(T data) { if (!ShouldProcess(data)) { // First allow the base class a chance to filter out data it doesn't want // before we start incrementing counts and what not. return; } //Fire the event if (_workingBar != null && GetRoundedBarTime(data.Time) > _workingBar.Time) { // *** I don't understand why this is needed. Refer class PeriodCountConsolidatorBase<>. var workingTradeBar = _workingBar as TradeBar; if (workingTradeBar != null) { // we kind of are cheating here... // if (_period.HasValue) // { // workingTradeBar.Period = _period.Value; workingTradeBar.Period = new TimeSpan(1, 0, 0, 0); // } // since trade bar has period it aggregates this properly // else if (!(data is TradeBar)) // { // workingTradeBar.Period = data.Time - _lastEmit.Value; // } } OnDataConsolidated(_workingBar); _lastEmit = _workingBar != null ? _workingBar.Time.AddDays(1) : data.Time; _workingBar = null; } if (data.Time >= _lastEmit) { AggregateBar(ref _workingBar, data); } } /// <summary> /// Scans this consolidator to see if it should emit a bar due to time passing. /// </summary> /// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>).</param> public override void Scan(DateTime currentLocalTime) { if (_workingBar != null) { currentLocalTime = GetRoundedBarTime(currentLocalTime); if (currentLocalTime > _workingBar.Time) { OnDataConsolidated(_workingBar); _lastEmit = currentLocalTime; _workingBar = null; } } } /// <summary> /// Determines whether or not the specified data should be processed. /// </summary> /// <param name="data">The data to check.</param> /// <returns>True if the consolidator should process this data, false otherwise.</returns> protected virtual bool ShouldProcess(T data) { return true; } /// <summary> /// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be /// null following the event firing. /// </summary> /// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new consolidated bar.</param> /// <param name="data">The new data.</param> protected abstract void AggregateBar(ref TConsolidated workingBar, T data); /// <summary> /// Gets a bar time rounded-down to the prior daily close time. Called by AggregateBar in derived classes. /// </summary> /// <param name="time">The bar time to be rounded down.</param> /// <returns>The rounded bar time.</returns> protected DateTime GetRoundedBarTime(DateTime time) { DateTime roundedBarTime = time.Date.Add(_dailyOpenTime); return time.TimeOfDay >= _dailyOpenTime ? roundedBarTime : roundedBarTime.AddDays(-1); } /// <summary> /// Event invocator for the <see cref="DataConsolidated"/> event. /// </summary> /// <param name="e">The consolidated data.</param> protected virtual void OnDataConsolidated(TConsolidated e) { base.OnDataConsolidated(e); var handler = DataConsolidated; if (handler != null) handler(this, e); } } }
namespace QuantConnect { /// <summary> /// Consolidates quotebars into larger quotebars at the specified time of day (in the QuoteBar time zone). /// </summary> public class TimeOfDayQuoteBarConsolidator : TimeOfDayConsolidatorBase<QuoteBar, QuoteBar> { /// <summary> /// Initializes a new instance of the <see cref="TickQuoteBarConsolidator"/> class. /// </summary> /// <param name="dailyOpenTime">The time of day to emit a consolidated bar.</param> public TimeOfDayQuoteBarConsolidator(TimeSpan dailyOpenTime) : base(dailyOpenTime) { } /// <summary> /// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be /// null following the event firing. /// </summary> /// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new consolidated bar.</param> /// <param name="data">The new data.</param> protected override void AggregateBar(ref QuoteBar workingBar, QuoteBar data) { var bid = data.Bid; var ask = data.Ask; if (workingBar == null) { workingBar = new QuoteBar { Symbol = data.Symbol, Time = GetRoundedBarTime(data.Time), Bid = bid == null ? null : bid.Clone(), Ask = ask == null ? null : ask.Clone(), Period = data.Period }; } // update the bid and ask if (bid != null) { workingBar.LastBidSize = data.LastBidSize; if (workingBar.Bid == null) { workingBar.Bid = new Bar(bid.Open, bid.High, bid.Low, bid.Close); } else { workingBar.Bid.Close = bid.Close; if (workingBar.Bid.High < bid.High) workingBar.Bid.High = bid.High; if (workingBar.Bid.Low > bid.Low) workingBar.Bid.Low = bid.Low; } } if (ask != null) { workingBar.LastAskSize = data.LastAskSize; if (workingBar.Ask == null) { workingBar.Ask = new Bar(ask.Open, ask.High, ask.Low, ask.Close); } else { workingBar.Ask.Close = ask.Close; if (workingBar.Ask.High < ask.High) workingBar.Ask.High = ask.High; if (workingBar.Ask.Low > ask.Low) workingBar.Ask.Low = ask.Low; } } workingBar.Value = data.Value; workingBar.Period += data.Period; } } }
namespace QuantConnect.Algorithm.CSharp { public class ConsolidatorTest : QCAlgorithm { private Symbol _symbol = QuantConnect.Symbol.Create("EURUSD", SecurityType.Forex, Market.Oanda); // private Symbol _symbol = QuantConnect.Symbol.Create("EURUSD", SecurityType.Forex, Market.FXCM); public override void Initialize() { SetStartDate(2019, 01, 01); //Set Start Date SetEndDate(2019, 02, 03); //Set End Date SetCash(100000); //Set Strategy Cash AddForex(_symbol, Resolution.Minute); var dailyCloseTime = new TimeSpan(17,0,0); var nyCloseConsolidator = new TimeOfDayQuoteBarConsolidator(dailyCloseTime); Log("dailyCloseTime = " + dailyCloseTime.ToString()); nyCloseConsolidator.DataConsolidated += OnNYClose; SubscriptionManager.AddConsolidator(_symbol, nyCloseConsolidator); } public override void OnData(Slice data) { } public void OnNYClose(object sender, QuoteBar bar) { Log("OnNYClose(): bar.Time = " + bar.Time.DayOfWeek.ToString() + " " + bar.Time.ToString() + ", OHLC = " + bar.Open.ToString("0.00000") + ", " + bar.High.ToString("0.00000") + ", " + bar.Low.ToString("0.00000") + ", " + bar.Close.ToString("0.00000")); } } }