コード例 #1
0
        private QCAlgorithm GetAlgorithm(decimal?holdings = null)
        {
            var algorithm = new AlgorithmStub();

            algorithm.Transactions.SetOrderProcessor(new FakeOrderProcessor());
            var aapl = algorithm.AddEquity(Symbols.AAPL.Value);

            Update(aapl, 1);

            if (holdings != null)
            {
                aapl.Holdings.SetHoldings(10, holdings.Value);
            }
            return(algorithm);
        }
コード例 #2
0
        public void WarmUpInternalSubscriptions()
        {
            var algo = new AlgorithmStub(new MockDataFeed())
            {
                HistoryProvider = new SubscriptionDataReaderHistoryProvider()
            };

            algo.SetStartDate(2013, 10, 08);
            algo.AddCfd("DE30EUR", Resolution.Second, Market.Oanda);
            algo.SetWarmup(10);
            algo.PostInitialize();
            algo.DataManager.UniverseSelection.EnsureCurrencyDataFeeds(SecurityChanges.None);

            Assert.AreEqual(algo.StartDate - TimeSpan.FromSeconds(10), algo.Time);
        }
コード例 #3
0
        public void Works()
        {
            var algorithm = new AlgorithmStub();

            algorithm.HistoryProvider = new TestHistoryProvider();
            var security = algorithm.AddEquity(Symbols.SPY);
            var model    = new TestVolatilityModel();

            security.VolatilityModel = model;

            AlgorithmManager.ProcessVolatilityHistoryRequirements(algorithm);

            Assert.AreEqual(1, model.dataUpdate.Count);
            Assert.AreEqual(Symbols.SPY, model.dataUpdate.First().Symbol);
            Assert.AreEqual(4, model.dataUpdate.First().Price);
        }
コード例 #4
0
        public void DailySampleValueBasedOnMarketHour(bool extendedMarketHoursEnabled)
        {
            var referenceDate = new DateTime(2020, 11, 25);
            var resultHandler = new LiveTradingResultHandler();

            resultHandler.Initialize(new LiveNodePacket(),
                                     new QuantConnect.Messaging.Messaging(),
                                     new Api.Api(),
                                     new BacktestingTransactionHandler());

            var algo = new AlgorithmStub(createDataManager: false);

            algo.SetFinishedWarmingUp();
            var dataManager = new DataManagerStub(new TestDataFeed(), algo);

            algo.SubscriptionManager.SetDataManager(dataManager);
            var aapl = algo.AddEquity("AAPL", extendedMarketHours: extendedMarketHoursEnabled);

            algo.PostInitialize();
            resultHandler.SetAlgorithm(algo, 100000);
            resultHandler.OnSecuritiesChanged(SecurityChangesTests.AddedNonInternal(aapl));

            // Add values during market hours, should always update
            algo.Portfolio.CashBook["USD"].AddAmount(1000);
            algo.Portfolio.InvalidateTotalPortfolioValue();

            resultHandler.Sample(referenceDate.AddHours(15));
            Assert.IsTrue(resultHandler.Charts.ContainsKey("Strategy Equity"));
            Assert.AreEqual(1, resultHandler.Charts["Strategy Equity"].Series["Equity"].Values.Count);

            var currentEquityValue = resultHandler.Charts["Strategy Equity"].Series["Equity"].Values.Last().y;

            Assert.AreEqual(101000, currentEquityValue);

            // Add value to portfolio, see if portfolio updates with new sample
            // will be changed to 'extendedMarketHoursEnabled' = true
            algo.Portfolio.CashBook["USD"].AddAmount(10000);
            algo.Portfolio.InvalidateTotalPortfolioValue();

            resultHandler.Sample(referenceDate.AddHours(22));
            Assert.AreEqual(2, resultHandler.Charts["Strategy Equity"].Series["Equity"].Values.Count);

            currentEquityValue = resultHandler.Charts["Strategy Equity"].Series["Equity"].Values.Last().y;
            Assert.AreEqual(extendedMarketHoursEnabled ? 111000 : 101000, currentEquityValue);

            resultHandler.Exit();
        }
