예제 #1
0
        /// <summary>
        /// Determines whether or not fill forward is required, and if true, will produce the new fill forward data
        /// </summary>
        /// <param name="fillForwardResolution"></param>
        /// <param name="previous">The last piece of data emitted by this enumerator</param>
        /// <param name="next">The next piece of data on the source enumerator, this may be null</param>
        /// <param name="fillForward">When this function returns true, this will have a non-null value, null when the function returns false</param>
        /// <returns>True when a new fill forward piece of data was produced and should be emitted by this enumerator</returns>
        protected override bool RequiresFillForwardData(TimeSpan fillForwardResolution, BaseData previous, BaseData next, out BaseData fillForward)
        {
            fillForward = null;
            var nextExpectedDataPointTime = (previous.EndTime + fillForwardResolution);

            if (next != null)
            {
                // if not future data, just return the 'next'
                if (next.EndTime <= nextExpectedDataPointTime)
                {
                    return(false);
                }
                // next is future data, fill forward in between
                var clone = previous.Clone(true);
                clone.Time  = previous.Time + fillForwardResolution;
                fillForward = clone;
                return(true);
            }

            // the underlying enumerator returned null, check to see if time has passed for fill fowarding
            var currentLocalTime = _timeProvider.GetUtcNow().ConvertFromUtc(Exchange.TimeZone);

            if (nextExpectedDataPointTime <= currentLocalTime)
            {
                var clone = previous.Clone(true);
                clone.Time  = previous.Time + fillForwardResolution;
                fillForward = clone;
                return(true);
            }

            return(false);
        }
예제 #2
0
        /// <summary>
        /// Determines whether or not fill forward is required, and if true, will produce the new fill forward data
        /// </summary>
        /// <param name="fillForwardResolution"></param>
        /// <param name="previous">The last piece of data emitted by this enumerator</param>
        /// <param name="next">The next piece of data on the source enumerator, this may be null</param>
        /// <param name="fillForward">When this function returns true, this will have a non-null value, null when the function returns false</param>
        /// <returns>True when a new fill forward piece of data was produced and should be emitted by this enumerator</returns>
        protected override bool RequiresFillForwardData(TimeSpan fillForwardResolution, BaseData previous, BaseData next, out BaseData fillForward)
        {
            // convert times to UTC for accurate comparisons and differences across DST changes
            fillForward = null;
            // Add a delay to the time we expect a data point if we've configured a delay for batching
            var nextExpectedDataPointTimeUtc = previous.EndTime.ConvertToUtc(Exchange.TimeZone) + fillForwardResolution;

            if (next != null)
            {
                // if not future data, just return the 'next'
                if (next.EndTime.ConvertToUtc(Exchange.TimeZone) <= nextExpectedDataPointTimeUtc)
                {
                    return(false);
                }
                // next is future data, fill forward in between
                var clone = previous.Clone(true);
                clone.Time  = previous.Time + fillForwardResolution;
                fillForward = clone;
                return(true);
            }

            // the underlying enumerator returned null, check to see if time has passed for fill forwarding
            if (nextExpectedDataPointTimeUtc <= _timeProvider.GetUtcNow())
            {
                var clone = previous.Clone(true);
                clone.Time  = previous.Time + fillForwardResolution;
                fillForward = clone;
                return(true);
            }

            return(false);
        }
예제 #3
0
        /// <summary>
        /// Clones the data, computes the utc emit time and performs exchange round down behavior, storing the result in a new <see cref="SubscriptionData"/> instance
        /// </summary>
        /// <param name="configuration">The subscription's configuration</param>
        /// <param name="exchangeHours">The exchange hours of the security</param>
        /// <param name="offsetProvider">The subscription's offset provider</param>
        /// <param name="data">The data being emitted</param>
        /// <param name="normalizationMode">Specifies how data is normalized</param>
        /// <param name="factor">price scale factor</param>
        /// <returns>A new <see cref="SubscriptionData"/> containing the specified data</returns>
        public static SubscriptionData Create(SubscriptionDataConfig configuration, SecurityExchangeHours exchangeHours, TimeZoneOffsetProvider offsetProvider, BaseData data, DataNormalizationMode normalizationMode, decimal?factor = null)
        {
            if (data == null)
            {
                return(null);
            }

            data = data.Clone(data.IsFillForward);
            var emitTimeUtc = offsetProvider.ConvertToUtc(data.EndTime);

            // Let's round down for any data source that implements a time delta between
            // the start of the data and end of the data (usually used with Bars).
            // The time delta ensures that the time collected from `EndTime` has
            // no look-ahead bias, and is point-in-time.
            if (data.Time != data.EndTime)
            {
                data.Time = data.Time.ExchangeRoundDownInTimeZone(configuration.Increment, exchangeHours, configuration.DataTimeZone, configuration.ExtendedMarketHours);
            }

            if (factor.HasValue && (configuration.SecurityType != SecurityType.Equity || (factor.Value != 1 || configuration.SumOfDividends != 0)))
            {
                var normalizedData = data.Clone(data.IsFillForward).Normalize(factor.Value, normalizationMode, configuration.SumOfDividends);

                return(new PrecalculatedSubscriptionData(configuration, data, normalizedData, normalizationMode, emitTimeUtc));
            }

            return(new SubscriptionData(data, emitTimeUtc));
        }
