/// <summary> /// Adds the base currency conversion feed. /// </summary> /// <param name="security">The security.</param> private void AddBaseCurrencyConversionFeed(Security security) { //get both ways string tickerbase = $"{security.BaseCurrency}/{_basecurrency}"; string tickerreversed = $"{_basecurrency}/{security.BaseCurrency}"; //Check both subscriptions var tickerbasesubscription = DataSubscriptionRequest.CreateSubscriptionRequest(new TickerSymbol(tickerbase, _basecurrency.ToString(), security.BaseCurrency), _datafeed.DataSource, null, DataType.Tick); var tickerreversesubscription = DataSubscriptionRequest.CreateSubscriptionRequest(new TickerSymbol(tickerreversed, security.BaseCurrency.ToString(), _basecurrency), _datafeed.DataSource, null, DataType.Tick); //Add to subscription if needed possible string warningmessage(string ticker) => $"Cannot get live updates for currency {ticker} from feed {_datafeed.Name}, currency conversion will not be based on live data as the feed does not provide this conversion"; if (_datafeed.CanSubscribe(tickerbasesubscription.Ticker)) { AddSubscription(tickerbasesubscription); } else { _log.Warn(warningmessage(tickerbase)); } if (_datafeed.CanSubscribe(tickerreversesubscription.Ticker)) { AddSubscription(tickerreversesubscription); } else { _log.Warn(warningmessage(tickerreversed)); } }
/// <summary> /// Adds a datasubscription for all non market price data available (delisting, splits, trading status etc) /// </summary> /// <param name="security">The security.</param> /// <param name="quantfund"></param> public void AddSubscription(IQuantFund quantfund, Security security) { //Helper function void AddSubscriptionType(DataType datatype) { var subscriptionrequest = DataSubscriptionRequest.CreateSubscriptionRequest(security.Ticker, _datafeed.DataSource, null, datatype); AddSubscription(subscriptionrequest); //Add subscription to registered subscriptions if (!_registeredsubscriptions.ContainsKey(quantfund.FundId)) { _registeredsubscriptions.Add(quantfund.FundId, new List <DataSubscription>() { new DataSubscription(quantfund.FundId, subscriptionrequest, security, TimeZone.Utc, null) }); } else if (_registeredsubscriptions[quantfund.FundId].Count(x => x.Request.GetSubscriptionName() == subscriptionrequest.GetSubscriptionName()) == 0) { _registeredsubscriptions[quantfund.FundId].Add(new DataSubscription(quantfund.FundId, subscriptionrequest, security, TimeZone.Utc, null)); } } //Add delisting information AddSubscriptionType(DataType.Delisting); //Add dividend notifications AddSubscriptionType(DataType.Dividend); //Add earning reports AddSubscriptionType(DataType.Earning); //Add financial reports AddSubscriptionType(DataType.Financial); //Add key stats AddSubscriptionType(DataType.KeyStat); //Add stock splits AddSubscriptionType(DataType.Split); //Add trading status updates AddSubscriptionType(DataType.TradingStatus); //Check base conversion AddBaseCurrencyConversionFeed(security); }
/// <summary> /// Adds a datasubscription which is derived from the requested data aggregator instance /// Force tick will force the data to contain the highest granularity (otherwise it might be based on 1-minute data) /// TODO: add unit test, if we request 1 minute data and than request tick data we should keep the tick data request and replace all 1 minute request with the tick data request? (so that we only keep the tick data request) /// TODO: we will only do ticks or tradebars! (where a trade bar is based on any data) /// </summary> /// <param name="quantfund"></param> /// <param name="security">The security.</param> /// <param name="aggregator">The aggregator.</param> /// <param name="forcetick">if set to <c>true</c> [forcetick].</param> /// <returns>Can be a different dataggregator due to change in data requested</returns> public DataAggregator AddSubscription(IQuantFund quantfund, Security security, DataAggregator aggregator, bool forcetick = false) { //Initial values TimeSpan?aggregationneeded = null; DataType datatypeneeded = DataType.Tick; TimeSpan preaggregated = TimeSpan.FromMinutes(1); if (!forcetick) { //TradeBar -> TradeBar if (aggregator is TimeSerieAggregator <TradeBar, TradeBar> tradetotrade && tradetotrade.IsTimeBased) { if (tradetotrade.Period.Value.TotalSeconds % 60 == 0D) { aggregator = new TradeAggregator(tradetotrade.Period.Value); aggregationneeded = preaggregated; datatypeneeded = DataType.TradeBar; } } //Tick -> TradeBar if (aggregator is TimeSerieAggregator <Tick, TradeBar> ticktobar && ticktobar.IsTimeBased) { if (ticktobar.Period.Value.TotalSeconds % 60 == 0D) { aggregator = new TickQuoteBarAggregator(ticktobar.Period.Value); aggregationneeded = TimeSpan.FromMinutes(1); datatypeneeded = DataType.TradeBar; } } } //get and add subscription var subscription = DataSubscriptionRequest.CreateSubscriptionRequest(security.Ticker, _datafeed.DataSource, aggregationneeded, datatypeneeded); subscription = AddSubscription(subscription); //Add base currency conversion AddBaseCurrencyConversionFeed(security); //Check if we already have a similar data aggregator, reuse the existing version if possible if (_registeredsubscriptions.ContainsKey(quantfund.FundId)) { var found = _registeredsubscriptions[quantfund.FundId].FirstOrDefault(x => x.Request.GetSubscriptionName() == subscription.GetSubscriptionName()); var existing = found?.Aggregators.FirstOrDefault(x => x.Name == aggregator.Name); if (existing != null) { return(existing); } else if (found == null) { _registeredsubscriptions[quantfund.FundId].Add(new DataSubscription(quantfund.FundId, subscription, security, security.Exchange.TimeZone, aggregator)); } else { found.Aggregators.Add(aggregator); } } else { //Add new _registeredsubscriptions.Add(quantfund.FundId, new List <DataSubscription>()); _registeredsubscriptions[quantfund.FundId].Add(new DataSubscription(quantfund.FundId, subscription, security, security.Exchange.TimeZone, aggregator)); } //Return our current aggregator return(aggregator); }