/// <summary> /// CFD Holding Class constructor /// </summary> /// <param name="security">The CFD security being held</param> public CfdHolding(Cfd security) : base(security) { _cfd = security; }
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(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); 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); 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); var cfd = new Cfd(SecurityExchangeHours.AlwaysOpen(tz), eurCash, new SubscriptionDataConfig(typeof(TradeBar), Symbols.DE10YBEUR, Resolution.Minute, tz, tz, true, false, false), properties); cfd.SetMarketPrice(new Tick { Value = price }); var multiplierTimesConversionRate = properties.ContractMultiplier*eurCash.ConversionRate; 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), }.Select(x => new TestCaseData(x).SetName(x.Name)).ToArray(); }
/// <summary> /// Ensures that we have a data feed to convert this currency into the base currency. /// This will add a subscription at the lowest resolution if one is not found. /// </summary> /// <param name="securities">The security manager</param> /// <param name="subscriptions">The subscription manager used for searching and adding subscriptions</param> /// <param name="marketHoursDatabase">A security exchange hours provider instance used to resolve exchange hours for new subscriptions</param> /// <param name="symbolPropertiesDatabase">A symbol properties database instance</param> /// <param name="marketMap">The market map that decides which market the new security should be in</param> /// <param name="cashBook">The cash book - used for resolving quote currencies for created conversion securities</param> /// <returns>Returns the added currency security if needed, otherwise null</returns> public Security EnsureCurrencyDataFeed(SecurityManager securities, SubscriptionManager subscriptions, MarketHoursDatabase marketHoursDatabase, SymbolPropertiesDatabase symbolPropertiesDatabase, IReadOnlyDictionary<SecurityType, string> marketMap, CashBook cashBook) { if (Symbol == CashBook.AccountCurrency) { SecuritySymbol = QuantConnect.Symbol.Empty; _isBaseCurrency = true; ConversionRate = 1.0m; return null; } if (subscriptions.Count == 0) { throw new InvalidOperationException("Unable to add cash when no subscriptions are present. Please add subscriptions in the Initialize() method."); } // we require a subscription that converts this into the base currency string normal = Symbol + CashBook.AccountCurrency; string invert = CashBook.AccountCurrency + Symbol; foreach (var config in subscriptions.Subscriptions.Where(config => config.SecurityType == SecurityType.Forex || config.SecurityType == SecurityType.Cfd)) { if (config.Symbol.Value == normal) { SecuritySymbol = config.Symbol; return null; } if (config.Symbol.Value == invert) { SecuritySymbol = config.Symbol; _invertRealTimePrice = true; return null; } } // if we've made it here we didn't find a subscription, so we'll need to add one var currencyPairs = Currencies.CurrencyPairs.Select(x => { // allow XAU or XAG to be used as quote currencies, but pairs including them are CFDs var securityType = Symbol.StartsWith("X") ? SecurityType.Cfd : SecurityType.Forex; var market = marketMap[securityType]; return QuantConnect.Symbol.Create(x, securityType, market); }); var minimumResolution = subscriptions.Subscriptions.Select(x => x.Resolution).DefaultIfEmpty(Resolution.Minute).Min(); var objectType = minimumResolution == Resolution.Tick ? typeof (Tick) : typeof (TradeBar); foreach (var symbol in currencyPairs) { if (symbol.Value == normal || symbol.Value == invert) { _invertRealTimePrice = symbol.Value == invert; var marketHoursDbEntry = marketHoursDatabase.GetEntry(symbol.ID.Market, symbol.Value, symbol.ID.SecurityType); var exchangeHours = marketHoursDbEntry.ExchangeHours; // set this as an internal feed so that the data doesn't get sent into the algorithm's OnData events var config = subscriptions.Add(objectType, symbol, minimumResolution, marketHoursDbEntry.DataTimeZone, exchangeHours.TimeZone, false, true, false, true); SecuritySymbol = config.Symbol; var securityType = symbol.ID.SecurityType; Security security; if (securityType == SecurityType.Cfd) { var symbolProperties = symbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market, symbol.Value, securityType); Cash quoteCash; if (!cashBook.TryGetValue(symbolProperties.QuoteCurrency, out quoteCash)) { throw new Exception("Unable to resolve quote cash: " + symbolProperties.QuoteCurrency + ". This is required to add conversion feed: " + symbol.ToString()); } security = new Cfd.Cfd(exchangeHours, quoteCash, config, symbolProperties); } else { security = new Forex.Forex(exchangeHours, this, config); } securities.Add(config.Symbol, security); Log.Trace("Cash.EnsureCurrencyDataFeed(): Adding " + symbol.Value + " for cash " + Symbol + " currency feed"); return security; } } // if this still hasn't been set then it's an error condition throw new ArgumentException(string.Format("In order to maintain cash in {0} you are required to add a subscription for Forex pair {0}{1} or {1}{0}", Symbol, CashBook.AccountCurrency)); }
/// <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}"); } 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; 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.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> /// 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 addToSymbolCache = true) { var sid = symbol.ID; // 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); Security security; switch (config.SecurityType) { case SecurityType.Equity: security = new Equity.Equity(exchangeHours, config, securityPortfolioManager.CashBook[CashBook.AccountCurrency], symbolProperties); break; case SecurityType.Forex: { // decompose the symbol into each currency pair string baseCurrency, quoteCurrency; 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); } security = new Forex.Forex(exchangeHours, securityPortfolioManager.CashBook[quoteCurrency], config, symbolProperties); } break; case SecurityType.Cfd: { 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); } security = new Cfd.Cfd(exchangeHours, securityPortfolioManager.CashBook[quoteCurrency], config, symbolProperties); } break; default: case SecurityType.Base: security = new Security(exchangeHours, config, securityPortfolioManager.CashBook[CashBook.AccountCurrency], symbolProperties); break; } // 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); } return(security); }
/// <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) { // 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; 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> /// Ensures that we have a data feed to convert this currency into the base currency. /// This will add a subscription at the lowest resolution if one is not found. /// </summary> /// <param name="securities">The security manager</param> /// <param name="subscriptions">The subscription manager used for searching and adding subscriptions</param> /// <param name="marketHoursDatabase">A security exchange hours provider instance used to resolve exchange hours for new subscriptions</param> /// <param name="symbolPropertiesDatabase">A symbol properties database instance</param> /// <param name="marketMap">The market map that decides which market the new security should be in</param> /// <param name="cashBook">The cash book - used for resolving quote currencies for created conversion securities</param> /// <returns>Returns the added currency security if needed, otherwise null</returns> public Security EnsureCurrencyDataFeed(SecurityManager securities, SubscriptionManager subscriptions, MarketHoursDatabase marketHoursDatabase, SymbolPropertiesDatabase symbolPropertiesDatabase, IReadOnlyDictionary <SecurityType, string> marketMap, CashBook cashBook) { if (Symbol == CashBook.AccountCurrency) { SecuritySymbol = QuantConnect.Symbol.Empty; _isBaseCurrency = true; ConversionRate = 1.0m; return(null); } if (subscriptions.Count == 0) { throw new InvalidOperationException("Unable to add cash when no subscriptions are present. Please add subscriptions in the Initialize() method."); } // we require a subscription that converts this into the base currency string normal = Symbol + CashBook.AccountCurrency; string invert = CashBook.AccountCurrency + Symbol; foreach (var config in subscriptions.Subscriptions.Where(config => config.SecurityType == SecurityType.Forex || config.SecurityType == SecurityType.Cfd)) { if (config.Symbol.Value == normal) { SecuritySymbol = config.Symbol; return(null); } if (config.Symbol.Value == invert) { SecuritySymbol = config.Symbol; _invertRealTimePrice = true; return(null); } } // if we've made it here we didn't find a subscription, so we'll need to add one var currencyPairs = Currencies.CurrencyPairs.Select(x => { // allow XAU or XAG to be used as quote currencies, but pairs including them are CFDs var securityType = Symbol.StartsWith("X") ? SecurityType.Cfd : SecurityType.Forex; var market = marketMap[securityType]; return(QuantConnect.Symbol.Create(x, securityType, market)); }); var minimumResolution = subscriptions.Subscriptions.Select(x => x.Resolution).DefaultIfEmpty(Resolution.Minute).Min(); var objectType = minimumResolution == Resolution.Tick ? typeof(Tick) : typeof(TradeBar); foreach (var symbol in currencyPairs) { if (symbol.Value == normal || symbol.Value == invert) { _invertRealTimePrice = symbol.Value == invert; var securityType = symbol.ID.SecurityType; var symbolProperties = symbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market, symbol.Value, securityType, Symbol); Cash quoteCash; if (!cashBook.TryGetValue(symbolProperties.QuoteCurrency, out quoteCash)) { throw new Exception("Unable to resolve quote cash: " + symbolProperties.QuoteCurrency + ". This is required to add conversion feed: " + symbol.ToString()); } var marketHoursDbEntry = marketHoursDatabase.GetEntry(symbol.ID.Market, symbol.Value, symbol.ID.SecurityType); var exchangeHours = marketHoursDbEntry.ExchangeHours; // set this as an internal feed so that the data doesn't get sent into the algorithm's OnData events var config = subscriptions.Add(objectType, symbol, minimumResolution, marketHoursDbEntry.DataTimeZone, exchangeHours.TimeZone, false, true, false, true); SecuritySymbol = config.Symbol; Security security; if (securityType == SecurityType.Cfd) { security = new Cfd.Cfd(exchangeHours, quoteCash, config, symbolProperties); } else { security = new Forex.Forex(exchangeHours, this, config, symbolProperties); } securities.Add(config.Symbol, security); Log.Trace("Cash.EnsureCurrencyDataFeed(): Adding " + symbol.Value + " for cash " + Symbol + " currency feed"); return(security); } } // if this still hasn't been set then it's an error condition throw new ArgumentException(string.Format("In order to maintain cash in {0} you are required to add a subscription for Forex pair {0}{1} or {1}{0}", Symbol, CashBook.AccountCurrency)); }
/// <summary> /// Ensures that we have a data feed to convert this currency into the base currency. /// This will add a subscription at the lowest resolution if one is not found. /// </summary> /// <param name="securities">The security manager</param> /// <param name="subscriptions">The subscription manager used for searching and adding subscriptions</param> /// <param name="marketHoursDatabase">A security exchange hours provider instance used to resolve exchange hours for new subscriptions</param> /// <param name="symbolPropertiesDatabase">A symbol properties database instance</param> /// <param name="marketMap">The market map that decides which market the new security should be in</param> /// <param name="cashBook">The cash book - used for resolving quote currencies for created conversion securities</param> /// <param name="changes"></param> /// <returns>Returns the added currency security if needed, otherwise null</returns> public Security EnsureCurrencyDataFeed(SecurityManager securities, SubscriptionManager subscriptions, MarketHoursDatabase marketHoursDatabase, SymbolPropertiesDatabase symbolPropertiesDatabase, IReadOnlyDictionary <SecurityType, string> marketMap, CashBook cashBook, SecurityChanges changes ) { // this gets called every time we add securities using universe selection, // so must of the time we've already resolved the value and don't need to again if (ConversionRateSecurity != null) { return(null); } if (Symbol == CashBook.AccountCurrency) { ConversionRateSecurity = null; _isBaseCurrency = true; ConversionRate = 1.0m; return(null); } // we require a security that converts this into the base currency string normal = Symbol + CashBook.AccountCurrency; string invert = CashBook.AccountCurrency + Symbol; var securitiesToSearch = securities.Select(kvp => kvp.Value) .Concat(changes.AddedSecurities) .Where(s => s.Type == SecurityType.Forex || s.Type == SecurityType.Cfd || s.Type == SecurityType.Crypto); foreach (var security in securitiesToSearch) { if (security.Symbol.Value == normal) { ConversionRateSecurity = security; return(null); } if (security.Symbol.Value == invert) { ConversionRateSecurity = security; _invertRealTimePrice = true; return(null); } } // if we've made it here we didn't find a security, so we'll need to add one // Create a SecurityType to Market mapping with the markets from SecurityManager members var markets = securities.Select(x => x.Key).GroupBy(x => x.SecurityType).ToDictionary(x => x.Key, y => y.First().ID.Market); if (markets.ContainsKey(SecurityType.Cfd) && !markets.ContainsKey(SecurityType.Forex)) { markets.Add(SecurityType.Forex, markets[SecurityType.Cfd]); } if (markets.ContainsKey(SecurityType.Forex) && !markets.ContainsKey(SecurityType.Cfd)) { markets.Add(SecurityType.Cfd, markets[SecurityType.Forex]); } var potentials = Currencies.CurrencyPairs.Select(fx => CreateSymbol(marketMap, fx, markets, SecurityType.Forex)) .Concat(Currencies.CfdCurrencyPairs.Select(cfd => CreateSymbol(marketMap, cfd, markets, SecurityType.Cfd))) .Concat(Currencies.CryptoCurrencyPairs.Select(crypto => CreateSymbol(marketMap, crypto, markets, SecurityType.Crypto))); var minimumResolution = subscriptions.Subscriptions.Select(x => x.Resolution).DefaultIfEmpty(Resolution.Minute).Min(); foreach (var symbol in potentials) { if (symbol.Value == normal || symbol.Value == invert) { _invertRealTimePrice = symbol.Value == invert; var securityType = symbol.ID.SecurityType; var symbolProperties = symbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market, symbol.Value, securityType, Symbol); Cash quoteCash; if (!cashBook.TryGetValue(symbolProperties.QuoteCurrency, out quoteCash)) { throw new Exception("Unable to resolve quote cash: " + symbolProperties.QuoteCurrency + ". This is required to add conversion feed: " + symbol.Value); } var marketHoursDbEntry = marketHoursDatabase.GetEntry(symbol.ID.Market, symbol.Value, symbol.ID.SecurityType); var exchangeHours = marketHoursDbEntry.ExchangeHours; // use the first subscription defined in the subscription manager var type = subscriptions.LookupSubscriptionConfigDataTypes(securityType, minimumResolution, false).First(); var objectType = type.Item1; var tickType = type.Item2; // set this as an internal feed so that the data doesn't get sent into the algorithm's OnData events var config = subscriptions.Add(objectType, tickType, symbol, minimumResolution, marketHoursDbEntry.DataTimeZone, exchangeHours.TimeZone, false, true, false, true); Security security; if (securityType == SecurityType.Cfd) { security = new Cfd.Cfd(exchangeHours, quoteCash, config, symbolProperties, cashBook); } else if (securityType == SecurityType.Crypto) { security = new Crypto.Crypto(exchangeHours, quoteCash, config, symbolProperties, cashBook); } else { security = new Forex.Forex(exchangeHours, quoteCash, config, symbolProperties, cashBook); } ConversionRateSecurity = security; securities.Add(config.Symbol, security); Log.Trace("Cash.EnsureCurrencyDataFeed(): Adding " + symbol.Value + " for cash " + Symbol + " currency feed"); return(security); } } // if this still hasn't been set then it's an error condition throw new ArgumentException(string.Format("In order to maintain cash in {0} you are required to add a subscription for Forex pair {0}{1} or {1}{0}", Symbol, CashBook.AccountCurrency)); }
/// <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 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); } return(security); }