예제 #4
0
        /// <summary>
        /// Dequeues the current working bar
        /// </summary>
        /// <param name="utcTriggerTime">The current trigger time in UTC</param>
        /// <returns>The base data instance, or null, if no data is to be emitted</returns>
        public BaseData TriggerArchive(DateTime utcTriggerTime)
        {
            BaseData bar;

            if (!_queue.TryDequeue(out bar))
            {
                // if a bar wasn't ready, check for fill forward
                if (_previous != null && _config.FillDataForward)
                {
                    // exchanges hours are in local time, so convert to local before checking if exchange is open
                    var localTriggerTime = utcTriggerTime.ConvertFromUtc(_config.TimeZone);

                    // only perform fill forward behavior if the exchange is considered open
                    var barStartTime = localTriggerTime - _increment;
                    if (_security.Exchange.IsOpenDuringBar(barStartTime, localTriggerTime, _config.ExtendedMarketHours))
                    {
                        bar      = _previous.Clone(true);
                        bar.Time = barStartTime.ExchangeRoundDown(_increment, _security.Exchange.Hours, _security.IsExtendedMarketHours);
                    }
                }
            }

            // we don't have data, so just return null
            if (bar == null)
            {
                return(null);
            }

            // reset the previous bar for fill forward
            _previous = bar.Clone();

            return(bar);
        }
