public void PerformsLimitFillSell() { var model = new SecurityTransactionModel(); var order = new LimitOrder(Symbols.SPY, -100, 101.5m, Noon); var config = CreateTradeBarConfig(Symbols.SPY); var security = new Security(SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); security.SetMarketPrice(new IndicatorDataPoint(Symbols.SPY, Noon, 101m)); var fill = model.LimitFill(security, order); Assert.AreEqual(0, fill.FillQuantity); Assert.AreEqual(0, fill.FillPrice); Assert.AreEqual(OrderStatus.None, fill.Status); security.SetMarketPrice(new TradeBar(Noon, Symbols.SPY, 102m, 103m, 101m, 102.3m, 100)); fill = model.LimitFill(security, order); // this fills worst case scenario, so it's at the limit price Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(Math.Max(order.LimitPrice, security.Low), fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); }
public void EnsureCurrencyDataFeedDoesNotMarkIsCurrencyDataFeedForExistantSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.USDJPY, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.USDJPY, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook); var config = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsFalse(config.IsInternalFeed); }
public void EnsureCurrencyDataFeedAddsSubscription() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(TimeKeeper); var abcConfig = subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.SPY, new Security(SecurityExchangeHours, abcConfig, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook); Assert.AreEqual(1, subscriptions.Subscriptions.Count(x => x.Symbol == Symbols.USDJPY)); Assert.AreEqual(1, securities.Values.Count(x => x.Symbol == Symbols.USDJPY)); }
public void TestShortCallsITM() { const decimal price = 14m; const decimal underlyingPrice = 196m; var tz = TimeZones.NewYork; var equity = new QuantConnect.Securities.Equity.Equity(SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Minute, tz, tz, true, false, false), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); equity.SetMarketPrice(new Tick { Value = underlyingPrice }); var optionCall = new Option(SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY_C_192_Feb19_2016, Resolution.Minute, tz, tz, true, false, false), new Cash(CashBook.AccountCurrency, 0, 1m), new OptionSymbolProperties("", CashBook.AccountCurrency.ToUpper(), 100, 0.01m, 1)); optionCall.SetMarketPrice(new Tick { Value = price }); optionCall.Underlying = equity; optionCall.Holdings.SetHoldings(price, -2); var buyingPowerModel = new TestOptionMarginBuyingPowerModel(); // short option positions are very expensive in terms of margin. // Margin = 2 * 100 * (14 + 0.2 * 196) = 10640 Assert.AreEqual(10640m, buyingPowerModel.GetMaintenanceMargin(optionCall)); }
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 enumeratorFactory = new BaseDataSubscriptionEnumeratorFactory(false, MapFileResolver.Create(Globals.DataFolder, Market.USA), new LocalDiskFactorFileProvider(new LocalDiskMapFileProvider())); var fillForwardResolution = Ref.CreateReadOnly(() => Resolution.Minute.ToTimeSpan()); Func <SubscriptionRequest, IEnumerator <BaseData> > underlyingEnumeratorFunc = (req) => { var input = enumeratorFactory.CreateEnumerator(req, new DefaultDataProvider()); 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); 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); }
/// <summary> /// Creates a new instance of the DataManager /// </summary> public DataManager( IDataFeed dataFeed, UniverseSelection universeSelection, IAlgorithm algorithm, ITimeKeeper timeKeeper, MarketHoursDatabase marketHoursDatabase, bool liveMode, IRegisteredSecurityDataTypesProvider registeredTypesProvider) { _dataFeed = dataFeed; UniverseSelection = universeSelection; UniverseSelection.SetDataManager(this); _algorithmSettings = algorithm.Settings; AvailableDataTypes = SubscriptionManager.DefaultDataTypes(); _timeKeeper = timeKeeper; _marketHoursDatabase = marketHoursDatabase; _liveMode = liveMode; _registeredTypesProvider = registeredTypesProvider; // wire ourselves up to receive notifications when universes are added/removed algorithm.UniverseManager.CollectionChanged += (sender, args) => { switch (args.Action) { case NotifyCollectionChangedAction.Add: foreach (var universe in args.NewItems.OfType <Universe>()) { var config = universe.Configuration; var start = algorithm.UtcTime; var end = algorithm.LiveMode ? Time.EndOfTime : algorithm.EndDate.ConvertToUtc(algorithm.TimeZone); Security security; if (!algorithm.Securities.TryGetValue(config.Symbol, out security)) { // create a canonical security object if it doesn't exist security = new Security( _marketHoursDatabase.GetExchangeHours(config), config, algorithm.Portfolio.CashBook[algorithm.AccountCurrency], SymbolProperties.GetDefault(algorithm.AccountCurrency), algorithm.Portfolio.CashBook, RegisteredSecurityDataTypesProvider.Null ); } AddSubscription( new SubscriptionRequest(true, universe, security, config, start, end)); } break; case NotifyCollectionChangedAction.Remove: foreach (var universe in args.OldItems.OfType <Universe>()) { // removing the subscription will be handled by the SubscriptionSynchronizer // in the next loop as well as executing a UniverseSelection one last time. if (!universe.DisposeRequested) { universe.Dispose(); } } break; default: throw new NotImplementedException("The specified action is not implemented: " + args.Action); } }; }
public void TestShortPutMovingFarITM() { const decimal optionPriceStart = 4.68m; const decimal underlyingPriceStart = 192m; const decimal optionPriceEnd = 0.18m; const decimal underlyingPriceEnd = 200m; var tz = TimeZones.NewYork; var equity = new QuantConnect.Securities.Equity.Equity(SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Minute, tz, tz, true, false, false), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); equity.SetMarketPrice(new Tick { Value = underlyingPriceStart }); var optionPutSymbol = Symbol.CreateOption(Symbols.SPY, Market.USA, OptionStyle.American, OptionRight.Put, 207m, new DateTime(2015, 02, 27)); var optionPut = new Option(SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), optionPutSymbol, Resolution.Minute, tz, tz, true, false, false), new Cash(CashBook.AccountCurrency, 0, 1m), new OptionSymbolProperties("", CashBook.AccountCurrency.ToUpper(), 100, 0.01m, 1)); optionPut.SetMarketPrice(new Tick { Value = optionPriceStart }); optionPut.Underlying = equity; optionPut.Holdings.SetHoldings(optionPriceStart, -2); var buyingPowerModel = new TestOptionMarginBuyingPowerModel(); // short option positions are very expensive in terms of margin. // Margin = 2 * 100 * (4.68 + 0.2 * 192) = 8616 Assert.AreEqual(8616, (double)buyingPowerModel.GetMaintenanceMargin(optionPut), 0.01); equity.SetMarketPrice(new Tick { Value = underlyingPriceEnd }); optionPut.SetMarketPrice(new Tick { Value = optionPriceEnd }); // short option positions are very expensive in terms of margin. // Margin = 2 * 100 * (4.68 + 0.2 * 200) = 8936 Assert.AreEqual(8936, (double)buyingPowerModel.GetMaintenanceMargin(optionPut), 0.01); }
public void EnsureInternalCurrencyDataFeedsForNonUsdQuoteCurrencyGetAdded() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cashJPY = new Cash("JPY", quantity, conversionRate); var cashGBP = new Cash("GBP", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cashJPY); cashBook.Add("GBP", cashGBP); var symbol = Symbol.Create("GBPJPY", SecurityType.Forex, Market.FXCM); var subscriptions = new SubscriptionManager(AlgorithmSettings, TimeKeeper, new DataManagerStub()); var securities = new SecurityManager(TimeKeeper); securities.Add(symbol, new Security(SecurityExchangeHours, subscriptions.Add(symbol, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cashJPY.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); var config1 = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsTrue(config1.IsInternalFeed); cashGBP.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); var config2 = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.GBPUSD); Assert.IsTrue(config2.IsInternalFeed); }
public void UpdateModifiesConversionRateAsInvertedValue() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(AlgorithmSettings, TimeKeeper, new DataManagerStub()); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.USDJPY, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.USDJPY, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); // we need to get subscription index cash.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); var last = 120m; cash.Update(new Tick(DateTime.Now, Symbols.USDJPY, last, 119.95m, 120.05m)); // jpy is inverted, so compare on the inverse Assert.AreEqual(1 / last, cash.ConversionRate); }
public void EnsureCurrencyDataFeedsAddsSubscriptionAtMinimumResolution() { const int quantity = 100; const decimal conversionRate = 1 / 100m; const Resolution minimumResolution = Resolution.Second; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(AlgorithmSettings, TimeKeeper, new DataManagerStub()); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.SPY, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities.Add(Symbols.EURUSD, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.EURUSD, minimumResolution, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cash.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); Assert.AreEqual(minimumResolution, subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY).Resolution); }
public void EnsureCurrencyDataFeedMarksIsCurrencyDataFeedForNewSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(AlgorithmSettings, TimeKeeper, new DataManagerStub()); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.EURUSD, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.EURUSD, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cash.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); var config = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsTrue(config.IsInternalFeed); }
public void EnsureCurrencyDataFeedChecksSecurityChangesForSecurity() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(AlgorithmSettings, TimeKeeper, new DataManagerStub()); var abcConfig = subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.SPY, new Security(SecurityExchangeHours, abcConfig, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var usdjpy = new Security(Symbols.USDJPY, SecurityExchangeHours, new Cash("JPY", 0, 0), SymbolProperties.GetDefault("JPY")); var changes = new SecurityChanges(new[] { usdjpy }, Enumerable.Empty <Security>()); var addedSecurity = cash.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, changes); // the security exists in SecurityChanges so it is NOT added to the security manager or subscriptions // this security will be added by the algorithm manager Assert.IsNull(addedSecurity); }
/// <summary> /// Creates a subscription to process the request /// </summary> private Subscription CreateSubscription(HistoryRequest request, DateTime start, DateTime end) { // data reader expects these values in local times start = start.ConvertFromUtc(request.ExchangeHours.TimeZone); end = end.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 ); var security = new Security( request.ExchangeHours, config, new Cash(Currencies.NullCurrency, 0, 1m), SymbolProperties.GetDefault(Currencies.NullCurrency), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); 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(start, config.MappedSymbol); } var dataReader = new SubscriptionDataReader(config, start, end, mapFileResolver, _factorFileProvider, Time.EachTradeableDay(request.ExchangeHours, start, end), false, _dataCacheProvider ); dataReader.InvalidConfigurationDetected += (sender, args) => { OnInvalidConfigurationDetected(new InvalidConfigurationDetectedEventArgs(args.Message)); }; dataReader.NumericalPrecisionLimited += (sender, args) => { OnNumericalPrecisionLimited(new NumericalPrecisionLimitedEventArgs(args.Message)); }; dataReader.DownloadFailed += (sender, args) => { OnDownloadFailed(new DownloadFailedEventArgs(args.Message, args.StackTrace)); }; dataReader.ReaderErrorDetected += (sender, args) => { OnReaderErrorDetected(new ReaderErrorDetectedEventArgs(args.Message, args.StackTrace)); }; var reader = CorporateEventEnumeratorFactory.CreateEnumerators( dataReader, config, _factorFileProvider, dataReader, mapFileResolver, false); // has to be initialized after adding all the enumerators since it will execute a MoveNext dataReader.Initialize(); // 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, security.IsExtendedMarketHours, end, 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, end); reader = new FilterEnumerator <BaseData>(reader, data => { // allow all ticks if (config.Resolution == Resolution.Tick) { return(true); } // filter out future data if (data.EndTime > end) { return(false); } // filter out data before the start return(data.EndTime > start); }); var timeZoneOffsetProvider = new TimeZoneOffsetProvider(security.Exchange.TimeZone, start, end); var subscriptionDataEnumerator = new SubscriptionDataEnumerator(config, security.Exchange.Hours, timeZoneOffsetProvider, reader); var subscriptionRequest = new SubscriptionRequest(false, null, security, config, start, end); return(new Subscription(subscriptionRequest, subscriptionDataEnumerator, timeZoneOffsetProvider)); }
private static TestCaseData[] GetValueTestParameters() { const decimal delta = 1m; const decimal price = 1.2345m; const int quantity = 100; const decimal pricePlusDelta = price + delta; const decimal priceMinusDelta = price - delta; var tz = TimeZones.NewYork; var time = new DateTime(2016, 2, 4, 16, 0, 0).ConvertToUtc(tz); var equity = new Equity( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Minute, tz, tz, true, false, false), new Cash(Currencies.USD, 0, 1m), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); equity.SetMarketPrice(new Tick { Value = price }); var gbpCash = new Cash("GBP", 0, 1.46m); var properties = SymbolProperties.GetDefault(gbpCash.Symbol); var forex = new Forex( SecurityExchangeHours.AlwaysOpen(tz), gbpCash, new SubscriptionDataConfig(typeof(TradeBar), Symbols.EURGBP, Resolution.Minute, tz, tz, true, false, false), properties, ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); forex.SetMarketPrice(new Tick { Value = price }); var eurCash = new Cash("EUR", 0, 1.12m); properties = new SymbolProperties("Euro-Bund", eurCash.Symbol, 10, 0.1m, 1, string.Empty); var cfd = new Cfd( SecurityExchangeHours.AlwaysOpen(tz), eurCash, new SubscriptionDataConfig(typeof(TradeBar), Symbols.DE10YBEUR, Resolution.Minute, tz, tz, true, false, false), properties, ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); cfd.SetMarketPrice(new Tick { Value = price }); var multiplierTimesConversionRate = properties.ContractMultiplier * eurCash.ConversionRate; var option = new Option( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig( typeof(TradeBar), Symbols.SPY_P_192_Feb19_2016, Resolution.Minute, tz, tz, true, false, false ), new Cash(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); option.SetMarketPrice(new Tick { Value = price }); return(new List <ValueTestParameters> { // equity orders new ValueTestParameters("EquityLongMarketOrder", equity, new MarketOrder(Symbols.SPY, quantity, time), quantity * price), new ValueTestParameters("EquityShortMarketOrder", equity, new MarketOrder(Symbols.SPY, -quantity, time), -quantity * price), new ValueTestParameters("EquityLongLimitOrder", equity, new LimitOrder(Symbols.SPY, quantity, priceMinusDelta, time), quantity * priceMinusDelta), new ValueTestParameters("EquityShortLimit Order", equity, new LimitOrder(Symbols.SPY, -quantity, pricePlusDelta, time), -quantity * pricePlusDelta), new ValueTestParameters("EquityLongStopLimitOrder", equity, new StopLimitOrder(Symbols.SPY, quantity, .5m * priceMinusDelta, priceMinusDelta, time), quantity * priceMinusDelta), new ValueTestParameters("EquityShortStopLimitOrder", equity, new StopLimitOrder(Symbols.SPY, -quantity, 1.5m * pricePlusDelta, pricePlusDelta, time), -quantity * pricePlusDelta), new ValueTestParameters("EquityLongStopMarketOrder", equity, new StopMarketOrder(Symbols.SPY, quantity, priceMinusDelta, time), quantity * priceMinusDelta), new ValueTestParameters("EquityLongStopMarketOrder", equity, new StopMarketOrder(Symbols.SPY, quantity, pricePlusDelta, time), quantity * price), new ValueTestParameters("EquityShortStopMarketOrder", equity, new StopMarketOrder(Symbols.SPY, -quantity, pricePlusDelta, time), -quantity * pricePlusDelta), new ValueTestParameters("EquityShortStopMarketOrder", equity, new StopMarketOrder(Symbols.SPY, -quantity, priceMinusDelta, time), -quantity * price), // forex orders new ValueTestParameters("ForexLongMarketOrder", forex, new MarketOrder(Symbols.EURGBP, quantity, time), quantity * price * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexShortMarketOrder", forex, new MarketOrder(Symbols.EURGBP, -quantity, time), -quantity * price * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexLongLimitOrder", forex, new LimitOrder(Symbols.EURGBP, quantity, priceMinusDelta, time), quantity * priceMinusDelta * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexShortLimit Order", forex, new LimitOrder(Symbols.EURGBP, -quantity, pricePlusDelta, time), -quantity * pricePlusDelta * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexLongStopLimitOrder", forex, new StopLimitOrder(Symbols.EURGBP, quantity, .5m * priceMinusDelta, priceMinusDelta, time), quantity * priceMinusDelta * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexShortStopLimitOrder", forex, new StopLimitOrder(Symbols.EURGBP, -quantity, 1.5m * pricePlusDelta, pricePlusDelta, time), -quantity * pricePlusDelta * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexLongStopMarketOrder", forex, new StopMarketOrder(Symbols.EURGBP, quantity, priceMinusDelta, time), quantity * priceMinusDelta * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexLongStopMarketOrder", forex, new StopMarketOrder(Symbols.EURGBP, quantity, pricePlusDelta, time), quantity * price * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexShortStopMarketOrder", forex, new StopMarketOrder(Symbols.EURGBP, -quantity, pricePlusDelta, time), -quantity * pricePlusDelta * forex.QuoteCurrency.ConversionRate), new ValueTestParameters("ForexShortStopMarketOrder", forex, new StopMarketOrder(Symbols.EURGBP, -quantity, priceMinusDelta, time), -quantity * price * forex.QuoteCurrency.ConversionRate), // cfd orders new ValueTestParameters("CfdLongMarketOrder", cfd, new MarketOrder(Symbols.DE10YBEUR, quantity, time), quantity * price * multiplierTimesConversionRate), new ValueTestParameters("CfdShortMarketOrder", cfd, new MarketOrder(Symbols.DE10YBEUR, -quantity, time), -quantity * price * multiplierTimesConversionRate), new ValueTestParameters("CfdLongLimitOrder", cfd, new LimitOrder(Symbols.DE10YBEUR, quantity, priceMinusDelta, time), quantity * priceMinusDelta * multiplierTimesConversionRate), new ValueTestParameters("CfdShortLimit Order", cfd, new LimitOrder(Symbols.DE10YBEUR, -quantity, pricePlusDelta, time), -quantity * pricePlusDelta * multiplierTimesConversionRate), new ValueTestParameters("CfdLongStopLimitOrder", cfd, new StopLimitOrder(Symbols.DE10YBEUR, quantity, .5m * priceMinusDelta, priceMinusDelta, time), quantity * priceMinusDelta * multiplierTimesConversionRate), new ValueTestParameters("CfdShortStopLimitOrder", cfd, new StopLimitOrder(Symbols.DE10YBEUR, -quantity, 1.5m * pricePlusDelta, pricePlusDelta, time), -quantity * pricePlusDelta * multiplierTimesConversionRate), new ValueTestParameters("CfdLongStopMarketOrder", cfd, new StopMarketOrder(Symbols.DE10YBEUR, quantity, priceMinusDelta, time), quantity * priceMinusDelta * multiplierTimesConversionRate), new ValueTestParameters("CfdLongStopMarketOrder", cfd, new StopMarketOrder(Symbols.DE10YBEUR, quantity, pricePlusDelta, time), quantity * price * multiplierTimesConversionRate), new ValueTestParameters("CfdShortStopMarketOrder", cfd, new StopMarketOrder(Symbols.DE10YBEUR, -quantity, pricePlusDelta, time), -quantity * pricePlusDelta * multiplierTimesConversionRate), new ValueTestParameters("CfdShortStopMarketOrder", cfd, new StopMarketOrder(Symbols.DE10YBEUR, -quantity, priceMinusDelta, time), -quantity * price * multiplierTimesConversionRate), // equity/index option orders new ValueTestParameters("OptionLongMarketOrder", option, new MarketOrder(Symbols.SPY_P_192_Feb19_2016, quantity, time), quantity * price), new ValueTestParameters("OptionShortMarketOrder", option, new MarketOrder(Symbols.SPY_P_192_Feb19_2016, -quantity, time), -quantity * price), new ValueTestParameters("OptionLongLimitOrder", option, new LimitOrder(Symbols.SPY_P_192_Feb19_2016, quantity, priceMinusDelta, time), quantity * priceMinusDelta), new ValueTestParameters("OptionShortLimit Order", option, new LimitOrder(Symbols.SPY_P_192_Feb19_2016, -quantity, pricePlusDelta, time), -quantity * pricePlusDelta), new ValueTestParameters("OptionLongStopLimitOrder", option, new StopLimitOrder(Symbols.SPY_P_192_Feb19_2016, quantity, .5m * priceMinusDelta, priceMinusDelta, time), quantity * priceMinusDelta), new ValueTestParameters("OptionShortStopLimitOrder", option, new StopLimitOrder(Symbols.SPY_P_192_Feb19_2016, -quantity, 1.5m * pricePlusDelta, pricePlusDelta, time), -quantity * pricePlusDelta), new ValueTestParameters("OptionLongStopMarketOrder", option, new StopMarketOrder(Symbols.SPY_P_192_Feb19_2016, quantity, priceMinusDelta, time), quantity * priceMinusDelta), new ValueTestParameters("OptionLongStopMarketOrder", option, new StopMarketOrder(Symbols.SPY_P_192_Feb19_2016, quantity, pricePlusDelta, time), quantity * price), new ValueTestParameters("OptionShortStopMarketOrder", option, new StopMarketOrder(Symbols.SPY_P_192_Feb19_2016, -quantity, pricePlusDelta, time), -quantity * pricePlusDelta), new ValueTestParameters("OptionShortStopMarketOrder", option, new StopMarketOrder(Symbols.SPY_P_192_Feb19_2016, -quantity, priceMinusDelta, time), -quantity * price), new ValueTestParameters("OptionExerciseOrderPut", option, new OptionExerciseOrder(Symbols.SPY_P_192_Feb19_2016, quantity, time), quantity * option.Symbol.ID.StrikePrice), new ValueTestParameters("OptionAssignmentOrderPut", option, new OptionExerciseOrder(Symbols.SPY_P_192_Feb19_2016, -quantity, time), -quantity * option.Symbol.ID.StrikePrice), new ValueTestParameters("OptionExerciseOrderCall", option, new OptionExerciseOrder(Symbols.SPY_C_192_Feb19_2016, quantity, time), quantity * option.Symbol.ID.StrikePrice), new ValueTestParameters("OptionAssignmentOrderCall", option, new OptionExerciseOrder(Symbols.SPY_C_192_Feb19_2016, -quantity, time), -quantity * option.Symbol.ID.StrikePrice), }.Select(x => new TestCaseData(x).SetName(x.Name)).ToArray()); }
public void EquitySellAppliesSettlementCorrectly() { var securityExchangeHours = SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); securities.Add(Symbols.AAPL, new QuantConnect.Securities.Equity.Equity(securityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SettlementModel = new DelayedSettlementModel(3, TimeSpan.FromHours(8)); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Buy on Monday var timeUtc = new DateTime(2015, 10, 26, 15, 30, 0); var orderFee = security.FeeModel.GetOrderFee(security,new MarketOrder(Symbols.AAPL, 10, timeUtc)); var fill = new OrderEvent(1, Symbols.AAPL, timeUtc, OrderStatus.Filled, OrderDirection.Buy, 100, 10, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(10, security.Holdings.Quantity); Assert.AreEqual(-1, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Sell on Tuesday, cash unsettled timeUtc = timeUtc.AddDays(1); orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.AAPL, 10, timeUtc)); fill = new OrderEvent(2, Symbols.AAPL, timeUtc, OrderStatus.Filled, OrderDirection.Sell, 100, -10, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday, still cash unsettled timeUtc = timeUtc.AddDays(2); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Friday at open, cash settled var marketOpen = securityExchangeHours.MarketHours[timeUtc.DayOfWeek].GetMarketOpen(TimeSpan.Zero, false); Assert.IsTrue(marketOpen.HasValue); timeUtc = timeUtc.AddDays(1).Date.Add(marketOpen.Value).ConvertToUtc(securityExchangeHours.TimeZone); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
private Security GetSecurity(Symbol symbol) { var config = SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc); return(new Equity(symbol, config, new Cash("USD", 0, 1), SymbolProperties.GetDefault("USD"))); }
public void TestCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, see TestData\CashTestingStrategy.csv // also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_cash_fills.xml"; const string equityFile = "TestData\\test_cash_equity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get<int>("OrderId"), SymbolMap[x.Get<string>("Symbol")], DateTime.MinValue, x.Get<OrderStatus>("Status"), x.Get<int>("FillQuantity") < 0 ? OrderDirection.Sell : x.Get<int>("FillQuantity") > 0 ? OrderDirection.Buy : OrderDirection.Hold, x.Get<decimal>("FillPrice"), x.Get<int>("FillQuantity"), 0m) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); var security = new Security(SecurityExchangeHours, subscriptions.Add(CASH, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); security.SetLeverage(10m); securities.Add(CASH, security); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork)); // the value of 'CASH' increments for each fill, the original test algo did this monthly // the time doesn't really matter though security.SetMarketPrice(new IndicatorDataPoint(CASH, time, i + 1)); portfolio.ProcessFill(fill); Assert.AreEqual(equity[i + 1], portfolio.TotalPortfolioValue, "Failed on " + i); } }
public void LoadsDefaultLotSize() { var defaultSymbolProperties = SymbolProperties.GetDefault(Currencies.USD); Assert.AreEqual(defaultSymbolProperties.LotSize, 1); }
private IEnumerable <Slice> GetSlices(Symbol symbol, int initialVolume) { var subscriptionDataConfig = new SubscriptionDataConfig(typeof(ZipEntryName), symbol, Resolution.Second, TimeZones.Utc, TimeZones.Utc, true, true, false); var security = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.Utc), subscriptionDataConfig, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); var refTime = DateTime.UtcNow; return(Enumerable .Range(0, 10) .Select(i => { var time = refTime.AddSeconds(i); var bid = new Bar(100, 100, 100, 100); var ask = new Bar(110, 110, 110, 110); var volume = (i + 1) * initialVolume; return TimeSlice.Create( time, TimeZones.Utc, new CashBook(), new List <DataFeedPacket> { new DataFeedPacket(security, subscriptionDataConfig, new List <BaseData> { new QuoteBar(time, symbol, bid, i * 10, ask, (i + 1) * 11), new TradeBar(time, symbol, 100, 100, 110, 106, volume) }), }, new SecurityChanges(Enumerable.Empty <Security>(), Enumerable.Empty <Security>()), new Dictionary <Universe, BaseDataCollection>()) .Slice; })); }
public void ForexCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, but for a Forex security, // see TestData\CashTestingStrategy.csv; also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_forex_fills.xml"; const string equityFile = "TestData\\test_forex_equity.xml"; const string mchQuantityFile = "TestData\\test_forex_fills_mch_quantity.xml"; const string jwbQuantityFile = "TestData\\test_forex_fills_jwb_quantity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get<int>("OrderId"), SymbolMap[x.Get<string>("Symbol")], DateTime.MinValue, x.Get<OrderStatus>("Status"), x.Get<int>("FillQuantity") < 0 ? OrderDirection.Sell : x.Get<int>("FillQuantity") > 0 ? OrderDirection.Buy : OrderDirection.Hold, x.Get<decimal>("FillPrice"), x.Get<int>("FillQuantity"), 0) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); var mchQuantity = XDocument.Load(mchQuantityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); var jwbQuantity = XDocument.Load(jwbQuantityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); portfolio.CashBook.Add("MCH", mchQuantity[0], 0); portfolio.CashBook.Add("JWB", jwbQuantity[0], 0); var jwbCash = portfolio.CashBook["JWB"]; var mchCash = portfolio.CashBook["MCH"]; var usdCash = portfolio.CashBook["USD"]; var mchJwbSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, jwbCash, subscriptions.Add(MCHJWB, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork), SymbolProperties.GetDefault(jwbCash.Symbol)); mchJwbSecurity.SetLeverage(10m); var mchUsdSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, usdCash, subscriptions.Add(MCHUSD, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork), SymbolProperties.GetDefault(usdCash.Symbol)); mchUsdSecurity.SetLeverage(10m); var usdJwbSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, mchCash, subscriptions.Add(USDJWB, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork), SymbolProperties.GetDefault(mchCash.Symbol)); usdJwbSecurity.SetLeverage(10m); // no fee model mchJwbSecurity.TransactionModel = new SecurityTransactionModel(); mchUsdSecurity.TransactionModel = new SecurityTransactionModel(); usdJwbSecurity.TransactionModel = new SecurityTransactionModel(); securities.Add(mchJwbSecurity); securities.Add(usdJwbSecurity); securities.Add(mchUsdSecurity); portfolio.CashBook.EnsureCurrencyDataFeeds(securities, subscriptions, MarketHoursDatabase.FromDataFolder(), SymbolPropertiesDatabase.FromDataFolder(), DefaultBrokerageModel.DefaultMarketMap); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); // the value of 'MCJWB' increments for each fill, the original test algo did this monthly // the time doesn't really matter though decimal mchJwb = i + 1; decimal mchUsd = (i + 1)/(i + 2m); decimal usdJwb = i + 2; Assert.AreEqual((double)mchJwb, (double)(mchUsd*usdJwb), 1e-10); //Console.WriteLine("Step: " + i + " -- MCHJWB: " + mchJwb); jwbCash.Update(new IndicatorDataPoint(MCHJWB, time, mchJwb)); usdCash.Update(new IndicatorDataPoint(MCHUSD, time, mchUsd)); mchCash.Update(new IndicatorDataPoint(JWBUSD, time, usdJwb)); var updateData = new Dictionary<Security, BaseData> { {mchJwbSecurity, new IndicatorDataPoint(MCHJWB, time, mchJwb)}, {mchUsdSecurity, new IndicatorDataPoint(MCHUSD, time, mchUsd)}, {usdJwbSecurity, new IndicatorDataPoint(JWBUSD, time, usdJwb)} }; foreach (var kvp in updateData) { kvp.Key.SetMarketPrice(kvp.Value); } portfolio.ProcessFill(fill); //Console.WriteLine("-----------------------"); //Console.WriteLine(fill); //Console.WriteLine("Post step: " + i); //foreach (var cash in portfolio.CashBook) //{ // Console.WriteLine(cash.Value); //} //Console.WriteLine("CashValue: " + portfolio.CashBook.TotalValueInAccountCurrency); Console.WriteLine(i + 1 + " " + portfolio.TotalPortfolioValue.ToString("C")); //Assert.AreEqual((double) equity[i + 1], (double)portfolio.TotalPortfolioValue, 2e-2); Assert.AreEqual((double) mchQuantity[i + 1], (double)portfolio.CashBook["MCH"].Amount); Assert.AreEqual((double) jwbQuantity[i + 1], (double)portfolio.CashBook["JWB"].Amount); //Console.WriteLine(); //Console.WriteLine(); } }
public void TestLongCallsPuts() { const decimal price = 1.2345m; const decimal underlyingPrice = 200m; var tz = TimeZones.NewYork; var equity = new QuantConnect.Securities.Equity.Equity(SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Minute, tz, tz, true, false, false), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); equity.SetMarketPrice(new Tick { Value = underlyingPrice }); var optionPut = new Option(SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY_P_192_Feb19_2016, Resolution.Minute, tz, tz, true, false, false), new Cash(CashBook.AccountCurrency, 0, 1m), new OptionSymbolProperties("", CashBook.AccountCurrency.ToUpper(), 100, 0.01m, 1)); optionPut.SetMarketPrice(new Tick { Value = price }); optionPut.Underlying = equity; optionPut.Holdings.SetHoldings(1m, 2); var optionCall = new Option(SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY_C_192_Feb19_2016, Resolution.Minute, tz, tz, true, false, false), new Cash(CashBook.AccountCurrency, 0, 1m), new OptionSymbolProperties("", CashBook.AccountCurrency.ToUpper(), 100, 0.01m, 1)); optionCall.SetMarketPrice(new Tick { Value = price }); optionCall.Underlying = equity; optionCall.Holdings.SetHoldings(1.5m, 2); var buyingPowerModel = new TestOptionMarginBuyingPowerModel(); // we expect long positions to be 100% charged. Assert.AreEqual(optionPut.Holdings.AbsoluteHoldingsCost, buyingPowerModel.GetMaintenanceMargin(optionPut)); Assert.AreEqual(optionCall.Holdings.AbsoluteHoldingsCost, buyingPowerModel.GetMaintenanceMargin(optionCall)); }
public void ComputeMarginProperlyAsSecurityPriceFluctuates() { const decimal leverage = 1m; const int quantity = (int) (1000*leverage); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(quantity); var config = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SetLeverage(leverage); var time = DateTime.Now; const decimal buyPrice = 1m; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, buyPrice, buyPrice, buyPrice, buyPrice, 1)); var order = new MarketOrder(Symbols.AAPL, quantity, time) {Price = buyPrice}; var fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = buyPrice, FillQuantity = quantity }; orderProcessor.AddOrder(order); var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); Assert.AreEqual(portfolio.CashBook["USD"].Amount, fill.FillPrice*fill.FillQuantity); portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var newOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1)) {Price = buyPrice}; bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, highPrice, highPrice, highPrice, highPrice, 1)); Assert.AreEqual(quantity, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var anotherOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder); Assert.IsTrue(sufficientCapital); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice/2; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, lowPrice, lowPrice, lowPrice, lowPrice, 1)); Assert.AreEqual(-quantity/2m, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity/2m, portfolio.TotalPortfolioValue); // this would not cause a margin call due to leverage = 1 bool issueMarginCallWarning; var marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // now change the leverage and buy more and we'll get a margin call security.SetLeverage(leverage * 2); order = new MarketOrder(Symbols.AAPL, quantity, time) { Price = buyPrice }; fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = buyPrice, FillQuantity = quantity }; portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.TotalPortfolioValue); marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreNotEqual(0, marginCallOrders.Count); Assert.AreEqual(-security.Holdings.Quantity, marginCallOrders[0].Quantity); // we bought twice Assert.GreaterOrEqual(-portfolio.MarginRemaining, security.Price * marginCallOrders[0].Quantity); }
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); EnqueueableEnumerator <BaseData> underlyingEnumerator = null; Func <SubscriptionRequest, IEnumerator <BaseData> > underlyingEnumeratorFunc = (req) => { underlyingEnumerator = new EnqueueableEnumerator <BaseData>(); return(new LiveFillForwardEnumerator( timeProvider, underlyingEnumerator, 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.Enqueue(new Tick { Symbol = Symbols.SPY, Value = 280m }); // 2018-10-19 10:01 AM UTC timeProvider.Advance(Time.OneMinute); underlyingEnumerator.Enqueue(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.Enqueue(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.Enqueue(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.Enqueue(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.Enqueue(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(); }
public void MarginComputesProperlyWithMultipleSecurities() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(1000); portfolio.CashBook.Add("EUR", 1000, 1.1m); portfolio.CashBook.Add("GBP", -1000, 2.0m); var eurCash = portfolio.CashBook["EUR"]; var gbpCash = portfolio.CashBook["GBP"]; var usdCash = portfolio.CashBook["USD"]; var time = DateTime.Now; var config1 = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config1, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities[Symbols.AAPL].SetLeverage(2m); securities[Symbols.AAPL].Holdings.SetHoldings(100, 100); securities[Symbols.AAPL].SetMarketPrice(new TradeBar{Time = time, Value = 100}); //Console.WriteLine("AAPL TMU: " + securities[Symbols.AAPL].MarginModel.GetMaintenanceMargin(securities[Symbols.AAPL])); //Console.WriteLine("AAPL Value: " + securities[Symbols.AAPL].Holdings.HoldingsValue); //Console.WriteLine(); var config2 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURUSD); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, usdCash, config2, SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities[Symbols.EURUSD].SetLeverage(100m); securities[Symbols.EURUSD].Holdings.SetHoldings(1.1m, 1000); securities[Symbols.EURUSD].SetMarketPrice(new TradeBar { Time = time, Value = 1.1m }); //Console.WriteLine("EURUSD TMU: " + securities[Symbols.EURUSD].MarginModel.GetMaintenanceMargin(securities[Symbols.EURUSD])); //Console.WriteLine("EURUSD Value: " + securities[Symbols.EURUSD].Holdings.HoldingsValue); //Console.WriteLine(); var config3 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURGBP); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, gbpCash, config3, SymbolProperties.GetDefault(gbpCash.Symbol))); securities[Symbols.EURGBP].SetLeverage(100m); securities[Symbols.EURGBP].Holdings.SetHoldings(1m, 1000); securities[Symbols.EURGBP].SetMarketPrice(new TradeBar { Time = time, Value = 1m }); //Console.WriteLine("EURGBP TMU: " + securities[Symbols.EURGBP].MarginModel.GetMaintenanceMargin(securities[Symbols.EURGBP])); //Console.WriteLine("EURGBP Value: " + securities[Symbols.EURGBP].Holdings.HoldingsValue); //Console.WriteLine(); //Console.WriteLine(portfolio.CashBook["USD"]); //Console.WriteLine(portfolio.CashBook["EUR"]); //Console.WriteLine(portfolio.CashBook["GBP"]); //Console.WriteLine("CashBook: " + portfolio.CashBook.TotalValueInAccountCurrency); //Console.WriteLine(); //Console.WriteLine("Total Margin Used: " + portfolio.TotalMarginUsed); //Console.WriteLine("Total Free Margin: " + portfolio.MarginRemaining); //Console.WriteLine("Total Portfolio Value: " + portfolio.TotalPortfolioValue); var acceptedOrder = new MarketOrder(Symbols.AAPL, 101, DateTime.Now) { Price = 100 }; orderProcessor.AddOrder(acceptedOrder); var request = new SubmitOrderRequest(OrderType.Market, acceptedOrder.SecurityType, acceptedOrder.Symbol, acceptedOrder.Quantity, 0, 0, acceptedOrder.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder); Assert.IsTrue(sufficientCapital); var rejectedOrder = new MarketOrder(Symbols.AAPL, 102, DateTime.Now) { Price = 100 }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder); Assert.IsFalse(sufficientCapital); }
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 = Symbol.CreateOption( new Symbol(SecurityIdentifier.GenerateEquity(DateTime.Now, symbol, Market.USA), symbol), Market.USA, OptionStyle.American, OptionRight.Call, 0m, DateTime.Now ); 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(), null ); } 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 void SellingShortFromShortAddsToCash() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(0); securities.Add(Symbols.AAPL, new Security(SecurityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities[Symbols.AAPL].Holdings.SetHoldings(100, -100); var fill = new OrderEvent(1, Symbols.AAPL, DateTime.MinValue, OrderStatus.Filled, OrderDirection.Sell, 100, -100, 0); Assert.AreEqual(-100, securities[Symbols.AAPL].Holdings.Quantity); portfolio.ProcessFill(fill); Assert.AreEqual(100 * 100, portfolio.Cash); Assert.AreEqual(-200, securities[Symbols.AAPL].Holdings.Quantity); }
public void UpdateModifiesConversionRate() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("GBP", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("GBP", cash); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.GBPUSD, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.GBPUSD, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); // we need to get subscription index cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook); var last = 1.5m; cash.Update(new Tick(DateTime.Now, Symbols.GBPUSD, last, last * 1.009m, last * 0.009m)); // jpy is inverted, so compare on the inverse Assert.AreEqual(last, cash.ConversionRate); }
public void ForexFillUpdatesCashCorrectly() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); portfolio.CashBook.Add("EUR", 0, 1.1000m); securities.Add(Symbols.EURUSD, new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, portfolio.CashBook["USD"], CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURUSD), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.EURUSD]; Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); var orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.EURUSD, 100, DateTime.MinValue)); var fill = new OrderEvent(1, Symbols.EURUSD, DateTime.MinValue, OrderStatus.Filled, OrderDirection.Buy, 1.1000m, 100, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(100, security.Holdings.Quantity); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(100, portfolio.CashBook["EUR"].Amount); Assert.AreEqual(888, portfolio.CashBook["USD"].Amount); }
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 ); 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 = new TaskFactory().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 = new TaskFactory().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 = new TaskFactory().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(); }
public void PerformsMarketFillSell() { var model = new SecurityTransactionModel(); var order = new MarketOrder(Symbols.SPY, -100, Noon); var config = CreateTradeBarConfig(Symbols.SPY); var security = new Security(SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(), config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); security.SetMarketPrice(new IndicatorDataPoint(Symbols.SPY, Noon, 101.123m)); var fill = model.MarketFill(security, order); Assert.AreEqual(order.Quantity, fill.FillQuantity); Assert.AreEqual(security.Price, fill.FillPrice); Assert.AreEqual(OrderStatus.Filled, fill.Status); }