/// <summary> /// Gets the instance of the <see cref="SecurityExchangeHoursProvider"/> class produced by reading in the market hours /// data found in /Data/market-hours/ /// </summary> /// <returns>A <see cref="SecurityExchangeHoursProvider"/> class that represents the data in the market-hours folder</returns> public static SecurityExchangeHoursProvider FromDataFolder() { lock (DataFolderSecurityExchangeHoursProviderLock) { if (DataFolderSecurityExchangeHoursProvider == null) { var directory = Path.Combine(Constants.DataFolder, "market-hours"); var holidays = ReadHolidaysFromDirectory(directory); DataFolderSecurityExchangeHoursProvider = FromCsvFile(Path.Combine(directory, "market-hours-database.csv"), holidays); } } return(DataFolderSecurityExchangeHoursProvider); }
/// <summary> /// Ensures that we have a data feed to conver 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="exchangeHoursProvider">A security exchange hours provider instance used to resolve exchange hours for new subscriptions</param> public void EnsureCurrencyDataFeed(SecurityManager securities, SubscriptionManager subscriptions, SecurityExchangeHoursProvider exchangeHoursProvider) { if (Symbol == CashBook.AccountCurrency) { SecuritySymbol = QuantConnect.Symbol.Empty; _isBaseCurrency = true; ConversionRate = 1.0m; return; } 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)) { if (config.Symbol.Value == normal) { SecuritySymbol = config.Symbol; return; } if (config.Symbol.Value == invert) { SecuritySymbol = config.Symbol; _invertRealTimePrice = true; return; } } // get the market from the first Forex subscription string market = (from config in subscriptions.Subscriptions where config.SecurityType == SecurityType.Forex select config.Market).FirstOrDefault() ?? "fxcm"; // if we've made it here we didn't find a subscription, so we'll need to add one var currencyPairs = Forex.Forex.CurrencyPairs.Select(x => new Symbol(x)); var minimumResolution = subscriptions.Subscriptions.Min(x => x.Resolution); 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 exchangeHours = exchangeHoursProvider.GetExchangeHours(market, symbol, SecurityType.Forex); // 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, SecurityType.Forex, symbol, minimumResolution, market, exchangeHours.TimeZone, true, false, true); var security = new Forex.Forex(this, config, 1m); SecuritySymbol = config.Symbol; securities.Add(config.Symbol, security); Log.Trace("Cash.EnsureCurrencyDataFeed(): Adding " + symbol + " for cash " + Symbol + " currency feed"); return; } } // 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> /// Checks the current subscriptions and adds necessary currency pair feeds to provide real time conversion data /// </summary> /// <param name="securities">The SecurityManager for the algorithm</param> /// <param name="subscriptions">The SubscriptionManager for the algorithm</param> /// <param name="exchangeHoursProvider">A security exchange hours provider instance used to resolve exchange hours for new subscriptions</param> public void EnsureCurrencyDataFeeds(SecurityManager securities, SubscriptionManager subscriptions, SecurityExchangeHoursProvider exchangeHoursProvider) { foreach (var cash in _currencies.Values) { cash.EnsureCurrencyDataFeed(securities, subscriptions, exchangeHoursProvider); } }
/// <summary> /// Creates a security and matching configuration. This applies the default leverage if /// leverage is less than or equal to zero /// </summary> public static Security CreateSecurity(SecurityPortfolioManager securityPortfolioManager, SubscriptionManager subscriptionManager, SecurityExchangeHoursProvider securityExchangeHoursProvider, SecurityType securityType, Symbol symbol, Resolution resolution, string market, bool fillDataForward, decimal leverage, bool extendedMarketHours, bool isInternalFeed, bool isCustomData) { //If it hasn't been set, use some defaults based on the portfolio type: if (leverage <= 0) { switch (securityType) { case SecurityType.Equity: leverage = 2; //Cash Ac. = 1, RegT Std = 2 or PDT = 4. break; case SecurityType.Forex: leverage = 50; break; } } if (market == null) { // set default values if (securityType == SecurityType.Forex) { market = "fxcm"; } else if (securityType == SecurityType.Equity) { market = "usa"; } else { market = "usa"; } } //Add the symbol to Data Manager -- generate unified data streams for algorithm events var exchangeHours = securityExchangeHoursProvider.GetExchangeHours(market, symbol, securityType); var tradeBarType = typeof(TradeBar); var type = resolution == Resolution.Tick ? typeof(Tick) : tradeBarType; var config = subscriptionManager.Add(type, securityType, symbol, resolution, market, exchangeHours.TimeZone, isCustomData, fillDataForward, extendedMarketHours, isInternalFeed); Security security; switch (config.SecurityType) { case SecurityType.Equity: security = new Equity.Equity(exchangeHours, config, leverage); 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, leverage); break; default: case SecurityType.Base: security = new Security(exchangeHours, config, leverage); break; } return(security); }