public void BlackScholesPortfolioTest() { const decimal price = 20.00m; const decimal underlyingPrice = 200m; const decimal underlyingVol = 0.15m; const decimal riskFreeRate = 0.01m; var tz = TimeZones.NewYork; var evaluationDate = new DateTime(2015, 2, 19); var SPY_C_192_Feb19_2016E = Symbol.CreateOption("SPY", Market.USA, OptionStyle.European, OptionRight.Call, 192m, new DateTime(2016, 02, 19)); // setting up underlying 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 = underlyingPrice }); equity.VolatilityModel = new DummyVolatilityModel(underlyingVol); // setting up European style option var contract = new OptionContract(SPY_C_192_Feb19_2016E, Symbols.SPY) { Time = evaluationDate }; var optionCall = new Option( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), SPY_C_192_Feb19_2016E, Resolution.Minute, tz, tz, true, false, false), new Cash(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); optionCall.SetMarketPrice(new Tick { Value = price }); optionCall.Underlying = equity; // running evaluation var priceModel = OptionPriceModels.BlackScholes(); var results = priceModel.Evaluate(optionCall, null, contract); var callPrice = results.TheoreticalPrice; var greeks = results.Greeks; // BS equation var rightPart = greeks.Theta + riskFreeRate * underlyingPrice * greeks.Delta + 0.5m * underlyingVol * underlyingVol * underlyingPrice * underlyingPrice * greeks.Gamma; var leftPart = riskFreeRate * callPrice; Assert.AreEqual((double)leftPart, (double)rightPart, 0.0001); }
public Option GetOption(Symbol symbol, Equity underlying, NodaTime.DateTimeZone tz) { var option = new Option( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), symbol, Resolution.Minute, tz, tz, true, false, false), new Cash(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); option.Underlying = underlying; return(option); }
public void FreeBuyingPowerPercentDefault_Option() { const decimal price = 25m; const decimal underlyingPrice = 25m; 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(Currencies.USD, 0, 1m), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); equity.SetMarketPrice(new Tick { Value = underlyingPrice }); var optionPutSymbol = Symbol.CreateOption(Symbols.SPY, Market.USA, OptionStyle.American, OptionRight.Put, 207m, new DateTime(2015, 02, 27)); var security = new Option( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), optionPutSymbol, Resolution.Minute, tz, tz, true, false, false), new Cash(Currencies.USD, 0, 1m), new OptionSymbolProperties("", Currencies.USD, 100, 0.01m, 1), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); security.SetMarketPrice(new Tick { Value = price }); security.Underlying = equity; var algo = GetAlgorithm(); security.SetLocalTimeKeeper(algo.TimeKeeper.GetLocalTimeKeeper(tz)); var actual = security.BuyingPowerModel.GetMaximumOrderQuantityForTargetBuyingPower( new GetMaximumOrderQuantityForTargetBuyingPowerParameters(algo.Portfolio, security, 1, 0)).Quantity; // (100000 * 1) / (25 * 100 contract multiplier) - 1 order due to fees Assert.AreEqual(39m, actual); Assert.IsTrue(HasSufficientBuyingPowerForOrder(actual, security, algo)); Assert.AreEqual(algo.Portfolio.Cash, security.BuyingPowerModel.GetBuyingPower(algo.Portfolio, security, OrderDirection.Buy)); }
public OptionPriceModelPriceGeneratorTests() { _underlying = new Security( SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), new SubscriptionDataConfig( typeof(TradeBar), Symbols.SPY, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork, false, false, false ), new Cash("USD", 0, 1m), SymbolProperties.GetDefault("USD"), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); var optionSymbol = Symbol.CreateOption( _underlying.Symbol, _underlying.Symbol.ID.Market, _underlying.Symbol.SecurityType.DefaultOptionStyle(), OptionRight.Call, 20, new DateTime(2022, 1, 1)); _option = new Option( optionSymbol, SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), new Cash("USD", 0, 1m), new OptionSymbolProperties(_underlying.SymbolProperties), new CashBook(), new RegisteredSecurityDataTypesProvider(), new OptionCache(), _underlying); }
/// <summary> /// Creates a security and matching configuration. This applies the default leverage if /// leverage is less than or equal to zero. /// This method also add the new symbol mapping to the <see cref="SymbolCache"/> /// </summary> public static Security CreateSecurity(List <Tuple <Type, TickType> > subscriptionDataTypes, SecurityPortfolioManager securityPortfolioManager, SubscriptionManager subscriptionManager, SecurityExchangeHours exchangeHours, DateTimeZone dataTimeZone, SymbolProperties symbolProperties, ISecurityInitializer securityInitializer, Symbol symbol, Resolution resolution, bool fillDataForward, decimal leverage, bool extendedMarketHours, bool isInternalFeed, bool isCustomData, bool isLiveMode, bool addToSymbolCache = true, bool isFilteredSubscription = true) { if (!subscriptionDataTypes.Any()) { throw new ArgumentNullException(nameof(subscriptionDataTypes), "At least one type needed to create security"); } // add the symbol to our cache if (addToSymbolCache) { SymbolCache.Set(symbol.Value, symbol); } // Add the symbol to Data Manager -- generate unified data streams for algorithm events var configList = new SubscriptionDataConfigList(symbol); configList.AddRange(from subscriptionDataType in subscriptionDataTypes let dataType = subscriptionDataType.Item1 let tickType = subscriptionDataType.Item2 select subscriptionManager.Add(dataType, tickType, symbol, resolution, dataTimeZone, exchangeHours.TimeZone, isCustomData, fillDataForward, extendedMarketHours, isInternalFeed, isFilteredSubscription)); // verify the cash book is in a ready state var quoteCurrency = symbolProperties.QuoteCurrency; if (!securityPortfolioManager.CashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero securityPortfolioManager.CashBook.Add(quoteCurrency, 0, 0); } if (symbol.ID.SecurityType == SecurityType.Forex || symbol.ID.SecurityType == SecurityType.Crypto) { // decompose the symbol into each currency pair string baseCurrency; Forex.Forex.DecomposeCurrencyPair(symbol.Value, out baseCurrency, out quoteCurrency); if (!securityPortfolioManager.CashBook.ContainsKey(baseCurrency)) { // since we have none it's safe to say the conversion is zero securityPortfolioManager.CashBook.Add(baseCurrency, 0, 0); } if (!securityPortfolioManager.CashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero securityPortfolioManager.CashBook.Add(quoteCurrency, 0, 0); } } var quoteCash = securityPortfolioManager.CashBook[symbolProperties.QuoteCurrency]; Security security; switch (configList.Symbol.ID.SecurityType) { case SecurityType.Equity: security = new Equity.Equity(symbol, exchangeHours, quoteCash, symbolProperties); break; case SecurityType.Option: if (addToSymbolCache) { SymbolCache.Set(symbol.Underlying.Value, symbol.Underlying); } configList.SetDataNormalizationMode(DataNormalizationMode.Raw); security = new Option.Option(symbol, exchangeHours, securityPortfolioManager.CashBook[CashBook.AccountCurrency], new Option.OptionSymbolProperties(symbolProperties)); break; case SecurityType.Future: configList.SetDataNormalizationMode(DataNormalizationMode.Raw); security = new Future.Future(symbol, exchangeHours, securityPortfolioManager.CashBook[CashBook.AccountCurrency], symbolProperties); break; case SecurityType.Forex: security = new Forex.Forex(symbol, exchangeHours, quoteCash, symbolProperties); break; case SecurityType.Cfd: security = new Cfd.Cfd(symbol, exchangeHours, quoteCash, symbolProperties); break; case SecurityType.Crypto: security = new Crypto.Crypto(symbol, exchangeHours, quoteCash, symbolProperties); break; default: case SecurityType.Base: security = new Security(symbol, exchangeHours, quoteCash, symbolProperties); break; } // if we're just creating this security and it only has an internal // feed, mark it as non-tradable since the user didn't request this data if (!configList.IsInternalFeed) { security.IsTradable = true; } security.AddData(configList); // invoke the security initializer securityInitializer.Initialize(security, true); // if leverage was specified then apply to security after the initializer has run, parameters of this // method take precedence over the intializer if (leverage > 0) { security.SetLeverage(leverage); } // In live mode, equity assumes specific price variation model if (isLiveMode && security.Type == SecurityType.Equity) { security.PriceVariationModel = new EquityPriceVariationModel(); } return(security); }
/// <summary> /// Creates a new security /// </summary> /// <remarks>Following the obsoletion of Security.Subscriptions, /// both overloads will be merged removing <see cref="SubscriptionDataConfig"/> arguments</remarks> public Security CreateSecurity(Symbol symbol, List <SubscriptionDataConfig> subscriptionDataConfigList, decimal leverage = 0, bool addToSymbolCache = true) { var configList = new SubscriptionDataConfigList(symbol); configList.AddRange(subscriptionDataConfigList); var exchangeHours = _marketHoursDatabase.GetEntry(symbol.ID.Market, symbol, symbol.ID.SecurityType).ExchangeHours; var defaultQuoteCurrency = _cashBook.AccountCurrency; if (symbol.ID.SecurityType == SecurityType.Forex) { defaultQuoteCurrency = symbol.Value.Substring(3); } if (symbol.ID.SecurityType == SecurityType.Crypto && !_symbolPropertiesDatabase.ContainsKey(symbol.ID.Market, symbol, symbol.ID.SecurityType)) { throw new ArgumentException($"Symbol can't be found in the Symbol Properties Database: {symbol.Value}"); } // For Futures Options that don't have a SPDB entry, the futures entry will be used instead. var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties( symbol.ID.Market, symbol, symbol.SecurityType, defaultQuoteCurrency); // add the symbol to our cache if (addToSymbolCache) { SymbolCache.Set(symbol.Value, symbol); } // verify the cash book is in a ready state var quoteCurrency = symbolProperties.QuoteCurrency; if (!_cashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero _cashBook.Add(quoteCurrency, 0, 0); } if (symbol.ID.SecurityType == SecurityType.Forex || symbol.ID.SecurityType == SecurityType.Crypto) { // decompose the symbol into each currency pair string baseCurrency; if (symbol.ID.SecurityType == SecurityType.Forex) { Forex.Forex.DecomposeCurrencyPair(symbol.Value, out baseCurrency, out quoteCurrency); } else { Crypto.Crypto.DecomposeCurrencyPair(symbol, symbolProperties, out baseCurrency, out quoteCurrency); } if (!_cashBook.ContainsKey(baseCurrency)) { // since we have none it's safe to say the conversion is zero _cashBook.Add(baseCurrency, 0, 0); } if (!_cashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero _cashBook.Add(quoteCurrency, 0, 0); } } var quoteCash = _cashBook[symbolProperties.QuoteCurrency]; var cache = _cacheProvider.GetSecurityCache(symbol); Security security; switch (symbol.ID.SecurityType) { case SecurityType.Equity: security = new Equity.Equity(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache); break; case SecurityType.Option: if (addToSymbolCache) { SymbolCache.Set(symbol.Underlying.Value, symbol.Underlying); } security = new Option.Option(symbol, exchangeHours, quoteCash, new Option.OptionSymbolProperties(symbolProperties), _cashBook, _registeredTypes, cache); break; case SecurityType.FutureOption: if (addToSymbolCache) { SymbolCache.Set(symbol.Underlying.Value, symbol.Underlying); } var optionSymbolProperties = new Option.OptionSymbolProperties(symbolProperties); // Future options exercised only gives us one contract back, rather than the // 100x seen in equities. optionSymbolProperties.SetContractUnitOfTrade(1); security = new FutureOption.FutureOption(symbol, exchangeHours, quoteCash, optionSymbolProperties, _cashBook, _registeredTypes, cache); break; case SecurityType.Future: security = new Future.Future(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache); break; case SecurityType.Forex: security = new Forex.Forex(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache); break; case SecurityType.Cfd: security = new Cfd.Cfd(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache); break; case SecurityType.Crypto: security = new Crypto.Crypto(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache); break; default: case SecurityType.Base: security = new Security(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache); break; } // if we're just creating this security and it only has an internal // feed, mark it as non-tradable since the user didn't request this data if (!configList.IsInternalFeed) { security.IsTradable = true; } security.AddData(configList); // invoke the security initializer _securityInitializerProvider.SecurityInitializer.Initialize(security); // if leverage was specified then apply to security after the initializer has run, parameters of this // method take precedence over the intializer if (leverage != Security.NullLeverage) { security.SetLeverage(leverage); } var isNotNormalized = configList.DataNormalizationMode() == DataNormalizationMode.Raw; // In live mode and non normalized data, equity assumes specific price variation model if ((_isLiveMode || isNotNormalized) && security.Type == SecurityType.Equity) { security.PriceVariationModel = new EquityPriceVariationModel(); } return(security); }
/// <summary> /// Initializes a new instance of the <see cref="OptionChainUniverse"/> class /// </summary> /// <param name="option">The canonical option chain security</param> /// <param name="universeSettings">The universe settings to be used for new subscriptions</param> /// <param name="securityInitializer">The security initializer to use on newly created securities</param> public OptionChainUniverse(Option option, UniverseSettings universeSettings, ISecurityInitializer securityInitializer = null) : base(option.SubscriptionDataConfig, securityInitializer) { _option = option; _universeSettings = universeSettings; }
/// <summary> /// Creates a new security /// </summary> /// <remarks>Following the obsoletion of Security.Subscriptions, /// both overloads will be merged removing <see cref="SubscriptionDataConfig"/> arguments</remarks> public Security CreateSecurity(Symbol symbol, List <SubscriptionDataConfig> subscriptionDataConfigList, decimal leverage = 0, bool addToSymbolCache = true) { var configList = new SubscriptionDataConfigList(symbol); configList.AddRange(subscriptionDataConfigList); var exchangeHours = _marketHoursDatabase.GetEntry(symbol.ID.Market, symbol, symbol.ID.SecurityType).ExchangeHours; var defaultQuoteCurrency = _cashBook.AccountCurrency; if (symbol.ID.SecurityType == SecurityType.Forex || symbol.ID.SecurityType == SecurityType.Crypto) { defaultQuoteCurrency = symbol.Value.Substring(3); } var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market, symbol, symbol.ID.SecurityType, defaultQuoteCurrency); // add the symbol to our cache if (addToSymbolCache) { SymbolCache.Set(symbol.Value, symbol); } // verify the cash book is in a ready state var quoteCurrency = symbolProperties.QuoteCurrency; if (!_cashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero _cashBook.Add(quoteCurrency, 0, 0); } if (symbol.ID.SecurityType == SecurityType.Forex || symbol.ID.SecurityType == SecurityType.Crypto) { // decompose the symbol into each currency pair string baseCurrency; Forex.Forex.DecomposeCurrencyPair(symbol.Value, out baseCurrency, out quoteCurrency); if (!_cashBook.ContainsKey(baseCurrency)) { // since we have none it's safe to say the conversion is zero _cashBook.Add(baseCurrency, 0, 0); } if (!_cashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero _cashBook.Add(quoteCurrency, 0, 0); } } var quoteCash = _cashBook[symbolProperties.QuoteCurrency]; Security security; switch (symbol.ID.SecurityType) { case SecurityType.Equity: security = new Equity.Equity(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook); break; case SecurityType.Option: if (addToSymbolCache) { SymbolCache.Set(symbol.Underlying.Value, symbol.Underlying); } security = new Option.Option(symbol, exchangeHours, _cashBook[_cashBook.AccountCurrency], new Option.OptionSymbolProperties(symbolProperties), _cashBook); break; case SecurityType.Future: security = new Future.Future(symbol, exchangeHours, _cashBook[_cashBook.AccountCurrency], symbolProperties, _cashBook); break; case SecurityType.Forex: security = new Forex.Forex(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook); break; case SecurityType.Cfd: security = new Cfd.Cfd(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook); break; case SecurityType.Crypto: security = new Crypto.Crypto(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook); break; default: case SecurityType.Base: security = new Security(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook); break; } // if we're just creating this security and it only has an internal // feed, mark it as non-tradable since the user didn't request this data if (!configList.IsInternalFeed) { security.IsTradable = true; } security.AddData(configList); // invoke the security initializer _securityInitializerProvider.SecurityInitializer.Initialize(security); // if leverage was specified then apply to security after the initializer has run, parameters of this // method take precedence over the intializer if (leverage > 0) { security.SetLeverage(leverage); } // In live mode, equity assumes specific price variation model if (_isLiveMode && security.Type == SecurityType.Equity) { security.PriceVariationModel = new EquityPriceVariationModel(); } return(security); }
public void ReturnsNoneIfNotWarmedUp() { const decimal underlyingPrice = 200m; const decimal underlyingVol = 0.15m; const decimal riskFreeRate = 0.01m; var tz = TimeZones.NewYork; var evaluationDate = new DateTime(2015, 2, 19); var SPY_C_192_Feb19_2016E = Symbol.CreateOption("SPY", Market.USA, OptionStyle.European, OptionRight.Call, 192m, new DateTime(2016, 02, 19)); var SPY_P_192_Feb19_2016E = Symbol.CreateOption("SPY", Market.USA, OptionStyle.European, OptionRight.Put, 192m, new DateTime(2016, 02, 19)); // setting up underlying 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 = underlyingPrice }); equity.VolatilityModel = new DummyVolatilityModel(underlyingVol); // setting up European style call option var contractCall = new OptionContract(SPY_C_192_Feb19_2016E, Symbols.SPY) { Time = evaluationDate }; var optionCall = new Option( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), SPY_C_192_Feb19_2016E, Resolution.Minute, tz, tz, true, false, false), new Cash(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); optionCall.Underlying = equity; // setting up European style put option var contractPut = new OptionContract(SPY_P_192_Feb19_2016E, Symbols.SPY) { Time = evaluationDate }; var optionPut = new Option( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), SPY_P_192_Feb19_2016E, Resolution.Minute, tz, tz, true, false, false), new Cash(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); optionPut.Underlying = equity; // running evaluation var volatilityModel = new Mock <IQLUnderlyingVolatilityEstimator>(); volatilityModel.SetupGet(s => s.IsReady).Returns(false); var priceModel = new QLOptionPriceModel(process => new AnalyticEuropeanEngine(process), volatilityModel.Object, null, null); var resultsCall = priceModel.Evaluate(optionCall, null, contractCall); var resultsPut = priceModel.Evaluate(optionPut, null, contractPut); Assert.AreEqual(OptionPriceModelResult.None, resultsCall); Assert.AreEqual(OptionPriceModelResult.None, resultsCall); }
public void PutCallParityTest() { const decimal underlyingPrice = 200m; const decimal underlyingVol = 0.15m; const decimal riskFreeRate = 0.01m; var tz = TimeZones.NewYork; var evaluationDate = new DateTime(2015, 2, 19); var SPY_C_192_Feb19_2016E = Symbol.CreateOption("SPY", Market.USA, OptionStyle.European, OptionRight.Call, 192m, new DateTime(2016, 02, 19)); var SPY_P_192_Feb19_2016E = Symbol.CreateOption("SPY", Market.USA, OptionStyle.European, OptionRight.Put, 192m, new DateTime(2016, 02, 19)); // setting up underlying 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 = underlyingPrice }); equity.VolatilityModel = new DummyVolatilityModel(underlyingVol); // setting up European style call option var contractCall = new OptionContract(SPY_C_192_Feb19_2016E, Symbols.SPY) { Time = evaluationDate }; var optionCall = new Option( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), SPY_C_192_Feb19_2016E, Resolution.Minute, tz, tz, true, false, false), new Cash(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); optionCall.Underlying = equity; // setting up European style put option var contractPut = new OptionContract(SPY_P_192_Feb19_2016E, Symbols.SPY) { Time = evaluationDate }; var optionPut = new Option( SecurityExchangeHours.AlwaysOpen(tz), new SubscriptionDataConfig(typeof(TradeBar), SPY_P_192_Feb19_2016E, Resolution.Minute, tz, tz, true, false, false), new Cash(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); optionPut.Underlying = equity; // running evaluation var priceModel = OptionPriceModels.BlackScholes(); var resultsCall = priceModel.Evaluate(optionCall, null, contractCall); var resultsPut = priceModel.Evaluate(optionPut, null, contractPut); var callPrice = resultsCall.TheoreticalPrice; var putPrice = resultsPut.TheoreticalPrice; // Put-call parity equation var rightPart = putPrice + underlyingPrice; // no yield var leftPart = callPrice + contractCall.Strike * (decimal)Math.Exp((double)-riskFreeRate); Assert.AreEqual((double)leftPart, (double)rightPart, 0.0001); }
public void GreekApproximationTest() { const decimal price = 20.00m; const decimal underlyingPrice = 190m; const decimal underlyingVol = 0.15m; var tz = TimeZones.NewYork; var evaluationDate = new DateTime(2016, 1, 19); 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 = underlyingPrice }); equity.VolatilityModel = new DummyVolatilityModel(underlyingVol); var contract = new OptionContract(Symbols.SPY_P_192_Feb19_2016, Symbols.SPY) { Time = evaluationDate }; 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(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); optionPut.SetMarketPrice(new Tick { Value = price }); optionPut.Underlying = equity; var priceModel = (QLOptionPriceModel)OptionPriceModels.CrankNicolsonFD(); priceModel.EnableGreekApproximation = false; var results = priceModel.Evaluate(optionPut, null, contract); var greeks = results.Greeks; Assert.AreEqual(greeks.Theta, 0); Assert.AreEqual(greeks.Rho, 0); Assert.AreEqual(greeks.Vega, 0); priceModel = (QLOptionPriceModel)OptionPriceModels.CrankNicolsonFD(); priceModel.EnableGreekApproximation = true; results = priceModel.Evaluate(optionPut, null, contract); greeks = results.Greeks; Assert.LessOrEqual(greeks.Theta, 0); Assert.AreNotEqual(greeks.Rho, 0); Assert.Greater(greeks.Vega, 0); }
public void EvaluationDateWorksInPortfolioTest() { const decimal price = 30.00m; const decimal underlyingPrice = 200m; const decimal underlyingVol = 0.25m; var tz = TimeZones.NewYork; var evaluationDate1 = new DateTime(2015, 2, 19); var evaluationDate2 = new DateTime(2015, 2, 20); 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 = underlyingPrice }); equity.VolatilityModel = new DummyVolatilityModel(underlyingVol); var contract = new OptionContract(Symbols.SPY_C_192_Feb19_2016, Symbols.SPY) { Time = evaluationDate1 }; 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(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); optionCall.SetMarketPrice(new Tick { Value = price }); optionCall.Underlying = equity; var priceModel = OptionPriceModels.BaroneAdesiWhaley(); var results = priceModel.Evaluate(optionCall, null, contract); var callPrice1 = results.TheoreticalPrice; contract.Time = evaluationDate2; results = priceModel.Evaluate(optionCall, null, contract); var callPrice2 = results.TheoreticalPrice; Assert.Greater(callPrice1, callPrice2); }
public void BaroneAdesiWhaleyPortfolioTest() { const decimal price = 30.00m; const decimal underlyingPrice = 200m; const decimal underlyingVol = 0.25m; const decimal riskFreeRate = 0.01m; var tz = TimeZones.NewYork; var evaluationDate = new DateTime(2015, 2, 19); 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 = underlyingPrice }); equity.VolatilityModel = new DummyVolatilityModel(underlyingVol); var contract = new OptionContract(Symbols.SPY_C_192_Feb19_2016, Symbols.SPY) { Time = evaluationDate }; 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(Currencies.USD, 0, 1m), new OptionSymbolProperties(SymbolProperties.GetDefault(Currencies.USD)), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null ); optionCall.SetMarketPrice(new Tick { Value = price }); optionCall.Underlying = equity; var priceModel = OptionPriceModels.BaroneAdesiWhaley(); var results = priceModel.Evaluate(optionCall, null, contract); var callPrice = results.TheoreticalPrice; var impliedVolatility = results.ImpliedVolatility; var greeks = results.Greeks; Assert.Greater(price, callPrice); Assert.Greater(impliedVolatility, underlyingVol); // BS equation (inequality) var rightPart = greeks.Theta + riskFreeRate * underlyingPrice * greeks.Delta + 0.5m * underlyingVol * underlyingVol * underlyingPrice * underlyingPrice * greeks.Gamma; var leftPart = riskFreeRate * callPrice; Assert.GreaterOrEqual(Math.Round(leftPart, 4), Math.Round(rightPart, 4)); }
/// <summary> /// Creates a security and matching configuration. This applies the default leverage if /// leverage is less than or equal to zero. /// This method also add the new symbol mapping to the <see cref="SymbolCache"/> /// </summary> public static Security CreateSecurity(Type factoryType, SecurityPortfolioManager securityPortfolioManager, SubscriptionManager subscriptionManager, SecurityExchangeHours exchangeHours, DateTimeZone dataTimeZone, SymbolProperties symbolProperties, ISecurityInitializer securityInitializer, Symbol symbol, Resolution resolution, bool fillDataForward, decimal leverage, bool extendedMarketHours, bool isInternalFeed, bool isCustomData, bool isLiveMode, bool addToSymbolCache = true, bool isFilteredSubscription = true) { // add the symbol to our cache if (addToSymbolCache) { SymbolCache.Set(symbol.Value, symbol); } //Add the symbol to Data Manager -- generate unified data streams for algorithm events var config = subscriptionManager.Add(factoryType, symbol, resolution, dataTimeZone, exchangeHours.TimeZone, isCustomData, fillDataForward, extendedMarketHours, isInternalFeed, isFilteredSubscription); // verify the cash book is in a ready state var quoteCurrency = symbolProperties.QuoteCurrency; if (!securityPortfolioManager.CashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero securityPortfolioManager.CashBook.Add(quoteCurrency, 0, 0); } if (symbol.ID.SecurityType == SecurityType.Forex) { // decompose the symbol into each currency pair string baseCurrency; Forex.Forex.DecomposeCurrencyPair(symbol.Value, out baseCurrency, out quoteCurrency); if (!securityPortfolioManager.CashBook.ContainsKey(baseCurrency)) { // since we have none it's safe to say the conversion is zero securityPortfolioManager.CashBook.Add(baseCurrency, 0, 0); } if (!securityPortfolioManager.CashBook.ContainsKey(quoteCurrency)) { // since we have none it's safe to say the conversion is zero securityPortfolioManager.CashBook.Add(quoteCurrency, 0, 0); } } var quoteCash = securityPortfolioManager.CashBook[symbolProperties.QuoteCurrency]; Security security; switch (config.SecurityType) { case SecurityType.Equity: security = new Equity.Equity(symbol, exchangeHours, quoteCash, symbolProperties); break; case SecurityType.Option: security = new Option.Option(exchangeHours, config, securityPortfolioManager.CashBook[CashBook.AccountCurrency], symbolProperties); break; case SecurityType.Forex: security = new Forex.Forex(symbol, exchangeHours, quoteCash, symbolProperties); break; case SecurityType.Cfd: security = new Cfd.Cfd(symbol, exchangeHours, quoteCash, symbolProperties); break; default: case SecurityType.Base: security = new Security(symbol, exchangeHours, quoteCash, symbolProperties); break; } // if we're just creating this security and it only has an internal // feed, mark it as non-tradable since the user didn't request this data if (!config.IsInternalFeed) { security.IsTradable = true; } security.AddData(config); // invoke the security initializer securityInitializer.Initialize(security); // if leverage was specified then apply to security after the initializer has run, parameters of this // method take precedence over the intializer if (leverage > 0) { security.SetLeverage(leverage); } // In live mode, equity assumes specific price variation model if (isLiveMode && security.Type == SecurityType.Equity) { security.PriceVariationModel = new EquityPriceVariationModel(); } return(security); }