예제 #5
0
        /// <summary>
        /// A time period has lapsed, trigger a save/queue of the current value of data.
        /// </summary>
        /// <param name="utcTriggerTime">The time we're triggering this archive for</param>
        /// <param name="fillForward">Data stream is a fillforward type</param>
        public void TriggerArchive(DateTime utcTriggerTime, bool fillForward)
        {
            var localTriggerTime = utcTriggerTime.ConvertTo(TimeZones.Utc, _config.TimeZone);

            lock (_lock)
            {
                try
                {
                    //When there's nothing to do:
                    if (_data == null && !fillForward)
                    {
                        Log.Debug("StreamStore.TriggerArchive(): No data to store, and not fill forward: " + Symbol);
                    }

                    if (_data != null)
                    {
                        //Create clone and reset original
                        Log.Debug("StreamStore.TriggerArchive(): Enqueued new data: S:" + _data.Symbol + " V:" + _data.Value);
                        _previousData = _data.Clone();
                        _queue.Enqueue(_data.Clone());
                        _data = null;
                    }
                    else if (fillForward && _data == null && _previousData != null)
                    {
                        // the time is actually the end time of a bar, check to see if the start time
                        // is within market hours, which is really just checking the _previousData's EndTime
                        if (!_security.Exchange.IsOpenDuringBar(localTriggerTime - _increment, localTriggerTime, _config.ExtendedMarketHours))
                        {
                            Log.Debug("StreamStore.TriggerArchive(): Exchange is closed: " + Symbol);
                            return;
                        }

                        //There was no other data in this timer period, and this is a fillforward subscription:
                        Log.Debug("StreamStore.TriggerArchive(): Fillforward, Previous Enqueued: S:" + _previousData.Symbol + " V:" + _previousData.Value);
                        var cloneForward = _previousData.Clone(true);
                        cloneForward.Time = _previousData.Time.Add(_increment);
                        _queue.Enqueue(cloneForward);

                        _previousData = cloneForward.Clone();
                    }
                }
                catch (Exception err)
                {
                    Log.Error("StreamStore.TriggerAchive(fillforward): Failed to archive: " + err.Message);
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Clones the data, computes the utc emit time and performs exchange round down behavior, storing the result in a new <see cref="SubscriptionData"/> instance
        /// </summary>
        /// <param name="configuration">The subscription's configuration</param>
        /// <param name="exchangeHours">The exchange hours of the security</param>
        /// <param name="offsetProvider">The subscription's offset provider</param>
        /// <param name="data">The data being emitted</param>
        /// <returns>A new <see cref="SubscriptionData"/> containing the specified data</returns>
        public static SubscriptionData Create(SubscriptionDataConfig configuration, SecurityExchangeHours exchangeHours, TimeZoneOffsetProvider offsetProvider, BaseData data)
        {
            if (data == null)
            {
                return(null);
            }

            data = data.Clone(data.IsFillForward);
            var emitTimeUtc = offsetProvider.ConvertToUtc(data.EndTime);

            data.Time = data.Time.ExchangeRoundDownInTimeZone(configuration.Increment, exchangeHours, configuration.DataTimeZone, configuration.ExtendedMarketHours);
            return(new SubscriptionData(data, emitTimeUtc));
        }
예제 #7
0
        }     // End of Update

        /// <summary>
        /// A time period has lapsed, trigger a save/queue of the current value of data.
        /// </summary>
        /// <param name="fillForward">Data stream is a fillforward type</param>
        public void TriggerArchive(bool fillForward)
        {
            lock (_lock)
            {
                try
                {
                    //When there's nothing to do:
                    if (_data == null && !fillForward)
                    {
                        Log.Debug("StreamStore.TriggerArchive(): No data to store, and not fill forward: " + Symbol);
                    }

                    if (_data != null)
                    {
                        //Create clone and reset original
                        Log.Debug("StreamStore.TriggerArchive(): Enqueued new data: S:" + _data.Symbol + " V:" + _data.Value);
                        _previousData = _data.Clone();
                        _queue.Enqueue(_data.Clone());
                        _data = null;
                    }
                    else if (fillForward && _data == null && _previousData != null)
                    {
                        //There was no other data in this timer period, and this is a fillforward subscription:
                        Log.Debug("StreamStore.TriggerArchive(): Fillforward, Previous Enqueued: S:" + _previousData.Symbol + " V:" + _previousData.Value);
                        var cloneForward = _previousData.Clone(true);
                        cloneForward.Time = _previousData.Time.Add(_increment);
                        _queue.Enqueue(cloneForward);

                        _previousData = cloneForward.Clone();
                    }
                }
                catch (Exception err)
                {
                    Log.Error("StreamStore.TriggerAchive(fillforward): Failed to archive: " + err.Message);
                }
            }
        }
예제 #8
0
        /// <summary>
        /// 複製一份資料。
        /// </summary>
        /// <returns></returns>
        internal ConfigurationRecord Clone()
        {
            ConfigurationRecord record = new ConfigurationRecord(Namespace);

            record.EditAction = EditAction;

            if (BaseData != null)
            {
                record.BaseData = BaseData.Clone();
            }

            if (PreviousData != null)
            {
                record.PreviousData = PreviousData.CloneNode(true) as XmlElement;
            }

            return(record);
        }
예제 #9
0
        /// <summary>
        /// Clones the data, computes the utc emit time and performs exchange round down behavior, storing the result in a new <see cref="SubscriptionData"/> instance
        /// </summary>
        /// <param name="configuration">The subscription's configuration</param>
        /// <param name="exchangeHours">The exchange hours of the security</param>
        /// <param name="offsetProvider">The subscription's offset provider</param>
        /// <param name="data">The data being emitted</param>
        /// <returns>A new <see cref="SubscriptionData"/> containing the specified data</returns>
        public static SubscriptionData Create(SubscriptionDataConfig configuration, SecurityExchangeHours exchangeHours, TimeZoneOffsetProvider offsetProvider, BaseData data)
        {
            if (data == null)
            {
                return(null);
            }

            data = data.Clone(data.IsFillForward);
            var emitTimeUtc = offsetProvider.ConvertToUtc(data.EndTime);

            // Let's round down for any data source that implements a time delta between
            // the start of the data and end of the data (usually used with Bars).
            // The time delta ensures that the time collected from `EndTime` has
            // no look-ahead bias, and is point-in-time.
            if (data.Time != data.EndTime)
            {
                data.Time = data.Time.ExchangeRoundDownInTimeZone(configuration.Increment, exchangeHours, configuration.DataTimeZone, configuration.ExtendedMarketHours);
            }

            return(new SubscriptionData(data, emitTimeUtc));
        }