public void ToXML_EnsuresUSLocaleForDecimals() { CultureInfo existingCulture = CultureInfo.CurrentCulture; try { #if netcore CultureInfo.CurrentCulture = new CultureInfo("it-IT"); #else Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("it-IT"); #endif TransactionRequest transactionRequest = new TransactionRequest { Amount = 100.0M, TaxAmount = 10.0M, }; SubscriptionRequest subscriptionRequest = new SubscriptionRequest { Price = 200.0M, }; SubscriptionTransactionRequest subscriptionTransactionRequest = new SubscriptionTransactionRequest { Amount = 300.0M }; ModificationRequest modificationRequest = new ModificationRequest { Amount = 400.0M }; TestHelper.AssertIncludes("<amount>100.00</amount>", transactionRequest.ToXml()); TestHelper.AssertIncludes("<tax-amount>10.00</tax-amount>", transactionRequest.ToXml()); TestHelper.AssertIncludes("<price>200.00</price>", subscriptionRequest.ToXml()); TestHelper.AssertIncludes("<amount>300.00</amount>", subscriptionTransactionRequest.ToXml()); TestHelper.AssertIncludes("<amount>400.00</amount>", modificationRequest.ToXml("root")); } finally { #if netcore CultureInfo.CurrentCulture = existingCulture; #else Thread.CurrentThread.CurrentCulture = existingCulture; #endif } }
public void Create_SubscriptionWithoutTrial() { TestPlan plan = PlanFixture.PLAN_WITHOUT_TRIAL; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Assert.AreEqual(creditCard.Token, subscription.PaymentMethodToken); Assert.AreEqual(plan.Id, subscription.PlanId); Assert.AreEqual(MerchantAccountIDs.DEFAULT_MERCHANT_ACCOUNT_ID, subscription.MerchantAccountId); Assert.AreEqual(plan.Price, subscription.Price); Assert.AreEqual(plan.Price, subscription.NextBillAmount); Assert.AreEqual(plan.Price, subscription.NextBillingPeriodAmount); Assert.AreEqual(0.00M, subscription.Balance); Assert.IsTrue(Regex.IsMatch(subscription.Id, "^\\w{6}$")); Assert.AreEqual(SubscriptionStatus.ACTIVE, subscription.Status); Assert.AreEqual(0, subscription.FailureCount); Assert.IsFalse((bool)subscription.HasTrialPeriod); Assert.AreEqual(1, subscription.CurrentBillingCycle); Assert.IsTrue(subscription.BillingPeriodEndDate.HasValue); Assert.IsTrue(subscription.BillingPeriodStartDate.HasValue); Assert.IsTrue(subscription.NextBillingDate.HasValue); Assert.IsTrue(subscription.FirstBillingDate.HasValue); Assert.IsTrue(subscription.CreatedAt.HasValue); Assert.IsTrue(subscription.UpdatedAt.HasValue); Assert.IsTrue(subscription.PaidThroughDate.HasValue); Assert.AreEqual(SubscriptionStatus.ACTIVE, subscription.StatusHistory[0].Status); Assert.AreEqual(SubscriptionSource.API, subscription.StatusHistory[0].Source); Assert.AreEqual(plan.Price, subscription.StatusHistory[0].Price); Assert.AreEqual(0.00M, subscription.StatusHistory[0].Balance); Assert.AreEqual("USD", subscription.StatusHistory[0].CurrencyIsoCode); Assert.AreEqual("integration_trialless_plan", subscription.StatusHistory[0].PlanId); }
public void ToXML_EnsuresUSLocaleForDecimals() { System.Globalization.CultureInfo existingCulture = System.Globalization.CultureInfo.CurrentCulture; try { System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo("it-IT"); TransactionRequest transactionRequest = new TransactionRequest { Amount = 100.0M }; SubscriptionRequest subscriptionRequest = new SubscriptionRequest { Price = 200.0M, }; SubscriptionTransactionRequest subscriptionTransactionRequest = new SubscriptionTransactionRequest { Amount = 300.0M }; ModificationRequest modificationRequest = new ModificationRequest { Amount = 400.0M }; TestHelper.AssertIncludes("<amount>100.0</amount>", transactionRequest.ToXml()); TestHelper.AssertIncludes("<price>200.0</price>", subscriptionRequest.ToXml()); TestHelper.AssertIncludes("<amount>300.0</amount>", subscriptionTransactionRequest.ToXml()); TestHelper.AssertIncludes("<amount>400.0</amount>", modificationRequest.ToXml("root")); } finally { System.Threading.Thread.CurrentThread.CurrentCulture = existingCulture; } }
public Subscription CreateSubscription(SubscriptionRequest request) { return(null); }
public void Create_HasTransactionOnCreateWithNoTrial() { TestPlan plan = PlanFixture.PLAN_WITHOUT_TRIAL; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id, Price = 482.48M }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Transaction transaction = subscription.Transactions[0]; Assert.AreEqual(1, subscription.Transactions.Count); Assert.AreEqual(482.48M, transaction.Amount); Assert.AreEqual(TransactionType.SALE, transaction.Type); Assert.AreEqual(subscription.Id, transaction.SubscriptionId); }
public void RefreshesOptionChainUniverseOnDateChange() { var startTime = new DateTime(2018, 10, 19, 10, 0, 0); var timeProvider = new ManualTimeProvider(startTime); var canonicalSymbol = Symbol.Create("SPY", SecurityType.Option, Market.USA, "?SPY"); var quoteCurrency = new Cash(Currencies.USD, 0, 1); var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.USA, canonicalSymbol, SecurityType.Option); var config = new SubscriptionDataConfig( typeof(ZipEntryName), canonicalSymbol, Resolution.Minute, TimeZones.Utc, TimeZones.NewYork, true, false, false, false, TickType.Quote, false, DataNormalizationMode.Raw ); var option = new Option( canonicalSymbol, exchangeHours, quoteCurrency, new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); var fillForwardResolution = Ref.CreateReadOnly(() => Resolution.Minute.ToTimeSpan()); var symbolUniverse = new TestDataQueueUniverseProvider(timeProvider); TradeBarBuilderEnumerator underlyingEnumerator = null; Func <SubscriptionRequest, IEnumerator <BaseData>, IEnumerator <BaseData> > underlyingEnumeratorFunc = (req, input) => { underlyingEnumerator = (TradeBarBuilderEnumerator)input; return(new LiveFillForwardEnumerator( timeProvider, input, option.Exchange, fillForwardResolution, false, Time.EndOfTime, Resolution.Minute.ToTimeSpan(), TimeZones.Utc, Time.BeginningOfTime)); }; var factory = new OptionChainUniverseSubscriptionEnumeratorFactory(underlyingEnumeratorFunc, symbolUniverse, timeProvider); var universeSettings = new UniverseSettings(Resolution.Minute, 0, true, false, TimeSpan.Zero); var universe = new OptionChainUniverse(option, universeSettings, true); var request = new SubscriptionRequest(true, universe, option, config, startTime, Time.EndOfTime); var enumerator = (DataQueueOptionChainUniverseDataCollectionEnumerator)factory.CreateEnumerator(request, new DefaultDataProvider()); // 2018-10-19 10:00 AM UTC underlyingEnumerator.ProcessData(new Tick { Symbol = Symbols.SPY, Value = 280m }); Assert.IsTrue(enumerator.MoveNext()); // no underlying data available yet Assert.IsNull(enumerator.Current); Assert.AreEqual(0, symbolUniverse.TotalLookupCalls); // 2018-10-19 10:01 AM UTC timeProvider.Advance(Time.OneMinute); underlyingEnumerator.ProcessData(new Tick { Symbol = Symbols.SPY, Value = 280m }); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNotNull(enumerator.Current); Assert.AreEqual(1, symbolUniverse.TotalLookupCalls); var data = enumerator.Current; Assert.IsNotNull(data); Assert.AreEqual(1, data.Data.Count); Assert.IsNotNull(data.Underlying); // 2018-10-19 10:02 AM UTC timeProvider.Advance(Time.OneMinute); underlyingEnumerator.ProcessData(new Tick { Symbol = Symbols.SPY, Value = 280m }); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNotNull(enumerator.Current); Assert.AreEqual(1, symbolUniverse.TotalLookupCalls); data = enumerator.Current; Assert.IsNotNull(data); Assert.AreEqual(1, data.Data.Count); Assert.IsNotNull(data.Underlying); // 2018-10-19 10:03 AM UTC timeProvider.Advance(Time.OneMinute); underlyingEnumerator.ProcessData(new Tick { Symbol = Symbols.SPY, Value = 280m }); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNotNull(enumerator.Current); Assert.AreEqual(1, symbolUniverse.TotalLookupCalls); data = enumerator.Current; Assert.IsNotNull(data); Assert.AreEqual(1, data.Data.Count); Assert.IsNotNull(data.Underlying); // 2018-10-20 10:03 AM UTC timeProvider.Advance(Time.OneDay); underlyingEnumerator.ProcessData(new Tick { Symbol = Symbols.SPY, Value = 280m }); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNotNull(enumerator.Current); Assert.AreEqual(2, symbolUniverse.TotalLookupCalls); data = enumerator.Current; Assert.IsNotNull(data); Assert.AreEqual(2, data.Data.Count); Assert.IsNotNull(data.Underlying); // 2018-10-20 10:04 AM UTC timeProvider.Advance(Time.OneMinute); underlyingEnumerator.ProcessData(new Tick { Symbol = Symbols.SPY, Value = 280m }); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNotNull(enumerator.Current); Assert.AreEqual(2, symbolUniverse.TotalLookupCalls); data = enumerator.Current; Assert.IsNotNull(data); Assert.AreEqual(2, data.Data.Count); Assert.IsNotNull(data.Underlying); enumerator.Dispose(); }
private Subscription CreateSubscription(Resolution resolution, string symbol = "AAPL", bool isInternalFeed = false, SecurityType type = SecurityType.Equity, TickType tickType = TickType.Trade) { var start = DateTime.UtcNow; var end = start.AddSeconds(10); Security security; Symbol _symbol; if (type == SecurityType.Equity) { _symbol = new Symbol(SecurityIdentifier.GenerateEquity(DateTime.Now, symbol, Market.USA), symbol); security = new Equity( _symbol, SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc), new Cash(Currencies.USD, 0, 1), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); } else if (type == SecurityType.Option) { _symbol = new Symbol(SecurityIdentifier.GenerateOption(DateTime.Now, SecurityIdentifier.GenerateEquity(DateTime.Now, symbol, Market.USA), Market.USA, 0.0m, OptionRight.Call, OptionStyle.American), symbol); security = new Option( _symbol, SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc), new Cash(Currencies.USD, 0, 1), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); } else if (type == SecurityType.Future) { _symbol = new Symbol(SecurityIdentifier.GenerateFuture(DateTime.Now, symbol, Market.COMEX), symbol); security = new Future( _symbol, SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc), new Cash(Currencies.USD, 0, 1), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); } else { throw new Exception("SecurityType not implemented"); } var config = new SubscriptionDataConfig(typeof(TradeBar), _symbol, resolution, DateTimeZone.Utc, DateTimeZone.Utc, true, false, isInternalFeed, false, tickType); var timeZoneOffsetProvider = new TimeZoneOffsetProvider(DateTimeZone.Utc, start, end); var enumerator = new EnqueueableEnumerator <BaseData>(); var subscriptionDataEnumerator = new SubscriptionDataEnumerator(config, security.Exchange.Hours, timeZoneOffsetProvider, enumerator); var subscriptionRequest = new SubscriptionRequest(false, null, security, config, start, end); return(new Subscription(subscriptionRequest, subscriptionDataEnumerator, timeZoneOffsetProvider)); }
public override Task <ResponseStatus> Subscribe(SubscriptionRequest request, ServerCallContext context) { return(lifetimeScopeExecutor.ExecuteInNewScope <ISubscriptionActionsService, ResponseStatus>(service => service.Subscribe(request, context))); }
/// <summary> /// Setups a new <see cref="Subscription"/> which will consume a blocking <see cref="EnqueueableEnumerator{T}"/> /// that will be feed by a worker task /// </summary> /// <param name="request">The subscription data request</param> /// <param name="enumerator">The data enumerator stack</param> /// <param name="factorFileProvider">The factor file provider</param> /// <param name="enablePriceScale">Enables price factoring</param> /// <returns>A new subscription instance ready to consume</returns> public static Subscription CreateAndScheduleWorker( SubscriptionRequest request, IEnumerator <BaseData> enumerator, IFactorFileProvider factorFileProvider, bool enablePriceScale) { var factorFile = GetFactorFileToUse(request.Configuration, factorFileProvider); var exchangeHours = request.Security.Exchange.Hours; var enqueueable = new EnqueueableEnumerator <SubscriptionData>(true); var timeZoneOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); var subscription = new Subscription(request, enqueueable, timeZoneOffsetProvider); var config = subscription.Configuration; var lastTradableDate = DateTime.MinValue; decimal?currentScale = null; Func <int, bool> produce = (workBatchSize) => { try { var count = 0; while (enumerator.MoveNext()) { // subscription has been removed, no need to continue enumerating if (enqueueable.HasFinished) { enumerator.DisposeSafely(); return(false); } var data = enumerator.Current; // Use our config filter to see if we should emit this // This currently catches Auxiliary data that we don't want to emit if (data != null && !config.ShouldEmitData(data)) { continue; } var requestMode = config.DataNormalizationMode; var mode = requestMode != DataNormalizationMode.Raw ? requestMode : DataNormalizationMode.Adjusted; // We update our price scale factor when the date changes for non fill forward bars or if we haven't initialized yet. // We don't take into account auxiliary data because we don't scale it and because the underlying price data could be fill forwarded if (enablePriceScale && data?.Time.Date > lastTradableDate && data.DataType != MarketDataType.Auxiliary && (!data.IsFillForward || lastTradableDate == DateTime.MinValue)) { lastTradableDate = data.Time.Date; currentScale = GetScaleFactor(factorFile, mode, data.Time.Date); } SubscriptionData subscriptionData = SubscriptionData.Create( config, exchangeHours, subscription.OffsetProvider, data, mode, enablePriceScale ? currentScale : null); // drop the data into the back of the enqueueable enqueueable.Enqueue(subscriptionData); count++; // stop executing if added more data than the work batch size, we don't want to fill the ram if (count > workBatchSize) { return(true); } } } catch (Exception exception) { Log.Error(exception, $"Subscription worker task exception {request.Configuration}."); } // we made it here because MoveNext returned false or we exploded, stop the enqueueable enqueueable.Stop(); // we have to dispose of the enumerator enumerator.DisposeSafely(); return(false); }; WeightedWorkScheduler.Instance.QueueWork(produce, // if the subscription finished we return 0, so the work is prioritized and gets removed () => { if (enqueueable.HasFinished) { return(0); } var count = enqueueable.Count; return(count > WeightedWorkScheduler.MaxWorkWeight ? WeightedWorkScheduler.MaxWorkWeight : count); } ); return(subscription); }
/// <summary> /// Creates a new subscription for universe selection /// </summary> /// <param name="request">The subscription request</param> private Subscription CreateUniverseSubscription(SubscriptionRequest request) { Subscription subscription = null; // TODO : Consider moving the creating of universe subscriptions to a separate, testable class // grab the relevant exchange hours var config = request.Universe.Configuration; var localEndTime = request.EndTimeUtc.ConvertFromUtc(request.Security.Exchange.TimeZone); var tzOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); IEnumerator <BaseData> enumerator; var timeTriggered = request.Universe as ITimeTriggeredUniverse; if (timeTriggered != null) { Log.Trace($"LiveTradingDataFeed.CreateUniverseSubscription(): Creating user defined universe: {config.Symbol}"); // spoof a tick on the requested interval to trigger the universe selection function var enumeratorFactory = new TimeTriggeredUniverseSubscriptionEnumeratorFactory(timeTriggered, MarketHoursDatabase.FromDataFolder(), _frontierTimeProvider); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = new FrontierAwareEnumerator(enumerator, _timeProvider, tzOffsetProvider); var enqueueable = new EnqueueableEnumerator <BaseData>(); _customExchange.AddEnumerator(new EnumeratorHandler(config.Symbol, enumerator, enqueueable)); enumerator = enqueueable; } else if (config.Type == typeof(CoarseFundamental)) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating coarse universe: " + config.Symbol.ToString()); // we subscribe using a normalized symbol, without a random GUID, // since the ticker plant will send the coarse data using this symbol var normalizedSymbol = CoarseFundamental.CreateUniverseSymbol(config.Symbol.ID.Market, false); // since we're binding to the data queue exchange we'll need to let him // know that we expect this data _dataQueueHandler.Subscribe(_job, new[] { normalizedSymbol }); var enqueable = new EnqueueableEnumerator <BaseData>(); // We `AddDataHandler` not `Set` so we can have multiple handlers for the coarse data _exchange.AddDataHandler(normalizedSymbol, data => { enqueable.Enqueue(data); subscription.OnNewDataAvailable(); }); enumerator = GetConfiguredFrontierAwareEnumerator(enqueable, tzOffsetProvider, // advance time if before 23pm or after 5am and not on Saturdays time => time.Hour < 23 && time.Hour > 5 && time.DayOfWeek != DayOfWeek.Saturday); } else if (request.Universe is OptionChainUniverse) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating option chain universe: " + config.Symbol.ToString()); Func <SubscriptionRequest, IEnumerator <BaseData>, IEnumerator <BaseData> > configure = (subRequest, input) => { // we check if input enumerator is an underlying enumerator. If yes, we subscribe it to the data. var aggregator = input as TradeBarBuilderEnumerator; if (aggregator != null) { _exchange.SetDataHandler(request.Configuration.Symbol, data => { aggregator.ProcessData((Tick)data); }); } var fillForwardResolution = _subscriptions.UpdateAndGetFillForwardResolution(request.Configuration); return(new LiveFillForwardEnumerator(_frontierTimeProvider, input, request.Security.Exchange, fillForwardResolution, request.Configuration.ExtendedMarketHours, localEndTime, request.Configuration.Increment, request.Configuration.DataTimeZone, request.StartTimeLocal)); }; var symbolUniverse = _dataQueueHandler as IDataQueueUniverseProvider; if (symbolUniverse == null) { throw new NotSupportedException("The DataQueueHandler does not support Options."); } var enumeratorFactory = new OptionChainUniverseSubscriptionEnumeratorFactory(configure, symbolUniverse, _timeProvider); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = GetConfiguredFrontierAwareEnumerator(enumerator, tzOffsetProvider, time => symbolUniverse.CanAdvanceTime(config.SecurityType)); } else if (request.Universe is FuturesChainUniverse) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating futures chain universe: " + config.Symbol.ToString()); var symbolUniverse = _dataQueueHandler as IDataQueueUniverseProvider; if (symbolUniverse == null) { throw new NotSupportedException("The DataQueueHandler does not support Futures."); } var enumeratorFactory = new FuturesChainUniverseSubscriptionEnumeratorFactory(symbolUniverse, _timeProvider); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = GetConfiguredFrontierAwareEnumerator(enumerator, tzOffsetProvider, time => symbolUniverse.CanAdvanceTime(config.SecurityType)); } else { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating custom universe: " + config.Symbol.ToString()); var factory = new LiveCustomDataSubscriptionEnumeratorFactory(_timeProvider); var enumeratorStack = factory.CreateEnumerator(request, _dataProvider); enumerator = new BaseDataCollectionAggregatorEnumerator(enumeratorStack, config.Symbol, liveMode: true); var enqueueable = new EnqueueableEnumerator <BaseData>(); _customExchange.AddEnumerator(new EnumeratorHandler(config.Symbol, enumerator, enqueueable)); enumerator = enqueueable; } // create the subscription var subscriptionDataEnumerator = new SubscriptionDataEnumerator(request.Configuration, request.Security.Exchange.Hours, tzOffsetProvider, enumerator); subscription = new Subscription(request, subscriptionDataEnumerator, tzOffsetProvider); return(subscription); }
public void Create_WithBadAddOnParamsCorrectlyParsesValidationErrors() { TestPlan plan = PlanFixture.ADD_ON_DISCOUNT_PLAN; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id, AddOns = new AddOnsRequest { Update = new UpdateAddOnRequest[] { new UpdateAddOnRequest { ExistingId = "increase_10", Amount = -200M }, new UpdateAddOnRequest { ExistingId = "increase_20", Quantity = -9 } } } }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsFalse(result.IsSuccess()); Assert.AreEqual(ValidationErrorCode.SUBSCRIPTION_MODIFICATION_AMOUNT_IS_INVALID, result.Errors.ForObject("Subscription").ForObject("AddOns").ForObject("Update").ForIndex(0).OnField("Amount")[0].Code); Assert.AreEqual(ValidationErrorCode.SUBSCRIPTION_MODIFICATION_QUANTITY_IS_INVALID, result.Errors.ForObject("Subscription").ForObject("AddOns").ForObject("Update").ForIndex(1).OnField("Quantity")[0].Code); }
public void Create_CanAddAddOnsAndDiscounts() { TestPlan plan = PlanFixture.ADD_ON_DISCOUNT_PLAN; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id, AddOns = new AddOnsRequest { Add = new AddAddOnRequest[] { new AddAddOnRequest { InheritedFromId = "increase_30", Amount = 35M, NumberOfBillingCycles = 3, Quantity = 8 } }, Remove = new string[] { "increase_10", "increase_20" } }, Discounts = new DiscountsRequest { Add = new AddDiscountRequest[] { new AddDiscountRequest { InheritedFromId = "discount_15", Amount = 17M, NeverExpires = true, Quantity = 9 } }, Remove = new string[] { "discount_7", "discount_11" } } }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Assert.AreEqual(1, subscription.AddOns.Count); Assert.AreEqual("increase_30", subscription.AddOns[0].Id); Assert.AreEqual(35M, subscription.AddOns[0].Amount); Assert.AreEqual(8, subscription.AddOns[0].Quantity); Assert.IsFalse(subscription.AddOns[0].NeverExpires.Value); Assert.AreEqual(3, subscription.AddOns[0].NumberOfBillingCycles); Assert.AreEqual(0, subscription.AddOns[0].CurrentBillingCycle); Assert.AreEqual(1, subscription.Discounts.Count); Assert.AreEqual("discount_15", subscription.Discounts[0].Id); Assert.AreEqual(17M, subscription.Discounts[0].Amount); Assert.AreEqual(9, subscription.Discounts[0].Quantity); Assert.IsTrue(subscription.Discounts[0].NeverExpires.Value); Assert.IsNull(subscription.Discounts[0].NumberOfBillingCycles); Assert.AreEqual(0, subscription.Discounts[0].CurrentBillingCycle); }
public void Create_CanRemoveInheritedAddOnsAndDiscounts() { TestPlan plan = PlanFixture.ADD_ON_DISCOUNT_PLAN; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id, AddOns = new AddOnsRequest { Remove = new string[] { "increase_10", "increase_20" } }, Discounts = new DiscountsRequest { Remove = new string[] { "discount_11" } } }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Assert.AreEqual(0, subscription.AddOns.Count); Assert.AreEqual(1, subscription.Discounts.Count); Assert.AreEqual("discount_7", subscription.Discounts[0].Id); }
public void Create_CanOverrideInheritedAddOnsAndDiscountsFromPlan() { TestPlan plan = PlanFixture.ADD_ON_DISCOUNT_PLAN; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id, AddOns = new AddOnsRequest { Update = new UpdateAddOnRequest[] { new UpdateAddOnRequest { ExistingId = "increase_10", Amount = 30M, Quantity = 9, NeverExpires = true }, new UpdateAddOnRequest { ExistingId = "increase_20", Amount = 40M, NumberOfBillingCycles = 20 } } }, Discounts = new DiscountsRequest { Update = new UpdateDiscountRequest[] { new UpdateDiscountRequest { ExistingId = "discount_7", Amount = 15M, Quantity = 7, NeverExpires = true }, new UpdateDiscountRequest { ExistingId = "discount_11", Amount = 23M, NumberOfBillingCycles = 11 } } } }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; List<AddOn> addOns = subscription.AddOns; addOns.Sort(TestHelper.CompareModificationsById); Assert.AreEqual(2, addOns.Count); Assert.AreEqual(30M, addOns[0].Amount); Assert.AreEqual(9, addOns[0].Quantity); Assert.IsTrue(addOns[0].NeverExpires.Value); Assert.IsNull(addOns[0].NumberOfBillingCycles); Assert.AreEqual(0, addOns[0].CurrentBillingCycle); Assert.AreEqual(40.00M, addOns[1].Amount); Assert.AreEqual(1, addOns[1].Quantity); Assert.IsFalse(addOns[1].NeverExpires.Value); Assert.AreEqual(20, addOns[1].NumberOfBillingCycles); Assert.AreEqual(0, addOns[1].CurrentBillingCycle); List<Discount> discounts = subscription.Discounts; discounts.Sort(TestHelper.CompareModificationsById); Assert.AreEqual(2, discounts.Count); Assert.AreEqual(23M, discounts[0].Amount); Assert.AreEqual(1, discounts[0].Quantity); Assert.IsFalse(discounts[0].NeverExpires.Value); Assert.AreEqual(11, discounts[0].NumberOfBillingCycles); Assert.AreEqual(0, discounts[0].CurrentBillingCycle); Assert.AreEqual(15M, discounts[1].Amount); Assert.AreEqual(7, discounts[1].Quantity); Assert.IsTrue(discounts[1].NeverExpires.Value); Assert.IsNull(discounts[1].NumberOfBillingCycles); Assert.AreEqual(0, discounts[1].CurrentBillingCycle); }
public void Create_InheritsAddOnsAndDiscountsFromPlan() { TestPlan plan = PlanFixture.ADD_ON_DISCOUNT_PLAN; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; List<AddOn> addOns = subscription.AddOns; addOns.Sort(TestHelper.CompareModificationsById); Assert.AreEqual(2, addOns.Count); Assert.AreEqual(10M, addOns[0].Amount); Assert.AreEqual(1, addOns[0].Quantity); Assert.IsTrue(addOns[0].NeverExpires.Value); Assert.IsNull(addOns[0].NumberOfBillingCycles); Assert.AreEqual(0, addOns[0].CurrentBillingCycle); Assert.AreEqual(20.00M, addOns[1].Amount); Assert.AreEqual(1, addOns[1].Quantity); Assert.IsTrue(addOns[1].NeverExpires.Value); Assert.IsNull(addOns[1].NumberOfBillingCycles); Assert.AreEqual(0, addOns[1].CurrentBillingCycle); List<Discount> discounts = subscription.Discounts; discounts.Sort(TestHelper.CompareModificationsById); Assert.AreEqual(2, discounts.Count); Assert.AreEqual(11M, discounts[0].Amount); Assert.AreEqual(1, discounts[0].Quantity); Assert.IsTrue(discounts[0].NeverExpires.Value); Assert.IsNull(discounts[0].NumberOfBillingCycles); Assert.AreEqual(0, discounts[0].CurrentBillingCycle); Assert.AreEqual(7M, discounts[1].Amount); Assert.AreEqual(1, discounts[1].Quantity); Assert.IsTrue(discounts[1].NeverExpires.Value); Assert.IsNull(discounts[1].NumberOfBillingCycles); Assert.AreEqual(0, discounts[1].CurrentBillingCycle); }
public void Create_InheritsNoAddOnsAndDiscountsWhenOptionIsPassed() { TestPlan plan = PlanFixture.ADD_ON_DISCOUNT_PLAN; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id, Options = new SubscriptionOptionsRequest { DoNotInheritAddOnsOrDiscounts = true } }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Assert.AreEqual(0, subscription.AddOns.Count); Assert.AreEqual(0, subscription.Discounts.Count); }
public void Create_HasNoTransactionOnCreateWithATrial() { TestPlan plan = PlanFixture.PLAN_WITH_TRIAL; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Assert.AreEqual(0, subscription.Transactions.Count); }
/// <summary> /// Creates a subscription to process the request /// </summary> private Subscription CreateSubscription(HistoryRequest request, DateTime startUtc, DateTime endUtc) { // data reader expects these values in local times var startTimeLocal = startUtc.ConvertFromUtc(request.ExchangeHours.TimeZone); var endTimeLocal = endUtc.ConvertFromUtc(request.ExchangeHours.TimeZone); var config = new SubscriptionDataConfig(request.DataType, request.Symbol, request.Resolution, request.DataTimeZone, request.ExchangeHours.TimeZone, request.FillForwardResolution.HasValue, request.IncludeExtendedMarketHours, false, request.IsCustomData, request.TickType, true, request.DataNormalizationMode ); _dataPermissionManager.AssertConfiguration(config); var security = new Security( request.ExchangeHours, config, new Cash(Currencies.NullCurrency, 0, 1m), SymbolProperties.GetDefault(Currencies.NullCurrency), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); var mapFileResolver = MapFileResolver.Empty; if (config.TickerShouldBeMapped()) { mapFileResolver = _mapFileProvider.Get(config.Market); var mapFile = mapFileResolver.ResolveMapFile(config.Symbol.ID.Symbol, config.Symbol.ID.Date); config.MappedSymbol = mapFile.GetMappedSymbol(startTimeLocal, config.MappedSymbol); } // Tradable dates are defined with the data time zone to access the right source var tradableDates = Time.EachTradeableDayInTimeZone(request.ExchangeHours, startTimeLocal, endTimeLocal, request.DataTimeZone, request.IncludeExtendedMarketHours); var dataReader = new SubscriptionDataReader(config, startTimeLocal, endTimeLocal, mapFileResolver, _factorFileProvider, tradableDates, false, _dataCacheProvider ); dataReader.InvalidConfigurationDetected += (sender, args) => { OnInvalidConfigurationDetected(args); }; dataReader.NumericalPrecisionLimited += (sender, args) => { OnNumericalPrecisionLimited(args); }; dataReader.StartDateLimited += (sender, args) => { OnStartDateLimited(args); }; dataReader.DownloadFailed += (sender, args) => { OnDownloadFailed(args); }; dataReader.ReaderErrorDetected += (sender, args) => { OnReaderErrorDetected(args); }; IEnumerator <BaseData> reader = dataReader; var intraday = GetIntradayDataEnumerator(dataReader, request); if (intraday != null) { // we optionally concatenate the intraday data enumerator reader = new ConcatEnumerator(true, reader, intraday); } reader = CorporateEventEnumeratorFactory.CreateEnumerators( reader, config, _factorFileProvider, dataReader, mapFileResolver, false, startTimeLocal); // optionally apply fill forward behavior if (request.FillForwardResolution.HasValue) { // copy forward Bid/Ask bars for QuoteBars if (request.DataType == typeof(QuoteBar)) { reader = new QuoteBarFillForwardEnumerator(reader); } var readOnlyRef = Ref.CreateReadOnly(() => request.FillForwardResolution.Value.ToTimeSpan()); reader = new FillForwardEnumerator(reader, security.Exchange, readOnlyRef, request.IncludeExtendedMarketHours, endTimeLocal, config.Increment, config.DataTimeZone); } // since the SubscriptionDataReader performs an any overlap condition on the trade bar's entire // range (time->end time) we can end up passing the incorrect data (too far past, possibly future), // so to combat this we deliberately filter the results from the data reader to fix these cases // which only apply to non-tick data reader = new SubscriptionFilterEnumerator(reader, security, endTimeLocal, config.ExtendedMarketHours, false, request.ExchangeHours); reader = new FilterEnumerator <BaseData>(reader, data => { // allow all ticks if (config.Resolution == Resolution.Tick) { return(true); } // filter out future data if (data.EndTime > endTimeLocal) { return(false); } // filter out data before the start return(data.EndTime > startTimeLocal); }); var subscriptionRequest = new SubscriptionRequest(false, null, security, config, request.StartTimeUtc, request.EndTimeUtc); if (_parallelHistoryRequestsEnabled) { return(SubscriptionUtils.CreateAndScheduleWorker(subscriptionRequest, reader, _factorFileProvider, false)); } return(SubscriptionUtils.Create(subscriptionRequest, reader)); }
/// <summary> /// Creates a new subscription for the specified security /// </summary> /// <param name="request">The subscription request</param> /// <returns>A new subscription instance of the specified security</returns> protected Subscription CreateSubscription(SubscriptionRequest request) { Subscription subscription = null; try { var localEndTime = request.EndTimeUtc.ConvertFromUtc(request.Security.Exchange.TimeZone); var timeZoneOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); IEnumerator <BaseData> enumerator; if (request.Configuration.IsCustomData) { if (!Quandl.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here Quandl.SetAuthCode(Config.Get("quandl-auth-token")); } // each time we exhaust we'll new up this enumerator stack var refresher = new RefreshEnumerator <BaseData>(() => { var dateInDataTimeZone = DateTime.UtcNow.ConvertFromUtc(request.Configuration.DataTimeZone).Date; var enumeratorFactory = new BaseDataSubscriptionEnumeratorFactory(r => new[] { dateInDataTimeZone }); var factoryReadEnumerator = enumeratorFactory.CreateEnumerator(request); var maximumDataAge = TimeSpan.FromTicks(Math.Max(request.Configuration.Increment.Ticks, TimeSpan.FromSeconds(5).Ticks)); var fastForward = new FastForwardEnumerator(factoryReadEnumerator, _timeProvider, request.Security.Exchange.TimeZone, maximumDataAge); return(new FrontierAwareEnumerator(fastForward, _frontierTimeProvider, timeZoneOffsetProvider)); }); // rate limit the refreshing of the stack to the requested interval // At Tick resolution, it will refresh at full speed // At Second and Minute resolution, it will refresh every second and minute respectively // At Hour and Daily resolutions, it will refresh every 30 minutes var minimumTimeBetweenCalls = Math.Min(request.Configuration.Increment.Ticks, TimeSpan.FromMinutes(30).Ticks); var rateLimit = new RateLimitEnumerator(refresher, _timeProvider, TimeSpan.FromTicks(minimumTimeBetweenCalls)); _customExchange.AddEnumerator(request.Configuration.Symbol, rateLimit); var enqueable = new EnqueueableEnumerator <BaseData>(); _customExchange.SetDataHandler(request.Configuration.Symbol, data => { enqueable.Enqueue(data); if (subscription != null) { subscription.RealtimePrice = data.Value; } }); enumerator = enqueable; } else if (request.Configuration.Resolution != Resolution.Tick) { // this enumerator allows the exchange to pump ticks into the 'back' of the enumerator, // and the time sync loop can pull aggregated trade bars off the front var aggregator = new TradeBarBuilderEnumerator(request.Configuration.Increment, request.Security.Exchange.TimeZone, _timeProvider); _exchange.SetDataHandler(request.Configuration.Symbol, data => { aggregator.ProcessData((Tick)data); if (subscription != null) { subscription.RealtimePrice = data.Value; } }); enumerator = aggregator; } else { // tick subscriptions can pass right through var tickEnumerator = new EnqueueableEnumerator <BaseData>(); _exchange.SetDataHandler(request.Configuration.Symbol, data => { tickEnumerator.Enqueue(data); if (subscription != null) { subscription.RealtimePrice = data.Value; } }); enumerator = tickEnumerator; } if (request.Configuration.FillDataForward) { enumerator = new LiveFillForwardEnumerator(_frontierTimeProvider, enumerator, request.Security.Exchange, _fillForwardResolution, request.Configuration.ExtendedMarketHours, localEndTime, request.Configuration.Increment); } // define market hours and user filters to incoming data if (request.Configuration.IsFilteredSubscription) { enumerator = new SubscriptionFilterEnumerator(enumerator, request.Security, localEndTime); } // finally, make our subscriptions aware of the frontier of the data feed, prevents future data from spewing into the feed enumerator = new FrontierAwareEnumerator(enumerator, _frontierTimeProvider, timeZoneOffsetProvider); subscription = new Subscription(request.Universe, request.Security, request.Configuration, enumerator, timeZoneOffsetProvider, request.StartTimeUtc, request.EndTimeUtc, false); } catch (Exception err) { Log.Error(err); } return(subscription); }
public void Find() { TestPlan plan = PlanFixture.PLAN_WITH_TRIAL; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id }; Subscription subscription = gateway.Subscription.Create(request).Target; Subscription foundSubscription = gateway.Subscription.Find(subscription.Id); Assert.AreEqual(subscription.Id, foundSubscription.Id); Assert.AreEqual(subscription.PaymentMethodToken, creditCard.Token); Assert.AreEqual(subscription.PlanId, plan.Id); }
/// <summary> /// Creates a new subscription to provide data for the specified security. /// </summary> /// <param name="request">Defines the subscription to be added, including start/end times the universe and security</param> /// <returns>The created <see cref="Subscription"/> if successful, null otherwise</returns> public Subscription CreateSubscription(SubscriptionRequest request) { return(request.IsUniverseSubscription ? CreateUniverseSubscription(request) : CreateDataSubscription(request)); }
public void Search_OnBillingCyclesRemainingIs() { SubscriptionRequest request1 = new SubscriptionRequest { NumberOfBillingCycles = 5, PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id, Price = 4M }; SubscriptionRequest request2 = new SubscriptionRequest { NumberOfBillingCycles = 10, PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id, Price = 4M }; Subscription subscription1 = gateway.Subscription.Create(request1).Target; Subscription subscription2 = gateway.Subscription.Create(request2).Target; SubscriptionSearchRequest request = new SubscriptionSearchRequest(). BillingCyclesRemaining.Is(5). Price.Is(4M); ResourceCollection<Subscription> collection = gateway.Subscription.Search(request); Assert.IsTrue(TestHelper.IncludesSubscription(collection, subscription1)); Assert.IsFalse(TestHelper.IncludesSubscription(collection, subscription2)); }
/// <summary> /// Applies universe selection the the data feed and algorithm /// </summary> /// <param name="universe">The universe to perform selection on</param> /// <param name="dateTimeUtc">The current date time in utc</param> /// <param name="universeData">The data provided to perform selection with</param> public SecurityChanges ApplyUniverseSelection(Universe universe, DateTime dateTimeUtc, BaseDataCollection universeData) { var algorithmEndDateUtc = _algorithm.EndDate.ConvertToUtc(_algorithm.TimeZone); if (dateTimeUtc > algorithmEndDateUtc) { return(SecurityChanges.None); } IEnumerable <Symbol> selectSymbolsResult; // check if this universe must be filtered with fine fundamental data var fineFiltered = universe as FineFundamentalFilteredUniverse; if (fineFiltered != null) { // perform initial filtering and limit the result selectSymbolsResult = universe.SelectSymbols(dateTimeUtc, universeData); // prepare a BaseDataCollection of FineFundamental instances var fineCollection = new BaseDataCollection(); var dataProvider = new DefaultDataProvider(); foreach (var symbol in selectSymbolsResult) { var factory = new FineFundamentalSubscriptionEnumeratorFactory(_algorithm.LiveMode, x => new[] { dateTimeUtc }); var config = FineFundamentalUniverse.CreateConfiguration(symbol); var exchangeHours = _marketHoursDatabase.GetEntry(symbol.ID.Market, symbol, symbol.ID.SecurityType).ExchangeHours; var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market, symbol, symbol.ID.SecurityType, CashBook.AccountCurrency); var quoteCash = _algorithm.Portfolio.CashBook[symbolProperties.QuoteCurrency]; var security = new Equity(symbol, exchangeHours, quoteCash, symbolProperties); var request = new SubscriptionRequest(true, universe, security, new SubscriptionDataConfig(config), dateTimeUtc, dateTimeUtc); using (var enumerator = factory.CreateEnumerator(request, dataProvider)) { if (enumerator.MoveNext()) { fineCollection.Data.Add(enumerator.Current); } } } // perform the fine fundamental universe selection selectSymbolsResult = fineFiltered.FineFundamentalUniverse.PerformSelection(dateTimeUtc, fineCollection); } else { // perform initial filtering and limit the result selectSymbolsResult = universe.PerformSelection(dateTimeUtc, universeData); } // check for no changes first if (ReferenceEquals(selectSymbolsResult, Universe.Unchanged)) { return(SecurityChanges.None); } // materialize the enumerable into a set for processing var selections = selectSymbolsResult.ToHashSet(); var additions = new List <Security>(); var removals = new List <Security>(); // remove previously deselected members which were kept in the universe because of holdings or open orders foreach (var member in _pendingRemovals.ToList()) { var openOrders = _algorithm.Transactions.GetOrders(x => x.Status.IsOpen() && x.Symbol == member.Symbol); if (!member.HoldStock && !openOrders.Any()) { RemoveSecurityFromUniverse(universe, member, removals, dateTimeUtc, algorithmEndDateUtc); _pendingRemovals.Remove(member); } } // determine which data subscriptions need to be removed from this universe foreach (var member in universe.Members.Values) { // if we've selected this subscription again, keep it if (selections.Contains(member.Symbol)) { continue; } // don't remove if the universe wants to keep him in if (!universe.CanRemoveMember(dateTimeUtc, member)) { continue; } // remove the member - this marks this member as not being // selected by the universe, but it may remain in the universe // until open orders are closed and the security is liquidated removals.Add(member); // 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 == member.Symbol); if (!member.HoldStock && !openOrders.Any()) { RemoveSecurityFromUniverse(universe, member, removals, dateTimeUtc, algorithmEndDateUtc); } else { _pendingRemovals.Add(member); } } var keys = _pendingSecurityAdditions.Keys; if (keys.Any() && keys.Single() != dateTimeUtc) { // if the frontier moved forward then we've added these securities to the algorithm _pendingSecurityAdditions.Clear(); } Dictionary <Symbol, Security> pendingAdditions; if (!_pendingSecurityAdditions.TryGetValue(dateTimeUtc, out pendingAdditions)) { // keep track of created securities so we don't create the same security twice, leads to bad things :) pendingAdditions = new Dictionary <Symbol, Security>(); _pendingSecurityAdditions[dateTimeUtc] = pendingAdditions; } // find new selections and add them to the algorithm foreach (var symbol in selections) { // create the new security, the algorithm thread will add this at the appropriate time Security security; if (!pendingAdditions.TryGetValue(symbol, out security) && !_algorithm.Securities.TryGetValue(symbol, out security)) { security = universe.CreateSecurity(symbol, _algorithm, _marketHoursDatabase, _symbolPropertiesDatabase); pendingAdditions.Add(symbol, security); } var addedSubscription = false; foreach (var request in universe.GetSubscriptionRequests(security, dateTimeUtc, algorithmEndDateUtc)) { // add the new subscriptions to the data feed _dataFeed.AddSubscription(request); // only update our security changes if we actually added data if (!request.IsUniverseSubscription) { addedSubscription = true; } } if (addedSubscription) { var addedMember = universe.AddMember(dateTimeUtc, security); if (addedMember) { additions.Add(security); } } } // return None if there's no changes, otherwise return what we've modified var securityChanges = additions.Count + removals.Count != 0 ? new SecurityChanges(additions, removals) : SecurityChanges.None; // Add currency data feeds that weren't explicitly added in Initialize if (additions.Count > 0) { var addedSecurities = _algorithm.Portfolio.CashBook.EnsureCurrencyDataFeeds(_algorithm.Securities, _algorithm.SubscriptionManager, _marketHoursDatabase, _symbolPropertiesDatabase, _algorithm.BrokerageModel.DefaultMarkets, securityChanges); foreach (var security in addedSecurities) { // assume currency feeds are always one subscription per, these are typically quote subscriptions _dataFeed.AddSubscription(new SubscriptionRequest(false, universe, security, new SubscriptionDataConfig(security.Subscriptions.First()), dateTimeUtc, algorithmEndDateUtc)); } } if (securityChanges != SecurityChanges.None) { Log.Debug("UniverseSelection.ApplyUniverseSelection(): " + dateTimeUtc + ": " + securityChanges); } return(securityChanges); }
public void Search_OnDaysPastDueBetween() { SubscriptionRequest subscriptionRequest = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id, }; Subscription subscription = gateway.Subscription.Create(subscriptionRequest).Target; MakePastDue(subscription, 3); SubscriptionSearchRequest request = new SubscriptionSearchRequest(). DaysPastDue.Between(2, 10); ResourceCollection<Subscription> collection = gateway.Subscription.Search(request); Assert.IsTrue(collection.MaximumCount > 0); foreach (Subscription foundSubscription in collection) { Assert.IsTrue(foundSubscription.DaysPastDue >= 2 && foundSubscription.DaysPastDue <= 10); } }
/// <summary> /// Creates a new subscription for universe selection /// </summary> /// <param name="request">The subscription request</param> private Subscription CreateUniverseSubscription(SubscriptionRequest request) { // TODO : Consider moving the creating of universe subscriptions to a separate, testable class // grab the relevant exchange hours var config = request.Universe.Configuration; var localEndTime = request.EndTimeUtc.ConvertFromUtc(request.Security.Exchange.TimeZone); var tzOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); IEnumerator <BaseData> enumerator; var timeTriggered = request.Universe as ITimeTriggeredUniverse; if (timeTriggered != null) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating user defined universe: " + config.Symbol.ToString()); // spoof a tick on the requested interval to trigger the universe selection function var enumeratorFactory = new TimeTriggeredUniverseSubscriptionEnumeratorFactory(timeTriggered, MarketHoursDatabase.FromDataFolder()); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = new FrontierAwareEnumerator(enumerator, _timeProvider, tzOffsetProvider); var enqueueable = new EnqueueableEnumerator <BaseData>(); _customExchange.AddEnumerator(new EnumeratorHandler(config.Symbol, enumerator, enqueueable)); enumerator = enqueueable; // Trigger universe selection when security added/removed after Initialize if (timeTriggered is UserDefinedUniverse) { var userDefined = (UserDefinedUniverse)timeTriggered; userDefined.CollectionChanged += (sender, args) => { var items = args.Action == NotifyCollectionChangedAction.Add ? args.NewItems : args.Action == NotifyCollectionChangedAction.Remove ? args.OldItems : null; var currentFrontierUtcTime = _frontierTimeProvider.GetUtcNow(); if (items == null || currentFrontierUtcTime == DateTime.MinValue) { return; } var symbol = items.OfType <Symbol>().FirstOrDefault(); if (symbol == null) { return; } var collection = new BaseDataCollection(currentFrontierUtcTime, symbol); var changes = _universeSelection.ApplyUniverseSelection(userDefined, currentFrontierUtcTime, collection); _algorithm.OnSecuritiesChanged(changes); }; } } else if (config.Type == typeof(CoarseFundamental)) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating coarse universe: " + config.Symbol.ToString()); // we subscribe using a normalized symbol, without a random GUID, // since the ticker plant will send the coarse data using this symbol var normalizedSymbol = CoarseFundamental.CreateUniverseSymbol(config.Symbol.ID.Market, false); // since we're binding to the data queue exchange we'll need to let him // know that we expect this data _dataQueueHandler.Subscribe(_job, new[] { normalizedSymbol }); var enqueable = new EnqueueableEnumerator <BaseData>(); // We `AddDataHandler` not `Set` so we can have multiple handlers for the coarse data _exchange.AddDataHandler(normalizedSymbol, data => { enqueable.Enqueue(data); }); enumerator = enqueable; } else if (request.Universe is OptionChainUniverse) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating option chain universe: " + config.Symbol.ToString()); Func <SubscriptionRequest, IEnumerator <BaseData>, IEnumerator <BaseData> > configure = (subRequest, input) => { // we check if input enumerator is an underlying enumerator. If yes, we subscribe it to the data. var aggregator = input as TradeBarBuilderEnumerator; if (aggregator != null) { _exchange.SetDataHandler(request.Configuration.Symbol, data => { aggregator.ProcessData((Tick)data); }); } var fillForwardResolution = _subscriptions.UpdateAndGetFillForwardResolution(request.Configuration); return(new LiveFillForwardEnumerator(_frontierTimeProvider, input, request.Security.Exchange, fillForwardResolution, request.Configuration.ExtendedMarketHours, localEndTime, request.Configuration.Increment, request.Configuration.DataTimeZone)); }; var symbolUniverse = _dataQueueHandler as IDataQueueUniverseProvider; if (symbolUniverse == null) { throw new NotSupportedException("The DataQueueHandler does not support Options."); } var enumeratorFactory = new OptionChainUniverseSubscriptionEnumeratorFactory(configure, symbolUniverse, _timeProvider); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = new FrontierAwareEnumerator(enumerator, _frontierTimeProvider, tzOffsetProvider); } else if (request.Universe is FuturesChainUniverse) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating futures chain universe: " + config.Symbol.ToString()); var symbolUniverse = _dataQueueHandler as IDataQueueUniverseProvider; if (symbolUniverse == null) { throw new NotSupportedException("The DataQueueHandler does not support Futures."); } var enumeratorFactory = new FuturesChainUniverseSubscriptionEnumeratorFactory(symbolUniverse, _timeProvider); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = new FrontierAwareEnumerator(enumerator, _frontierTimeProvider, tzOffsetProvider); } else { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating custom universe: " + config.Symbol.ToString()); var factory = new LiveCustomDataSubscriptionEnumeratorFactory(_timeProvider); var enumeratorStack = factory.CreateEnumerator(request, _dataProvider); enumerator = new BaseDataCollectionAggregatorEnumerator(enumeratorStack, config.Symbol); var enqueueable = new EnqueueableEnumerator <BaseData>(); _customExchange.AddEnumerator(new EnumeratorHandler(config.Symbol, enumerator, enqueueable)); enumerator = enqueueable; } // create the subscription var subscriptionDataEnumerator = SubscriptionData.Enumerator(request.Configuration, request.Security, tzOffsetProvider, enumerator); var subscription = new Subscription(request, subscriptionDataEnumerator, tzOffsetProvider); return(subscription); }
public void Search_OnIdIs() { SubscriptionRequest request1 = new SubscriptionRequest { Id = string.Format("find_me{0}", new Random().Next(1000000)), PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id, Price = 3M }; SubscriptionRequest request2 = new SubscriptionRequest { Id = string.Format("do_not_find_me{0}", new Random().Next(1000000)), PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id, Price = 3M }; Subscription subscription1 = gateway.Subscription.Create(request1).Target; Subscription subscription2 = gateway.Subscription.Create(request2).Target; SubscriptionSearchRequest request = new SubscriptionSearchRequest(). Id.StartsWith("find_me"). Price.Is(3M); ResourceCollection<Subscription> collection = gateway.Subscription.Search(request); Assert.IsTrue(TestHelper.IncludesSubscription(collection, subscription1)); Assert.IsFalse(TestHelper.IncludesSubscription(collection, subscription2)); }
/// <summary> /// Creates a new subscription for the specified security /// </summary> /// <param name="request">The subscription request</param> /// <returns>A new subscription instance of the specified security</returns> protected Subscription CreateDataSubscription(SubscriptionRequest request) { Subscription subscription = null; try { var localEndTime = request.EndTimeUtc.ConvertFromUtc(request.Security.Exchange.TimeZone); var timeZoneOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); IEnumerator <BaseData> enumerator; if (!_channelProvider.ShouldStreamSubscription(_job, request.Configuration)) { if (!Quandl.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here Quandl.SetAuthCode(Config.Get("quandl-auth-token")); } if (!Tiingo.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here Tiingo.SetAuthCode(Config.Get("tiingo-auth-token")); } if (!USEnergyAPI.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here USEnergyAPI.SetAuthCode(Config.Get("us-energy-information-auth-token")); } if (!FredApi.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here FredApi.SetAuthCode(Config.Get("fred-auth-token")); } if (!TradingEconomicsCalendar.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here TradingEconomicsCalendar.SetAuthCode(Config.Get("trading-economics-auth-token")); } var factory = new LiveCustomDataSubscriptionEnumeratorFactory(_timeProvider); var enumeratorStack = factory.CreateEnumerator(request, _dataProvider); _customExchange.AddEnumerator(request.Configuration.Symbol, enumeratorStack); var enqueable = new EnqueueableEnumerator <BaseData>(); _customExchange.SetDataHandler(request.Configuration.Symbol, data => { enqueable.Enqueue(data); subscription.OnNewDataAvailable(); }); enumerator = enqueable; } else { EventHandler handler = (sender, args) => subscription?.OnNewDataAvailable(); enumerator = _dataQueueHandler.Subscribe(request.Configuration, handler); if (request.Configuration.Symbol.SecurityType == SecurityType.Equity && !request.Configuration.IsInternalFeed) { var dividends = _dataQueueHandler.Subscribe(new SubscriptionDataConfig(request.Configuration, typeof(Dividend)), handler); var splits = _dataQueueHandler.Subscribe(new SubscriptionDataConfig(request.Configuration, typeof(Split)), handler); enumerator = new LiveEquityDataSynchronizingEnumerator(_timeProvider, request.Configuration.ExchangeTimeZone, enumerator, dividends, splits); } } if (request.Configuration.FillDataForward) { var fillForwardResolution = _subscriptions.UpdateAndGetFillForwardResolution(request.Configuration); enumerator = new LiveFillForwardEnumerator(_frontierTimeProvider, enumerator, request.Security.Exchange, fillForwardResolution, request.Configuration.ExtendedMarketHours, localEndTime, request.Configuration.Increment, request.Configuration.DataTimeZone, request.StartTimeLocal); } // define market hours and user filters to incoming data if (request.Configuration.IsFilteredSubscription) { enumerator = new SubscriptionFilterEnumerator(enumerator, request.Security, localEndTime, request.Configuration.ExtendedMarketHours, true); } // finally, make our subscriptions aware of the frontier of the data feed, prevents future data from spewing into the feed enumerator = new FrontierAwareEnumerator(enumerator, _frontierTimeProvider, timeZoneOffsetProvider); var subscriptionDataEnumerator = new SubscriptionDataEnumerator(request.Configuration, request.Security.Exchange.Hours, timeZoneOffsetProvider, enumerator); subscription = new Subscription(request, subscriptionDataEnumerator, timeZoneOffsetProvider); } catch (Exception err) { Log.Error(err); } return(subscription); }
public void Create_SubscriptionWithPaymentMethodNonce() { TestPlan plan = PlanFixture.PLAN_WITHOUT_TRIAL; string nonce = TestHelper.GenerateUnlockedNonce(gateway, "4242424242424242", creditCard.CustomerId); SubscriptionRequest request = new SubscriptionRequest { PaymentMethodNonce = nonce, PlanId = plan.Id }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Transaction transaction = subscription.Transactions[0]; Assert.AreEqual("424242", transaction.CreditCard.Bin); }
// reproduces GH issue 3877 public void ConfigurationForAddedSubscriptionIsAlwaysPresent() { var dataPermissionManager = new DataPermissionManager(); var dataFeed = new TestDataFeed(); var dataManager = new DataManager(dataFeed, new UniverseSelection(_algorithm, _securityService, dataPermissionManager, new DefaultDataProvider()), _algorithm, _algorithm.TimeKeeper, MarketHoursDatabase.AlwaysOpen, false, new RegisteredSecurityDataTypesProvider(), dataPermissionManager); var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, false, false, false); // Universe A: adds the config dataManager.SubscriptionManagerGetOrAdd(config); var request = new SubscriptionRequest(false, null, new Security(Symbols.SPY, SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc), new Cash(Currencies.USD, 1, 1), SymbolProperties.GetDefault(Currencies.USD), new IdentityCurrencyConverter(Currencies.USD), new RegisteredSecurityDataTypesProvider(), new SecurityCache()), config, new DateTime(2019, 1, 1), new DateTime(2019, 1, 1)); dataFeed.Subscription = new Subscription(request, new EnqueueableEnumerator <SubscriptionData>(), null); // Universe A: adds the subscription dataManager.AddSubscription(request); // Universe B: adds the config dataManager.SubscriptionManagerGetOrAdd(config); // Universe A: removes the subscription Assert.IsTrue(dataManager.RemoveSubscription(config)); Assert.AreEqual(0, dataManager.GetSubscriptionDataConfigs(config.Symbol).Count); // Universe B: adds the subscription Assert.IsTrue(dataManager.AddSubscription(request)); // the config should be present Assert.AreEqual(1, dataManager.GetSubscriptionDataConfigs(config.Symbol).Count); dataManager.RemoveAllSubscriptions(); }
public void Search_OnInTrialPeriodIs() { SubscriptionRequest request1 = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id }; SubscriptionRequest request2 = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITHOUT_TRIAL.Id }; Subscription trial = gateway.Subscription.Create(request1).Target; Subscription noTrial = gateway.Subscription.Create(request2).Target; SubscriptionSearchRequest request = new SubscriptionSearchRequest(). InTrialPeriod.Is(true); ResourceCollection<Subscription> trialResults = gateway.Subscription.Search(request); Assert.IsTrue(TestHelper.IncludesSubscription(trialResults, trial)); Assert.IsFalse(TestHelper.IncludesSubscription(trialResults, noTrial)); request = new SubscriptionSearchRequest(). InTrialPeriod.Is(false); ResourceCollection<Subscription> noTrialResults = gateway.Subscription.Search(request); Assert.IsTrue(TestHelper.IncludesSubscription(noTrialResults, noTrial)); Assert.IsFalse(TestHelper.IncludesSubscription(noTrialResults, trial)); }
CreateSubscriptionAsync(string customerId, SubscriptionRequest request) { return(await this.PostAsync <SubscriptionResponse>($"customers/{customerId}/subscriptions", request) .ConfigureAwait(false)); }
public void Search_OnMerchantAccountIdIs() { SubscriptionRequest request1 = new SubscriptionRequest { MerchantAccountId = MerchantAccountIDs.DEFAULT_MERCHANT_ACCOUNT_ID, PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id, Price = 2M }; SubscriptionRequest request2 = new SubscriptionRequest { MerchantAccountId = MerchantAccountIDs.NON_DEFAULT_MERCHANT_ACCOUNT_ID, PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id, Price = 2M }; Subscription defaultMerchantAccountSubscription = gateway.Subscription.Create(request1).Target; Subscription nonDefaultMerchantAccountSubscription = gateway.Subscription.Create(request2).Target; SubscriptionSearchRequest request = new SubscriptionSearchRequest(). MerchantAccountId.Is(MerchantAccountIDs.NON_DEFAULT_MERCHANT_ACCOUNT_ID). Price.Is(2M); ResourceCollection<Subscription> collection = gateway.Subscription.Search(request); Assert.IsTrue(TestHelper.IncludesSubscription(collection, nonDefaultMerchantAccountSubscription)); Assert.IsFalse(TestHelper.IncludesSubscription(collection, defaultMerchantAccountSubscription)); }
/// <summary> /// Creates a file based data enumerator for the given subscription request /// </summary> /// <remarks>Protected so it can be used by the <see cref="LiveTradingDataFeed"/> to warmup requests</remarks> protected IEnumerator <BaseData> CreateEnumerator(SubscriptionRequest request) { return(request.IsUniverseSubscription ? CreateUniverseEnumerator(request, CreateDataEnumerator) : CreateDataEnumerator(request)); }
public void Search_OnMerchantAccountIdWithBogusMerchantId() { Random random = new Random(); string subscriptionId = random.Next(0, 100000).ToString(); var subscriptionRequest = new SubscriptionRequest { MerchantAccountId = MerchantAccountIDs.NON_DEFAULT_MERCHANT_ACCOUNT_ID, PaymentMethodToken = creditCard.Token, PlanId = PlanFixture.PLAN_WITH_TRIAL.Id, Price = 2M, Id = subscriptionId }; gateway.Subscription.Create(subscriptionRequest); var searchRequest = new SubscriptionSearchRequest(). MerchantAccountId.Is(MerchantAccountIDs.NON_DEFAULT_MERCHANT_ACCOUNT_ID). Id.Is(subscriptionId). Price.Is(2M); var collection = gateway.Subscription.Search(searchRequest); Assert.AreEqual(1, collection.MaximumCount); searchRequest = new SubscriptionSearchRequest(). MerchantAccountId.IncludedIn(MerchantAccountIDs.NON_DEFAULT_MERCHANT_ACCOUNT_ID, "bogus_merchant_account_id"). Id.Is(subscriptionId). Price.Is(2M); collection = gateway.Subscription.Search(searchRequest); Assert.AreEqual(1, collection.MaximumCount); searchRequest = new SubscriptionSearchRequest(). MerchantAccountId.Is("bogus_merchant_account_id"). Id.Is(subscriptionId). Price.Is(2M); collection = gateway.Subscription.Search(searchRequest); Assert.AreEqual(0, collection.MaximumCount); }
/// <summary> /// Creates a new subscription for the specified security /// </summary> /// <param name="request">The subscription request</param> /// <returns>A new subscription instance of the specified security</returns> protected Subscription CreateDataSubscription(SubscriptionRequest request) { Subscription subscription = null; try { var localEndTime = request.EndTimeUtc.ConvertFromUtc(request.Security.Exchange.TimeZone); var timeZoneOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); IEnumerator <BaseData> enumerator; if (!_channelProvider.ShouldStreamSubscription(request.Configuration)) { if (!Quandl.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here Quandl.SetAuthCode(Config.Get("quandl-auth-token")); } if (!Tiingo.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here Tiingo.SetAuthCode(Config.Get("tiingo-auth-token")); } var factory = new LiveCustomDataSubscriptionEnumeratorFactory(_timeProvider); var enumeratorStack = factory.CreateEnumerator(request, _dataProvider); _customExchange.AddEnumerator(request.Configuration.Symbol, enumeratorStack); var enqueable = new EnqueueableEnumerator <BaseData>(); _customExchange.SetDataHandler(request.Configuration.Symbol, data => { enqueable.Enqueue(data); subscription.OnNewDataAvailable(); }); enumerator = enqueable; } else { var auxEnumerators = new List <IEnumerator <BaseData> >(); if (LiveAuxiliaryDataEnumerator.TryCreate(request.Configuration, _timeProvider, _dataQueueHandler, request.Security.Cache, _mapFileProvider, _factorFileProvider, request.StartTimeLocal, out var auxDataEnumator)) { auxEnumerators.Add(auxDataEnumator); } EventHandler handler = (_, _) => subscription?.OnNewDataAvailable(); enumerator = _dataQueueHandler.Subscribe(request.Configuration, handler); if (request.Configuration.EmitSplitsAndDividends()) { auxEnumerators.Add(_dataQueueHandler.Subscribe(new SubscriptionDataConfig(request.Configuration, typeof(Dividend)), handler)); auxEnumerators.Add(_dataQueueHandler.Subscribe(new SubscriptionDataConfig(request.Configuration, typeof(Split)), handler)); } if (auxEnumerators.Count > 0) { enumerator = new LiveAuxiliaryDataSynchronizingEnumerator(_timeProvider, request.Configuration.ExchangeTimeZone, enumerator, auxEnumerators); } } if (request.Configuration.FillDataForward) { var fillForwardResolution = _subscriptions.UpdateAndGetFillForwardResolution(request.Configuration); enumerator = new LiveFillForwardEnumerator(_frontierTimeProvider, enumerator, request.Security.Exchange, fillForwardResolution, request.Configuration.ExtendedMarketHours, localEndTime, request.Configuration.Increment, request.Configuration.DataTimeZone); } // define market hours and user filters to incoming data if (request.Configuration.IsFilteredSubscription) { enumerator = new SubscriptionFilterEnumerator(enumerator, request.Security, localEndTime, request.Configuration.ExtendedMarketHours, true, request.ExchangeHours); } // finally, make our subscriptions aware of the frontier of the data feed, prevents future data from spewing into the feed enumerator = new FrontierAwareEnumerator(enumerator, _frontierTimeProvider, timeZoneOffsetProvider); var subscriptionDataEnumerator = new SubscriptionDataEnumerator(request.Configuration, request.Security.Exchange.Hours, timeZoneOffsetProvider, enumerator, request.IsUniverseSubscription); subscription = new Subscription(request, subscriptionDataEnumerator, timeZoneOffsetProvider); } catch (Exception err) { Log.Error(err); } return(subscription); }
public void Search_OnNextBillingDate() { TestPlan triallessPlan = PlanFixture.PLAN_WITHOUT_TRIAL; TestPlan trialPlan = PlanFixture.PLAN_WITH_TRIAL; SubscriptionRequest request1 = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = triallessPlan.Id, Price = 7M }; SubscriptionRequest request2 = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = trialPlan.Id, Price = 7M }; Subscription triallessSubscription = gateway.Subscription.Create(request1).Target; Subscription trialSubscription = gateway.Subscription.Create(request2).Target; SubscriptionSearchRequest request = new SubscriptionSearchRequest(). NextBillingDate.GreaterThanOrEqualTo(DateTime.Now.AddDays(5)); ResourceCollection<Subscription> collection = gateway.Subscription.Search(request); Assert.IsTrue(TestHelper.IncludesSubscription(collection, triallessSubscription)); Assert.IsFalse(TestHelper.IncludesSubscription(collection, trialSubscription)); }
/// <summary> /// Creates a new subscription for universe selection /// </summary> /// <param name="request">The subscription request</param> private Subscription CreateUniverseSubscription(SubscriptionRequest request) { // TODO : Consider moving the creating of universe subscriptions to a separate, testable class // grab the relevant exchange hours var config = request.Universe.Configuration; var tzOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); IEnumerator <BaseData> enumerator; var userDefined = request.Universe as UserDefinedUniverse; if (userDefined != null) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating user defined universe: " + config.Symbol.ToString()); // spoof a tick on the requested interval to trigger the universe selection function var enumeratorFactory = new UserDefinedUniverseSubscriptionEnumeratorFactory(userDefined, MarketHoursDatabase.FromDataFolder()); enumerator = enumeratorFactory.CreateEnumerator(request); enumerator = new FrontierAwareEnumerator(enumerator, _timeProvider, tzOffsetProvider); var enqueueable = new EnqueueableEnumerator <BaseData>(); _customExchange.AddEnumerator(new EnumeratorHandler(config.Symbol, enumerator, enqueueable)); enumerator = enqueueable; // Trigger universe selection when security added/removed after Initialize userDefined.CollectionChanged += (sender, args) => { var items = args.Action == NotifyCollectionChangedAction.Add ? args.NewItems : args.Action == NotifyCollectionChangedAction.Remove ? args.OldItems : null; if (items == null || _frontierUtc == DateTime.MinValue) { return; } var symbol = items.OfType <Symbol>().FirstOrDefault(); if (symbol == null) { return; } var collection = new BaseDataCollection(_frontierUtc, symbol); var changes = _universeSelection.ApplyUniverseSelection(userDefined, _frontierUtc, collection); _algorithm.OnSecuritiesChanged(changes); }; } else if (config.Type == typeof(CoarseFundamental)) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating coarse universe: " + config.Symbol.ToString()); // since we're binding to the data queue exchange we'll need to let him // know that we expect this data _dataQueueHandler.Subscribe(_job, new[] { request.Security.Symbol }); var enqueable = new EnqueueableEnumerator <BaseData>(); _exchange.SetDataHandler(config.Symbol, data => { enqueable.Enqueue(data); }); enumerator = enqueable; } else { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating custom universe: " + config.Symbol.ToString()); // each time we exhaust we'll new up this enumerator stack var refresher = new RefreshEnumerator <BaseDataCollection>(() => { var sourceProvider = (BaseData)Activator.CreateInstance(config.Type); var dateInDataTimeZone = DateTime.UtcNow.ConvertFromUtc(config.DataTimeZone).Date; var source = sourceProvider.GetSource(config, dateInDataTimeZone, true); var factory = SubscriptionDataSourceReader.ForSource(source, config, dateInDataTimeZone, false); var factorEnumerator = factory.Read(source).GetEnumerator(); var fastForward = new FastForwardEnumerator(factorEnumerator, _timeProvider, request.Security.Exchange.TimeZone, config.Increment); var frontierAware = new FrontierAwareEnumerator(fastForward, _frontierTimeProvider, tzOffsetProvider); return(new BaseDataCollectionAggregatorEnumerator(frontierAware, config.Symbol)); }); // rate limit the refreshing of the stack to the requested interval var minimumTimeBetweenCalls = Math.Min(config.Increment.Ticks, TimeSpan.FromMinutes(30).Ticks); var rateLimit = new RateLimitEnumerator(refresher, _timeProvider, TimeSpan.FromTicks(minimumTimeBetweenCalls)); var enqueueable = new EnqueueableEnumerator <BaseData>(); _customExchange.AddEnumerator(new EnumeratorHandler(config.Symbol, rateLimit, enqueueable)); enumerator = enqueueable; } // create the subscription var subscription = new Subscription(request.Universe, request.Security, config, enumerator, tzOffsetProvider, request.StartTimeUtc, request.EndTimeUtc, true); return(subscription); }
public void Search_OnPlanIdIs() { TestPlan triallessPlan = PlanFixture.PLAN_WITHOUT_TRIAL; TestPlan trialPlan = PlanFixture.PLAN_WITH_TRIAL; SubscriptionRequest request1 = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = trialPlan.Id, Price = 5M }; SubscriptionRequest request2 = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = triallessPlan.Id, Price = 5M }; Subscription trialSubscription = gateway.Subscription.Create(request1).Target; Subscription triallessSubscription = gateway.Subscription.Create(request2).Target; SubscriptionSearchRequest request = new SubscriptionSearchRequest(). PlanId.Is(trialPlan.Id). Price.Is(5M); ResourceCollection<Subscription> collection = gateway.Subscription.Search(request); Assert.IsTrue(TestHelper.IncludesSubscription(collection, trialSubscription)); Assert.IsFalse(TestHelper.IncludesSubscription(collection, triallessSubscription)); }
public void Find_FindsAssociatedSubscriptions() { Customer customer = gateway.Customer.Create(new CustomerRequest()).Target; var creditCardRequest = new CreditCardRequest { CustomerId = customer.Id, Number = "5105105105105100", ExpirationDate = "05/12", CVV = "123" }; CreditCard originalCreditCard = gateway.CreditCard.Create(creditCardRequest).Target; string id = Guid.NewGuid().ToString(); var subscriptionRequest = new SubscriptionRequest { Id = id, PlanId = "integration_trialless_plan", PaymentMethodToken = originalCreditCard.Token, Price = 1.00M }; gateway.Subscription.Create(subscriptionRequest); CreditCard creditCard = gateway.CreditCard.Find(originalCreditCard.Token); Subscription subscription = creditCard.Subscriptions[0]; Assert.AreEqual(id, subscription.Id); Assert.AreEqual("integration_trialless_plan", subscription.PlanId); Assert.AreEqual(1.00M, subscription.Price); }
public void Find_FindsAssociatedSubscriptions() { Customer customer = gateway.Customer.Create(new CustomerRequest()).Target; var creditCardRequest = new CreditCardRequest { CustomerId = customer.Id, Number = "5555555555554444", ExpirationDate = EXP_MONTH_YEAR, CVV = "123" }; CreditCard originalCreditCard = gateway.CreditCard.Create(creditCardRequest).Target; string id = Guid.NewGuid().ToString(); var subscriptionRequest = new SubscriptionRequest { Id = id, PlanId = "integration_trialless_plan", PaymentMethodToken = originalCreditCard.Token, Price = 1.00M }; var resp = gateway.Subscription.Create(subscriptionRequest); Assert.IsNotNull(resp); if (!resp.IsSuccess()) Assert.Inconclusive(resp.Message); else { CreditCard creditCard = gateway.CreditCard.Find(originalCreditCard.Token); Assert.IsNotNull(creditCard); Assert.IsNotEmpty(creditCard.Subscriptions); Subscription subscription = creditCard.Subscriptions[0]; Assert.IsNotNull(subscription); Assert.AreEqual(id, subscription.Id); Assert.AreEqual("integration_trialless_plan", subscription.PlanId); Assert.AreEqual(1.00M, subscription.Price); } }
public Task Update([FromBody] SubscriptionRequest request) { return(_eventBusSubscriptionsManager.SaveSubscriptionAsync(request)); }
/// <summary> /// Updates an existing subscription /// </summary> /// <param name="request"> /// The request. /// </param> /// <returns> /// The <see cref="Attempt"/>. /// </returns> public Attempt<Subscription> Update(SubscriptionRequest request) { Updating.RaiseEvent(new SaveEventArgs<SubscriptionRequest>(request), this); var attempt = TryGetApiResult(() => BraintreeGateway.Subscription.Update(request.Id, request)); if (!attempt.Success) return Attempt<Subscription>.Fail(attempt.Exception); var result = attempt.Result; if (result.IsSuccess()) { Updated.RaiseEvent(new SaveEventArgs<Subscription>(result.Target), this); return Attempt<Subscription>.Succeed(result.Target); } var error = new BraintreeApiException(result.Errors, result.Message); LogHelper.Error<BraintreeSubscriptionApiService>("Failed to create a subscription", error); return Attempt<Subscription>.Fail(error); }
/// <summary> /// Invokes the configuration following enumerator creation /// </summary> /// <param name="request">The subscription request to be read</param> /// <returns>An enumerator reading the subscription request</returns> public IEnumerator <BaseData> CreateEnumerator(SubscriptionRequest request) { return(_configurator(_factory.CreateEnumerator(request))); }
/// <inheritdoc /> public bool AddSubscription(SubscriptionRequest request) { throw new NotImplementedException("Unexpected usage of null data feed implementation."); }
/// <summary> /// Applies universe selection the the data feed and algorithm /// </summary> /// <param name="universe">The universe to perform selection on</param> /// <param name="dateTimeUtc">The current date time in utc</param> /// <param name="universeData">The data provided to perform selection with</param> public SecurityChanges ApplyUniverseSelection(Universe universe, DateTime dateTimeUtc, BaseDataCollection universeData) { var algorithmEndDateUtc = _algorithm.EndDate.ConvertToUtc(_algorithm.TimeZone); if (dateTimeUtc > algorithmEndDateUtc) { return(SecurityChanges.None); } IEnumerable <Symbol> selectSymbolsResult; // check if this universe must be filtered with fine fundamental data var fineFiltered = universe as FineFundamentalFilteredUniverse; if (fineFiltered != null) { // perform initial filtering and limit the result selectSymbolsResult = universe.SelectSymbols(dateTimeUtc, universeData); if (!ReferenceEquals(selectSymbolsResult, Universe.Unchanged)) { // prepare a BaseDataCollection of FineFundamental instances var fineCollection = new BaseDataCollection(); var dataProvider = new DefaultDataProvider(); // Create a dictionary of CoarseFundamental keyed by Symbol that also has FineFundamental // Coarse raw data has SID collision on: CRHCY R735QTJ8XC9X var allCoarse = universeData.Data.OfType <CoarseFundamental>(); var coarseData = allCoarse.Where(c => c.HasFundamentalData) .DistinctBy(c => c.Symbol) .ToDictionary(c => c.Symbol); // Remove selected symbols that does not have fine fundamental data var anyDoesNotHaveFundamentalData = false; // only pre filter selected symbols if there actually is any coarse data. This way we can support custom universe filtered by fine fundamental data // which do not use coarse data as underlying, in which case it could happen that we try to load fine fundamental data that is missing, but no problem, // 'FineFundamentalSubscriptionEnumeratorFactory' won't emit it if (allCoarse.Any()) { selectSymbolsResult = selectSymbolsResult .Where( symbol => { var result = coarseData.ContainsKey(symbol); anyDoesNotHaveFundamentalData |= !result; return(result); } ); } if (!_anyDoesNotHaveFundamentalDataWarningLogged && anyDoesNotHaveFundamentalData) { _algorithm.Debug("Note: Your coarse selection filter was updated to exclude symbols without fine fundamental data. Make sure your coarse filter excludes symbols where HasFundamental is false."); _anyDoesNotHaveFundamentalDataWarningLogged = true; } // use all available threads, the entire system is waiting for this to complete var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; Parallel.ForEach(selectSymbolsResult, options, symbol => { var config = FineFundamentalUniverse.CreateConfiguration(symbol); var security = _securityService.CreateSecurity(symbol, config, addToSymbolCache: false); var localStartTime = dateTimeUtc.ConvertFromUtc(config.ExchangeTimeZone).AddDays(-1); var factory = new FineFundamentalSubscriptionEnumeratorFactory(_algorithm.LiveMode, x => new[] { localStartTime }); var request = new SubscriptionRequest(true, universe, security, new SubscriptionDataConfig(config), localStartTime, localStartTime); using (var enumerator = factory.CreateEnumerator(request, dataProvider)) { if (enumerator.MoveNext()) { lock (fineCollection.Data) { fineCollection.Data.Add(enumerator.Current); } } } }); // WARNING -- HACK ATTACK -- WARNING // Fine universes are considered special due to their chaining behavior. // As such, we need a means of piping the fine data read in here back to the data feed // so that it can be properly emitted via a TimeSlice.Create call. There isn't a mechanism // in place for this function to return such data. The following lines are tightly coupled // to the universeData dictionaries in SubscriptionSynchronizer and LiveTradingDataFeed and // rely on reference semantics to work. universeData.Data = new List <BaseData>(); foreach (var fine in fineCollection.Data.OfType <FineFundamental>()) { var fundamentals = new Fundamentals { Symbol = fine.Symbol, Time = fine.Time, EndTime = fine.EndTime, DataType = fine.DataType, AssetClassification = fine.AssetClassification, CompanyProfile = fine.CompanyProfile, CompanyReference = fine.CompanyReference, EarningReports = fine.EarningReports, EarningRatios = fine.EarningRatios, FinancialStatements = fine.FinancialStatements, OperationRatios = fine.OperationRatios, SecurityReference = fine.SecurityReference, ValuationRatios = fine.ValuationRatios, Market = fine.Symbol.ID.Market }; CoarseFundamental coarse; if (coarseData.TryGetValue(fine.Symbol, out coarse)) { // the only time the coarse data won't exist is if the selection function // doesn't use the data provided, and instead returns a constant list of // symbols -- coupled with a potential hole in the data fundamentals.Value = coarse.Value; fundamentals.Volume = coarse.Volume; fundamentals.DollarVolume = coarse.DollarVolume; fundamentals.HasFundamentalData = coarse.HasFundamentalData; // set the fine fundamental price property to yesterday's closing price fine.Value = coarse.Value; } universeData.Data.Add(fundamentals); } // END -- HACK ATTACK -- END // perform the fine fundamental universe selection selectSymbolsResult = fineFiltered.FineFundamentalUniverse.PerformSelection(dateTimeUtc, fineCollection); } } else { // perform initial filtering and limit the result selectSymbolsResult = universe.PerformSelection(dateTimeUtc, universeData); } // materialize the enumerable into a set for processing var selections = selectSymbolsResult.ToHashSet(); var additions = new List <Security>(); var removals = new List <Security>(); // first check for no pending removals, even if the universe selection // didn't change we might need to remove a security because a position was closed RemoveSecurityFromUniverse( _pendingRemovalsManager.CheckPendingRemovals(selections, universe), removals, dateTimeUtc, algorithmEndDateUtc); // check for no changes second if (ReferenceEquals(selectSymbolsResult, Universe.Unchanged)) { return(SecurityChanges.None); } // determine which data subscriptions need to be removed from this universe foreach (var member in universe.Members.Values) { // if we've selected this subscription again, keep it if (selections.Contains(member.Symbol)) { continue; } // don't remove if the universe wants to keep him in if (!universe.CanRemoveMember(dateTimeUtc, member)) { continue; } // remove the member - this marks this member as not being // selected by the universe, but it may remain in the universe // until open orders are closed and the security is liquidated removals.Add(member); RemoveSecurityFromUniverse(_pendingRemovalsManager.TryRemoveMember(member, universe), removals, dateTimeUtc, algorithmEndDateUtc); } var keys = _pendingSecurityAdditions.Keys; if (keys.Any() && keys.Single() != dateTimeUtc) { // if the frontier moved forward then we've added these securities to the algorithm _pendingSecurityAdditions.Clear(); } Dictionary <Symbol, Security> pendingAdditions; if (!_pendingSecurityAdditions.TryGetValue(dateTimeUtc, out pendingAdditions)) { // keep track of created securities so we don't create the same security twice, leads to bad things :) pendingAdditions = new Dictionary <Symbol, Security>(); _pendingSecurityAdditions[dateTimeUtc] = pendingAdditions; } // find new selections and add them to the algorithm foreach (var symbol in selections) { if (universe.Securities.ContainsKey(symbol)) { // if its already part of the universe no need to re add it continue; } // create the new security, the algorithm thread will add this at the appropriate time Security security; if (!pendingAdditions.TryGetValue(symbol, out security) && !_algorithm.Securities.TryGetValue(symbol, out security)) { // For now this is required for retro compatibility with usages of security.Subscriptions var configs = _algorithm.SubscriptionManager.SubscriptionDataConfigService.Add(symbol, universe.UniverseSettings.Resolution, universe.UniverseSettings.FillForward, universe.UniverseSettings.ExtendedMarketHours, dataNormalizationMode: universe.UniverseSettings.DataNormalizationMode); security = _securityService.CreateSecurity(symbol, configs, universe.UniverseSettings.Leverage, symbol.ID.SecurityType == SecurityType.Option); pendingAdditions.Add(symbol, security); SetUnderlyingSecurity(universe, security); } var addedSubscription = false; foreach (var request in universe.GetSubscriptionRequests(security, dateTimeUtc, algorithmEndDateUtc, _algorithm.SubscriptionManager.SubscriptionDataConfigService)) { if (security.Symbol == request.Configuration.Symbol && // Just in case check its the same symbol, else AddData will throw. !security.Subscriptions.Contains(request.Configuration)) { // For now this is required for retro compatibility with usages of security.Subscriptions security.AddData(request.Configuration); } var toRemove = _currencySubscriptionDataConfigManager.GetSubscriptionDataConfigToRemove(request.Configuration.Symbol); if (toRemove != null) { Log.Trace($"UniverseSelection.ApplyUniverseSelection(): Removing internal currency data feed {toRemove}"); _dataManager.RemoveSubscription(toRemove); } _dataManager.AddSubscription(request); // only update our security changes if we actually added data if (!request.IsUniverseSubscription) { addedSubscription = true; } } if (addedSubscription) { var addedMember = universe.AddMember(dateTimeUtc, security); if (addedMember) { additions.Add(security); } } } // return None if there's no changes, otherwise return what we've modified var securityChanges = additions.Count + removals.Count != 0 ? new SecurityChanges(additions, removals) : SecurityChanges.None; // Add currency data feeds that weren't explicitly added in Initialize if (additions.Count > 0) { EnsureCurrencyDataFeeds(securityChanges); } if (securityChanges != SecurityChanges.None && Log.DebuggingEnabled) { // for performance lets not create the message string if debugging is not enabled // this can be executed many times and its in the algorithm thread Log.Debug("UniverseSelection.ApplyUniverseSelection(): " + dateTimeUtc + ": " + securityChanges); } return(securityChanges); }
public async Task <Subscription> CreateSubscription(SubscriptionRequest createSubscriptionRequest) { var url = string.Format(SUBSCRIPTIONS_PATH, createSubscriptionRequest.CustomerId); return(await SendRequest <Subscription>(HttpMethod.Post, url, createSubscriptionRequest)); }
/// <summary> /// Creates a new subscription for the specified security /// </summary> /// <param name="request">The subscription request</param> /// <returns>A new subscription instance of the specified security</returns> protected Subscription CreateDataSubscription(SubscriptionRequest request) { Subscription subscription = null; try { var localEndTime = request.EndTimeUtc.ConvertFromUtc(request.Security.Exchange.TimeZone); var timeZoneOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); IEnumerator <BaseData> enumerator; if (request.Configuration.IsCustomData) { if (!Quandl.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here Quandl.SetAuthCode(Config.Get("quandl-auth-token")); } if (!Tiingo.IsAuthCodeSet) { // we're not using the SubscriptionDataReader, so be sure to set the auth token here Tiingo.SetAuthCode(Config.Get("tiingo-auth-token")); } var factory = new LiveCustomDataSubscriptionEnumeratorFactory(_timeProvider); var enumeratorStack = factory.CreateEnumerator(request, _dataProvider); _customExchange.AddEnumerator(request.Configuration.Symbol, enumeratorStack); var enqueable = new EnqueueableEnumerator <BaseData>(); _customExchange.SetDataHandler(request.Configuration.Symbol, data => { enqueable.Enqueue(data); UpdateSubscriptionRealTimePrice( subscription, timeZoneOffsetProvider, request.Security.Exchange.Hours, data); }); enumerator = enqueable; } else if (request.Configuration.Resolution != Resolution.Tick) { // this enumerator allows the exchange to pump ticks into the 'back' of the enumerator, // and the time sync loop can pull aggregated trade bars off the front switch (request.Configuration.TickType) { case TickType.Quote: var quoteBarAggregator = new QuoteBarBuilderEnumerator(request.Configuration.Increment, request.Security.Exchange.TimeZone, _timeProvider); _exchange.AddDataHandler(request.Configuration.Symbol, data => { var tick = data as Tick; if (tick.TickType == TickType.Quote) { quoteBarAggregator.ProcessData(tick); UpdateSubscriptionRealTimePrice( subscription, timeZoneOffsetProvider, request.Security.Exchange.Hours, data); } }); enumerator = quoteBarAggregator; break; case TickType.Trade: default: var tradeBarAggregator = new TradeBarBuilderEnumerator(request.Configuration.Increment, request.Security.Exchange.TimeZone, _timeProvider); var auxDataEnumerator = new LiveAuxiliaryDataEnumerator(request.Security.Exchange.TimeZone, _timeProvider); _exchange.AddDataHandler(request.Configuration.Symbol, data => { if (data.DataType == MarketDataType.Auxiliary) { auxDataEnumerator.Enqueue(data); } else { var tick = data as Tick; if (tick.TickType == TickType.Trade) { tradeBarAggregator.ProcessData(tick); UpdateSubscriptionRealTimePrice( subscription, timeZoneOffsetProvider, request.Security.Exchange.Hours, data); } } }); enumerator = request.Configuration.SecurityType == SecurityType.Equity ? (IEnumerator <BaseData>) new LiveEquityDataSynchronizingEnumerator(_frontierTimeProvider, request.Security.Exchange.TimeZone, auxDataEnumerator, tradeBarAggregator) : tradeBarAggregator; break; case TickType.OpenInterest: var oiAggregator = new OpenInterestEnumerator(request.Configuration.Increment, request.Security.Exchange.TimeZone, _timeProvider); _exchange.AddDataHandler(request.Configuration.Symbol, data => { var tick = data as Tick; if (tick.TickType == TickType.OpenInterest) { oiAggregator.ProcessData(tick); } }); enumerator = oiAggregator; break; } } else { // tick subscriptions can pass right through var tickEnumerator = new EnqueueableEnumerator <BaseData>(); _exchange.SetDataHandler(request.Configuration.Symbol, data => { tickEnumerator.Enqueue(data); if (data.DataType != MarketDataType.Auxiliary) { UpdateSubscriptionRealTimePrice( subscription, timeZoneOffsetProvider, request.Security.Exchange.Hours, data); } }); enumerator = tickEnumerator; } if (request.Configuration.FillDataForward) { var fillForwardResolution = _subscriptions.UpdateAndGetFillForwardResolution(request.Configuration); enumerator = new LiveFillForwardEnumerator(_frontierTimeProvider, enumerator, request.Security.Exchange, fillForwardResolution, request.Configuration.ExtendedMarketHours, localEndTime, request.Configuration.Increment, request.Configuration.DataTimeZone); } // define market hours and user filters to incoming data if (request.Configuration.IsFilteredSubscription) { enumerator = new SubscriptionFilterEnumerator(enumerator, request.Security, localEndTime); } // finally, make our subscriptions aware of the frontier of the data feed, prevents future data from spewing into the feed enumerator = new FrontierAwareEnumerator(enumerator, _frontierTimeProvider, timeZoneOffsetProvider); var subscriptionDataEnumerator = SubscriptionData.Enumerator(request.Configuration, request.Security, timeZoneOffsetProvider, enumerator); subscription = new Subscription(request, subscriptionDataEnumerator, timeZoneOffsetProvider); } catch (Exception err) { Log.Error(err); } return(subscription); }
internal SubscriptionStream(SubscriptionRequest request) { this.Request = request; }
public void RefreshesFutureChainUniverseOnDateChange() { var startTime = new DateTime(2018, 10, 17, 10, 0, 0); var timeProvider = new ManualTimeProvider(startTime); var symbolUniverse = new TestDataQueueUniverseProvider(timeProvider); var factory = new FuturesChainUniverseSubscriptionEnumeratorFactory(symbolUniverse, timeProvider); var canonicalSymbol = Symbol.Create("VX", SecurityType.Future, Market.USA, "/VX"); var quoteCurrency = new Cash(Currencies.USD, 0, 1); var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.USA, canonicalSymbol, SecurityType.Future); var config = new SubscriptionDataConfig( typeof(ZipEntryName), canonicalSymbol, Resolution.Minute, TimeZones.Utc, TimeZones.Chicago, true, false, false, false, TickType.Quote, false, DataNormalizationMode.Raw ); var future = new Future( canonicalSymbol, exchangeHours, quoteCurrency, SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance ); var universeSettings = new UniverseSettings(Resolution.Minute, 0, true, false, TimeSpan.Zero); var universe = new FuturesChainUniverse(future, universeSettings); var request = new SubscriptionRequest(true, universe, future, config, startTime, Time.EndOfTime); var enumerator = factory.CreateEnumerator(request, new DefaultDataProvider()); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNotNull(enumerator.Current); Assert.AreEqual(1, symbolUniverse.TotalLookupCalls); var data = enumerator.Current as FuturesChainUniverseDataCollection; Assert.IsNotNull(data); Assert.AreEqual(1, data.Data.Count); timeProvider.Advance(Time.OneSecond); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNull(enumerator.Current); Assert.AreEqual(1, symbolUniverse.TotalLookupCalls); timeProvider.Advance(Time.OneMinute); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNull(enumerator.Current); Assert.AreEqual(1, symbolUniverse.TotalLookupCalls); timeProvider.Advance(Time.OneDay); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNotNull(enumerator.Current); Assert.AreEqual(2, symbolUniverse.TotalLookupCalls); data = enumerator.Current as FuturesChainUniverseDataCollection; Assert.IsNotNull(data); Assert.AreEqual(2, data.Data.Count); timeProvider.Advance(Time.OneMinute); Assert.IsTrue(enumerator.MoveNext()); Assert.IsNull(enumerator.Current); Assert.AreEqual(2, symbolUniverse.TotalLookupCalls); enumerator.Dispose(); }
/// <summary> /// Creates a <see cref="Subscription"/>. /// </summary> /// <param name="request"> /// The request. /// </param> /// <returns> /// The <see cref="Attempt{Subscription}"/>. /// </returns> public Attempt<Subscription> Create(SubscriptionRequest request) { Creating.RaiseEvent(new Core.Events.NewEventArgs<SubscriptionRequest>(request), this); LogHelper.Info<BraintreeTransactionApiService>(string.Format("Braintree create subscription attempt PlanID: {0}, Price: {1}", request.PlanId, request.Price)); var attempt = this.TryGetApiResult(() => this.BraintreeGateway.Subscription.Create(request)); if (!attempt.Success) return Attempt<Subscription>.Fail(attempt.Exception); var result = attempt.Result; if (result.IsSuccess()) { Created.RaiseEvent(new Core.Events.NewEventArgs<Subscription>(result.Target), this); return Attempt<Subscription>.Succeed(result.Target); } var error = new BraintreeApiException(result.Errors, result.Message); LogHelper.Error<BraintreeSubscriptionApiService>("Failed to create a subscription", error); return Attempt<Subscription>.Fail(error); }
public void EnumerationWhileUpdatingDoesNotThrow() { var cts = new CancellationTokenSource(); var subscriptions = new SubscriptionCollection(); var start = DateTime.UtcNow; var end = start.AddSeconds(10); var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Minute, DateTimeZone.Utc, DateTimeZone.Utc, true, false, false); var security = new Equity( Symbols.SPY, SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc), new Cash(Currencies.USD, 0, 1), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); var timeZoneOffsetProvider = new TimeZoneOffsetProvider(DateTimeZone.Utc, start, end); var enumerator = new EnqueueableEnumerator <BaseData>(); var subscriptionDataEnumerator = new SubscriptionDataEnumerator(config, security.Exchange.Hours, timeZoneOffsetProvider, enumerator); var subscriptionRequest = new SubscriptionRequest(false, null, security, config, start, end); var subscription = new Subscription(subscriptionRequest, subscriptionDataEnumerator, timeZoneOffsetProvider); var addTask = Task.Factory.StartNew(() => { Console.WriteLine("Add task started"); while (DateTime.UtcNow < end) { if (!subscriptions.Contains(config)) { subscriptions.TryAdd(subscription); } Thread.Sleep(1); } Console.WriteLine("Add task ended"); }, cts.Token); var removeTask = Task.Factory.StartNew(() => { Console.WriteLine("Remove task started"); while (DateTime.UtcNow < end) { Subscription removed; subscriptions.TryRemove(config, out removed); Thread.Sleep(1); } Console.WriteLine("Remove task ended"); }, cts.Token); var readTask = Task.Factory.StartNew(() => { Console.WriteLine("Read task started"); while (DateTime.UtcNow < end) { foreach (var sub in subscriptions) { } Thread.Sleep(1); } Console.WriteLine("Read task ended"); }, cts.Token); Task.WaitAll(addTask, removeTask, readTask); subscription.Dispose(); }
/// <summary> /// Updates an existing subscription /// </summary> /// <param name="request"> /// The request. /// </param> /// <returns> /// The <see cref="Attempt"/>. /// </returns> public Attempt<Subscription> Update(SubscriptionRequest request) { Updating.RaiseEvent(new SaveEventArgs<SubscriptionRequest>(request), this); LogHelper.Info<BraintreeTransactionApiService>(string.Format("Braintree Update subscription attempt PlanId: {0}", request.PlanId)); var attempt = this.TryGetApiResult(() => this.BraintreeGateway.Subscription.Update(request.Id, request)); if (!attempt.Success) return Attempt<Subscription>.Fail(attempt.Exception); var result = attempt.Result; if (result.IsSuccess()) { Updated.RaiseEvent(new SaveEventArgs<Subscription>(result.Target), this); var cacheKey = this.MakeSubscriptionCacheKey(request.Id); this.RuntimeCache.ClearCacheItem(cacheKey); return Attempt<Subscription>.Succeed(result.Target); } var error = new BraintreeApiException(result.Errors, result.Message); LogHelper.Error<BraintreeSubscriptionApiService>("Failed to create a subscription", error); return Attempt<Subscription>.Fail(error); }
/// <summary> /// Creates a new subscription for universe selection /// </summary> /// <param name="request">The subscription request</param> private Subscription CreateUniverseSubscription(SubscriptionRequest request) { Subscription subscription = null; // TODO : Consider moving the creating of universe subscriptions to a separate, testable class // grab the relevant exchange hours var config = request.Universe.Configuration; var localEndTime = request.EndTimeUtc.ConvertFromUtc(request.Security.Exchange.TimeZone); var tzOffsetProvider = new TimeZoneOffsetProvider(request.Security.Exchange.TimeZone, request.StartTimeUtc, request.EndTimeUtc); IEnumerator <BaseData> enumerator = null; var timeTriggered = request.Universe as ITimeTriggeredUniverse; if (timeTriggered != null) { Log.Trace($"LiveTradingDataFeed.CreateUniverseSubscription(): Creating user defined universe: {config.Symbol.ID}"); // spoof a tick on the requested interval to trigger the universe selection function var enumeratorFactory = new TimeTriggeredUniverseSubscriptionEnumeratorFactory(timeTriggered, MarketHoursDatabase.FromDataFolder(), _frontierTimeProvider); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = new FrontierAwareEnumerator(enumerator, _timeProvider, tzOffsetProvider); var enqueueable = new EnqueueableEnumerator <BaseData>(); _customExchange.AddEnumerator(new EnumeratorHandler(config.Symbol, enumerator, enqueueable)); enumerator = enqueueable; } else if (config.Type == typeof(CoarseFundamental)) { Log.Trace($"LiveTradingDataFeed.CreateUniverseSubscription(): Creating coarse universe: {config.Symbol.ID}"); // we subscribe using a normalized symbol, without a random GUID, // since the ticker plant will send the coarse data using this symbol var normalizedSymbol = CoarseFundamental.CreateUniverseSymbol(config.Symbol.ID.Market, false); // Will try to pull coarse data from the data folder every 30min, file with today's date. // If lean is started today it will trigger initial coarse universe selection var factory = new LiveCustomDataSubscriptionEnumeratorFactory(_timeProvider, // we adjust time to the previous tradable date time => Time.GetStartTimeForTradeBars(request.Security.Exchange.Hours, time, Time.OneDay, 1, false, config.DataTimeZone) ); var enumeratorStack = factory.CreateEnumerator(request, _dataProvider); // aggregates each coarse data point into a single BaseDataCollection var aggregator = new BaseDataCollectionAggregatorEnumerator(enumeratorStack, normalizedSymbol, true); _customExchange.AddEnumerator(normalizedSymbol, aggregator); var enqueable = new EnqueueableEnumerator <BaseData>(); _customExchange.SetDataHandler(normalizedSymbol, data => { var coarseData = data as BaseDataCollection; enqueable.Enqueue(new BaseDataCollection(coarseData.Time, config.Symbol, coarseData.Data)); subscription.OnNewDataAvailable(); }); enumerator = GetConfiguredFrontierAwareEnumerator(enqueable, tzOffsetProvider, // advance time if before 23pm or after 5am and not on Saturdays time => time.Hour < 23 && time.Hour > 5 && time.DayOfWeek != DayOfWeek.Saturday); } else if (request.Universe is OptionChainUniverse) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating option chain universe: " + config.Symbol.ID); Func <SubscriptionRequest, IEnumerator <BaseData> > configure = (subRequest) => { var fillForwardResolution = _subscriptions.UpdateAndGetFillForwardResolution(subRequest.Configuration); var input = _dataQueueHandler.Subscribe(subRequest.Configuration, (sender, args) => subscription.OnNewDataAvailable()); return(new LiveFillForwardEnumerator(_frontierTimeProvider, input, subRequest.Security.Exchange, fillForwardResolution, subRequest.Configuration.ExtendedMarketHours, localEndTime, subRequest.Configuration.Increment, subRequest.Configuration.DataTimeZone, subRequest.StartTimeLocal)); }; var symbolUniverse = _dataQueueHandler as IDataQueueUniverseProvider; if (symbolUniverse == null) { throw new NotSupportedException("The DataQueueHandler does not support Options."); } var timeProvider = new PredicateTimeProvider(_timeProvider, time => symbolUniverse.CanAdvanceTime(config.SecurityType)); var enumeratorFactory = new OptionChainUniverseSubscriptionEnumeratorFactory(configure, symbolUniverse, timeProvider); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = new FrontierAwareEnumerator(enumerator, _frontierTimeProvider, tzOffsetProvider); } else if (request.Universe is FuturesChainUniverse) { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating futures chain universe: " + config.Symbol.ID); var symbolUniverse = _dataQueueHandler as IDataQueueUniverseProvider; if (symbolUniverse == null) { throw new NotSupportedException("The DataQueueHandler does not support Futures."); } var timeProvider = new PredicateTimeProvider(_timeProvider, time => symbolUniverse.CanAdvanceTime(config.SecurityType)); var enumeratorFactory = new FuturesChainUniverseSubscriptionEnumeratorFactory(symbolUniverse, timeProvider); enumerator = enumeratorFactory.CreateEnumerator(request, _dataProvider); enumerator = new FrontierAwareEnumerator(enumerator, _frontierTimeProvider, tzOffsetProvider); } else { Log.Trace("LiveTradingDataFeed.CreateUniverseSubscription(): Creating custom universe: " + config.Symbol.ID); var factory = new LiveCustomDataSubscriptionEnumeratorFactory(_timeProvider); var enumeratorStack = factory.CreateEnumerator(request, _dataProvider); enumerator = new BaseDataCollectionAggregatorEnumerator(enumeratorStack, config.Symbol, liveMode: true); var enqueueable = new EnqueueableEnumerator <BaseData>(); _customExchange.AddEnumerator(new EnumeratorHandler(config.Symbol, enumerator, enqueueable)); enumerator = enqueueable; } // create the subscription var subscriptionDataEnumerator = new SubscriptionDataEnumerator(request.Configuration, request.Security.Exchange.Hours, tzOffsetProvider, enumerator); subscription = new Subscription(request, subscriptionDataEnumerator, tzOffsetProvider); // send the subscription for the new symbol through to the data queuehandler if (_channelProvider.ShouldStreamSubscription(_job, subscription.Configuration)) { _dataQueueHandler.Subscribe(request.Configuration, (sender, args) => subscription.OnNewDataAvailable()); } return(subscription); }
/// <summary> /// Creates a <see cref="SubscriptionRequest"/>. /// </summary> /// <param name="paymentMethodToken"> /// The payment method token. /// </param> /// <param name="planId"> /// The plan id. /// </param> /// <param name="price"> /// An optional price used to override the plan price. /// </param> /// <returns> /// The <see cref="SubscriptionRequest"/>. /// </returns> public SubscriptionRequest CreateSubscriptionRequest(string paymentMethodToken, string planId, decimal? price = null) { Mandate.ParameterNotNullOrEmpty(paymentMethodToken, "paymentMethodToken"); Mandate.ParameterNotNullOrEmpty(planId, "planId"); var request = new SubscriptionRequest() { PaymentMethodToken = paymentMethodToken, PlanId = planId, }; // TODO figure out the descriptor for nicer Credit Card statements // TODO https://www.braintreepayments.com/docs/dotnet/transactions/dynamic_descriptors //if (_settings.MerchantDescriptor.HasValues()) //{ // request.Descriptor = _settings.MerchantDescriptor.AsDescriptorRequest(); //} if (price != null) request.Price = price.Value; return request; }
public void DoesNotEmitInvalidData() { var startTime = new DateTime(2014, 06, 06, 0, 0, 0); var endTime = new DateTime(2014, 06, 09, 20, 0, 0); var canonicalSymbol = Symbol.Create("AAPL", SecurityType.Option, Market.USA, "?AAPL"); var quoteCurrency = new Cash(Currencies.USD, 0, 1); var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.USA, canonicalSymbol, SecurityType.Option); var config = new SubscriptionDataConfig( typeof(ZipEntryName), canonicalSymbol, Resolution.Minute, TimeZones.Utc, TimeZones.NewYork, true, false, false, false, TickType.Quote, false, DataNormalizationMode.Raw ); var option = new Option( canonicalSymbol, exchangeHours, quoteCurrency, new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); var fillForwardResolution = Ref.CreateReadOnly(() => Resolution.Minute.ToTimeSpan()); Func <SubscriptionRequest, IEnumerator <BaseData>, IEnumerator <BaseData> > underlyingEnumeratorFunc = (req, input) => { input = new BaseDataCollectionAggregatorEnumerator(input, req.Configuration.Symbol); return(new FillForwardEnumerator( input, option.Exchange, fillForwardResolution, false, endTime, Resolution.Minute.ToTimeSpan(), TimeZones.Utc, startTime)); }; var factory = new OptionChainUniverseSubscriptionEnumeratorFactory(underlyingEnumeratorFunc, MapFileResolver.Create(Globals.DataFolder, Market.USA), new LocalDiskFactorFileProvider(new LocalDiskMapFileProvider())); var request = new SubscriptionRequest(true, null, option, config, startTime, endTime); var enumerator = factory.CreateEnumerator(request, new DefaultDataProvider()); var emittedCount = 0; foreach (var data in enumerator.AsEnumerable()) { emittedCount++; var optionData = data as OptionChainUniverseDataCollection; Assert.IsNotNull(optionData); Assert.IsNotNull(optionData.Underlying); Assert.AreNotEqual(0, optionData.Data.Count); } // 9:30 to 15:59 -> 6.5 hours * 60 => 390 minutes * 2 days = 780 Assert.AreEqual(780, emittedCount); }
public void Create_SetId() { TestPlan plan = PlanFixture.PLAN_WITH_TRIAL; string newId = "new-id-" + new Random().Next(1000000); SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id, Price = 482.48M, Id = newId }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Assert.AreEqual(newId, subscription.Id); }
/// <summary> /// Creates an enumerator to read the specified request. /// </summary> /// <param name="request">The subscription request to be read</param> /// <param name="dataProvider">Provider used to get data when it is not present on disk</param> /// <returns>An enumerator reading the subscription request</returns> public IEnumerator <BaseData> CreateEnumerator(SubscriptionRequest request, IDataProvider dataProvider) { var config = request.Configuration; // frontier value used to prevent emitting duplicate time stamps between refreshed enumerators // also provides some immediate fast-forward to handle spooling through remote files quickly var frontier = Ref.Create(_dateAdjustment?.Invoke(request.StartTimeLocal) ?? request.StartTimeLocal); var lastSourceRefreshTime = DateTime.MinValue; var sourceFactory = config.GetBaseDataInstance(); // this is refreshing the enumerator stack for each new source var refresher = new RefreshEnumerator <BaseData>(() => { // rate limit the refresh of this enumerator stack var utcNow = _timeProvider.GetUtcNow(); var minimumTimeBetweenCalls = GetMinimumTimeBetweenCalls(config.Increment, _minimumIntervalCheck); if (utcNow - lastSourceRefreshTime < minimumTimeBetweenCalls) { return(Enumerable.Empty <BaseData>().GetEnumerator()); } lastSourceRefreshTime = utcNow; var localDate = _dateAdjustment?.Invoke(utcNow.ConvertFromUtc(config.ExchangeTimeZone).Date) ?? utcNow.ConvertFromUtc(config.ExchangeTimeZone).Date; var source = sourceFactory.GetSource(config, localDate, true); // fetch the new source and enumerate the data source reader var enumerator = EnumerateDataSourceReader(config, dataProvider, frontier, source, localDate, sourceFactory); if (SourceRequiresFastForward(source)) { // The FastForwardEnumerator implements these two features: // (1) make sure we never emit past data // (2) data filtering based on a maximum data age // For custom data we don't want feature (2) because we would reject data points emitted later // (e.g. Quandl daily data after a weekend), so we disable it using a huge maximum data age. // apply fast forward logic for file transport mediums var maximumDataAge = GetMaximumDataAge(Time.MaxTimeSpan); enumerator = new FastForwardEnumerator(enumerator, _timeProvider, config.ExchangeTimeZone, maximumDataAge); } else { // rate limit calls to this enumerator stack enumerator = new RateLimitEnumerator <BaseData>(enumerator, _timeProvider, minimumTimeBetweenCalls); } if (source.Format == FileFormat.UnfoldingCollection) { // unroll collections into individual data points after fast forward/rate limiting applied enumerator = enumerator.SelectMany(data => { var collection = data as BaseDataCollection; IEnumerator <BaseData> collectionEnumerator; if (collection != null) { if (source.TransportMedium == SubscriptionTransportMedium.Rest) { // we want to make sure the data points we *unroll* are not past collectionEnumerator = collection.Data .Where(baseData => baseData.EndTime > frontier.Value) .GetEnumerator(); } else { collectionEnumerator = collection.Data.GetEnumerator(); } } else { collectionEnumerator = new List <BaseData> { data }.GetEnumerator(); } return(collectionEnumerator); }); } return(enumerator); }); return(refresher); }
public void Create_SetMerchantAccountId() { TestPlan plan = PlanFixture.PLAN_WITH_TRIAL; SubscriptionRequest request = new SubscriptionRequest { PaymentMethodToken = creditCard.Token, PlanId = plan.Id, MerchantAccountId = MerchantAccountIDs.NON_DEFAULT_MERCHANT_ACCOUNT_ID }; Result<Subscription> result = gateway.Subscription.Create(request); Assert.IsTrue(result.IsSuccess()); Subscription subscription = result.Target; Assert.AreEqual(MerchantAccountIDs.NON_DEFAULT_MERCHANT_ACCOUNT_ID, subscription.MerchantAccountId); }
public void Can_Create_A_Subscription_For_A_Customer_With_Discount() { //// Arrange // Step 1 - Plan selection var plan = this.BraintreeApiService.Subscription.GetAllPlans().FirstOrDefault(); Assert.NotNull(plan, "The plan was null"); var discount = this.BraintreeApiService.Subscription.GetAllDiscounts().FirstOrDefault(); Assert.NotNull(discount, "The discount was null"); // Step 2 - establish the customer var customer = this.BraintreeApiService.Customer.GetBraintreeCustomer(this.TestCustomer); // Step 3 - select the paymentmethod PaymentMethod paymentMethod; if (customer.PaymentMethods.Any()) { // use the default payment method paymentMethod = customer.DefaultPaymentMethod; } else { // or create a new payment method var billingAddress = new Core.Models.Address() { Address1 = "114 W. Magnolia St. Suite 300", Locality = "Bellingham", Region = "WA", PostalCode = "98225", CountryCode = "US", AddressType = AddressType.Billing }; // The 'true' value sets this to the default payment method. This is true by default var attemptPaymentMethod = this.BraintreeApiService.PaymentMethod.Create(this.TestCustomer, "nonce-from-the-client", billingAddress, true); if (!attemptPaymentMethod.Success) Assert.Fail("Failed to create the payment method"); paymentMethod = attemptPaymentMethod.Result; } //// Act // note there are additional paremeters to fill out here var subscriptionRequest = new SubscriptionRequest() { PaymentMethodToken = paymentMethod.Token, PlanId = plan.Id, Discounts = new DiscountsRequest() { Add = new[] { new AddDiscountRequest() { InheritedFromId = discount.Id } } } }; var subscriptionAttempt = this.BraintreeApiService.Subscription.Create(subscriptionRequest); //// Assert Assert.IsTrue(subscriptionAttempt.Success, "Failed to create the subscription "); var subscription = subscriptionAttempt.Result; if (subscription.Status == SubscriptionStatus.ACTIVE) { var trans = subscription.Transactions.FirstOrDefault(); var cs = trans.Customer; Assert.NotNull(cs); } }
public void Subscribe(SubscriptionRequest request) { }