コード例 #5
0
        public void DailySampleValueBasedOnMarketHour(bool extendedMarketHoursEnabled)
        {
            var referenceDate = new DateTime(2020, 11, 25);
            var resultHandler = new TestLiveTradingResultHandler
            {
                // market is open
                InitialSampleTime = referenceDate.AddHours(10)
            };

            resultHandler.Initialize(new LiveNodePacket(),
                                     new QuantConnect.Messaging.Messaging(),
                                     new Api.Api(),
                                     new BacktestingTransactionHandler());

            var algo = new AlgorithmStub(createDataManager: false);

            algo.SetFinishedWarmingUp();
            var dataManager = new DataManagerStub(new TestDataFeed(), algo);

            algo.SubscriptionManager.SetDataManager(dataManager);
            var aapl = algo.AddEquity("AAPL", extendedMarketHours: extendedMarketHoursEnabled);

            algo.PostInitialize();
            resultHandler.SetAlgorithm(algo, 100000);
            resultHandler.OnSecuritiesChanged(SecurityChanges.Added(aapl));

            algo.Portfolio.CashBook["USD"].AddAmount(1000);
            algo.Portfolio.InvalidateTotalPortfolioValue();
            resultHandler.Sample(referenceDate.AddHours(15));

            Assert.IsFalse(resultHandler.Charts.ContainsKey("Strategy Equity"), "Should not sample on the same start date");

            // will be ignored based on 'extendedMarketHoursEnabled'
            algo.Portfolio.CashBook["USD"].AddAmount(10000);
            algo.Portfolio.InvalidateTotalPortfolioValue();
            resultHandler.Sample(referenceDate.AddHours(22));

            Assert.IsFalse(resultHandler.Charts.ContainsKey("Strategy Equity"), "Should not sample on the same start date");

            resultHandler.Sample(referenceDate.AddHours(24));
            Assert.IsTrue(resultHandler.Charts.ContainsKey("Strategy Equity"), "Expect sample of date change");

            Assert.AreEqual(extendedMarketHoursEnabled ? 111000 : 101000,
                            resultHandler.Charts["Strategy Equity"].Series["Equity"].Values.Single().y);

            resultHandler.Exit();
        }
コード例 #6
0
        public void WarmUpPythonIndicatorProperly()
        {
            var algo = new AlgorithmStub
            {
                HistoryProvider = new SubscriptionDataReaderHistoryProvider()
            };
            var zipCacheProvider = new ZipDataCacheProvider(TestGlobals.DataProvider);

            algo.HistoryProvider.Initialize(new HistoryProviderInitializeParameters(
                                                null,
                                                null,
                                                TestGlobals.DataProvider,
                                                zipCacheProvider,
                                                TestGlobals.MapFileProvider,
                                                TestGlobals.FactorFileProvider,
                                                null,
                                                false,
                                                new DataPermissionManager()));
            algo.SetStartDate(2013, 10, 08);
            algo.AddEquity("SPY", Resolution.Minute);

            // Different types of indicators
            var indicatorDataPoint = new SimpleMovingAverage("SPY", 10);
            var indicatorDataBar   = new AverageTrueRange("SPY", 10);
            var indicatorTradeBar  = new VolumeWeightedAveragePriceIndicator("SPY", 10);

            using (Py.GIL())
            {
                var sma   = indicatorDataPoint.ToPython();
                var atr   = indicatorTradeBar.ToPython();
                var vwapi = indicatorDataBar.ToPython();

                Assert.DoesNotThrow(() => algo.WarmUpIndicator("SPY", sma, Resolution.Minute));
                Assert.DoesNotThrow(() => algo.WarmUpIndicator("SPY", atr, Resolution.Minute));
                Assert.DoesNotThrow(() => algo.WarmUpIndicator("SPY", vwapi, Resolution.Minute));

                var smaIsReady   = ((dynamic)sma).IsReady;
                var atrIsReady   = ((dynamic)atr).IsReady;
                var vwapiIsReady = ((dynamic)vwapi).IsReady;

                Assert.IsTrue(smaIsReady.IsTrue());
                Assert.IsTrue(atrIsReady.IsTrue());
                Assert.IsTrue(vwapiIsReady.IsTrue());
            }

            zipCacheProvider.DisposeSafely();
        }
