public void VerifyMarginCallOrderLongOpenMarket() { var securityPrice = 100m; var quantity = 300; var orderProcessor = new FakeOrderProcessor(); var portfolio = GetPortfolio(orderProcessor, quantity, Noon); var model = GetModel(); // Open Market var security = CreateSecurity(model.SecurityModel, Noon); security.BuyingPowerModel = model; security.Holdings.SetHoldings(securityPrice, quantity); portfolio.Securities.Add(security); portfolio.CashBook["USD"].AddAmount(-25000); portfolio.InvalidateTotalPortfolioValue(); var netLiquidationValue = portfolio.TotalPortfolioValue; var totalMargin = portfolio.TotalMarginUsed; portfolio.MarginCallModel = new TestDefaultMarginCallModel(portfolio, new OrderProperties()); var expected = -(int)(Math.Round((totalMargin - netLiquidationValue) / securityPrice, MidpointRounding.AwayFromZero) * 4m); var actual = (portfolio.MarginCallModel as TestDefaultMarginCallModel).GenerateMarginCallOrder(security, netLiquidationValue, totalMargin).Quantity; Assert.AreEqual(expected, actual); }
public void VerifyMarginCallOrderShort() { var netLiquidationValue = 5000m; var totalMargin = 10000m; var securityPrice = 100m; var quantity = -300; var orderProcessor = new FakeOrderProcessor(); var portfolio = GetPortfolio(orderProcessor, quantity); var model = new PatternDayTradingMarginModel(); // Open Market var security = CreateSecurity(Noon); security.Holdings.SetHoldings(securityPrice, quantity); var expected = (int)(Math.Round((totalMargin - netLiquidationValue) / securityPrice, MidpointRounding.AwayFromZero) * 4m); var actual = portfolio.MarginCallModel.GenerateMarginCallOrder(security, netLiquidationValue, totalMargin, model.GetMaintenanceMarginRequirement(security)).Quantity; Assert.AreEqual(expected, actual); // Closed Market security = CreateSecurity(Midnight); security.Holdings.SetHoldings(securityPrice, quantity); expected = (int)(Math.Round((totalMargin - netLiquidationValue) / securityPrice, MidpointRounding.AwayFromZero) * 2m); actual = portfolio.MarginCallModel.GenerateMarginCallOrder(security, netLiquidationValue, totalMargin, model.GetMaintenanceMarginRequirement(security)).Quantity; Assert.AreEqual(expected, actual); }
public void HasSufficientBuyingPowerForOrderInvalidTargets(decimal target) { var algorithm = new QCAlgorithm(); algorithm.SetFinishedWarmingUp(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); var orderProcessor = new FakeOrderProcessor(); algorithm.Transactions.SetOrderProcessor(orderProcessor); var ticker = QuantConnect.Securities.Futures.Financials.EuroDollar; var futureSecurity = algorithm.AddFuture(ticker); // set closed market for simpler math futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 1)); Update(futureSecurity, 100, algorithm); var model = futureSecurity.BuyingPowerModel as FutureMarginModel; var quantity = algorithm.CalculateOrderQuantity(futureSecurity.Symbol, target); var request = GetOrderRequest(futureSecurity.Symbol, quantity); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(algorithm.Transactions, request)); var result = model.HasSufficientBuyingPowerForOrder(new HasSufficientBuyingPowerForOrderParameters( algorithm.Portfolio, futureSecurity, // we get the maximum target value 1/-1 and add a lot size it shouldn't be a valid order new MarketOrder(futureSecurity.Symbol, quantity + futureSecurity.SymbolProperties.LotSize * Math.Sign(quantity), DateTime.UtcNow))); Assert.IsFalse(result.IsSufficient); }
public void GetMarginRemainingTests() { const int quantity = 1000; const decimal leverage = 2; var orderProcessor = new FakeOrderProcessor(); var portfolio = GetPortfolio(orderProcessor, quantity); var security = GetSecurity(Symbols.AAPL); var buyingPowerModel = new TestSecurityMarginModel(leverage); security.BuyingPowerModel = buyingPowerModel; portfolio.Securities.Add(security); security.Holdings.SetHoldings(1m, quantity); var actual1 = buyingPowerModel.GetMarginRemaining(portfolio, security, OrderDirection.Buy); Assert.AreEqual(quantity / leverage, actual1); var actual2 = buyingPowerModel.GetMarginRemaining(portfolio, security, OrderDirection.Sell); Assert.AreEqual(quantity, actual2); security.Holdings.SetHoldings(1m, -quantity); var actual3 = buyingPowerModel.GetMarginRemaining(portfolio, security, OrderDirection.Sell); Assert.AreEqual(quantity / leverage, actual3); var actual4 = buyingPowerModel.GetMarginRemaining(portfolio, security, OrderDirection.Buy); Assert.AreEqual(quantity, actual4); }
public void ClosingSoonIntradayClosedMarketMargins(decimal target) { var algorithm = new QCAlgorithm(); algorithm.SetFinishedWarmingUp(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); var orderProcessor = new FakeOrderProcessor(); algorithm.Transactions.SetOrderProcessor(orderProcessor); var ticker = QuantConnect.Securities.Futures.Financials.EuroDollar; var futureSecurity = algorithm.AddFuture(ticker); Update(futureSecurity, 100, algorithm); var localTime = new DateTime(2020, 2, 3); var utcTime = localTime.ConvertToUtc(futureSecurity.Exchange.TimeZone); var timeKeeper = new TimeKeeper(utcTime, futureSecurity.Exchange.TimeZone); var model = GetModel(futureSecurity, out _futureMarginModel, algorithm.Portfolio); // this is important _futureMarginModel.EnableIntradayMargins = true; // Open market futureSecurity.Exchange.SetLocalDateTimeFrontier(localTime); var quantity = algorithm.CalculateOrderQuantity(futureSecurity.Symbol, target); var request = GetOrderRequest(futureSecurity.Symbol, quantity); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(algorithm.Transactions, request)); Assert.IsTrue(model.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, quantity, DateTime.UtcNow))).IsSufficient); // Closing soon market futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 3, 15, 50, 0)); Assert.IsFalse(model.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, quantity, DateTime.UtcNow))).IsSufficient); Assert.IsTrue(futureSecurity.Exchange.ExchangeOpen); Assert.IsTrue(futureSecurity.Exchange.ClosingSoon); // Close market futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 1)); Assert.IsFalse(futureSecurity.Exchange.ExchangeOpen); Assert.IsFalse(model.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, quantity, DateTime.UtcNow))).IsSufficient); }
public void IntradayVersusOvernightMargins(decimal target) { var algorithm = new QCAlgorithm(); algorithm.SetFinishedWarmingUp(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); var orderProcessor = new FakeOrderProcessor(); algorithm.Transactions.SetOrderProcessor(orderProcessor); var ticker = QuantConnect.Securities.Futures.Financials.EuroDollar; var futureSecurity = algorithm.AddFuture(ticker); var lotSize = futureSecurity.SymbolProperties.LotSize; Update(futureSecurity, 100, algorithm); var model = GetModel(futureSecurity, out _futureMarginModel, algorithm.Portfolio); // Close market futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 1)); var quantityClosedMarket = algorithm.CalculateOrderQuantity(futureSecurity.Symbol, target); Assert.AreEqual(quantityClosedMarket.DiscretelyRoundBy(lotSize), quantityClosedMarket, "Calculated order quantity was not whole number multiple of the lot size" ); var request = GetOrderRequest(futureSecurity.Symbol, quantityClosedMarket); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(algorithm.Transactions, request)); Assert.IsTrue(model.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, quantityClosedMarket, DateTime.UtcNow))).IsSufficient); var initialOvernight = _futureMarginModel.InitialOvernightMarginRequirement; var maintenanceOvernight = _futureMarginModel.MaintenanceOvernightMarginRequirement; // Open market futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 3)); var fourtyPercentQuantity = (quantityClosedMarket * 0.4m).DiscretelyRoundBy(lotSize); futureSecurity.Holdings.SetHoldings(100, fourtyPercentQuantity); var halfQuantity = (quantityClosedMarket / 2).DiscretelyRoundBy(lotSize); Assert.IsTrue(model.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, halfQuantity, DateTime.UtcNow))).IsSufficient); Assert.Greater(initialOvernight, _futureMarginModel.InitialIntradayMarginRequirement); Assert.Greater(maintenanceOvernight, _futureMarginModel.MaintenanceIntradayMarginRequirement); }
private static QCAlgorithm GetAlgorithm() { SymbolCache.Clear(); // Initialize algorithm var algo = new QCAlgorithm(); algo.SetFinishedWarmingUp(); _fakeOrderProcessor = new FakeOrderProcessor(); algo.Transactions.SetOrderProcessor(_fakeOrderProcessor); return(algo); }
private static QCAlgorithm GetAlgorithm(out Security security, decimal fee) { SymbolCache.Clear(); // Initialize algorithm var algo = new QCAlgorithm(); algo.SetCash(100000); algo.SetFinishedWarmingUp(); _fakeOrderProcessor = new FakeOrderProcessor(); algo.Transactions.SetOrderProcessor(_fakeOrderProcessor); security = algo.AddEquity("SPY"); security.TransactionModel = new ConstantFeeTransactionModel(fee); Update(algo.Portfolio.CashBook, security, 25); return(algo); }
public void IntradayVersusOvernightMargins(decimal target) { var algorithm = new QCAlgorithm(); algorithm.SetFinishedWarmingUp(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); var orderProcessor = new FakeOrderProcessor(); algorithm.Transactions.SetOrderProcessor(orderProcessor); var ticker = QuantConnect.Securities.Futures.Financials.EuroDollar; var futureSecurity = algorithm.AddFuture(ticker); Update(futureSecurity, 100, algorithm); var model = futureSecurity.BuyingPowerModel as FutureMarginModel; // Close market futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 1)); var quantityClosedMarket = algorithm.CalculateOrderQuantity(futureSecurity.Symbol, target); var request = GetOrderRequest(futureSecurity.Symbol, quantityClosedMarket); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(algorithm.Transactions, request)); Assert.IsTrue(model.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, quantityClosedMarket, DateTime.UtcNow))).IsSufficient); var initialOvernight = model.InitialOvernightMarginRequirement; var maintenanceOvernight = model.MaintenanceOvernightMarginRequirement; // Open market futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 3)); futureSecurity.Holdings.SetHoldings(100, quantityClosedMarket * 0.4m); Assert.IsTrue(model.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, quantityClosedMarket / 2, DateTime.UtcNow))).IsSufficient); Assert.Greater(initialOvernight, model.InitialIntradayMarginRequirement); Assert.Greater(maintenanceOvernight, model.MaintenanceIntradayMarginRequirement); }
public void GetMarginRemainingTests() { const int quantity = 1000; const decimal leverage = 2; var orderProcessor = new FakeOrderProcessor(); var portfolio = GetPortfolio(orderProcessor, cash: 1000); var security = GetSecurity(Symbols.AAPL); var buyingPowerModel = new TestSecurityMarginModel(leverage); security.BuyingPowerModel = buyingPowerModel; portfolio.Securities.Add(security); // we buy $1000 worth of shares security.Holdings.SetHoldings(1m, quantity); portfolio.SetCash(0); // current value is used to determine reserved buying power security.SetMarketPrice(new TradeBar { Time = DateTime.Now, Symbol = security.Symbol, Open = 1, High = 1, Low = 1, Close = 1 }); var actual1 = buyingPowerModel.GetMarginRemaining(portfolio, security, OrderDirection.Buy); Assert.AreEqual(quantity / leverage, actual1); var actual2 = buyingPowerModel.GetMarginRemaining(portfolio, security, OrderDirection.Sell); Assert.AreEqual(quantity + quantity / leverage, actual2); security.Holdings.SetHoldings(1m, -quantity); var actual3 = buyingPowerModel.GetMarginRemaining(portfolio, security, OrderDirection.Sell); Assert.AreEqual(quantity / leverage, actual3); var actual4 = buyingPowerModel.GetMarginRemaining(portfolio, security, OrderDirection.Buy); Assert.AreEqual(quantity + quantity / leverage, actual4); }
public void GetMaximumOrderQuantityForTargetBuyingPower_WithHoldingsInverseDirection(decimal target) { var algorithm = new QCAlgorithm(); algorithm.SetFinishedWarmingUp(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); var orderProcessor = new FakeOrderProcessor(); algorithm.Transactions.SetOrderProcessor(orderProcessor); var ticker = QuantConnect.Securities.Futures.Financials.EuroDollar; var futureSecurity = algorithm.AddFuture(ticker); // set closed market for simpler math futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 1)); futureSecurity.Holdings.SetHoldings(100, 10 * -1 * Math.Sign(target)); Update(futureSecurity, 100, algorithm); var model = GetModel(futureSecurity, out _futureMarginModel, algorithm.Portfolio); futureSecurity.BuyingPowerModel = _futureMarginModel; var quantity = algorithm.CalculateOrderQuantity(futureSecurity.Symbol, target); var expected = (algorithm.Portfolio.TotalPortfolioValue * Math.Abs(target) + Math.Abs(model.GetInitialMarginRequirement(futureSecurity, futureSecurity.Holdings.Quantity))) / _futureMarginModel.InitialOvernightMarginRequirement - 1 * Math.Abs(target); // -1 fees expected -= expected % futureSecurity.SymbolProperties.LotSize; Log.Trace($"Expected {expected}"); Assert.AreEqual(expected * Math.Sign(target), quantity); var request = GetOrderRequest(futureSecurity.Symbol, quantity); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(algorithm.Transactions, request)); Assert.IsTrue(model.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, expected * Math.Sign(target), DateTime.UtcNow))).IsSufficient); }
public void NegativeMarginRemaining(bool isError, int target, int side) { var algo = GetAlgorithm(); var security = InitAndGetSecurity(algo, 5); security.Holdings.SetHoldings(security.Price, 1000 * side); algo.Portfolio.CashBook.Add(algo.AccountCurrency, -100000, 1); var fakeOrderProcessor = new FakeOrderProcessor(); algo.Transactions.SetOrderProcessor(fakeOrderProcessor); Assert.IsTrue(algo.Portfolio.MarginRemaining < 0); var quantity = security.BuyingPowerModel.GetMaximumOrderQuantityForTargetBuyingPower( new GetMaximumOrderQuantityForTargetBuyingPowerParameters(algo.Portfolio, security, target * side, 0)).Quantity; if (!isError) { Assert.AreEqual(1000 * side * -1, quantity); } else { // even if we don't have margin 'GetMaximumOrderQuantityForTargetBuyingPower' doesn't care Assert.AreNotEqual(0, quantity); } var order = new MarketOrder(security.Symbol, quantity, new DateTime(2020, 1, 1)); fakeOrderProcessor.AddTicket(order.ToOrderTicket(algo.Transactions)); var actual = security.BuyingPowerModel.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algo.Portfolio, security, order)); Assert.AreEqual(!isError, actual.IsSufficient); }
public void GetMaximumOrderQuantityForTargetBuyingPower_TwoStep(decimal target) { var algorithm = new QCAlgorithm(); algorithm.SetFinishedWarmingUp(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); var orderProcessor = new FakeOrderProcessor(); algorithm.Transactions.SetOrderProcessor(orderProcessor); var ticker = QuantConnect.Securities.Futures.Financials.EuroDollar; var futureSecurity = algorithm.AddFuture(ticker); futureSecurity.BuyingPowerModel = GetModel(futureSecurity, out _futureMarginModel, algorithm.Portfolio); // set closed market for simpler math futureSecurity.Exchange.SetLocalDateTimeFrontier(new DateTime(2020, 2, 1)); Update(futureSecurity, 100, algorithm); var expectedFinalQuantity = algorithm.CalculateOrderQuantity(futureSecurity.Symbol, target); var quantity = algorithm.CalculateOrderQuantity(futureSecurity.Symbol, target / 2); futureSecurity.Holdings.SetHoldings(100, quantity); algorithm.Portfolio.InvalidateTotalPortfolioValue(); var quantity2 = algorithm.CalculateOrderQuantity(futureSecurity.Symbol, target); var request = GetOrderRequest(futureSecurity.Symbol, quantity2); request.SetOrderId(0); orderProcessor.AddTicket(new OrderTicket(algorithm.Transactions, request)); Assert.IsTrue(futureSecurity.BuyingPowerModel.HasSufficientBuyingPowerForOrder( new HasSufficientBuyingPowerForOrderParameters(algorithm.Portfolio, futureSecurity, new MarketOrder(futureSecurity.Symbol, quantity2, DateTime.UtcNow))).IsSufficient); // two step operation is the same as 1 step Assert.AreEqual(expectedFinalQuantity, quantity + quantity2); }
public void GenerateMarginCallOrderTests() { const int quantity = 1000; const decimal leverage = 1m; var orderProcessor = new FakeOrderProcessor(); var portfolio = GetPortfolio(orderProcessor, quantity); portfolio.MarginCallModel = new DefaultMarginCallModel(portfolio, null); var security = GetSecurity(Symbols.AAPL); portfolio.Securities.Add(security); var time = DateTime.Now; const decimal buyPrice = 1m; security.SetMarketPrice(new Tick(time, Symbols.AAPL, buyPrice, buyPrice)); 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.Cash, 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 }; var hasSufficientBuyingPower = security.BuyingPowerModel.HasSufficientBuyingPowerForOrder(portfolio, security, newOrder).IsSufficient; Assert.IsFalse(hasSufficientBuyingPower); // now the stock doubles, so we should have margin remaining time = time.AddDays(1); const decimal highPrice = buyPrice * 2; security.SetMarketPrice(new Tick(time, Symbols.AAPL, highPrice, highPrice)); 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 }; hasSufficientBuyingPower = security.BuyingPowerModel.HasSufficientBuyingPowerForOrder(portfolio, security, anotherOrder).IsSufficient; Assert.IsTrue(hasSufficientBuyingPower); // now the stock plummets, so we should have negative margin remaining time = time.AddDays(1); const decimal lowPrice = buyPrice / 2; security.SetMarketPrice(new Tick(time, Symbols.AAPL, lowPrice, lowPrice)); 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.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning); Assert.IsFalse(issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // now change the leverage to test margin call warning and margin call logic security.SetLeverage(leverage * 2); // Stock price increase by minimum variation const decimal newPrice = lowPrice + 0.01m; security.SetMarketPrice(new Tick(time, Symbols.AAPL, newPrice, newPrice)); // this would not cause a margin call, only a margin call warning marginCallOrders = portfolio.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning); Assert.IsTrue(issueMarginCallWarning); Assert.AreEqual(0, marginCallOrders.Count); // Price drops again to previous low, margin call orders will be issued security.SetMarketPrice(new Tick(time, Symbols.AAPL, lowPrice, lowPrice)); 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.MarginCallModel.GetMarginCallOrders(out issueMarginCallWarning); Assert.IsTrue(issueMarginCallWarning); Assert.AreEqual(1, marginCallOrders.Count); }