public void PartiallyFilledOrdersAreTakenIntoAccount(Language language) { var actualOrdersSubmitted = new List <SubmitOrderRequest>(); var algorithm = new QCAlgorithm(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); algorithm.SetPandasConverter(); var security = algorithm.AddEquity(Symbols.AAPL.Value); security.SetMarketPrice(new TradeBar { Value = 250 }); algorithm.SetFinishedWarmingUp(); var openOrderRequest = new SubmitOrderRequest(OrderType.Market, SecurityType.Equity, Symbols.AAPL, 100, 0, 0, DateTime.MinValue, ""); openOrderRequest.SetOrderId(1); var openOrderTicket = new OrderTicket(algorithm.Transactions, openOrderRequest); openOrderTicket.AddOrderEvent(new OrderEvent(1, Symbols.AAPL, DateTime.MinValue, OrderStatus.PartiallyFilled, OrderDirection.Buy, 250, 70, OrderFee.Zero)); var orderProcessor = new Mock <IOrderProcessor>(); orderProcessor.Setup(m => m.Process(It.IsAny <SubmitOrderRequest>())) .Returns((SubmitOrderRequest request) => new OrderTicket(algorithm.Transactions, request)) .Callback((SubmitOrderRequest request) => actualOrdersSubmitted.Add(request)); orderProcessor.Setup(m => m.GetOpenOrders(It.IsAny <Func <Order, bool> >())) .Returns(new List <Order> { new MarketOrder(Symbols.AAPL, 100, DateTime.MinValue) }); orderProcessor.Setup(m => m.GetOpenOrderTickets(It.IsAny <Func <OrderTicket, bool> >())) .Returns(new List <OrderTicket> { openOrderTicket }); algorithm.Transactions.SetOrderProcessor(orderProcessor.Object); var model = GetExecutionModel(language); algorithm.SetExecution(model); var changes = new SecurityChanges(Enumerable.Empty <Security>(), Enumerable.Empty <Security>()); model.OnSecuritiesChanged(algorithm, changes); var targets = new IPortfolioTarget[] { new PortfolioTarget(Symbols.AAPL, 80) }; model.Execute(algorithm, targets); Assert.AreEqual(1, actualOrdersSubmitted.Count); // Remaining quantity for partially filled order = 100 - 70 = 30 // Quantity submitted = 80 - 30 = 50 Assert.AreEqual(50, actualOrdersSubmitted.Sum(x => x.Quantity)); }
/// <summary> /// Gets the remaining quantity to be ordered to reach the specified target quantity. /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="target">The portfolio target</param> /// <param name="security">The target security</param> /// <returns>The signed remaining quantity to be ordered</returns> public static decimal GetUnorderedQuantity(IAlgorithm algorithm, IPortfolioTarget target, Security security) { var holdings = security.Holdings.Quantity; var openOrderQuantity = algorithm.Transactions.GetOpenOrderTickets(target.Symbol) .Aggregate(0m, (d, t) => d + t.Quantity - t.QuantityFilled); var quantity = target.Quantity - holdings - openOrderQuantity; return(AdjustByLotSize(security, quantity)); }
public void FillsOnTradesOnlyRespectingExchangeOpen(Language language, int expectedOrdersSubmitted, decimal expectedTotalQuantity, bool exchangeOpen) { var actualOrdersSubmitted = new List <SubmitOrderRequest>(); var time = new DateTime(2018, 8, 2, 0, 0, 0); if (exchangeOpen) { time = time.AddHours(14); } var algorithm = new QCAlgorithm(); algorithm.SetPandasConverter(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); algorithm.SetDateTime(time.AddMinutes(5)); var security = algorithm.AddEquity(Symbols.AAPL.Value); security.SetMarketPrice(new TradeBar { Value = 250 }); algorithm.SetFinishedWarmingUp(); var orderProcessor = new Mock <IOrderProcessor>(); orderProcessor.Setup(m => m.Process(It.IsAny <SubmitOrderRequest>())) .Returns((SubmitOrderRequest request) => new OrderTicket(algorithm.Transactions, request)) .Callback((OrderRequest request) => actualOrdersSubmitted.Add((SubmitOrderRequest)request)); orderProcessor.Setup(m => m.GetOpenOrders(It.IsAny <Func <Order, bool> >())) .Returns(new List <Order>()); algorithm.Transactions.SetOrderProcessor(orderProcessor.Object); var model = GetExecutionModel(language); algorithm.SetExecution(model); var changes = new SecurityChanges(new[] { security }, Enumerable.Empty <Security>()); model.OnSecuritiesChanged(algorithm, changes); var targets = new IPortfolioTarget[] { new PortfolioTarget(Symbols.AAPL, 10) }; model.Execute(algorithm, targets); Assert.AreEqual(expectedOrdersSubmitted, actualOrdersSubmitted.Count); Assert.AreEqual(expectedTotalQuantity, actualOrdersSubmitted.Sum(x => x.Quantity)); if (actualOrdersSubmitted.Count == 1) { var request = actualOrdersSubmitted[0]; Assert.AreEqual(expectedTotalQuantity, request.Quantity); Assert.AreEqual(algorithm.UtcTime, request.Time); } }
/// <summary> /// Gets the remaining quantity to be ordered to reach the specified target quantity. /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="target">The portfolio target</param> /// <returns>The remaining quantity to be ordered</returns> public static decimal GetUnorderedQuantity(IAlgorithm algorithm, IPortfolioTarget target) { var security = algorithm.Securities[target.Symbol]; var holdings = security.Holdings.Quantity; var openOrderQuantity = algorithm.Transactions.GetOpenOrders(target.Symbol).Aggregate(0m, (d, o) => d + o.Quantity); var quantity = target.Quantity - holdings - openOrderQuantity; // check if we're below the lot size threshold if (Math.Abs(quantity) < security.SymbolProperties.LotSize) { return(0m); } return(quantity); }
public void OrdersAreSubmittedImmediatelyForTargetsToExecute( Language language, double[] historicalPrices, decimal openOrdersQuantity, int expectedOrdersSubmitted, decimal expectedTotalQuantity) { var actualOrdersSubmitted = new List <SubmitOrderRequest>(); var time = new DateTime(2018, 8, 2, 16, 0, 0); var historyProvider = new Mock <IHistoryProvider>(); historyProvider.Setup(m => m.GetHistory(It.IsAny <IEnumerable <HistoryRequest> >(), It.IsAny <DateTimeZone>())) .Returns(historicalPrices.Select((x, i) => new Slice(time.AddMinutes(i), new List <BaseData> { new TradeBar { Time = time.AddMinutes(i), Symbol = Symbols.AAPL, Open = Convert.ToDecimal(x), High = Convert.ToDecimal(x), Low = Convert.ToDecimal(x), Close = Convert.ToDecimal(x), Volume = 100m } }))); var algorithm = new QCAlgorithm(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); algorithm.SetPandasConverter(); algorithm.SetHistoryProvider(historyProvider.Object); algorithm.SetDateTime(time.AddMinutes(5)); var security = algorithm.AddEquity(Symbols.AAPL.Value); security.SetMarketPrice(new TradeBar { Value = 250 }); algorithm.SetFinishedWarmingUp(); var openOrderRequest = new SubmitOrderRequest(OrderType.Market, SecurityType.Equity, Symbols.AAPL, openOrdersQuantity, 0, 0, DateTime.MinValue, ""); openOrderRequest.SetOrderId(1); var openOrderTicket = new OrderTicket(algorithm.Transactions, openOrderRequest); var orderProcessor = new Mock <IOrderProcessor>(); orderProcessor.Setup(m => m.Process(It.IsAny <SubmitOrderRequest>())) .Returns((SubmitOrderRequest request) => new OrderTicket(algorithm.Transactions, request)) .Callback((OrderRequest request) => actualOrdersSubmitted.Add((SubmitOrderRequest)request)); orderProcessor.Setup(m => m.GetOpenOrders(It.IsAny <Func <Order, bool> >())) .Returns(new List <Order> { new MarketOrder(Symbols.AAPL, openOrdersQuantity, DateTime.MinValue) }); orderProcessor.Setup(m => m.GetOpenOrderTickets(It.IsAny <Func <OrderTicket, bool> >())) .Returns(new List <OrderTicket> { openOrderTicket }); algorithm.Transactions.SetOrderProcessor(orderProcessor.Object); var model = GetExecutionModel(language); algorithm.SetExecution(model); var changes = SecurityChangesTests.CreateNonInternal(new[] { security }, Enumerable.Empty <Security>()); model.OnSecuritiesChanged(algorithm, changes); var targets = new IPortfolioTarget[] { new PortfolioTarget(Symbols.AAPL, 10) }; model.Execute(algorithm, targets); Assert.AreEqual(expectedOrdersSubmitted, actualOrdersSubmitted.Count); Assert.AreEqual(expectedTotalQuantity, actualOrdersSubmitted.Sum(x => x.Quantity)); if (actualOrdersSubmitted.Count == 1) { var request = actualOrdersSubmitted[0]; Assert.AreEqual(expectedTotalQuantity, request.Quantity); Assert.AreEqual(algorithm.UtcTime, request.Time); } }
/// <summary> /// They different framework models will process the new provided insight. /// The <see cref="IPortfolioConstructionModel"/> will create targets, /// the <see cref="IRiskManagementModel"/> will adjust the targets /// and the <see cref="IExecutionModel"/> will execute the <see cref="IPortfolioTarget"/> /// </summary> /// <param name="insights">The insight to process</param> private void ProcessInsights(Insight[] insights) { // construct portfolio targets from insights var targetsEnumerable = PortfolioConstruction.CreateTargets(this, insights); // for performance only call 'ToArray' if not empty enumerable (which is static) var targets = targetsEnumerable == Enumerable.Empty <IPortfolioTarget>() ? new IPortfolioTarget[] {} : targetsEnumerable.ToArray(); // set security targets w/ those generated via portfolio construction module foreach (var target in targets) { var security = Securities[target.Symbol]; security.Holdings.Target = target; } if (DebugMode) { // debug printing of generated targets if (targets.Length > 0) { Log($"{Time}: PORTFOLIO: {string.Join(" | ", targets.Select(t => t.ToString()).OrderBy(t => t))}"); } } var riskTargetOverridesEnumerable = RiskManagement.ManageRisk(this, targets); // for performance only call 'ToArray' if not empty enumerable (which is static) var riskTargetOverrides = riskTargetOverridesEnumerable == Enumerable.Empty <IPortfolioTarget>() ? new IPortfolioTarget[] { } : riskTargetOverridesEnumerable.ToArray(); // override security targets w/ those generated via risk management module foreach (var target in riskTargetOverrides) { var security = Securities[target.Symbol]; security.Holdings.Target = target; } if (DebugMode) { // debug printing of generated risk target overrides if (riskTargetOverrides.Length > 0) { Log($"{Time}: RISK: {string.Join(" | ", riskTargetOverrides.Select(t => t.ToString()).OrderBy(t => t))}"); } } IPortfolioTarget[] riskAdjustedTargets; // for performance we check the length before if (riskTargetOverrides.Length != 0 || targets.Length != 0) { // execute on the targets, overriding targets for symbols w/ risk targets riskAdjustedTargets = riskTargetOverrides.Concat(targets).DistinctBy(pt => pt.Symbol).ToArray(); } else { riskAdjustedTargets = new IPortfolioTarget[] { }; } if (DebugMode) { // only log adjusted targets if we've performed an adjustment if (riskTargetOverrides.Length > 0) { Log($"{Time}: RISK ADJUSTED TARGETS: {string.Join(" | ", riskAdjustedTargets.Select(t => t.ToString()).OrderBy(t => t))}"); } } Execution.Execute(this, riskAdjustedTargets); }
public void OrdersAreSubmittedWhenRequiredForTargetsToExecute( Language language, double[] historicalPrices, decimal lastVolume, int expectedOrdersSubmitted, decimal expectedTotalQuantity) { var actualOrdersSubmitted = new List <SubmitOrderRequest>(); var time = new DateTime(2018, 8, 2, 16, 0, 0); var historyProvider = new Mock <IHistoryProvider>(); historyProvider.Setup(m => m.GetHistory(It.IsAny <IEnumerable <HistoryRequest> >(), It.IsAny <DateTimeZone>())) .Returns(historicalPrices.Select((x, i) => new Slice(time.AddMinutes(i), new List <BaseData> { new TradeBar { Time = time.AddMinutes(i), Symbol = Symbols.AAPL, Open = Convert.ToDecimal(x), High = Convert.ToDecimal(x), Low = Convert.ToDecimal(x), Close = Convert.ToDecimal(x), Volume = 100m } }))); var algorithm = new QCAlgorithm(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); algorithm.SetPandasConverter(); algorithm.SetHistoryProvider(historyProvider.Object); algorithm.SetDateTime(time.AddMinutes(5)); var security = algorithm.AddEquity(Symbols.AAPL.Value); security.SetMarketPrice(new TradeBar { Value = 250, Volume = lastVolume }); algorithm.SetFinishedWarmingUp(); var orderProcessor = new Mock <IOrderProcessor>(); orderProcessor.Setup(m => m.Process(It.IsAny <SubmitOrderRequest>())) .Returns((SubmitOrderRequest request) => new OrderTicket(algorithm.Transactions, request)) .Callback((OrderRequest request) => actualOrdersSubmitted.Add((SubmitOrderRequest)request)); orderProcessor.Setup(m => m.GetOpenOrders(It.IsAny <Func <Order, bool> >())) .Returns(new List <Order>()); algorithm.Transactions.SetOrderProcessor(orderProcessor.Object); var model = GetExecutionModel(language); algorithm.SetExecution(model); var changes = new SecurityChanges(new[] { security }, Enumerable.Empty <Security>()); model.OnSecuritiesChanged(algorithm, changes); algorithm.History(new List <Symbol> { security.Symbol }, historicalPrices.Length, Resolution.Minute) .PushThroughConsolidators(symbol => algorithm.Securities[symbol].Subscriptions.Single(s => s.TickType == LeanData.GetCommonTickType(SecurityType.Equity)).Consolidators.First()); var targets = new IPortfolioTarget[] { new PortfolioTarget(security.Symbol, 10) }; model.Execute(algorithm, targets); Assert.AreEqual(expectedOrdersSubmitted, actualOrdersSubmitted.Count); Assert.AreEqual(expectedTotalQuantity, actualOrdersSubmitted.Sum(x => x.Quantity)); if (actualOrdersSubmitted.Count == 1) { var request = actualOrdersSubmitted[0]; Assert.AreEqual(expectedTotalQuantity, request.Quantity); Assert.AreEqual(algorithm.UtcTime, request.Time); } }
public void OrdersAreSubmittedWhenRequiredForTargetsToExecute( Language language, decimal currentPrice, int expectedOrdersSubmitted, decimal expectedTotalQuantity) { var actualOrdersSubmitted = new List <SubmitOrderRequest>(); var time = new DateTime(2018, 8, 2, 14, 0, 0); var algorithm = new QCAlgorithm(); algorithm.SetPandasConverter(); algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm)); algorithm.SetDateTime(time.AddMinutes(5)); var security = algorithm.AddEquity(Symbols.AAPL.Value); security.SetMarketPrice(new TradeBar { Value = 250 }); // pushing the ask higher will cause the spread the widen and no trade to happen var ask = expectedOrdersSubmitted == 0 ? currentPrice * 1.1m : currentPrice; security.SetMarketPrice(new QuoteBar { Time = time, Symbol = Symbols.AAPL, Ask = new Bar(ask, ask, ask, ask), Bid = new Bar(currentPrice, currentPrice, currentPrice, currentPrice) }); algorithm.SetFinishedWarmingUp(); var orderProcessor = new Mock <IOrderProcessor>(); orderProcessor.Setup(m => m.Process(It.IsAny <SubmitOrderRequest>())) .Returns((SubmitOrderRequest request) => new OrderTicket(algorithm.Transactions, request)) .Callback((OrderRequest request) => actualOrdersSubmitted.Add((SubmitOrderRequest)request)); orderProcessor.Setup(m => m.GetOpenOrders(It.IsAny <Func <Order, bool> >())) .Returns(new List <Order>()); algorithm.Transactions.SetOrderProcessor(orderProcessor.Object); var model = GetExecutionModel(language); algorithm.SetExecution(model); var changes = new SecurityChanges(new[] { security }, Enumerable.Empty <Security>()); model.OnSecuritiesChanged(algorithm, changes); var targets = new IPortfolioTarget[] { new PortfolioTarget(Symbols.AAPL, 10) }; model.Execute(algorithm, targets); Assert.AreEqual(expectedOrdersSubmitted, actualOrdersSubmitted.Count); Assert.AreEqual(expectedTotalQuantity, actualOrdersSubmitted.Sum(x => x.Quantity)); if (actualOrdersSubmitted.Count == 1) { var request = actualOrdersSubmitted[0]; Assert.AreEqual(expectedTotalQuantity, request.Quantity); Assert.AreEqual(algorithm.UtcTime, request.Time); } }
/// <summary> /// Gets the remaining quantity to be ordered to reach the specified target quantity. /// </summary> /// <param name="algorithm">The algorithm instance</param> /// <param name="target">The portfolio target</param> /// <returns>The signed remaining quantity to be ordered</returns> public static decimal GetUnorderedQuantity(IAlgorithm algorithm, IPortfolioTarget target) { var security = algorithm.Securities[target.Symbol]; return(GetUnorderedQuantity(algorithm, target, security)); }
/// <summary> /// They different framework models will process the new provided insight. /// The <see cref="IPortfolioConstructionModel"/> will create targets, /// the <see cref="IRiskManagementModel"/> will adjust the targets /// and the <see cref="IExecutionModel"/> will execute the <see cref="IPortfolioTarget"/> /// </summary> /// <param name="insights">The insight to process</param> protected void ProcessInsights(Insight[] insights) { // construct portfolio targets from insights var targetsEnumerable = PortfolioConstruction.CreateTargets(this, insights); // for performance only call 'ToArray' if not empty enumerable (which is static) var targets = targetsEnumerable == Enumerable.Empty <IPortfolioTarget>() ? new IPortfolioTarget[] {} : targetsEnumerable.ToArray(); // set security targets w/ those generated via portfolio construction module foreach (var target in targets) { var security = Securities[target.Symbol]; security.Holdings.Target = target; } if (DebugMode) { // debug printing of generated targets if (targets.Length > 0) { Log($"{Time}: PORTFOLIO: {string.Join(" | ", targets.Select(t => t.ToString()).OrderBy(t => t))}"); } } var riskTargetOverridesEnumerable = RiskManagement.ManageRisk(this, targets); // for performance only call 'ToArray' if not empty enumerable (which is static) var riskTargetOverrides = riskTargetOverridesEnumerable == Enumerable.Empty <IPortfolioTarget>() ? new IPortfolioTarget[] { } : riskTargetOverridesEnumerable.ToArray(); // override security targets w/ those generated via risk management module foreach (var target in riskTargetOverrides) { var security = Securities[target.Symbol]; security.Holdings.Target = target; } if (DebugMode) { // debug printing of generated risk target overrides if (riskTargetOverrides.Length > 0) { Log($"{Time}: RISK: {string.Join(" | ", riskTargetOverrides.Select(t => t.ToString()).OrderBy(t => t))}"); } } IPortfolioTarget[] riskAdjustedTargets; // for performance we check the length before if (riskTargetOverrides.Length != 0 || targets.Length != 0) { // execute on the targets, overriding targets for symbols w/ risk targets riskAdjustedTargets = riskTargetOverrides.Concat(targets).DistinctBy(pt => pt.Symbol).ToArray(); } else { riskAdjustedTargets = new IPortfolioTarget[] { }; } if (DebugMode) { // only log adjusted targets if we've performed an adjustment if (riskTargetOverrides.Length > 0) { Log($"{Time}: RISK ADJUSTED TARGETS: {string.Join(" | ", riskAdjustedTargets.Select(t => t.ToString()).OrderBy(t => t))}"); } } if (riskAdjustedTargets.Length > 0 && Execution.GetType() != typeof(NullExecutionModel) && BrokerageModel.AccountType == AccountType.Cash) { throw new InvalidOperationException($"Non null {nameof(IExecutionModel)} and {nameof(IPortfolioConstructionModel)} are currently unsuitable for Cash Modeled brokerages (e.g. GDAX) and may result in unexpected trades." + " To prevent possible user error we've restricted them to Margin trading. You can select margin account types with" + $" SetBrokerage( ... AccountType.Margin). Or please set them to {nameof(NullExecutionModel)}, {nameof(NullPortfolioConstructionModel)}"); } Execution.Execute(this, riskAdjustedTargets); }