コード例 #7
0
        public void GetUnorderedQuantityHoldingsNoOrders(decimal holdings, decimal target, decimal expected)
        {
            var algo = new AlgorithmStub();

            algo.Transactions.SetOrderProcessor(new FakeOrderProcessor());
            var security = algo.AddFutureContract(Symbols.Future_CLF19_Jan2019);

            security.SetMarketPrice(new TradeBar {
                Value = 250
            });
            security.Holdings.SetHoldings(250, holdings);

            var result = OrderSizing.GetUnorderedQuantity(algo,
                                                          new PortfolioTarget(Symbols.Future_CLF19_Jan2019, target));

            Assert.AreEqual(expected, result);
        }
コード例 #8
0
        public void WarmUpUniverseSelection()
        {
            var algo = new AlgorithmStub(new MockDataFeed())
            {
                HistoryProvider = new SubscriptionDataReaderHistoryProvider()
            };

            algo.SetStartDate(2013, 10, 08);
            var universe = algo.AddUniverse((_) => Enumerable.Empty <Symbol>());
            var barCount = 3;

            algo.SetWarmup(barCount);
            algo.PostInitialize();

            // +2 is due to the weekend
            Assert.AreEqual(algo.StartDate - universe.Configuration.Resolution.ToTimeSpan() * (barCount + 2), algo.Time);
        }
コード例 #9
0
        public void GetOrderSizeForMaximumValue(decimal maximumOrderValue, decimal target, decimal expected)
        {
            var algo     = new AlgorithmStub();
            var security = algo.AddFutureContract(Symbols.Future_CLF19_Jan2019);

            security.SetMarketPrice(new TradeBar {
                Value = 250
            });

            var result = OrderSizing.GetOrderSizeForMaximumValue(security, maximumOrderValue, target);

            var expectedCalculated = maximumOrderValue / (security.Price * security.SymbolProperties.ContractMultiplier);

            expectedCalculated -= expectedCalculated % security.SymbolProperties.LotSize;

            Assert.AreEqual(Math.Min(expectedCalculated, Math.Abs(target)) * Math.Sign(target), result);
            Assert.AreEqual(expected, result);
        }
コード例 #10
0
        public void DoesNotAddOnEndOfDayEventsIfNotImplemented(Language language)
        {
            Security   security;
            IAlgorithm algorithm;

            if (language == Language.CSharp)
            {
                algorithm = new AlgorithmStub();
                security  = (algorithm as QCAlgorithm).AddEquity("SPY");
            }
            else
            {
                algorithm = new AlgorithmPythonWrapper("Test_CustomDataAlgorithm");
                algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm));
                security = algorithm.AddSecurity(SecurityType.Equity,
                                                 "SPY",
                                                 Resolution.Daily,
                                                 Market.USA,
                                                 false,
                                                 1,
                                                 false);
            }

            var realTimeHandler = new TestBacktestingRealTimeHandler();

            realTimeHandler.Setup(algorithm,
                                  new AlgorithmNodePacket(PacketType.AlgorithmNode)
            {
                Language = language
            },
                                  _resultHandler,
                                  null,
                                  new TestTimeLimitManager());

            Assert.AreEqual(0, realTimeHandler.GetScheduledEventsCount);

            realTimeHandler.OnSecuritiesChanged(
                new SecurityChanges(new[] { security }, Enumerable.Empty <Security>()));

            Assert.AreEqual(0, realTimeHandler.GetScheduledEventsCount);

            realTimeHandler.Exit();
        }
