public void EnsureCurrencyDataFeedDoesNotMarkIsCurrencyDataFeedForExistantSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(); var dataManager = new DataManagerStub(TimeKeeper); subscriptions.SetDataManager(dataManager); var securities = new SecurityManager(TimeKeeper); securities.Add( Symbols.USDJPY, new Security( SecurityExchangeHours, subscriptions.Add(Symbols.USDJPY, Resolution.Minute, TimeZone, TimeZone), new Cash(cashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(cashBook.AccountCurrency), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ) ); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketMap, SecurityChanges.None, dataManager.SecurityService, cashBook.AccountCurrency); var config = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsFalse(config.IsInternalFeed); }
public void UpdateModifiesConversionRate() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("GBP", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("GBP", cash); var subscriptions = new SubscriptionManager(); subscriptions.SetDataManager(new DataManagerStub(TimeKeeper)); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.GBPUSD, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.GBPUSD, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); // we need to get subscription index cash.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); var last = 1.5m; cash.Update(new Tick(DateTime.Now, Symbols.GBPUSD, last, last * 1.009m, last * 0.009m)); // jpy is inverted, so compare on the inverse Assert.AreEqual(last, cash.ConversionRate); }
/// <summary> /// Creates the brokerage under test and connects it /// </summary> /// <param name="orderProvider"></param> /// <param name="securityProvider"></param> /// <returns></returns> protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider) { var securities = new SecurityManager(new TimeKeeper(DateTime.UtcNow, new[] { TimeZones.NewYork })); securities.Add(Symbol, CreateSecurity(Symbol)); var transactions = new SecurityTransactionManager(null, securities); transactions.SetOrderProcessor(new FakeOrderProcessor()); var algorithm = new Mock <IAlgorithm>(); algorithm.Setup(a => a.Transactions).Returns(transactions); algorithm.Setup(a => a.BrokerageModel).Returns(new BitfinexBrokerageModel(AccountType.Margin)); algorithm.Setup(a => a.Portfolio).Returns(new SecurityPortfolioManager(securities, transactions)); var priceProvider = new Mock <IPriceProvider>(); priceProvider.Setup(a => a.GetLastPrice(It.IsAny <Symbol>())).Returns(1.234m); return(new BitfinexBrokerage( Config.Get("bitfinex-url", "wss://api.bitfinex.com/ws"), Config.Get("bitfinex-rest", "https://api.bitfinex.com"), Config.Get("bitfinex-api-key"), Config.Get("bitfinex-api-secret"), algorithm.Object, priceProvider.Object )); }
public void EnsureCurrencyDataFeedChecksSecurityChangesForSecurity() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(); var dataManager = new DataManagerStub(TimeKeeper); subscriptions.SetDataManager(dataManager); var abcConfig = subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add( Symbols.SPY, new Security( SecurityExchangeHours, abcConfig, new Cash(cashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(cashBook.AccountCurrency), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ) ); var usdjpy = new Security(Symbols.USDJPY, SecurityExchangeHours, new Cash("JPY", 0, 0), SymbolProperties.GetDefault("JPY"), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache()); var changes = SecurityChangesTests.CreateNonInternal(new[] { usdjpy }, Enumerable.Empty <Security>()); var addedSecurities = cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketMap, changes, dataManager.SecurityService, cashBook.AccountCurrency); // the security exists in SecurityChanges so it is NOT added to the security manager or subscriptions // this security will be added by the algorithm manager Assert.True(addedSecurities == null || addedSecurities.Count == 0); }
public void NotifiesWhenSecurityAdded() { var timeKeeper = new TimeKeeper(new DateTime(2015, 12, 07)); var manager = new SecurityManager(timeKeeper); var security = new Security( SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), CreateTradeBarConfig(), new Cash(Currencies.USD, 0, 1m), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ); manager.CollectionChanged += (sender, args) => { if (args.NewItems.OfType <object>().Single() != security) { Assert.Fail("Expected args.NewItems to have exactly one element equal to security"); } else { Assert.IsTrue(args.Action == NotifyCollectionChangedAction.Add); Assert.Pass(); } }; manager.Add(security.Symbol, security); }
public void EnsureCurrencyDataFeedsAddsSubscriptionAtMinimumResolution() { const int quantity = 100; const decimal conversionRate = 1 / 100m; const Resolution minimumResolution = Resolution.Second; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add("ABC", new Security(SecurityExchangeHours, subscriptions.Add(SecurityType.Equity, "ABC", Resolution.Minute, "usa", TimeZone), 1m)); securities.Add("BCD", new Security(SecurityExchangeHours, subscriptions.Add(SecurityType.Forex, "BCD", minimumResolution, "fxcm", TimeZone), 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions, SecurityExchangeHoursProvider.AlwaysOpen); Assert.AreEqual(minimumResolution, subscriptions.Subscriptions.Single(x => x.Symbol == "USDJPY").Resolution); }
public void EnsureInternalCurrencyDataFeedsForNonUsdQuoteCurrencyGetAdded() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cashJPY = new Cash("JPY", quantity, conversionRate); var cashGBP = new Cash("GBP", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cashJPY); cashBook.Add("GBP", cashGBP); var symbol = Symbol.Create("GBPJPY", SecurityType.Forex, Market.FXCM); var subscriptions = new SubscriptionManager(AlgorithmSettings, TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(symbol, new Security(SecurityExchangeHours, subscriptions.Add(symbol, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cashJPY.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); var config1 = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsTrue(config1.IsInternalFeed); cashGBP.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); var config2 = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.GBPUSD); Assert.IsTrue(config2.IsInternalFeed); }
public void EnsureCurrencyDataFeedAddsSubscription() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(); subscriptions.SetDataManager(new DataManagerStub(TimeKeeper)); var abcConfig = subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add( Symbols.SPY, new Security( SecurityExchangeHours, abcConfig, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency), ErrorCurrencyConverter.Instance ) ); cash.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, SecurityChanges.None); Assert.AreEqual(1, subscriptions.Subscriptions.Count(x => x.Symbol == Symbols.USDJPY)); Assert.AreEqual(1, securities.Values.Count(x => x.Symbol == Symbols.USDJPY)); }
public void EnsureCurrencyDataFeedMarksIsCurrencyDataFeedForNewSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(); var dataManager = new DataManagerStub(TimeKeeper); subscriptions.SetDataManager(dataManager); var securities = new SecurityManager(TimeKeeper); securities.Add( Symbols.EURUSD, new Security( SecurityExchangeHours, subscriptions.Add(Symbols.EURUSD, Resolution.Minute, TimeZone, TimeZone), new Cash(cashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(cashBook.AccountCurrency), ErrorCurrencyConverter.Instance ) ); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketMap, SecurityChanges.None, dataManager.SecurityService, cashBook.AccountCurrency); var config = subscriptions.SubscriptionDataConfigService.GetSubscriptionDataConfigs(Symbols.USDJPY, includeInternalConfigs: true).Single(); Assert.IsTrue(config.IsInternalFeed); }
public void EnsureCurrencyDataFeedChecksSecurityChangesForSecurity() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(); subscriptions.SetDataManager(new DataManagerStub(TimeKeeper)); var abcConfig = subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add( Symbols.SPY, new Security( SecurityExchangeHours, abcConfig, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency), ErrorCurrencyConverter.Instance ) ); var usdjpy = new Security(Symbols.USDJPY, SecurityExchangeHours, new Cash("JPY", 0, 0), SymbolProperties.GetDefault("JPY"), ErrorCurrencyConverter.Instance); var changes = new SecurityChanges(new[] { usdjpy }, Enumerable.Empty <Security>()); var addedSecurity = cash.EnsureCurrencyDataFeed(securities, subscriptions, AlwaysOpenMarketHoursDatabase, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook, changes); // the security exists in SecurityChanges so it is NOT added to the security manager or subscriptions // this security will be added by the algorithm manager Assert.IsNull(addedSecurity); }
private Security InitializeTest(DateTime reference, out SecurityPortfolioManager portfolio) { var security = new Security( SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), CreateTradeBarConfig(), new Cash(Currencies.USD, 0, 1m), SymbolProperties.GetDefault(Currencies.USD), ErrorCurrencyConverter.Instance ); security.SetMarketPrice(new Tick { Value = 100 }); var timeKeeper = new TimeKeeper(reference); var securityManager = new SecurityManager(timeKeeper); securityManager.Add(security); var transactionManager = new SecurityTransactionManager(null, securityManager); portfolio = new SecurityPortfolioManager(securityManager, transactionManager); portfolio.SetCash(Currencies.USD, 100 * 1000m, 1m); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(100 * 1000m, portfolio.CashBook[Currencies.USD].Amount); return(security); }
public void UpdateModifiesConversionRate() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("GBP", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add("GBPUSD", new Security(SecurityExchangeHours.AlwaysOpen, subscriptions.Add(SecurityType.Forex, "GBPUSD", Resolution.Minute, "fxcm", TimeZones.NewYork), 1m)); // we need to get subscription index cash.EnsureCurrencyDataFeed(securities, subscriptions, SecurityExchangeHoursProvider.AlwaysOpen); var last = 1.5m; var data = new Dictionary <int, List <BaseData> >(); data.Add(0, new List <BaseData> { new Tick(DateTime.Now, "GBPUSD", last, last * 1.009m, last * 0.009m) }); cash.Update(data); // jpy is inverted, so compare on the inverse Assert.AreEqual(last, cash.ConversionRate); }
public void EnsureCurrencyDataFeedAddsSubscription() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(); var dataManager = new DataManagerStub(TimeKeeper); subscriptions.SetDataManager(dataManager); var abcConfig = subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add( Symbols.SPY, new Security( SecurityExchangeHours, abcConfig, new Cash(Currencies.USD, 0, 1m), SymbolProperties.GetDefault(cashBook.AccountCurrency), cashBook, RegisteredSecurityDataTypesProvider.Null, new SecurityCache())); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketMap, SecurityChanges.None, dataManager.SecurityService, cashBook.AccountCurrency); Assert.AreEqual(1, subscriptions.SubscriptionDataConfigService.GetSubscriptionDataConfigs(Symbols.USDJPY, includeInternalConfigs: true).Count); Assert.AreEqual(1, securities.Values.Count(x => x.Symbol == Symbols.USDJPY)); }
public static SecurityManager CreateHoldings(decimal quantity) { var manager = new SecurityManager(new TimeKeeper(DateTime.UtcNow)); manager.Add(GetSecurity(123, quantity)); return(manager); }
public void EnsureCurrencyDataFeedsAddsSubscriptionAtMinimumResolution() { const int quantity = 100; const decimal conversionRate = 1 / 100m; const Resolution minimumResolution = Resolution.Second; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(); var dataManager = new DataManagerStub(TimeKeeper); subscriptions.SetDataManager(dataManager); var securities = new SecurityManager(TimeKeeper); securities.Add( Symbols.SPY, new Security( SecurityExchangeHours, subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone), new Cash(cashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(cashBook.AccountCurrency), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ) ); securities.Add( Symbols.EURUSD, new Security( SecurityExchangeHours, subscriptions.Add(Symbols.EURUSD, minimumResolution, TimeZone, TimeZone), new Cash(cashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(cashBook.AccountCurrency), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ) ); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketMap, SecurityChanges.None, dataManager.SecurityService, cashBook.AccountCurrency); Assert.AreEqual(minimumResolution, subscriptions.SubscriptionDataConfigService.GetSubscriptionDataConfigs(Symbols.USDJPY, includeInternalConfigs: true).Single().Resolution); }
public void EnsureCurrencyDataFeedsAddsSubscriptionAtMinimumResolution() { const int quantity = 100; const decimal conversionRate = 1 / 100m; const Resolution minimumResolution = Resolution.Second; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.SPY, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities.Add(Symbols.EURUSD, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.EURUSD, minimumResolution, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook); Assert.AreEqual(minimumResolution, subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY).Resolution); }
private static DateRules GetDateRules() { var timeKeeper = new TimeKeeper(DateTime.Today, new List <DateTimeZone>()); var manager = new SecurityManager(timeKeeper); var securityExchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.USA, null, SecurityType.Equity); var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, true, false, false); manager.Add(Symbols.SPY, new Security(securityExchangeHours, config, 1)); var rules = new DateRules(manager); return(rules); }
private static TimeRules GetTimeRules(DateTimeZone dateTimeZone) { var timeKeeper = new TimeKeeper(DateTime.Today, new List <DateTimeZone>()); var manager = new SecurityManager(timeKeeper); var securityExchangeHours = SecurityExchangeHoursProvider.FromDataFolder().GetExchangeHours("usa", null, SecurityType.Equity); var config = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, "SPY", Resolution.Daily, "usa", securityExchangeHours.TimeZone, true, false, false); manager.Add("SPY", new Security(securityExchangeHours, config, 1, false)); var rules = new TimeRules(manager, dateTimeZone); return(rules); }
public void TestCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, see TestData\CashTestingStrategy.csv // also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_cash_fills.xml"; const string equityFile = "TestData\\test_cash_equity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get <int>("OrderId"), SymbolMap[x.Get <string>("Symbol")], DateTime.MinValue, x.Get <OrderStatus>("Status"), x.Get <int>("FillQuantity") < 0 ? OrderDirection.Sell : x.Get <int>("FillQuantity") > 0 ? OrderDirection.Buy : OrderDirection.Hold, x.Get <decimal>("FillPrice"), x.Get <int>("FillQuantity"), 0m) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); var security = new Security(SecurityExchangeHours, subscriptions.Add(CASH, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); security.SetLeverage(10m); securities.Add(CASH, security); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork)); // the value of 'CASH' increments for each fill, the original test algo did this monthly // the time doesn't really matter though security.SetMarketPrice(new IndicatorDataPoint(CASH, time, i + 1)); portfolio.ProcessFill(fill); Assert.AreEqual(equity[i + 1], portfolio.TotalPortfolioValue, "Failed on " + i); } }
public void EnsureCurrencyDataFeedsForNonUsdQuoteCurrencyDoNotGetAddedToSymbolCache() { SymbolCache.Clear(); const int quantity = 100; const decimal conversionRate = 1 / 100m; var cashJPY = new Cash("JPY", quantity, conversionRate); var cashGBP = new Cash("GBP", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cashJPY); cashBook.Add("GBP", cashGBP); var symbol = Symbol.Create("GBPJPY", SecurityType.Forex, Market.FXCM); var subscriptions = new SubscriptionManager(); var dataManager = new DataManagerStub(TimeKeeper); subscriptions.SetDataManager(dataManager); var securities = new SecurityManager(TimeKeeper); securities.Add( symbol, new Security( SecurityExchangeHours, subscriptions.Add(symbol, Resolution.Minute, TimeZone, TimeZone), new Cash(cashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(cashBook.AccountCurrency), ErrorCurrencyConverter.Instance, RegisteredSecurityDataTypesProvider.Null, new SecurityCache() ) ); Assert.IsNotNull( cashGBP.EnsureCurrencyDataFeed( securities, subscriptions, MarketMap, SecurityChanges.None, dataManager.SecurityService, cashBook.AccountCurrency)); Assert.IsNotNull( cashJPY.EnsureCurrencyDataFeed(securities, subscriptions, MarketMap, SecurityChanges.None, dataManager.SecurityService, cashBook.AccountCurrency)); Assert.IsFalse(SymbolCache.TryGetSymbol("USDJPY", out symbol)); Assert.IsFalse(SymbolCache.TryGetSymbol("GBPUSD", out symbol)); }
private static TimeRules GetTimeRules(DateTimeZone dateTimeZone) { var timeKeeper = new TimeKeeper(DateTime.Today, new List <DateTimeZone>()); var manager = new SecurityManager(timeKeeper); var marketHourDbEntry = MarketHoursDatabase.FromDataFolder().GetEntry(Market.USA, null, SecurityType.Equity); var securityExchangeHours = marketHourDbEntry.ExchangeHours; var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Daily, marketHourDbEntry.DataTimeZone, securityExchangeHours.TimeZone, true, false, false); manager.Add(Symbols.SPY, new Security(securityExchangeHours, config)); var rules = new TimeRules(manager, dateTimeZone); return(rules); }
public void TestCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, see TestData\CashTestingStrategy.csv // also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_cash_fills.xml"; const string equityFile = "TestData\\test_cash_equity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get<int>("OrderId"), SymbolMap[x.Get<string>("Symbol")], DateTime.MinValue, x.Get<OrderStatus>("Status"), x.Get<int>("FillQuantity") < 0 ? OrderDirection.Sell : x.Get<int>("FillQuantity") > 0 ? OrderDirection.Buy : OrderDirection.Hold, x.Get<decimal>("FillPrice"), x.Get<int>("FillQuantity"), 0m) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); var security = new Security(SecurityExchangeHours, subscriptions.Add(CASH, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); security.SetLeverage(10m); securities.Add(CASH, security); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork)); // the value of 'CASH' increments for each fill, the original test algo did this monthly // the time doesn't really matter though security.SetMarketPrice(new IndicatorDataPoint(CASH, time, i + 1)); portfolio.ProcessFill(fill); Assert.AreEqual(equity[i + 1], portfolio.TotalPortfolioValue, "Failed on " + i); } }
public void EnsureCurrencyDataFeedAddsSubscription() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var abcConfig = subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.SPY, new Security(SecurityExchangeHours, abcConfig, 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen); Assert.AreEqual(1, subscriptions.Subscriptions.Count(x => x.Symbol == Symbols.USDJPY)); Assert.AreEqual(1, securities.Values.Count(x => x.Symbol == Symbols.USDJPY)); }
public void EquitySellAppliesSettlementCorrectly() { var securityExchangeHours = SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); securities.Add(Symbols.AAPL, new QuantConnect.Securities.Equity.Equity(securityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SettlementModel = new DelayedSettlementModel(3, TimeSpan.FromHours(8)); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Buy on Monday var timeUtc = new DateTime(2015, 10, 26, 15, 30, 0); var orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.AAPL, 10, timeUtc)); var fill = new OrderEvent(1, Symbols.AAPL, timeUtc, OrderStatus.Filled, OrderDirection.Buy, 100, 10, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(10, security.Holdings.Quantity); Assert.AreEqual(-1, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Sell on Tuesday, cash unsettled timeUtc = timeUtc.AddDays(1); orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.AAPL, 10, timeUtc)); fill = new OrderEvent(2, Symbols.AAPL, timeUtc, OrderStatus.Filled, OrderDirection.Sell, 100, -10, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday, still cash unsettled timeUtc = timeUtc.AddDays(2); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Friday at open, cash settled var marketOpen = securityExchangeHours.MarketHours[timeUtc.DayOfWeek].GetMarketOpen(TimeSpan.Zero, false); Assert.IsTrue(marketOpen.HasValue); timeUtc = timeUtc.AddDays(1).Date.Add(marketOpen.Value).ConvertToUtc(securityExchangeHours.TimeZone); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
public void TestCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, see TestData\CashTestingStrategy.csv // also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_cash_fills.xml"; const string equityFile = "TestData\\test_cash_equity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get <int>("OrderId"), x.Get <string>("Symbol"), x.Get <OrderStatus>("Status"), x.Get <decimal>("FillPrice"), x.Get <int>("FillQuantity")) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add("CASH", new Security(SecurityExchangeHours.AlwaysOpen, subscriptions.Add(SecurityType.Base, "CASH", Resolution.Daily, "usa", TimeZones.NewYork), leverage: 10)); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); // the value of 'CASH' increments for each fill, the original test algo did this monthly // the time doesn't really matter though var updateData = new Dictionary <int, List <BaseData> >(); updateData.Add(0, new List <BaseData> { new IndicatorDataPoint("CASH", time, i + 1) }); securities.Update(time, updateData); portfolio.ProcessFill(fill); Assert.AreEqual(equity[i + 1], portfolio.TotalPortfolioValue, "Failed on " + i); } }
public void EnsureCurrencyDataFeedAddsSubscription() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var abcConfig = subscriptions.Add(SecurityType.Equity, "ABC", Resolution.Minute, "fxcm", TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add("ABC", new Security(SecurityExchangeHours, abcConfig, 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions, SecurityExchangeHoursProvider.AlwaysOpen); Assert.AreEqual(1, subscriptions.Subscriptions.Count(x => x.Symbol == "USDJPY")); Assert.AreEqual(1, securities.Values.Count(x => x.Symbol == "USDJPY")); }
public void EnsureCurrencyDataFeedAddsSubscription() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var abcConfig = subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone, TimeZone); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.SPY, new Security(SecurityExchangeHours, abcConfig)); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen); Assert.AreEqual(1, subscriptions.Subscriptions.Count(x => x.Symbol == Symbols.USDJPY)); Assert.AreEqual(1, securities.Values.Count(x => x.Symbol == Symbols.USDJPY)); }
public void SellingShortFromZeroAddsToCash() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(0); securities.Add(Symbols.AAPL, new Security(SecurityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var fill = new OrderEvent(1, Symbols.AAPL, DateTime.MinValue, OrderStatus.Filled, OrderDirection.Sell, 100, -100, 0); portfolio.ProcessFill(fill); Assert.AreEqual(100 * 100, portfolio.Cash); Assert.AreEqual(-100, securities[Symbols.AAPL].Holdings.Quantity); }
public void EnsureCurrencyDataFeedAddsSubscription() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(); var abcConfig = subscriptions.Add(SecurityType.Equity, "ABC", Resolution.Minute); var securities = new SecurityManager(); securities.Add("ABC", abcConfig); cash.EnsureCurrencyDataFeed(subscriptions, securities); Assert.AreEqual(1, subscriptions.Subscriptions.Count(x => x.Symbol == "USDJPY")); Assert.AreEqual(1, securities.Values.Count(x => x.Symbol == "USDJPY")); }
public void EnsureCurrencyDataFeedDoesNotMarkIsCurrencyDataFeedForExistantSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.USDJPY, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.USDJPY, Resolution.Minute, TimeZone, TimeZone))); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen); var config = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsFalse(config.IsInternalFeed); }
public void EnsureCurrencyDataFeedMarksIsCurrencyDataFeedForNewSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add("ABC", new Security(SecurityExchangeHours, subscriptions.Add(SecurityType.Forex, "ABC", Resolution.Minute, "fxcm", TimeZone), 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions, SecurityExchangeHoursProvider.AlwaysOpen); var config = subscriptions.Subscriptions.Single(x => x.Symbol == "USDJPY"); Assert.IsTrue(config.IsInternalFeed); }
public void EnsureCurrencyDataFeedDoesNotMarkIsCurrencyDataFeedForExistantSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(); var securities = new SecurityManager(); securities.Add("USDJPY", subscriptions.Add(SecurityType.Forex, "USDJPY", Resolution.Minute)); cash.EnsureCurrencyDataFeed(subscriptions, securities); var config = subscriptions.Subscriptions.Single(x => x.Symbol == "USDJPY"); Assert.IsFalse(config.IsInternalFeed); }
public void NotifiesWhenSecurityAdded() { var timeKeeper = new TimeKeeper(new DateTime(2015, 12, 07)); var manager = new SecurityManager(timeKeeper); var security = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), CreateTradeBarConfig(), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency)); manager.CollectionChanged += (sender, args) => { if (args.NewItems.OfType<object>().Single() != security) { Assert.Fail("Expected args.NewItems to have exactly one element equal to security"); } else { Assert.IsTrue(args.Action == NotifyCollectionChangedAction.Add); Assert.Pass(); } }; manager.Add(security.Symbol, security); }
public void MarginComputesProperlyWithMultipleSecurities() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(1000); portfolio.CashBook.Add("EUR", 1000, 1.1m); portfolio.CashBook.Add("GBP", -1000, 2.0m); var eurCash = portfolio.CashBook["EUR"]; var gbpCash = portfolio.CashBook["GBP"]; var usdCash = portfolio.CashBook["USD"]; var time = DateTime.Now; var config1 = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config1, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities[Symbols.AAPL].SetLeverage(2m); securities[Symbols.AAPL].Holdings.SetHoldings(100, 100); securities[Symbols.AAPL].SetMarketPrice(new TradeBar{Time = time, Value = 100}); //Console.WriteLine("AAPL TMU: " + securities[Symbols.AAPL].MarginModel.GetMaintenanceMargin(securities[Symbols.AAPL])); //Console.WriteLine("AAPL Value: " + securities[Symbols.AAPL].Holdings.HoldingsValue); //Console.WriteLine(); var config2 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURUSD); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, usdCash, config2, SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities[Symbols.EURUSD].SetLeverage(100m); securities[Symbols.EURUSD].Holdings.SetHoldings(1.1m, 1000); securities[Symbols.EURUSD].SetMarketPrice(new TradeBar { Time = time, Value = 1.1m }); //Console.WriteLine("EURUSD TMU: " + securities[Symbols.EURUSD].MarginModel.GetMaintenanceMargin(securities[Symbols.EURUSD])); //Console.WriteLine("EURUSD Value: " + securities[Symbols.EURUSD].Holdings.HoldingsValue); //Console.WriteLine(); var config3 = CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURGBP); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, gbpCash, config3, SymbolProperties.GetDefault(gbpCash.Symbol))); securities[Symbols.EURGBP].SetLeverage(100m); securities[Symbols.EURGBP].Holdings.SetHoldings(1m, 1000); securities[Symbols.EURGBP].SetMarketPrice(new TradeBar { Time = time, Value = 1m }); //Console.WriteLine("EURGBP TMU: " + securities[Symbols.EURGBP].MarginModel.GetMaintenanceMargin(securities[Symbols.EURGBP])); //Console.WriteLine("EURGBP Value: " + securities[Symbols.EURGBP].Holdings.HoldingsValue); //Console.WriteLine(); //Console.WriteLine(portfolio.CashBook["USD"]); //Console.WriteLine(portfolio.CashBook["EUR"]); //Console.WriteLine(portfolio.CashBook["GBP"]); //Console.WriteLine("CashBook: " + portfolio.CashBook.TotalValueInAccountCurrency); //Console.WriteLine(); //Console.WriteLine("Total Margin Used: " + portfolio.TotalMarginUsed); //Console.WriteLine("Total Free Margin: " + portfolio.MarginRemaining); //Console.WriteLine("Total Portfolio Value: " + portfolio.TotalPortfolioValue); var acceptedOrder = new MarketOrder(Symbols.AAPL, 101, DateTime.Now) { Price = 100 }; orderProcessor.AddOrder(acceptedOrder); var request = new SubmitOrderRequest(OrderType.Market, acceptedOrder.SecurityType, acceptedOrder.Symbol, acceptedOrder.Quantity, 0, 0, acceptedOrder.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder); Assert.IsTrue(sufficientCapital); var rejectedOrder = new MarketOrder(Symbols.AAPL, 102, DateTime.Now) { Price = 100 }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder); Assert.IsFalse(sufficientCapital); }
public void ComputeMarginProperlyAsSecurityPriceFluctuates() { const decimal leverage = 1m; const int quantity = (int) (1000*leverage); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(quantity); var config = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SetLeverage(leverage); var time = DateTime.Now; const decimal buyPrice = 1m; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, buyPrice, buyPrice, buyPrice, buyPrice, 1)); var order = new MarketOrder(Symbols.AAPL, quantity, time) {Price = buyPrice}; var fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = buyPrice, FillQuantity = quantity }; orderProcessor.AddOrder(order); var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); Assert.AreEqual(portfolio.CashBook["USD"].Amount, fill.FillPrice*fill.FillQuantity); portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var newOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1)) {Price = buyPrice}; bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, highPrice, highPrice, highPrice, highPrice, 1)); Assert.AreEqual(quantity, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var anotherOrder = new MarketOrder(Symbols.AAPL, 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder); Assert.IsTrue(sufficientCapital); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice/2; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, lowPrice, lowPrice, lowPrice, lowPrice, 1)); Assert.AreEqual(-quantity/2m, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity/2m, portfolio.TotalPortfolioValue); // this would not cause a margin call due to leverage = 1 bool issueMarginCallWarning; var marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // now change the leverage and buy more and we'll get a margin call security.SetLeverage(leverage * 2); order = new MarketOrder(Symbols.AAPL, quantity, time) { Price = buyPrice }; fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = buyPrice, FillQuantity = quantity }; portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.TotalPortfolioValue); marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreNotEqual(0, marginCallOrders.Count); Assert.AreEqual(-security.Holdings.Quantity, marginCallOrders[0].Quantity); // we bought twice Assert.GreaterOrEqual(-portfolio.MarginRemaining, security.Price * marginCallOrders[0].Quantity); }
public void ForexCashFills() { // this test asserts the portfolio behaves according to the Test_Cash algo, but for a Forex security, // see TestData\CashTestingStrategy.csv; also "https://www.dropbox.com/s/oiliumoyqqj1ovl/2013-cash.csv?dl=1" const string fillsFile = "TestData\\test_forex_fills.xml"; const string equityFile = "TestData\\test_forex_equity.xml"; const string mchQuantityFile = "TestData\\test_forex_fills_mch_quantity.xml"; const string jwbQuantityFile = "TestData\\test_forex_fills_jwb_quantity.xml"; var fills = XDocument.Load(fillsFile).Descendants("OrderEvent").Select(x => new OrderEvent( x.Get<int>("OrderId"), SymbolMap[x.Get<string>("Symbol")], DateTime.MinValue, x.Get<OrderStatus>("Status"), x.Get<int>("FillQuantity") < 0 ? OrderDirection.Sell : x.Get<int>("FillQuantity") > 0 ? OrderDirection.Buy : OrderDirection.Hold, x.Get<decimal>("FillPrice"), x.Get<int>("FillQuantity"), 0) ).ToList(); var equity = XDocument.Load(equityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); var mchQuantity = XDocument.Load(mchQuantityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); var jwbQuantity = XDocument.Load(jwbQuantityFile).Descendants("decimal") .Select(x => decimal.Parse(x.Value, CultureInfo.InvariantCulture)) .ToList(); Assert.AreEqual(fills.Count + 1, equity.Count); // we're going to process fills and very our equity after each fill var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(equity[0]); portfolio.CashBook.Add("MCH", mchQuantity[0], 0); portfolio.CashBook.Add("JWB", jwbQuantity[0], 0); var jwbCash = portfolio.CashBook["JWB"]; var mchCash = portfolio.CashBook["MCH"]; var usdCash = portfolio.CashBook["USD"]; var mchJwbSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, jwbCash, subscriptions.Add(MCHJWB, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork), SymbolProperties.GetDefault(jwbCash.Symbol)); mchJwbSecurity.SetLeverage(10m); var mchUsdSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, usdCash, subscriptions.Add(MCHUSD, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork), SymbolProperties.GetDefault(usdCash.Symbol)); mchUsdSecurity.SetLeverage(10m); var usdJwbSecurity = new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, mchCash, subscriptions.Add(USDJWB, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork), SymbolProperties.GetDefault(mchCash.Symbol)); usdJwbSecurity.SetLeverage(10m); // no fee model mchJwbSecurity.TransactionModel = new SecurityTransactionModel(); mchUsdSecurity.TransactionModel = new SecurityTransactionModel(); usdJwbSecurity.TransactionModel = new SecurityTransactionModel(); securities.Add(mchJwbSecurity); securities.Add(usdJwbSecurity); securities.Add(mchUsdSecurity); portfolio.CashBook.EnsureCurrencyDataFeeds(securities, subscriptions, MarketHoursDatabase.FromDataFolder(), SymbolPropertiesDatabase.FromDataFolder(), DefaultBrokerageModel.DefaultMarketMap); for (int i = 0; i < fills.Count; i++) { // before processing the fill we must deduct the cost var fill = fills[i]; var time = DateTime.Today.AddDays(i); // the value of 'MCJWB' increments for each fill, the original test algo did this monthly // the time doesn't really matter though decimal mchJwb = i + 1; decimal mchUsd = (i + 1)/(i + 2m); decimal usdJwb = i + 2; Assert.AreEqual((double)mchJwb, (double)(mchUsd*usdJwb), 1e-10); //Console.WriteLine("Step: " + i + " -- MCHJWB: " + mchJwb); jwbCash.Update(new IndicatorDataPoint(MCHJWB, time, mchJwb)); usdCash.Update(new IndicatorDataPoint(MCHUSD, time, mchUsd)); mchCash.Update(new IndicatorDataPoint(JWBUSD, time, usdJwb)); var updateData = new Dictionary<Security, BaseData> { {mchJwbSecurity, new IndicatorDataPoint(MCHJWB, time, mchJwb)}, {mchUsdSecurity, new IndicatorDataPoint(MCHUSD, time, mchUsd)}, {usdJwbSecurity, new IndicatorDataPoint(JWBUSD, time, usdJwb)} }; foreach (var kvp in updateData) { kvp.Key.SetMarketPrice(kvp.Value); } portfolio.ProcessFill(fill); //Console.WriteLine("-----------------------"); //Console.WriteLine(fill); //Console.WriteLine("Post step: " + i); //foreach (var cash in portfolio.CashBook) //{ // Console.WriteLine(cash.Value); //} //Console.WriteLine("CashValue: " + portfolio.CashBook.TotalValueInAccountCurrency); Console.WriteLine(i + 1 + " " + portfolio.TotalPortfolioValue.ToString("C")); //Assert.AreEqual((double) equity[i + 1], (double)portfolio.TotalPortfolioValue, 2e-2); Assert.AreEqual((double) mchQuantity[i + 1], (double)portfolio.CashBook["MCH"].Amount); Assert.AreEqual((double) jwbQuantity[i + 1], (double)portfolio.CashBook["JWB"].Amount); //Console.WriteLine(); //Console.WriteLine(); } }
public void SellingShortFromZeroAddsToCash() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(0); securities.Add("AAPL", new Security(SecurityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, "AAPL"), 1)); var fill = new OrderEvent(1, "AAPL", DateTime.MinValue, OrderStatus.Filled, OrderDirection.Sell, 100, -100, 0); portfolio.ProcessFill(fill); Assert.AreEqual(100 * 100, portfolio.Cash); Assert.AreEqual(-100, securities["AAPL"].Holdings.Quantity); }
public void ComputeMarginProperlyShortCoverZeroLong() { const decimal leverage = 2m; const int amount = 1000; const int quantity = (int)(amount * leverage); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var orderProcessor = new OrderProcessor(); transactions.SetOrderProcessor(orderProcessor); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].SetAmount(amount); var config = CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL); securities.Add(new Security(SecurityExchangeHours, config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SetLeverage(leverage); var time = DateTime.Now; const decimal sellPrice = 1m; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, sellPrice, sellPrice, sellPrice, sellPrice, 1)); var order = new MarketOrder(Symbols.AAPL, -quantity, time) { Price = sellPrice }; var fill = new OrderEvent(order, DateTime.UtcNow, 0) { FillPrice = sellPrice, FillQuantity = -quantity }; orderProcessor.AddOrder(order); var request = new SubmitOrderRequest(OrderType.Market, security.Type, security.Symbol, order.Quantity, 0, 0, order.Time, null); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(null, request)); portfolio.ProcessFill(fill); // we shouldn't be able to place a new short order var newOrder = new MarketOrder(Symbols.AAPL, -1, time.AddSeconds(1)) { Price = sellPrice }; var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // we should be able to place cover to zero newOrder = new MarketOrder(Symbols.AAPL, quantity, time.AddSeconds(1)) { Price = sellPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsTrue(sufficientCapital); // now the stock doubles, so we should have negative margin remaining time = time.AddDays(1); const decimal highPrice = sellPrice * 2; security.SetMarketPrice(new TradeBar(time, Symbols.AAPL, highPrice, highPrice, highPrice, highPrice, 1)); // we still shouldn be able to place cover to zero newOrder = new MarketOrder(Symbols.AAPL, quantity, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsTrue(sufficientCapital); // we shouldn't be able to place cover to long newOrder = new MarketOrder(Symbols.AAPL, quantity + 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); }
public void EquitySellAppliesSettlementCorrectly() { var securityExchangeHours = SecurityExchangeHoursTests.CreateUsEquitySecurityExchangeHours(); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); securities.Add(Symbols.AAPL, new QuantConnect.Securities.Equity.Equity(securityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.AAPL]; security.SettlementModel = new DelayedSettlementModel(3, TimeSpan.FromHours(8)); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Buy on Monday var timeUtc = new DateTime(2015, 10, 26, 15, 30, 0); var orderFee = security.FeeModel.GetOrderFee(security,new MarketOrder(Symbols.AAPL, 10, timeUtc)); var fill = new OrderEvent(1, Symbols.AAPL, timeUtc, OrderStatus.Filled, OrderDirection.Buy, 100, 10, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(10, security.Holdings.Quantity); Assert.AreEqual(-1, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); // Sell on Tuesday, cash unsettled timeUtc = timeUtc.AddDays(1); orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.AAPL, 10, timeUtc)); fill = new OrderEvent(2, Symbols.AAPL, timeUtc, OrderStatus.Filled, OrderDirection.Sell, 100, -10, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Thursday, still cash unsettled timeUtc = timeUtc.AddDays(2); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(-2, portfolio.Cash); Assert.AreEqual(1000, portfolio.UnsettledCash); // Friday at open, cash settled var marketOpen = securityExchangeHours.MarketHours[timeUtc.DayOfWeek].GetMarketOpen(TimeSpan.Zero, false); Assert.IsTrue(marketOpen.HasValue); timeUtc = timeUtc.AddDays(1).Date.Add(marketOpen.Value).ConvertToUtc(securityExchangeHours.TimeZone); portfolio.ScanForCashSettlement(timeUtc); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(0, portfolio.UnsettledCash); }
/// <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)); }
public void EnsureCurrencyDataFeedsAddsSubscriptionAtMinimumResolution() { const int quantity = 100; const decimal conversionRate = 1 / 100m; const Resolution minimumResolution = Resolution.Second; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(); var securities = new SecurityManager(); securities.Add("ABC", new Security(subscriptions.Add(SecurityType.Equity, "ABC", Resolution.Minute), 1m)); securities.Add("BCD", new Security(subscriptions.Add(SecurityType.Equity, "BCD", minimumResolution), 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions); Assert.AreEqual(minimumResolution, subscriptions.Subscriptions.Single(x => x.Symbol == "USDJPY").Resolution); }
public void EnsureCurrencyDataFeedMarksIsCurrencyDataFeedForNewSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(); var securities = new SecurityManager(); securities.Add("ABC", new Security(subscriptions.Add(SecurityType.Forex, "ABC", Resolution.Minute), 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions); var config = subscriptions.Subscriptions.Single(x => x.Symbol == "USDJPY"); Assert.IsTrue(config.IsInternalFeed); }
private static TimeRules GetTimeRules(DateTimeZone dateTimeZone) { var timeKeeper = new TimeKeeper(DateTime.Today, new List<DateTimeZone>()); var manager = new SecurityManager(timeKeeper); var securityExchangeHours = SecurityExchangeHoursProvider.FromDataFolder().GetExchangeHours("usa", null, SecurityType.Equity); var config = new SubscriptionDataConfig(typeof(TradeBar), SecurityType.Equity, "SPY", Resolution.Daily, "usa", securityExchangeHours.TimeZone, true, false, false); manager.Add("SPY", new Security(securityExchangeHours, config, 1)); var rules = new TimeRules(manager, dateTimeZone); return rules; }
private static DateRules GetDateRules() { var timeKeeper = new TimeKeeper(DateTime.Today, new List<DateTimeZone>()); var manager = new SecurityManager(timeKeeper); var securityExchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.USA, null, SecurityType.Equity); var config = new SubscriptionDataConfig(typeof(TradeBar), Symbols.SPY, Resolution.Daily, TimeZones.NewYork, TimeZones.NewYork, true, false, false); manager.Add(Symbols.SPY, new Security(securityExchangeHours, config, new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var rules = new DateRules(manager); return rules; }
public void SellingShortFromShortAddsToCash() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(0); securities.Add(Symbols.AAPL, new Security(SecurityExchangeHours, CreateTradeBarDataConfig(SecurityType.Equity, Symbols.AAPL), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); securities[Symbols.AAPL].Holdings.SetHoldings(100, -100); var fill = new OrderEvent(1, Symbols.AAPL, DateTime.MinValue, OrderStatus.Filled, OrderDirection.Sell, 100, -100, 0); Assert.AreEqual(-100, securities[Symbols.AAPL].Holdings.Quantity); portfolio.ProcessFill(fill); Assert.AreEqual(100 * 100, portfolio.Cash); Assert.AreEqual(-200, securities[Symbols.AAPL].Holdings.Quantity); }
public void ForexFillUpdatesCashCorrectly() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.SetCash(1000); portfolio.CashBook.Add("EUR", 0, 1.1000m); securities.Add(Symbols.EURUSD, new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, portfolio.CashBook["USD"], CreateTradeBarDataConfig(SecurityType.Forex, Symbols.EURUSD), SymbolProperties.GetDefault(CashBook.AccountCurrency))); var security = securities[Symbols.EURUSD]; Assert.AreEqual(0, security.Holdings.Quantity); Assert.AreEqual(1000, portfolio.Cash); var orderFee = security.FeeModel.GetOrderFee(security, new MarketOrder(Symbols.EURUSD, 100, DateTime.MinValue)); var fill = new OrderEvent(1, Symbols.EURUSD, DateTime.MinValue, OrderStatus.Filled, OrderDirection.Buy, 1.1000m, 100, orderFee); portfolio.ProcessFill(fill); Assert.AreEqual(100, security.Holdings.Quantity); Assert.AreEqual(998, portfolio.Cash); Assert.AreEqual(100, portfolio.CashBook["EUR"].Amount); Assert.AreEqual(888, portfolio.CashBook["USD"].Amount); }
public void EnsureInternalCurrencyDataFeedsForNonUsdQuoteCurrencyGetAdded() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cashJPY = new Cash("JPY", quantity, conversionRate); var cashGBP = new Cash("GBP", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cashJPY); cashBook.Add("GBP", cashGBP); var symbol = Symbol.Create("GBPJPY", SecurityType.Forex, Market.FXCM); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(symbol, new Security(SecurityExchangeHours, subscriptions.Add(symbol, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cashJPY.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook); var config1 = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsTrue(config1.IsInternalFeed); cashGBP.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook); var config2 = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.GBPUSD); Assert.IsTrue(config2.IsInternalFeed); }
public void ComputeMarginProperlyAsSecurityPriceFluctuates() { const decimal leverage = 1m; const int quantity = (int) (1000*leverage); var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].Quantity = quantity; var config = CreateTradeBarDataConfig(SecurityType.Equity, "AAPL"); securities.Add(new Security(SecurityExchangeHours, config, leverage, false)); var time = DateTime.Now; const decimal buyPrice = 1m; var security = securities["AAPL"]; security.SetMarketPrice(new TradeBar(time, "AAPL", buyPrice, buyPrice, buyPrice, buyPrice, 1)); var order = new MarketOrder("AAPL", quantity, time) {Price = buyPrice}; var fill = new OrderEvent(order){FillPrice = buyPrice, FillQuantity = quantity}; Assert.AreEqual(portfolio.CashBook["USD"].Quantity, fill.FillPrice*fill.FillQuantity); portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var newOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1)) {Price = buyPrice}; bool sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, newOrder); Assert.IsFalse(sufficientCapital); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; security.SetMarketPrice(new TradeBar(time, "AAPL", highPrice, highPrice, highPrice, highPrice, 1)); Assert.AreEqual(quantity, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity * 2, portfolio.TotalPortfolioValue); // we shouldn't be able to place a trader var anotherOrder = new MarketOrder("AAPL", 1, time.AddSeconds(1)) { Price = highPrice }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, anotherOrder); Assert.IsTrue(sufficientCapital); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice/2; security.SetMarketPrice(new TradeBar(time, "AAPL", lowPrice, lowPrice, lowPrice, lowPrice, 1)); Assert.AreEqual(-quantity/2m, portfolio.MarginRemaining); Assert.AreEqual(quantity, portfolio.TotalMarginUsed); Assert.AreEqual(quantity/2m, portfolio.TotalPortfolioValue); // this would not cause a margin call due to leverage = 1 bool issueMarginCallWarning; var marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // now change the leverage and buy more and we'll get a margin call security.SetLeverage(leverage * 2); order = new MarketOrder("AAPL", quantity, time) { Price = buyPrice }; fill = new OrderEvent(order) { FillPrice = buyPrice, FillQuantity = quantity }; portfolio.ProcessFill(fill); Assert.AreEqual(0, portfolio.TotalPortfolioValue); marginCallOrders = portfolio.ScanForMarginCall(out issueMarginCallWarning); Assert.AreNotEqual(0, marginCallOrders.Count); Assert.AreEqual(-security.Holdings.Quantity, marginCallOrders[0].Quantity); // we bought twice Assert.GreaterOrEqual(-portfolio.MarginRemaining, security.Price * marginCallOrders[0].Quantity); }
/// <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)); }
public void EnsureCurrencyDataFeedsAddsSubscriptionAtMinimumResolution() { const int quantity = 100; const decimal conversionRate = 1 / 100m; const Resolution minimumResolution = Resolution.Second; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.SPY, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.SPY, Resolution.Minute, TimeZone), 1m)); securities.Add(Symbols.EURUSD, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.EURUSD, minimumResolution, TimeZone), 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions, SecurityExchangeHoursProvider.AlwaysOpen); Assert.AreEqual(minimumResolution, subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY).Resolution); }
public void UpdateModifiesConversionRateAsInvertedValue() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.USDJPY, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.USDJPY, Resolution.Minute, TimeZone), 1m)); // we need to get subscription index cash.EnsureCurrencyDataFeed(securities, subscriptions, SecurityExchangeHoursProvider.AlwaysOpen); var last = 120m; cash.Update(new Tick(DateTime.Now, Symbols.USDJPY, last, 119.95m, 120.05m)); // jpy is inverted, so compare on the inverse Assert.AreEqual(1 / last, cash.ConversionRate); }
public void UpdateModifiesConversionRateAsInvertedValue() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(); var securities = new SecurityManager(); securities.Add("USDJPY", new Security(subscriptions.Add(SecurityType.Forex, "USDJPY", Resolution.Minute), 1m)); // we need to get subscription index cash.EnsureCurrencyDataFeed(securities, subscriptions); var last = 120m; var data = new Dictionary<int, List<BaseData>>(); data.Add(0, new List<BaseData> { new Tick(DateTime.Now, "USDJPY", last, 119.95m, 120.05m) }); cash.Update(data); // jpy is inverted, so compare on the inverse Assert.AreEqual(1 / last, cash.ConversionRate); }
public void MarginComputesProperlyWithMultipleSecurities() { var securities = new SecurityManager(TimeKeeper); var transactions = new SecurityTransactionManager(securities); var portfolio = new SecurityPortfolioManager(securities, transactions); portfolio.CashBook["USD"].Quantity = 1000; portfolio.CashBook.Add("EUR", 1000, 1.1m); portfolio.CashBook.Add("GBP", -1000, 2.0m); var eurCash = portfolio.CashBook["EUR"]; var gbpCash = portfolio.CashBook["GBP"]; var usdCash = portfolio.CashBook["USD"]; var time = DateTime.Now; var config1 = CreateTradeBarDataConfig(SecurityType.Equity, "AAPL"); securities.Add(new Security(SecurityExchangeHours, config1, 2)); securities["AAPL"].Holdings.SetHoldings(100, 100); securities["AAPL"].SetMarketPrice(new TradeBar{Time = time, Value = 100}); //Console.WriteLine("AAPL TMU: " + securities["AAPL"].MarginModel.GetMaintenanceMargin(securities["AAPL"])); //Console.WriteLine("AAPL Value: " + securities["AAPL"].Holdings.HoldingsValue); //Console.WriteLine(); var config2 = CreateTradeBarDataConfig(SecurityType.Forex, "EURUSD"); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, usdCash, config2, 100)); securities["EURUSD"].Holdings.SetHoldings(1.1m, 1000); securities["EURUSD"].SetMarketPrice(new TradeBar { Time = time, Value = 1.1m }); //Console.WriteLine("EURUSD TMU: " + securities["EURUSD"].MarginModel.GetMaintenanceMargin(securities["EURUSD"])); //Console.WriteLine("EURUSD Value: " + securities["EURUSD"].Holdings.HoldingsValue); //Console.WriteLine(); var config3 = CreateTradeBarDataConfig(SecurityType.Forex, "EURGBP"); securities.Add(new QuantConnect.Securities.Forex.Forex(SecurityExchangeHours, gbpCash, config3, 100)); securities["EURGBP"].Holdings.SetHoldings(1m, 1000); securities["EURGBP"].SetMarketPrice(new TradeBar { Time = time, Value = 1m }); //Console.WriteLine("EURGBP TMU: " + securities["EURGBP"].MarginModel.GetMaintenanceMargin(securities["EURGBP"])); //Console.WriteLine("EURGBP Value: " + securities["EURGBP"].Holdings.HoldingsValue); //Console.WriteLine(); //Console.WriteLine(portfolio.CashBook["USD"]); //Console.WriteLine(portfolio.CashBook["EUR"]); //Console.WriteLine(portfolio.CashBook["GBP"]); //Console.WriteLine("CashBook: " + portfolio.CashBook.TotalValueInAccountCurrency); //Console.WriteLine(); //Console.WriteLine("Total Margin Used: " + portfolio.TotalMarginUsed); //Console.WriteLine("Total Free Margin: " + portfolio.MarginRemaining); //Console.WriteLine("Total Portfolio Value: " + portfolio.TotalPortfolioValue); var acceptedOrder = new MarketOrder("AAPL", 101, DateTime.Now) {Price = 100}; var sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, acceptedOrder); Assert.IsTrue(sufficientCapital); var rejectedOrder = new MarketOrder("AAPL", 102, DateTime.Now) { Price = 100 }; sufficientCapital = transactions.GetSufficientCapitalForOrder(portfolio, rejectedOrder); Assert.IsFalse(sufficientCapital); }
/// <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)); }
public void EnsureCurrencyDataFeedAddsSubscription() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(); var abcConfig = subscriptions.Add(SecurityType.Equity, "ABC", Resolution.Minute); var securities = new SecurityManager(); securities.Add("ABC", new Security(abcConfig, 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions); Assert.AreEqual(1, subscriptions.Subscriptions.Count(x => x.Symbol == "USDJPY")); Assert.AreEqual(1, securities.Values.Count(x => x.Symbol == "USDJPY")); }
public void EnsureCurrencyDataFeedDoesNotMarkIsCurrencyDataFeedForExistantSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("JPY", cash); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.USDJPY, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.USDJPY, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook); var config = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsFalse(config.IsInternalFeed); }
public void EnsureCurrencyDataFeedMarksIsCurrencyDataFeedForNewSubscriptions() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("JPY", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.EURUSD, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.EURUSD, Resolution.Minute, TimeZone), 1m)); cash.EnsureCurrencyDataFeed(securities, subscriptions, SecurityExchangeHoursProvider.AlwaysOpen); var config = subscriptions.Subscriptions.Single(x => x.Symbol == Symbols.USDJPY); Assert.IsTrue(config.IsInternalFeed); }
public void UpdateModifiesConversionRate() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("GBP", quantity, conversionRate); var cashBook = new CashBook(); cashBook.Add("GBP", cash); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add(Symbols.GBPUSD, new Security(SecurityExchangeHours, subscriptions.Add(Symbols.GBPUSD, Resolution.Minute, TimeZone, TimeZone), new Cash(CashBook.AccountCurrency, 0, 1m), SymbolProperties.GetDefault(CashBook.AccountCurrency))); // we need to get subscription index cash.EnsureCurrencyDataFeed(securities, subscriptions, MarketHoursDatabase.AlwaysOpen, SymbolPropertiesDatabase.FromDataFolder(), MarketMap, cashBook); var last = 1.5m; cash.Update(new Tick(DateTime.Now, Symbols.GBPUSD, last, last * 1.009m, last * 0.009m)); // jpy is inverted, so compare on the inverse Assert.AreEqual(last, cash.ConversionRate); }
public void UpdateModifiesConversionRate() { const int quantity = 100; const decimal conversionRate = 1 / 100m; var cash = new Cash("GBP", quantity, conversionRate); var subscriptions = new SubscriptionManager(TimeKeeper); var securities = new SecurityManager(TimeKeeper); securities.Add("GBPUSD", new Security(SecurityExchangeHours, subscriptions.Add(SecurityType.Forex, "GBPUSD", Resolution.Minute, "fxcm", TimeZone), 1m)); // we need to get subscription index cash.EnsureCurrencyDataFeed(securities, subscriptions, SecurityExchangeHoursProvider.AlwaysOpen); var last = 1.5m; cash.Update(new Tick(DateTime.Now, "GBPUSD", last, last * 1.009m, last * 0.009m)); // jpy is inverted, so compare on the inverse Assert.AreEqual(last, cash.ConversionRate); }