/// <summary> /// Event invocator for the <see cref="UniverseSelection"/> event /// </summary> /// <param name="universe">The universe to perform selection on the data</param> /// <param name="config">The configuration of the universe</param> /// <param name="dateTimeUtc">The current date time in UTC</param> /// <param name="data">The universe selection data to be operated on</param> protected virtual void OnUniverseSelection(Universe universe, SubscriptionDataConfig config, DateTime dateTimeUtc, IReadOnlyList <BaseData> data) { if (UniverseSelection != null) { var eventArgs = new UniverseSelectionEventArgs(universe, config, dateTimeUtc, data); var multicast = (MulticastDelegate)UniverseSelection; foreach (UniverseSelectionHandler handler in multicast.GetInvocationList()) { _changes += handler(this, eventArgs); } } }
/// <summary> /// Applies universe selection the the data feed and algorithm /// </summary> /// <param name="args">The arguments from a universe selection event, containing the universe and /// the data produced for selection</param> public SecurityChanges ApplyUniverseSelection(UniverseSelectionEventArgs args) { var universe = args.Universe; var settings = universe.SubscriptionSettings; var limit = 1000; //daily/hourly limit var resolution = settings.Resolution; switch (resolution) { case Resolution.Tick: limit = _algorithm.Securities.TickLimit; break; case Resolution.Second: limit = _algorithm.Securities.SecondLimit; break; case Resolution.Minute: limit = _algorithm.Securities.MinuteLimit; break; } // subtract current subscriptions that can't be removed limit -= _algorithm.Securities.Count(x => x.Value.Resolution == resolution && x.Value.HoldStock); if (limit < 1) { // if we don't have room for more securities then we can't really do anything here. _algorithm.Error("Unable to add more securities from universe selection due to holding stock."); return(SecurityChanges.None); } // perform initial filtering and limit the result var selections = universe.SelectSymbols(args.Data).Take(limit).ToHashSet(); // create a hash set of our existing subscriptions by sid var existingSubscriptions = _dataFeed.Subscriptions.ToHashSet(x => x.Security.Symbol); var additions = new List <Security>(); var removals = new List <Security>(); // determine which data subscriptions need to be removed for this market foreach (var subscription in _dataFeed.Subscriptions) { // universes can only remove members of their own if (!universe.ContainsMember(subscription.Security)) { continue; } // never remove universe selection subscriptions if (subscription.IsUniverseSelectionSubscription) { continue; } var config = subscription.Configuration; // never remove internal feeds if (config.IsInternalFeed) { continue; } // if we've selected this subscription again, keep it if (selections.Contains(config.Symbol)) { continue; } // let the algorithm know this security has been removed from the universe removals.Add(subscription.Security); // but don't physically remove it from the algorithm if we hold stock or have open orders against it var openOrders = _algorithm.Transactions.GetOrders(x => x.Status.IsOpen() && x.Symbol == config.Symbol); if (!subscription.Security.HoldStock && !openOrders.Any()) { // we need to mark this security as untradeable while it has no data subscription // it is expected that this function is called while in sync with the algo thread, // so we can make direct edits to the security here subscription.Security.Cache.Reset(); if (_dataFeed.RemoveSubscription(subscription)) { universe.RemoveMember(subscription.Security); } } } // find new selections and add them to the algorithm foreach (var symbol in selections) { // we already have a subscription for this symbol so don't re-add it if (existingSubscriptions.Contains(symbol)) { continue; } // create the new security, the algorithm thread will add this at the appropriate time Security security; if (!_algorithm.Securities.TryGetValue(symbol, out security)) { security = SecurityManager.CreateSecurity(_algorithm.Portfolio, _algorithm.SubscriptionManager, _marketHoursDatabase, symbol, settings.Resolution, settings.FillForward, settings.Leverage, settings.ExtendedMarketHours, false, false); } additions.Add(security); // add the new subscriptions to the data feed if (_dataFeed.AddSubscription(universe, security, args.DateTimeUtc, _algorithm.EndDate.ConvertToUtc(_algorithm.TimeZone))) { universe.AddMember(security); } } // return None if there's no changes, otherwise return what we've modified return(additions.Count + removals.Count != 0 ? new SecurityChanges(additions, removals) : SecurityChanges.None); }
/// <summary> /// Event invocator for the <see cref="UniverseSelection"/> event /// </summary> /// <param name="universe">The universe to perform selection on the data</param> /// <param name="config">The configuration of the universe</param> /// <param name="dateTimeUtc">The current date time in UTC</param> /// <param name="data">The universe selection data to be operated on</param> protected virtual void OnUniverseSelection(Universe universe, SubscriptionDataConfig config, DateTime dateTimeUtc, IReadOnlyList<BaseData> data) { if (UniverseSelection != null) { var eventArgs = new UniverseSelectionEventArgs(universe, config, dateTimeUtc, data); var multicast = (MulticastDelegate)UniverseSelection; foreach (UniverseSelectionHandler handler in multicast.GetInvocationList()) { _changes += handler(this, eventArgs); } } }
/// <summary> /// Applies universe selection the the data feed and algorithm /// </summary> /// <param name="args">The arguments from a universe selection event, containing the universe and /// the data produced for selection</param> public SecurityChanges ApplyUniverseSelection(UniverseSelectionEventArgs args) { var universe = args.Universe; var settings = universe.SubscriptionSettings; var limit = 1000; //daily/hourly limit var resolution = settings.Resolution; switch (resolution) { case Resolution.Tick: limit = _algorithm.Securities.TickLimit; break; case Resolution.Second: limit = _algorithm.Securities.SecondLimit; break; case Resolution.Minute: limit = _algorithm.Securities.MinuteLimit; break; } // subtract current subscriptions that can't be removed limit -= _algorithm.Securities.Count(x => x.Value.Resolution == resolution && x.Value.HoldStock); if (limit < 1) { // if we don't have room for more securities then we can't really do anything here. _algorithm.Error("Unable to add more securities from universe selection due to holding stock."); return SecurityChanges.None; } // perform initial filtering and limit the result var selections = universe.SelectSymbols(args.Data).Take(limit).ToHashSet(); // create a hash set of our existing subscriptions by sid var existingSubscriptions = _dataFeed.Subscriptions.ToHashSet(x => x.Security.Symbol); var additions = new List<Security>(); var removals = new List<Security>(); // determine which data subscriptions need to be removed for this market foreach (var subscription in _dataFeed.Subscriptions) { // universes can only remove members of their own if (!universe.ContainsMember(subscription.Security)) continue; // never remove universe selection subscriptions if (subscription.IsUniverseSelectionSubscription) continue; var config = subscription.Configuration; // never remove internal feeds if (config.IsInternalFeed) continue; // if we've selected this subscription again, keep it if (selections.Contains(config.Symbol)) continue; // let the algorithm know this security has been removed from the universe removals.Add(subscription.Security); // but don't physically remove it from the algorithm if we hold stock or have open orders against it var openOrders = _algorithm.Transactions.GetOrders(x => x.Status.IsOpen() && x.Symbol == config.Symbol); if (!subscription.Security.HoldStock && !openOrders.Any()) { // we need to mark this security as untradeable while it has no data subscription // it is expected that this function is called while in sync with the algo thread, // so we can make direct edits to the security here subscription.Security.Cache.Reset(); if (_dataFeed.RemoveSubscription(subscription)) { universe.RemoveMember(subscription.Security); } } } // find new selections and add them to the algorithm foreach (var symbol in selections) { // we already have a subscription for this symbol so don't re-add it if (existingSubscriptions.Contains(symbol)) continue; // create the new security, the algorithm thread will add this at the appropriate time Security security; if (!_algorithm.Securities.TryGetValue(symbol, out security)) { security = SecurityManager.CreateSecurity(_algorithm.Portfolio, _algorithm.SubscriptionManager, _marketHoursDatabase, symbol, settings.Resolution, settings.FillForward, settings.Leverage, settings.ExtendedMarketHours, false, false); } additions.Add(security); // add the new subscriptions to the data feed if (_dataFeed.AddSubscription(universe, security, args.DateTimeUtc, _algorithm.EndDate.ConvertToUtc(_algorithm.TimeZone))) { universe.AddMember(security); } } // return None if there's no changes, otherwise return what we've modified return additions.Count + removals.Count != 0 ? new SecurityChanges(additions, removals) : SecurityChanges.None; }
/// <summary> /// Applies universe selection the the data feed and algorithm /// </summary> /// <param name="args">The arguments from a universe selection event, containing the universe and /// the data produced for selection</param> public SecurityChanges ApplyUniverseSelection(UniverseSelectionEventArgs args) { var limit = 1000; //daily/hourly limit var resolution = _algorithm.UniverseSettings.Resolution; switch (resolution) { case Resolution.Tick: limit = _algorithm.Securities.TickLimit; break; case Resolution.Second: limit = _algorithm.Securities.SecondLimit; break; case Resolution.Minute: limit = _algorithm.Securities.MinuteLimit; break; } // subtract current subscriptions that can't be removed limit -= _algorithm.Securities.Count(x => x.Value.Resolution == resolution && x.Value.HoldStock); if (limit < 1) { // if we don't have room for more securities then we can't really do anything here. _algorithm.Error("Unable to add more securities from universe selection due to holding stock."); return SecurityChanges.None; } // perform initial filtering and limit the result var initialSelections = args.Universe.SelectSymbols(args.Data).Take(limit).ToHashSet(); // create a hash set of our existing subscriptions by sid var existingSubscriptions = _dataFeed.Subscriptions.ToHashSet(x => x.Security.Symbol); // create a map of each selection to its 'unique' first symbol/date var selectedSubscriptions = initialSelections.ToHashSet(); var additions = new List<Security>(); var removals = new List<Security>(); // determine which data subscriptions need to be removed for this market foreach (var subscription in _dataFeed.Subscriptions) { // never remove subscriptions set explicitly by the user if (subscription.IsUserDefined) continue; // never remove universe selection subscriptions if (subscription.IsUniverseSelectionSubscription) continue; var config = subscription.Configuration; // never remove internal feeds if (config.IsInternalFeed) continue; // don't remove subscriptions for different markets and non-equity types if (config.Market != args.Configuration.Market || config.SecurityType != SecurityType.Equity) continue; // if we've selected this subscription again, keep it if (selectedSubscriptions.Contains(config.Symbol)) continue; // let the algorithm know this security has been removed from the universe removals.Add(subscription.Security); // but don't physically remove it from the algorithm if we hold stock or have open orders against it var openOrders = _algorithm.Transactions.GetOrders(x => x.Status.IsOpen() && x.Symbol == config.Symbol); if (!subscription.Security.HoldStock && !openOrders.Any()) { // we need to mark this security as untradeable while it has no data subscription // it is expected that this function is called while in sync with the algo thread, // so we can make direct edits to the security here subscription.Security.Cache.Reset(); _dataFeed.RemoveSubscription(subscription.Security); } } var settings = _algorithm.UniverseSettings; // find new selections and add them to the algorithm foreach (var sid in selectedSubscriptions) { // we already have a subscription for this symbol so don't re-add it if (existingSubscriptions.Contains(sid)) continue; // create the new security, the algorithm thread will add this at the appropriate time var security = SecurityManager.CreateSecurity(_algorithm.Portfolio, _algorithm.SubscriptionManager, _hoursProvider, SecurityType.Equity, sid, settings.Resolution, args.Configuration.Market, settings.FillForward, settings.Leverage, settings.ExtendedMarketHours, false, false); additions.Add(security);; // add the new subscriptions to the data feed -- TODO : this conversion keeps the behavior the same but stinks like a bug! _dataFeed.AddSubscription(security, args.DateTimeUtc.ConvertFromUtc(args.Configuration.TimeZone), _algorithm.EndDate, false); } // return None if there's no changes, otherwise return what we've modified return additions.Count + removals.Count != 0 ? new SecurityChanges(additions, removals) : SecurityChanges.None; }