コード例 #11
0
        public void GetUnorderedQuantityHoldingsOpenOrders(decimal holdings, decimal target, decimal filledQuantity, decimal expected)
        {
            var algo           = new AlgorithmStub();
            var orderProcessor = new FakeOrderProcessor();
            var orderRequest   = new SubmitOrderRequest(
                OrderType.Market,
                SecurityType.Future,
                Symbols.Future_CLF19_Jan2019,
                filledQuantity * 2,
                250,
                250,
                new DateTime(2020, 1, 1),
                "Pepe"
                );

            var order  = Order.CreateOrder(orderRequest);
            var ticket = new OrderTicket(algo.Transactions, orderRequest);

            ticket.SetOrder(order);

            ticket.AddOrderEvent(new OrderEvent(1,
                                                Symbols.Future_CLF19_Jan2019,
                                                new DateTime(2020, 1, 1),
                                                OrderStatus.Filled,
                                                filledQuantity > 0 ? OrderDirection.Buy : OrderDirection.Sell,
                                                250,
                                                filledQuantity,
                                                OrderFee.Zero));

            orderProcessor.AddTicket(ticket);
            algo.Transactions.SetOrderProcessor(orderProcessor);
            var security = algo.AddFutureContract(Symbols.Future_CLF19_Jan2019);

            security.SetMarketPrice(new TradeBar {
                Value = 250
            });
            security.Holdings.SetHoldings(250, holdings);

            var result = OrderSizing.GetUnorderedQuantity(algo,
                                                          new PortfolioTarget(Symbols.Future_CLF19_Jan2019, target));

            Assert.AreEqual(expected, result);
        }
コード例 #12
0
ファイル: PaperBrokerageTests.cs プロジェクト: adam-may/Lean
        public void AppliesDividendDistributionDirectlyToPortfolioCashBook()
        {
            // init algorithm
            var algorithm = new AlgorithmStub(new MockDataFeed());

            algorithm.AddSecurities(equities: new List <string> {
                "SPY"
            });
            algorithm.PostInitialize();

            // init holdings
            var SPY = algorithm.Securities[Symbols.SPY];

            SPY.SetMarketPrice(new Tick {
                Value = 100m
            });
            SPY.Holdings.SetHoldings(100m, 1000);

            // resolve expected outcome
            var USD = algorithm.Portfolio.CashBook[Currencies.USD];
            var preDistributionCash       = USD.Amount;
            var distributionPerShare      = 10m;
            var expectedTotalDistribution = distributionPerShare * SPY.Holdings.Quantity;

            // create slice w/ dividend
            var slice = new Slice(algorithm.Time, new List <BaseData>(), algorithm.Time);

            slice.Dividends.Add(new Dividend(Symbols.SPY, algorithm.Time, distributionPerShare, 100m));
            algorithm.SetCurrentSlice(slice);

            // invoke brokerage
            var brokerage = new PaperBrokerage(algorithm, null);

            brokerage.Scan();

            // verify results
            var postDistributionCash = USD.Amount;

            Assert.AreEqual(preDistributionCash + expectedTotalDistribution, postDistributionCash);
        }
コード例 #13
0
        public void WarmupStartDate_NoAsset(bool withResolution)
        {
            var algo = new AlgorithmStub();

            algo.SetStartDate(2013, 10, 01);
            DateTime expected;

            if (withResolution)
            {
                algo.SetWarmUp(100, Resolution.Daily);
                expected = new DateTime(2013, 06, 23);
            }
            else
            {
                algo.SetWarmUp(100);
                // defaults to universe settings
                expected = new DateTime(2013, 09, 30, 22, 20, 0);
            }
            algo.PostInitialize();

            Assert.AreEqual(expected, algo.Time);
        }
