private Security CreateSecurity() { var config = CreateTradeBarDataConfig(SecurityType.Forex); var security = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), new Cash("abc", 0, 0), config); return(security); }
/// <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> public void EnsureCurrencyDataFeed(SecurityManager securities, SubscriptionManager subscriptions) { if (Symbol == CashBook.AccountCurrency) { _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; for (int i = 0; i < subscriptions.Subscriptions.Count; i++) { var config = subscriptions.Subscriptions[i]; if (config.SecurityType != SecurityType.Forex) { continue; } if (config.Symbol == normal) { _config = config; return; } if (config.Symbol == invert) { _config = config; _invertRealTimePrice = true; return; } } // if we've made it here we didn't find a subscription, so we'll need to add one var currencyPairs = Forex.Forex.CurrencyPairs; var minimumResolution = subscriptions.Subscriptions.Min(x => x.Resolution); var objectType = minimumResolution == Resolution.Tick ? typeof(Tick) : typeof(TradeBar); var isTradeBar = objectType == typeof(TradeBar); foreach (var symbol in currencyPairs) { if (symbol == normal || symbol == invert) { _invertRealTimePrice = symbol == invert; // set this as an internal feed so that the data doesn't get sent into the algorithm's OnData events _config = subscriptions.Add(objectType, SecurityType.Forex, symbol, minimumResolution, true, false, isTradeBar, isTradeBar, true); var security = new Forex.Forex(this, _config, 1m, false); securities.Add(symbol, security); 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> /// Add a new security by all of its properties. /// </summary> /// <param name="symbol">Symbol of the security</param> /// <param name="config">The SubscriptionDataConfig for this symbol</param> /// <param name="leverage">Leverage for this security, default = 1</param> /// <param name="isDynamicallyLoadedData">Use dynamic data</param> public void Add(string symbol, SubscriptionDataConfig config, decimal leverage = 1m, bool isDynamicallyLoadedData = false) { //Upper case sybol: symbol = symbol.ToUpper(); if (symbol != config.Symbol) { throw new ArgumentException("Expected SubscriptionDataConfig for " + symbol + " but received " + config.Symbol); } CheckResolutionCounts(config.Resolution); //If we don't already have this asset, add it to the securities list. if (_securityManager.ContainsKey(symbol)) { //Otherwise, we already have it, just change its resolution: Log.Trace("Algorithm.Securities.Add(): Changing security information will overwrite portfolio"); } switch (config.Security) { case SecurityType.Equity: _securityManager[symbol] = new Equity.Equity(symbol, config, leverage, isDynamicallyLoadedData); break; case SecurityType.Forex: _securityManager[symbol] = new Forex.Forex(symbol, config, leverage, isDynamicallyLoadedData); break; case SecurityType.Base: _securityManager[symbol] = new Security(symbol, config, leverage, isDynamicallyLoadedData); break; } }
public void TotalProfitIsCorrectlyEstimated(string ticker, decimal conversionRate, decimal minimumPriceVariation, int lotSize, decimal entryPrice, decimal pips, int entryQuantity) { // Arrange var timeKeeper = new TimeKeeper(DateTime.Now, TimeZones.NewYork); var symbol = Symbol.Create(ticker, SecurityType.Forex, Market.FXCM); var pairQuoteCurrency = symbol.Value.Substring(startIndex: 3); var cash = new Cash(pairQuoteCurrency, amount: 100000, conversionRate: conversionRate); var subscription = new SubscriptionDataConfig(typeof(QuoteBar), symbol, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, fillForward: true, extendedHours: true, isInternalFeed: true); var pair = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), cash, subscription, new SymbolProperties("", pairQuoteCurrency, 1, minimumPriceVariation, lotSize)); pair.SetLocalTimeKeeper(timeKeeper.GetLocalTimeKeeper(TimeZones.NewYork)); pair.SetFeeModel(new ConstantFeeModel(decimal.Zero)); var forexHolding = new ForexHolding(pair); // Act forexHolding.SetHoldings(entryPrice, entryQuantity); var priceVariation = pips * 10 * minimumPriceVariation; forexHolding.UpdateMarketPrice(entryPrice + priceVariation); pair.SetMarketPrice(new Tick(DateTime.Now, pair.Symbol, forexHolding.Price, forexHolding.Price)); var actualPips = forexHolding.TotalCloseProfitPips(); // Assert Assert.AreEqual(pips, actualPips); }
/// <summary> /// Add a new security by all of its properties. /// </summary> /// <param name="symbol">Symbol of the security</param> /// <param name="type">Type of security: Equity, Forex or Future</param> /// <param name="resolution">Resolution of data required: currently only tick, second and minute for QuantConnect sources.</param> /// <param name="fillDataForward">Return previous bar's data when there is no trading in this bar</param> /// <param name="leverage">Leverage for this security, default = 1</param> /// <param name="extendedMarketHours">Request all the data available, including the extended market hours from 4am - 8pm.</param> /// <param name="isDynamicallyLoadedData">Use dynamic data</param> public void Add(string symbol, SecurityType type = SecurityType.Equity, Resolution resolution = Resolution.Minute, bool fillDataForward = true, decimal leverage = 1, bool extendedMarketHours = false, bool isDynamicallyLoadedData = false) { //Upper case sybol: symbol = symbol.ToUpper(); //Maximum Data Usage: mainly RAM constraints but this has never been fully tested. if (GetResolutionCount(Resolution.Tick) == 30 && resolution == Resolution.Tick) { throw new Exception("We currently only support 30 tick assets at a time."); } if (GetResolutionCount(Resolution.Second) == 100 && resolution == Resolution.Second) { throw new Exception("We currently only support 100 second resolution securities at a time."); } if (GetResolutionCount(Resolution.Minute) == 1000 && resolution == Resolution.Minute) { throw new Exception("We currently only support 1000 minute assets at a time."); } //If we don't already have this asset, add it to the securities list. if (!_securityManager.ContainsKey(symbol)) { switch (type) { case SecurityType.Equity: Add(symbol, new Equity.Equity(symbol, resolution, fillDataForward, leverage, extendedMarketHours, isDynamicallyLoadedData)); break; case SecurityType.Forex: Add(symbol, new Forex.Forex(symbol, resolution, fillDataForward, leverage, extendedMarketHours, isDynamicallyLoadedData)); break; case SecurityType.Base: Add(symbol, new Security(symbol, SecurityType.Base, resolution, fillDataForward, leverage, extendedMarketHours)); break; } } else { //Otherwise, we already have it, just change its resolution: Log.Trace("Algorithm.Securities.Add(): Changing security information will overwrite portfolio"); switch (type) { case SecurityType.Equity: _securityManager[symbol] = new Equity.Equity(symbol, resolution, fillDataForward, leverage, extendedMarketHours); break; case SecurityType.Forex: _securityManager[symbol] = new Forex.Forex(symbol, resolution, fillDataForward, leverage, extendedMarketHours); break; case SecurityType.Base: _securityManager[symbol] = new Security(symbol, SecurityType.Base, resolution, fillDataForward, leverage, extendedMarketHours); break; } } }
private Security CreateSecurity() { var config = CreateTradeBarDataConfig(SecurityType.Forex); var security = new QuantConnect.Securities.Forex.Forex( SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), new Cash("abc", 0, 0), config, SymbolProperties.GetDefault("abc"), ErrorCurrencyConverter.Instance ); return(security); }
/// <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="marketHoursDatabase">A security exchange hours provider instance used to resolve exchange hours for new subscriptions</param> public void EnsureCurrencyDataFeed(SecurityManager securities, SubscriptionManager subscriptions, MarketHoursDatabase marketHoursDatabase) { 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() ?? Market.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(SecurityIdentifier.GenerateForex(x, market), 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 marketHoursDbEntry = marketHoursDatabase.GetEntry(market, symbol, SecurityType.Forex); 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); var security = new Forex.Forex(exchangeHours, this, config, 1m); SecuritySymbol = config.Symbol; securities.Add(config.Symbol, security); Log.Trace("Cash.EnsureCurrencyDataFeed(): Adding " + symbol.ToString() + " 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)); }
/******************************************************** * CONSTRUCTOR/DELEGATE DEFINITIONS *********************************************************/ /// <summary> /// Forex Holding Class /// </summary> /// <param name="security">The forex security being held</param> /// <param name="transactionModel">The transaction model used for the security</param> /// <param name="marginModel">The margin model used for the security</param> public ForexHolding(Forex security, ISecurityTransactionModel transactionModel, ISecurityMarginModel marginModel) : base(security) { _forex = 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> /// 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, 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); 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); break; default: case SecurityType.Base: security = new Security(exchangeHours, config); 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); }
private Security CreateSecurity() { var config = CreateTradeBarDataConfig(SecurityType.Forex, Symbol); var security = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), new Cash("abc", 0, 0), config, 1); return security; }
/// <summary> /// Forex Holding Class /// </summary> /// <param name="security">The forex security being held</param> public ForexHolding(Forex security) : base(security) { _forex = 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 || 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); }
/// <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> /// 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 = string.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 == normal) { SecuritySymbol = config.Symbol; return; } if (config.Symbol == 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; var minimumResolution = subscriptions.Subscriptions.Min(x => x.Resolution); var objectType = minimumResolution == Resolution.Tick ? typeof (Tick) : typeof (TradeBar); foreach (var symbol in currencyPairs) { if (symbol == normal || symbol == invert) { _invertRealTimePrice = symbol == 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(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> /// 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> public void EnsureCurrencyDataFeed(SecurityManager securities, SubscriptionManager subscriptions) { if (Symbol == CashBook.AccountCurrency) { _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; for (int i = 0; i < subscriptions.Subscriptions.Count; i++) { var config = subscriptions.Subscriptions[i]; if (config.SecurityType != SecurityType.Forex) { continue; } if (config.Symbol == normal) { _config = config; return; } if (config.Symbol == invert) { _config = config; _invertRealTimePrice = true; return; } } // if we've made it here we didn't find a subscription, so we'll need to add one var currencyPairs = Forex.Forex.CurrencyPairs; var minimumResolution = subscriptions.Subscriptions.Min(x => x.Resolution); var objectType = minimumResolution == Resolution.Tick ? typeof (Tick) : typeof (TradeBar); var isTradeBar = objectType == typeof (TradeBar); foreach (var symbol in currencyPairs) { if (symbol == normal || symbol == invert) { _invertRealTimePrice = symbol == invert; // set this as an internal feed so that the data doesn't get sent into the algorithm's OnData events _config = subscriptions.Add(objectType, SecurityType.Forex, symbol, minimumResolution, true, false, isTradeBar, isTradeBar, true); var security = new Forex.Forex(this, _config, 1m, false); securities.Add(symbol, security); Log.Trace("Cash.EnsureCurrencyDataFeed(): Adding " + symbol + " for cash " + this.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> /// Forex Holding Class /// </summary> /// <param name="security">The forex security being held</param> /// <param name="currencyConverter">A currency converter instance</param> public ForexHolding(Forex security, ICurrencyConverter currencyConverter) : base(security, currencyConverter) { }
/// <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(); var objectType = minimumResolution == Resolution.Tick ? typeof(Tick) : typeof(QuoteBar); 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; // 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.Quote, symbol, minimumResolution, marketHoursDbEntry.DataTimeZone, exchangeHours.TimeZone, false, true, false, true); Security security; if (securityType == SecurityType.Cfd) { security = new Cfd.Cfd(exchangeHours, quoteCash, config, symbolProperties); } else if (securityType == SecurityType.Crypto) { security = new Crypto.Crypto(exchangeHours, quoteCash, config, symbolProperties); } else { security = new Forex.Forex(exchangeHours, quoteCash, config, symbolProperties); } 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 /// </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); }
/// <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 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(SecurityPortfolioManager securityPortfolioManager, SubscriptionManager subscriptionManager, MarketHoursDatabase marketHoursDatabase, Symbol symbol, Resolution resolution, bool fillDataForward, decimal leverage, bool extendedMarketHours, bool isInternalFeed, bool isCustomData) { var sid = symbol.ID; //If it hasn't been set, use some defaults based on the security type if (leverage <= 0) { if (sid.SecurityType == SecurityType.Equity) { leverage = 2; } else if (sid.SecurityType == SecurityType.Forex) { leverage = 50; } // default to 1 for everything else else { leverage = 1m; } } // add the symbol to our cache SymbolCache.Set(symbol.Value, symbol); var market = sid.Market; var securityType = sid.SecurityType; //Add the symbol to Data Manager -- generate unified data streams for algorithm events var marketHoursDbEntry = marketHoursDatabase.GetEntry(market, symbol, securityType); var exchangeHours = marketHoursDbEntry.ExchangeHours; var tradeBarType = typeof(TradeBar); var type = resolution == Resolution.Tick ? typeof(Tick) : tradeBarType; var config = subscriptionManager.Add(type, symbol, resolution, marketHoursDbEntry.DataTimeZone, exchangeHours.TimeZone, isCustomData, fillDataForward: fillDataForward, extendedMarketHours: extendedMarketHours, isInternalFeed: 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); }
/// <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, quoteCash, 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> /// Add a new security by all of its properties. /// </summary> /// <param name="symbol">Symbol of the security</param> /// <param name="type">Type of security: Equity, Forex or Future</param> /// <param name="resolution">Resolution of data required: currently only tick, second and minute for QuantConnect sources.</param> /// <param name="fillDataForward">Return previous bar's data when there is no trading in this bar</param> /// <param name="leverage">Leverage for this security, default = 1</param> /// <param name="extendedMarketHours">Request all the data available, including the extended market hours from 4am - 8pm.</param> /// <param name="isDynamicallyLoadedData">Use dynamic data</param> public void Add(string symbol, SecurityType type = SecurityType.Equity, Resolution resolution = Resolution.Minute, bool fillDataForward = true, decimal leverage = 1, bool extendedMarketHours = false, bool isDynamicallyLoadedData = false) { //Upper case sybol: symbol = symbol.ToUpper(); //Maximum Data Usage: mainly RAM constraints but this has never been fully tested. if (GetResolutionCount(Resolution.Tick) >= _tickLimit && resolution == Resolution.Tick) { throw new Exception("We currently only support " + _tickLimit + " tick assets at a time due to physical memory limitations."); } if (GetResolutionCount(Resolution.Second) >= _secondLimit && resolution == Resolution.Second) { throw new Exception("We currently only support " + _secondLimit + " second resolution securities at a time due to physical memory limitations."); } if (GetResolutionCount(Resolution.Minute) >= _minuteLimit && resolution == Resolution.Minute) { throw new Exception("We currently only support " + _minuteLimit + " minute assets at a time due to physical memory limitations."); } //Current ram usage: this especially applies during live trading where micro servers have limited resources: var currentEstimatedRam = GetRamEstimate(GetResolutionCount(Resolution.Minute), GetResolutionCount(Resolution.Second), GetResolutionCount(Resolution.Tick)); if (currentEstimatedRam > _maxRamEstimate) { throw new Exception("We estimate you will run out of memory (" + currentEstimatedRam + "mb of " + _maxRamEstimate + "mb physically available). Please reduce the number of symbols you're analysing or if in live trading upgrade your server to allow more memory."); } //If we don't already have this asset, add it to the securities list. if (!_securityManager.ContainsKey(symbol)) { switch (type) { case SecurityType.Equity: Add(symbol, new Equity.Equity(symbol, resolution, fillDataForward, leverage, extendedMarketHours, isDynamicallyLoadedData)); break; case SecurityType.Forex: Add(symbol, new Forex.Forex(symbol, resolution, fillDataForward, leverage, extendedMarketHours, isDynamicallyLoadedData)); break; case SecurityType.Base: Add(symbol, new Security(symbol, SecurityType.Base, resolution, fillDataForward, leverage, extendedMarketHours, isDynamicallyLoadedData)); break; } } else { //Otherwise, we already have it, just change its resolution: Log.Trace("Algorithm.Securities.Add(): Changing security information will overwrite portfolio"); switch (type) { case SecurityType.Equity: _securityManager[symbol] = new Equity.Equity(symbol, resolution, fillDataForward, leverage, extendedMarketHours); break; case SecurityType.Forex: _securityManager[symbol] = new Forex.Forex(symbol, resolution, fillDataForward, leverage, extendedMarketHours); break; case SecurityType.Base: _securityManager[symbol] = new Security(symbol, SecurityType.Base, resolution, fillDataForward, leverage, extendedMarketHours, isDynamicallyLoadedData); break; } } }
/// <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); }
/// <summary> /// Forex Holding Class /// </summary> /// <param name="security">The forex security being held</param> /// <param name="transactionModel">The transaction model used for the security</param> /// <param name="marginModel">The margin model used for the security</param> public ForexHolding(Forex security, ISecurityTransactionModel transactionModel, ISecurityMarginModel marginModel) : base(security) { _forex = security; }
public override void ProcessFill(SecurityPortfolioManager portfolio, Security security, OrderEvent fill) { // split the symbol into base and quote currencies string baseCurrency; string quoteCurrency; Forex.DecomposeCurrencyPair(security.Symbol, out baseCurrency, out quoteCurrency); // e.g. EUR GBP // EUR var baseCash = portfolio.CashBook[baseCurrency]; // GBP var quoteCash = portfolio.CashBook[quoteCurrency]; //Get the required information from the vehicle this order will affect var closedPosition = false; var isLong = security.Holdings.IsLong; var isShort = security.Holdings.IsShort; //Make local decimals to avoid any rounding errors from int multiplication var averageHoldingsPrice = security.Holdings.AveragePrice; var quantityHoldings = (decimal)security.Holdings.Quantity; var absoluteHoldingsQuantity = security.Holdings.AbsoluteQuantity; var lastTradeProfit = 0m; try { //Update the Vehicle approximate total sales volume. var saleValueInQuoteCurrency = fill.FillPrice * Convert.ToDecimal(fill.AbsoluteFillQuantity); var saleValue = saleValueInQuoteCurrency * quoteCash.ConversionRate; security.Holdings.AddNewSale(saleValue); //Get the Fee for this Order - Update the Portfolio Cash Balance: Remove Transaction Fees. var order = new MarketOrder(security.Symbol, fill.FillQuantity, security.Time, type: security.Type) { Price = fill.FillPrice }; var feeThisOrder = Math.Abs(security.TransactionModel.GetOrderFee(security, order)); security.Holdings.AddNewFee(feeThisOrder); portfolio.CashBook[CashBook.AccountCurrency].Quantity -= feeThisOrder; baseCash.Quantity += fill.FillQuantity; quoteCash.Quantity -= fill.FillQuantity * fill.FillPrice; //Calculate & Update the Last Trade Profit; if (isLong && fill.Direction == OrderDirection.Sell) { //Closing up a long position if (quantityHoldings >= fill.AbsoluteFillQuantity) { //Closing up towards Zero -- this is in the quote currency lastTradeProfit = (fill.FillPrice - averageHoldingsPrice) * fill.AbsoluteFillQuantity; } else { //Closing up to Neg/Short Position (selling more than we have) - Only calc profit on the stock we have to sell. lastTradeProfit = (fill.FillPrice - averageHoldingsPrice) * quantityHoldings; } closedPosition = true; } else if (isShort && fill.Direction == OrderDirection.Buy) { //Closing up a short position. if (absoluteHoldingsQuantity >= fill.FillQuantity) { //Reducing the stock we have, and enough stock on hand to process order. lastTradeProfit = (averageHoldingsPrice - fill.FillPrice) * fill.AbsoluteFillQuantity; } else { //Increasing stock holdings, short to positive through zero, but only calc profit on stock we Buy. lastTradeProfit = (averageHoldingsPrice - fill.FillPrice) * absoluteHoldingsQuantity; } closedPosition = true; } if (closedPosition) { // convert the compute profit into the account currency lastTradeProfit *= quoteCash.ConversionRate; //Update Vehicle Profit Tracking: security.Holdings.AddNewProfit(lastTradeProfit); security.Holdings.SetLastTradeProfit(lastTradeProfit); portfolio.AddTransactionRecord(security.Time, lastTradeProfit - 2 * feeThisOrder); } //UPDATE HOLDINGS QUANTITY, AVG PRICE: //Currently NO holdings. The order is ALL our holdings. if (quantityHoldings == 0) { //First transaction just subtract order from cash and set our holdings: averageHoldingsPrice = fill.FillPrice; quantityHoldings = fill.FillQuantity; } else if (isLong) { //If we're currently LONG on the stock. switch (fill.Direction) { case OrderDirection.Buy: //Update the Holding Average Price: Total Value / Total Quantity: averageHoldingsPrice = ((averageHoldingsPrice * quantityHoldings) + (fill.FillQuantity * fill.FillPrice)) / (quantityHoldings + fill.FillQuantity); //Add the new quantity: quantityHoldings += fill.FillQuantity; break; case OrderDirection.Sell: quantityHoldings += fill.FillQuantity; //+ a short = a subtraction if (quantityHoldings < 0) { //If we've now passed through zero from selling stock: new avg price: averageHoldingsPrice = fill.FillPrice; } else if (quantityHoldings == 0) { averageHoldingsPrice = 0; } break; } } else if (isShort) { //We're currently SHORTING the stock: What is the new position now? switch (fill.Direction) { case OrderDirection.Buy: //Buying when we're shorting moves to close position: quantityHoldings += fill.FillQuantity; if (quantityHoldings > 0) { //If we were short but passed through zero, new average price is what we paid. The short position was closed. averageHoldingsPrice = fill.FillPrice; } else if (quantityHoldings == 0) { averageHoldingsPrice = 0; } break; case OrderDirection.Sell: //We are increasing a Short position: //E.g. -100 @ $5, adding -100 @ $10: Avg: $7.5 // dAvg = (-500 + -1000) / -200 = 7.5 averageHoldingsPrice = ((averageHoldingsPrice * quantityHoldings) + (fill.FillQuantity * fill.FillPrice)) / (quantityHoldings + fill.FillQuantity); quantityHoldings += fill.FillQuantity; break; } } } catch (Exception err) { Log.Error("ForexPortfolioManager.ProcessFill(orderEvent): " + err.Message); } //Set the results back to the vehicle. security.Holdings.SetHoldings(averageHoldingsPrice, Convert.ToInt32(quantityHoldings)); }
/// <summary> /// Forex Holding Class /// </summary> /// <param name="security">The forex security being held</param> public ForexHolding(Forex security) : base(security) { }