コード例 #14
0
        public void SetsAlgorithmRunTimeErrorOnDisconnectIfNonCustomSecurityIsOpen()
        {
            var algorithm = new AlgorithmStub(equities: new List <string> {
                "SPY"
            });

            algorithm.Securities["SPY"].Exchange = new SecurityExchange(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork));
            var job     = new LiveNodePacket();
            var results = new TestResultHandler();//packet => Console.WriteLine(FieldsToString(packet)));
            var api     = new Api.Api();
            var handler = new DefaultBrokerageMessageHandler(algorithm, job, results, api, TimeSpan.Zero);

            Assert.IsNull(algorithm.RunTimeError);

            handler.Handle(BrokerageMessageEvent.Disconnected("Disconnection!"));

            Thread.Sleep(10);

            Assert.IsNotNull(algorithm.RunTimeError);

            results.Exit();
        }
コード例 #15
0
        public void WarmUpInternalSubscriptionsHistoryRequest()
        {
            var algo = new AlgorithmStub(new MockDataFeed())
            {
                HistoryProvider = new SubscriptionDataReaderHistoryProvider()
            };

            algo.SetStartDate(2013, 10, 08);
            algo.AddCfd("DE30EUR", Resolution.Second, Market.Oanda);
            algo.SetWarmup(10);
            algo.PostInitialize();
            algo.OnEndOfTimeStep();
            algo.DataManager.UniverseSelection.EnsureCurrencyDataFeeds(SecurityChanges.None);

            var result = algo.GetWarmupHistoryRequests();

            foreach (var historyRequest in result)
            {
                Assert.AreEqual(Resolution.Second, historyRequest.Resolution);
                Assert.AreEqual(TimeSpan.FromSeconds(10), historyRequest.EndTimeUtc - historyRequest.StartTimeUtc);
            }
        }
コード例 #16
0
        public void DoesNotSetAlgorithmRunTimeErrorOnDisconnectIfAllSecuritiesClosed()
        {
            var referenceTime = DateTime.UtcNow;
            var algorithm     = new AlgorithmStub(equities: new List <string> {
                "SPY"
            });

            algorithm.SetDateTime(referenceTime);
            algorithm.Securities[Symbols.SPY].Exchange.SetMarketHours(Enumerable.Empty <MarketHoursSegment>(), referenceTime.ConvertFromUtc(TimeZones.NewYork).DayOfWeek);
            var job     = new LiveNodePacket();
            var results = new TestResultHandler();//packet => Console.WriteLine(FieldsToString(packet)));
            var api     = new Api.Api();
            var handler = new DefaultBrokerageMessageHandler(algorithm, job, results, api, TimeSpan.FromMinutes(15));

            Assert.IsNull(algorithm.RunTimeError);

            handler.Handle(BrokerageMessageEvent.Disconnected("Disconnection!"));

            Assert.IsNull(algorithm.RunTimeError);

            results.Exit();
        }
コード例 #17
0
        public void OptionExersiceWhenFullyInvested()
        {
            var algorithm = new AlgorithmStub();

            algorithm.SetFinishedWarmingUp();
            var backtestingTransactionHandler = new BacktestingTransactionHandler();

            algorithm.Transactions.SetOrderProcessor(backtestingTransactionHandler);
            backtestingTransactionHandler.Initialize(algorithm, new BacktestingBrokerage(algorithm), new TestResultHandler(packet => { }));

            const decimal price   = 2600m;
            var           time    = new DateTime(2020, 10, 14);
            var           expDate = new DateTime(2021, 3, 19);

            // For this symbol we dont have any history, but only one date and margins line
            var ticker = QuantConnect.Securities.Futures.Indices.SP500EMini;
            var future = Symbol.CreateFuture(ticker, Market.CME, expDate);
            var symbol = Symbol.CreateOption(future, Market.CME, OptionStyle.American, OptionRight.Call, 2550m,
                                             new DateTime(2021, 3, 19));

            var optionSecurity = algorithm.AddOptionContract(symbol);

            optionSecurity.Underlying = algorithm.AddFutureContract(future);

            optionSecurity.Underlying.SetMarketPrice(new Tick {
                Value = price, Time = time
            });
            optionSecurity.SetMarketPrice(new Tick {
                Value = 150, Time = time
            });
            optionSecurity.Holdings.SetHoldings(1.5m, 10);

            var request = optionSecurity.CreateDelistedSecurityOrderRequest(algorithm.UtcTime);

            var ticket = algorithm.Transactions.AddOrder(request);

            Assert.AreEqual(OrderStatus.Filled, ticket.Status);
        }
コード例 #18
0
        public void DoesNotSetRunTimeErrorWhenReconnectMessageComesThrough()
        {
            var algorithm = new AlgorithmStub();

            algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm));
            algorithm.AddSecurities(equities: new List <string> {
                "SPY"
            });
            var referenceTime = DateTime.UtcNow;

            algorithm.SetDateTime(referenceTime);
            var localReferencTime = referenceTime.ConvertFromUtc(TimeZones.NewYork);
            var open        = localReferencTime.AddSeconds(1).TimeOfDay;
            var closed      = TimeSpan.FromDays(1);
            var marketHours = new MarketHoursSegment(MarketHoursState.Market, open, closed);

            algorithm.Securities[Symbols.SPY].Exchange.SetMarketHours(new [] { marketHours }, localReferencTime.DayOfWeek);
            var job     = new LiveNodePacket();
            var results = new TestResultHandler();//packet => Console.WriteLine(FieldsToString(packet)));
            var api     = new Api.Api();
            var handler = new DefaultBrokerageMessageHandler(algorithm, job, api, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(.25));

            Assert.IsNull(algorithm.RunTimeError);

            handler.Handle(BrokerageMessageEvent.Disconnected("Disconnection!"));

            Thread.Sleep(100);

            handler.Handle(BrokerageMessageEvent.Reconnected("Reconnected!"));

            Thread.Sleep(500);

            Assert.IsNull(algorithm.RunTimeError);

            results.Exit();
        }
コード例 #19
0
ファイル: PaperBrokerageTests.cs プロジェクト: adam-may/Lean
        public void AppliesDividendsOnce()
        {
            // init algorithm
            var algorithm = new AlgorithmStub(new MockDataFeed());

            algorithm.SetLiveMode(true);
            var dividend = new Dividend(Symbols.SPY, DateTime.UtcNow, 10m, 100m);

            var feed = new MockDataFeed();

            var marketHoursDatabase      = MarketHoursDatabase.FromDataFolder();
            var symbolPropertiesDataBase = SymbolPropertiesDatabase.FromDataFolder();
            var dataPermissionManager    = new DataPermissionManager();
            var dataManager = new DataManager(feed,
                                              new UniverseSelection(
                                                  algorithm,
                                                  new SecurityService(algorithm.Portfolio.CashBook, marketHoursDatabase, symbolPropertiesDataBase, algorithm, RegisteredSecurityDataTypesProvider.Null, new SecurityCacheProvider(algorithm.Portfolio)),
                                                  dataPermissionManager,
                                                  new DefaultDataProvider()),
                                              algorithm,
                                              algorithm.TimeKeeper,
                                              marketHoursDatabase,
                                              true,
                                              RegisteredSecurityDataTypesProvider.Null,
                                              dataPermissionManager);
            var synchronizer = new NullSynchronizer(algorithm, dividend);

            algorithm.SubscriptionManager.SetDataManager(dataManager);
            algorithm.AddSecurities(equities: new List <string> {
                "SPY"
            });
            algorithm.Securities[Symbols.SPY].Holdings.SetHoldings(100m, 1);
            algorithm.PostInitialize();

            var initializedCash = algorithm.Portfolio.CashBook[Currencies.USD].Amount;

            // init algorithm manager
            var manager = new AlgorithmManager(true);
            var job     = new LiveNodePacket
            {
                UserId    = 1,
                ProjectId = 2,
                DeployId  = $"{nameof(PaperBrokerageTests)}.{nameof(AppliesDividendsOnce)}"
            };
            var results      = new LiveTradingResultHandler();
            var transactions = new BacktestingTransactionHandler();
            var brokerage    = new PaperBrokerage(algorithm, job);

            // initialize results and transactions
            results.Initialize(job, new EventMessagingHandler(), new Api.Api(), transactions);
            results.SetAlgorithm(algorithm, algorithm.Portfolio.TotalPortfolioValue);
            transactions.Initialize(algorithm, brokerage, results);

            var realTime = new BacktestingRealTimeHandler();

            // run algorithm manager
            manager.Run(job,
                        algorithm,
                        synchronizer,
                        transactions,
                        results,
                        realTime,
                        new AlgorithmManagerTests.NullLeanManager(),
                        new AlgorithmManagerTests.NullAlphaHandler(),
                        new CancellationToken()
                        );

            var postDividendCash = algorithm.Portfolio.CashBook[Currencies.USD].Amount;

            realTime.Exit();
            results.Exit();
            Assert.AreEqual(initializedCash + dividend.Distribution, postDividendCash);
        }
コード例 #20
0
        public void PythonDoesNotImplementDetermineTargetPercent()
        {
            var algorithm = new AlgorithmStub();

            using (Py.GIL())
            {
                dynamic model = PythonEngine.ModuleFromString(
                    "TestPCM",
                    @"

from clr import AddReference
AddReference(""QuantConnect.Algorithm.Framework"")

from QuantConnect.Algorithm.Framework.Portfolio import *

class PyPCM(EqualWeightingPortfolioConstructionModel):
    def __init__(self):
        self.CreateTargets_WasCalled = False
        self.OnSecuritiesChanged_WasCalled = False
        self.ShouldCreateTargetForInsight_WasCalled = False
        self.IsRebalanceDue_WasCalled = False
        self.GetTargetInsights_WasCalled = False

    def CreateTargets(self, algorithm, insights):
        self.CreateTargets_WasCalled = True
        return super().CreateTargets(algorithm, insights)

    def OnSecuritiesChanged(self, algorithm, changes):
        self.OnSecuritiesChanged_WasCalled = True
        super().OnSecuritiesChanged(algorithm, changes)

    def ShouldCreateTargetForInsight(self, insight):
        self.ShouldCreateTargetForInsight_WasCalled = True
        return super().ShouldCreateTargetForInsight(insight)

    def IsRebalanceDue(self, insights, algorithmUtc):
        self.IsRebalanceDue_WasCalled = True
        return True

    def GetTargetInsights(self):
        self.GetTargetInsights_WasCalled = True
        return super().GetTargetInsights()
"
                    ).GetAttr("PyPCM").Invoke();

                var now          = new DateTime(2020, 1, 10);
                var wrappedModel = new PortfolioConstructionModelPythonWrapper(model);
                var aapl         = algorithm.AddEquity("AAPL");
                aapl.SetMarketPrice(new Tick(now, aapl.Symbol, 10, 10));
                algorithm.SetDateTime(now);

                wrappedModel.OnSecuritiesChanged(algorithm, new SecurityChanges(SecurityChanges.Added(aapl)));
                Assert.IsTrue((bool)model.OnSecuritiesChanged_WasCalled);

                var insight = new Insight(now, aapl.Symbol, TimeSpan.FromDays(1), InsightType.Price, InsightDirection.Down, null, null);
                var result  = wrappedModel.CreateTargets(algorithm, new[] { insight }).ToList();
                Assert.AreEqual(1, result.Count);
                Assert.IsTrue((bool)model.CreateTargets_WasCalled);
                Assert.IsTrue((bool)model.GetTargetInsights_WasCalled);
                Assert.IsTrue((bool)model.IsRebalanceDue_WasCalled);
                Assert.IsTrue((bool)model.ShouldCreateTargetForInsight_WasCalled);
            }
        }