/// <summary>
        /// 使用Redis
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static StatisticsBuilder UseRedis(this StatisticsBuilder builder)
        {
            Check.NotNull(builder, nameof(builder));

            builder.Services.AddSingleton <IStatisticsStore, RedisStatisticsStore>();
            return(builder);
        }
Ejemplo n.º 2
0
        public Statistics Encode(string inputFilePath, string outputFilePath, HuffmanEncodeModel huffmanEncodeModel)
        {
            Statistics             statiscs;
            IHuffmanCoderInterface huffmanCoderInterface;
            IStatisticsBuilder     statisticsBuilder = new StatisticsBuilder();

            using (IInputReader input = new InputReader(inputFilePath))
            {
                ICoderOutputWriter output = new CoderOutputWriter(new ByteCreator(), new HeaderCreator());
                if (huffmanEncodeModel == HuffmanEncodeModel.Standard)
                {
                    huffmanCoderInterface = new StandardHuffmanCoderInterface(input, output);
                }
                else if (huffmanEncodeModel == HuffmanEncodeModel.Block)
                {
                    huffmanCoderInterface = new PairHuffmanCoderInterface(input, output);
                }
                else
                {
                    huffmanCoderInterface = new MarkowHuffmanCoderInterface(input, output);
                }
                huffmanCoderInterface.Encode();
                System.IO.File.WriteAllBytes(outputFilePath, output.FileBytes);
                statiscs = statisticsBuilder.BuildStatistics(output.SymbolMap, output.Header, input.Size, output.Size);

                if (huffmanEncodeModel == HuffmanEncodeModel.Standard)
                {
                    IHistogramBuilder histogramBuilder = new HistogramBuilder();
                    histogramBuilder.BuildHistogram(output.SymbolMap, outputFilePath);
                }
            }
            return(statiscs);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static IServiceCollection AddStatisticsCenter(this IServiceCollection services,
                                                             Action <StatisticsBuilder> configure)
        {
            services.AddSingleton <IHostedService, StatisticsCenter>();

            var spiderStatisticsBuilder = new StatisticsBuilder(services);

            configure?.Invoke(spiderStatisticsBuilder);

            return(services);
        }
Ejemplo n.º 4
0
        public void Generate_HandlesMultipleEntriesPerDay_ResamplesProperly()
        {
            var testBenchmarkPoints = new List <ChartPoint>
            {
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 0, 0, 0), DateTimeKind.Utc), 0), // Should be resampled away
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 16, 0, 0), DateTimeKind.Utc), 100),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 2, 16, 0, 0), DateTimeKind.Utc), 102),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 3, 0, 0, 0), DateTimeKind.Utc), 0), // Should be resampled away
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 3, 16, 0, 0), DateTimeKind.Utc), 110),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 4, 16, 0, 0), DateTimeKind.Utc), 110),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 5, 16, 0, 0), DateTimeKind.Utc), 120),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 6, 16, 0, 0), DateTimeKind.Utc), 130),
            };

            var testEquityPoints = new List <ChartPoint>
            {
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 16, 0, 0), DateTimeKind.Utc), 100000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 2, 16, 0, 0), DateTimeKind.Utc), 102000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 3, 16, 0, 0), DateTimeKind.Utc), 110000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 4, 16, 0, 0), DateTimeKind.Utc), 110000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 5, 16, 0, 0), DateTimeKind.Utc), 120000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 6, 16, 0, 0), DateTimeKind.Utc), 130000),
            };

            var testPerformancePoints = new List <ChartPoint>
            {
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 9, 30, 0), DateTimeKind.Utc), 500000m * 100m),             // Should be resampled away
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 10, 30, 0), DateTimeKind.Utc), 1m * 100m),                 // Should be resampled away
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 11, 30, 0), DateTimeKind.Utc), 2m * 100m),                 // Should be resampled away
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 16, 0, 0), DateTimeKind.Utc), 100000m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 2, 4, 0, 0), DateTimeKind.Utc), 50m * 100m),                  // Should be resampled away
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 2, 16, 0, 0), DateTimeKind.Utc), 0.02m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 3, 16, 0, 0), DateTimeKind.Utc), 0.0784313725490196m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 4, 16, 0, 0), DateTimeKind.Utc), 0),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 5, 16, 0, 0), DateTimeKind.Utc), 0.090909090909090m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 6, 0, 0, 0), DateTimeKind.Utc), 0m * 100m),                   // Should be resampled away
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 6, 16, 0, 0), DateTimeKind.Utc), 0.083333333333333m * 100m)
            };

            var performance = StatisticsBuilder.Generate(
                new List <Trade>(),
                new SortedDictionary <DateTime, decimal>(),
                testEquityPoints,
                testPerformancePoints,
                testBenchmarkPoints,
                100000m,
                0m,
                1,
                null);

            Assert.AreEqual(1, Math.Round(performance.TotalPerformance.PortfolioStatistics.Beta, 5));
            Assert.AreEqual(0, performance.TotalPerformance.PortfolioStatistics.Drawdown);
        }
Ejemplo n.º 5
0
        public void MisalignedValues_ShouldThrow_DuringGeneration()
        {
            var testBenchmarkPoints = new List <ChartPoint>
            {
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 16, 0, 0), DateTimeKind.Utc), 100),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 2, 16, 0, 0), DateTimeKind.Utc), 102),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 3, 16, 0, 0), DateTimeKind.Utc), 110),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 4, 16, 0, 0), DateTimeKind.Utc), 110),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 5, 16, 0, 0), DateTimeKind.Utc), 120),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 6, 16, 0, 0), DateTimeKind.Utc), 130),
            };

            var testEquityPoints = new List <ChartPoint>
            {
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2018, 12, 31, 16, 0, 0), DateTimeKind.Utc), 100000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 16, 0, 0), DateTimeKind.Utc), 100000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 2, 16, 0, 0), DateTimeKind.Utc), 102000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 3, 16, 0, 0), DateTimeKind.Utc), 110000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 4, 16, 0, 0), DateTimeKind.Utc), 110000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 5, 16, 0, 0), DateTimeKind.Utc), 120000),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 6, 16, 0, 0), DateTimeKind.Utc), 130000),
            };

            var misalignedTestPerformancePoints = new List <ChartPoint>
            {
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2018, 12, 31), DateTimeKind.Utc), 1000m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 1, 16, 0, 0), DateTimeKind.Utc), 0.25m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 2, 16, 0, 0), DateTimeKind.Utc), 0.02m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 3, 16, 0, 0), DateTimeKind.Utc), 0.0784313725490196m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 4, 16, 0, 0), DateTimeKind.Utc), 0 * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 5, 16, 0, 0), DateTimeKind.Utc), 0.090909090909090m * 100m),
                new ChartPoint(DateTime.SpecifyKind(new DateTime(2019, 1, 6, 16, 0, 0), DateTimeKind.Utc), 0.083333333333333m * 100m)
            };

            Assert.Throws <ArgumentException>(() =>
            {
                StatisticsBuilder.Generate(
                    new List <Trade>(),
                    new SortedDictionary <DateTime, decimal>(),
                    testEquityPoints,
                    misalignedTestPerformancePoints,
                    testBenchmarkPoints,
                    100000m,
                    0m,
                    1,
                    null,
                    "$");
            }, "Misaligned values provided, but we still generate statistics");
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Will generate the statistics results and update the provided runtime statistics
        /// </summary>
        protected StatisticsResults GenerateStatisticsResults(Dictionary <string, Chart> charts,
                                                              SortedDictionary <DateTime, decimal> profitLoss = null)
        {
            var statisticsResults = new StatisticsResults();

            if (profitLoss == null)
            {
                profitLoss = new SortedDictionary <DateTime, decimal>();
            }

            try
            {
                //Generates error when things don't exist (no charting logged, runtime errors in main algo execution)
                const string strategyEquityKey   = "Strategy Equity";
                const string equityKey           = "Equity";
                const string dailyPerformanceKey = "Daily Performance";
                const string benchmarkKey        = "Benchmark";

                // make sure we've taken samples for these series before just blindly requesting them
                if (charts.ContainsKey(strategyEquityKey) &&
                    charts[strategyEquityKey].Series.ContainsKey(equityKey) &&
                    charts[strategyEquityKey].Series.ContainsKey(dailyPerformanceKey) &&
                    charts.ContainsKey(benchmarkKey) &&
                    charts[benchmarkKey].Series.ContainsKey(benchmarkKey))
                {
                    var equity            = charts[strategyEquityKey].Series[equityKey].Values;
                    var performance       = charts[strategyEquityKey].Series[dailyPerformanceKey].Values;
                    var totalTransactions = Algorithm.Transactions.GetOrders(x => x.Status.IsFill()).Count();
                    var benchmark         = charts[benchmarkKey].Series[benchmarkKey].Values;

                    var trades = Algorithm.TradeBuilder.ClosedTrades;

                    statisticsResults = StatisticsBuilder.Generate(trades, profitLoss, equity, performance, benchmark,
                                                                   StartingPortfolioValue, Algorithm.Portfolio.TotalFees, totalTransactions);
                }
            }
            catch (Exception err)
            {
                Log.Error(err, "BaseResultsHandler.GenerateStatisticsResults(): Error generating statistics packet");
            }

            return(statisticsResults);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Runs a single backtest/live job from the job queue
        /// </summary>
        /// <param name="job">The algorithm job to be processed</param>
        /// <param name="manager"></param>
        /// <param name="assemblyPath">The path to the algorithm's assembly</param>
        public void Run(AlgorithmNodePacket job, AlgorithmManager manager, string assemblyPath)
        {
            var marketHoursDatabaseTask = Task.Run(() => StaticInitializations());

            var algorithm        = default(IAlgorithm);
            var algorithmManager = manager;

            try
            {
                //Reset thread holders.
                var          initializeComplete = false;
                Thread       threadResults      = null;
                Thread       threadRealTime     = null;
                Thread       threadAlphas       = null;
                WorkerThread workerThread       = null;

                //-> Initialize messaging system
                SystemHandlers.Notify.SetAuthentication(job);

                //-> Set the result handler type for this algorithm job, and launch the associated result thread.
                AlgorithmHandlers.Results.Initialize(job, SystemHandlers.Notify, SystemHandlers.Api, AlgorithmHandlers.Transactions);

                threadResults = new Thread(AlgorithmHandlers.Results.Run, 0)
                {
                    IsBackground = true, Name = "Result Thread"
                };
                threadResults.Start();

                IBrokerage  brokerage    = null;
                DataManager dataManager  = null;
                var         synchronizer = _liveMode ? new LiveSynchronizer() : new Synchronizer();
                try
                {
                    // we get the mhdb before creating the algorithm instance,
                    // since the algorithm constructor will use it
                    var marketHoursDatabase = marketHoursDatabaseTask.Result;

                    // start worker thread
                    workerThread = new WorkerThread();
                    AlgorithmHandlers.Setup.WorkerThread = workerThread;

                    // Save algorithm to cache, load algorithm instance:
                    algorithm = AlgorithmHandlers.Setup.CreateAlgorithmInstance(job, assemblyPath);

                    // Set algorithm in ILeanManager
                    SystemHandlers.LeanManager.SetAlgorithm(algorithm);

                    // initialize the alphas handler with the algorithm instance
                    AlgorithmHandlers.Alphas.Initialize(job, algorithm, SystemHandlers.Notify, SystemHandlers.Api);

                    // Initialize the brokerage
                    IBrokerageFactory factory;
                    brokerage = AlgorithmHandlers.Setup.CreateBrokerage(job, algorithm, out factory);

                    var symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder();

                    var securityService = new SecurityService(algorithm.Portfolio.CashBook,
                                                              marketHoursDatabase,
                                                              symbolPropertiesDatabase,
                                                              (ISecurityInitializerProvider)algorithm);

                    algorithm.Securities.SetSecurityService(securityService);

                    dataManager = new DataManager(AlgorithmHandlers.DataFeed,
                                                  new UniverseSelection(
                                                      algorithm,
                                                      securityService),
                                                  algorithm,
                                                  algorithm.TimeKeeper,
                                                  marketHoursDatabase,
                                                  _liveMode);

                    AlgorithmHandlers.Results.SetDataManager(dataManager);
                    algorithm.SubscriptionManager.SetDataManager(dataManager);

                    synchronizer.Initialize(algorithm, dataManager);

                    // Initialize the data feed before we initialize so he can intercept added securities/universes via events
                    AlgorithmHandlers.DataFeed.Initialize(
                        algorithm,
                        job,
                        AlgorithmHandlers.Results,
                        AlgorithmHandlers.MapFileProvider,
                        AlgorithmHandlers.FactorFileProvider,
                        AlgorithmHandlers.DataProvider,
                        dataManager,
                        (IDataFeedTimeProvider)synchronizer);

                    // set the order processor on the transaction manager (needs to be done before initializing BrokerageHistoryProvider)
                    algorithm.Transactions.SetOrderProcessor(AlgorithmHandlers.Transactions);
                    algorithm.SetOrderEventProvider(AlgorithmHandlers.Transactions);

                    // set the history provider before setting up the algorithm
                    var historyProvider = GetHistoryProvider(job.HistoryProvider);
                    if (historyProvider is BrokerageHistoryProvider)
                    {
                        (historyProvider as BrokerageHistoryProvider).SetBrokerage(brokerage);
                    }

                    var historyDataCacheProvider = new ZipDataCacheProvider(AlgorithmHandlers.DataProvider, isDataEphemeral: _liveMode);
                    historyProvider.Initialize(
                        new HistoryProviderInitializeParameters(
                            job,
                            SystemHandlers.Api,
                            AlgorithmHandlers.DataProvider,
                            historyDataCacheProvider,
                            AlgorithmHandlers.MapFileProvider,
                            AlgorithmHandlers.FactorFileProvider,
                            progress =>
                    {
                        // send progress updates to the result handler only during initialization
                        if (!algorithm.GetLocked() || algorithm.IsWarmingUp)
                        {
                            AlgorithmHandlers.Results.SendStatusUpdate(AlgorithmStatus.History,
                                                                       $"Processing history {progress}%...");
                        }
                    }
                            )
                        );

                    historyProvider.InvalidConfigurationDetected += (sender, args) => { AlgorithmHandlers.Results.ErrorMessage(args.Message); };
                    historyProvider.NumericalPrecisionLimited    += (sender, args) => { AlgorithmHandlers.Results.DebugMessage(args.Message); };
                    historyProvider.DownloadFailed      += (sender, args) => { AlgorithmHandlers.Results.ErrorMessage(args.Message, args.StackTrace); };
                    historyProvider.ReaderErrorDetected += (sender, args) => { AlgorithmHandlers.Results.RuntimeError(args.Message, args.StackTrace); };

                    algorithm.HistoryProvider = historyProvider;

                    // initialize the default brokerage message handler
                    algorithm.BrokerageMessageHandler = factory.CreateBrokerageMessageHandler(algorithm, job, SystemHandlers.Api);

                    //Initialize the internal state of algorithm and job: executes the algorithm.Initialize() method.
                    initializeComplete = AlgorithmHandlers.Setup.Setup(new SetupHandlerParameters(dataManager.UniverseSelection, algorithm, brokerage, job, AlgorithmHandlers.Results, AlgorithmHandlers.Transactions, AlgorithmHandlers.RealTime));

                    // set this again now that we've actually added securities
                    AlgorithmHandlers.Results.SetAlgorithm(algorithm, AlgorithmHandlers.Setup.StartingPortfolioValue);

                    // alpha handler needs start/end dates to determine sample step sizes
                    AlgorithmHandlers.Alphas.OnAfterAlgorithmInitialized(algorithm);

                    //If there are any reasons it failed, pass these back to the IDE.
                    if (!initializeComplete || algorithm.ErrorMessages.Count > 0 || AlgorithmHandlers.Setup.Errors.Count > 0)
                    {
                        initializeComplete = false;
                        //Get all the error messages: internal in algorithm and external in setup handler.
                        var errorMessage = string.Join(",", algorithm.ErrorMessages);
                        errorMessage += string.Join(",", AlgorithmHandlers.Setup.Errors.Select(e =>
                        {
                            var message = e.Message;
                            if (e.InnerException != null)
                            {
                                var err  = _exceptionInterpreter.Value.Interpret(e.InnerException, _exceptionInterpreter.Value);
                                message += _exceptionInterpreter.Value.GetExceptionMessageHeader(err);
                            }
                            return(message);
                        }));
                        Log.Error("Engine.Run(): " + errorMessage);
                        AlgorithmHandlers.Results.RuntimeError(errorMessage);
                        SystemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, errorMessage);
                    }
                }
                catch (Exception err)
                {
                    Log.Error(err);
                    var runtimeMessage = "Algorithm.Initialize() Error: " + err.Message + " Stack Trace: " + err;
                    AlgorithmHandlers.Results.RuntimeError(runtimeMessage, err.ToString());
                    SystemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, runtimeMessage);
                }


                // log the job endpoints
                Log.Trace("JOB HANDLERS: ");
                Log.Trace("         DataFeed:     " + AlgorithmHandlers.DataFeed.GetType().FullName);
                Log.Trace("         Setup:        " + AlgorithmHandlers.Setup.GetType().FullName);
                Log.Trace("         RealTime:     " + AlgorithmHandlers.RealTime.GetType().FullName);
                Log.Trace("         Results:      " + AlgorithmHandlers.Results.GetType().FullName);
                Log.Trace("         Transactions: " + AlgorithmHandlers.Transactions.GetType().FullName);
                Log.Trace("         Alpha:        " + AlgorithmHandlers.Alphas.GetType().FullName);
                if (algorithm?.HistoryProvider != null)
                {
                    Log.Trace("         History Provider:     " + algorithm.HistoryProvider.GetType().FullName);
                }
                if (job is LiveNodePacket)
                {
                    Log.Trace("         Brokerage:      " + brokerage?.GetType().FullName);
                }

                //-> Using the job + initialization: load the designated handlers:
                if (initializeComplete)
                {
                    // notify the LEAN manager that the algorithm is initialized and starting
                    SystemHandlers.LeanManager.OnAlgorithmStart();

                    //-> Reset the backtest stopwatch; we're now running the algorithm.
                    var startTime = DateTime.Now;

                    //Set algorithm as locked; set it to live mode if we're trading live, and set it to locked for no further updates.
                    algorithm.SetAlgorithmId(job.AlgorithmId);
                    algorithm.SetLocked();

                    //Load the associated handlers for transaction and realtime events:
                    AlgorithmHandlers.Transactions.Initialize(algorithm, brokerage, AlgorithmHandlers.Results);
                    AlgorithmHandlers.RealTime.Setup(algorithm, job, AlgorithmHandlers.Results, SystemHandlers.Api);

                    // wire up the brokerage message handler
                    brokerage.Message += (sender, message) =>
                    {
                        algorithm.BrokerageMessageHandler.Handle(message);

                        // fire brokerage message events
                        algorithm.OnBrokerageMessage(message);
                        switch (message.Type)
                        {
                        case BrokerageMessageType.Disconnect:
                            algorithm.OnBrokerageDisconnect();
                            break;

                        case BrokerageMessageType.Reconnect:
                            algorithm.OnBrokerageReconnect();
                            break;
                        }
                    };

                    //Send status to user the algorithm is now executing.
                    AlgorithmHandlers.Results.SendStatusUpdate(AlgorithmStatus.Running);

                    //Launch the data, transaction and realtime handlers into dedicated threads
                    threadRealTime = new Thread(AlgorithmHandlers.RealTime.Run)
                    {
                        IsBackground = true, Name = "RealTime Thread"
                    };
                    threadAlphas = new Thread(() => AlgorithmHandlers.Alphas.Run())
                    {
                        IsBackground = true, Name = "Alpha Thread"
                    };

                    //Launch the data feed, result sending, and transaction models/handlers in separate threads.
                    threadRealTime.Start(); // RealTime scan time for time based events:
                    threadAlphas.Start();   // Alpha thread for processing algorithm alpha insights

                    // Result manager scanning message queue: (started earlier)
                    AlgorithmHandlers.Results.DebugMessage(
                        $"Launching analysis for {job.AlgorithmId} with LEAN Engine v{Globals.Version}");

                    try
                    {
                        //Create a new engine isolator class
                        var isolator = new Isolator();

                        // Execute the Algorithm Code:
                        var complete = isolator.ExecuteWithTimeLimit(AlgorithmHandlers.Setup.MaximumRuntime, algorithmManager.TimeLoopWithinLimits, () =>
                        {
                            try
                            {
                                //Run Algorithm Job:
                                // -> Using this Data Feed,
                                // -> Send Orders to this TransactionHandler,
                                // -> Send Results to ResultHandler.
                                algorithmManager.Run(job, algorithm, synchronizer, AlgorithmHandlers.Transactions, AlgorithmHandlers.Results, AlgorithmHandlers.RealTime, SystemHandlers.LeanManager, AlgorithmHandlers.Alphas, isolator.CancellationToken);
                            }
                            catch (Exception err)
                            {
                                //Debugging at this level is difficult, stack trace needed.
                                Log.Error(err);
                                algorithm.RunTimeError = err;
                                algorithmManager.SetStatus(AlgorithmStatus.RuntimeError);
                                return;
                            }

                            Log.Trace("Engine.Run(): Exiting Algorithm Manager");
                        }, job.Controls.RamAllocation, workerThread: workerThread);

                        if (!complete)
                        {
                            Log.Error("Engine.Main(): Failed to complete in time: " + AlgorithmHandlers.Setup.MaximumRuntime.ToString("F"));
                            throw new Exception("Failed to complete algorithm within " + AlgorithmHandlers.Setup.MaximumRuntime.ToString("F")
                                                + " seconds. Please make it run faster.");
                        }

                        // Algorithm runtime error:
                        if (algorithm.RunTimeError != null)
                        {
                            HandleAlgorithmError(job, algorithm.RunTimeError);
                        }
                    }
                    catch (Exception err)
                    {
                        //Error running the user algorithm: purge datafeed, send error messages, set algorithm status to failed.
                        HandleAlgorithmError(job, err);
                    }

                    // notify the LEAN manager that the algorithm has finished
                    SystemHandlers.LeanManager.OnAlgorithmEnd();

                    try
                    {
                        var trades            = algorithm.TradeBuilder.ClosedTrades;
                        var charts            = new Dictionary <string, Chart>(AlgorithmHandlers.Results.Charts);
                        var orders            = new Dictionary <int, Order>(AlgorithmHandlers.Transactions.Orders);
                        var holdings          = new Dictionary <string, Holding>();
                        var banner            = new Dictionary <string, string>();
                        var statisticsResults = new StatisticsResults();

                        var csvTransactionsFileName = Config.Get("transaction-log");
                        if (!string.IsNullOrEmpty(csvTransactionsFileName))
                        {
                            SaveListOfTrades(AlgorithmHandlers.Transactions, csvTransactionsFileName);
                        }

                        try
                        {
                            //Generates error when things don't exist (no charting logged, runtime errors in main algo execution)
                            const string strategyEquityKey   = "Strategy Equity";
                            const string equityKey           = "Equity";
                            const string dailyPerformanceKey = "Daily Performance";
                            const string benchmarkKey        = "Benchmark";

                            // make sure we've taken samples for these series before just blindly requesting them
                            if (charts.ContainsKey(strategyEquityKey) &&
                                charts[strategyEquityKey].Series.ContainsKey(equityKey) &&
                                charts[strategyEquityKey].Series.ContainsKey(dailyPerformanceKey) &&
                                charts.ContainsKey(benchmarkKey) &&
                                charts[benchmarkKey].Series.ContainsKey(benchmarkKey)
                                )
                            {
                                var equity            = charts[strategyEquityKey].Series[equityKey].Values;
                                var performance       = charts[strategyEquityKey].Series[dailyPerformanceKey].Values;
                                var profitLoss        = new SortedDictionary <DateTime, decimal>(algorithm.Transactions.TransactionRecord);
                                var totalTransactions = algorithm.Transactions.GetOrders(x => x.Status.IsFill()).Count();
                                var benchmark         = charts[benchmarkKey].Series[benchmarkKey].Values;

                                statisticsResults = StatisticsBuilder.Generate(trades, profitLoss, equity, performance, benchmark,
                                                                               AlgorithmHandlers.Setup.StartingPortfolioValue, algorithm.Portfolio.TotalFees, totalTransactions);

                                //Some users have $0 in their brokerage account / starting cash of $0. Prevent divide by zero errors
                                var netReturn = AlgorithmHandlers.Setup.StartingPortfolioValue > 0 ?
                                                (algorithm.Portfolio.TotalPortfolioValue - AlgorithmHandlers.Setup.StartingPortfolioValue) / AlgorithmHandlers.Setup.StartingPortfolioValue
                                                : 0;

                                //Add other fixed parameters.
                                banner.Add("Unrealized", "$" + algorithm.Portfolio.TotalUnrealizedProfit.ToString("N2"));
                                banner.Add("Fees", "-$" + algorithm.Portfolio.TotalFees.ToString("N2"));
                                banner.Add("Net Profit", "$" + algorithm.Portfolio.TotalProfit.ToString("N2"));
                                banner.Add("Return", netReturn.ToString("P"));
                                banner.Add("Equity", "$" + algorithm.Portfolio.TotalPortfolioValue.ToString("N2"));
                            }
                        }
                        catch (Exception err)
                        {
                            Log.Error(err, "Error generating statistics packet");
                        }

                        //Diagnostics Completed, Send Result Packet:
                        var totalSeconds = (DateTime.Now - startTime).TotalSeconds;
                        var dataPoints   = algorithmManager.DataPoints + algorithm.HistoryProvider.DataPointCount;

                        if (!_liveMode)
                        {
                            var kps = dataPoints / (double)1000 / totalSeconds;
                            AlgorithmHandlers.Results.DebugMessage($"Algorithm Id:({job.AlgorithmId}) completed in {totalSeconds:F2} seconds at {kps:F0}k data points per second. Processing total of {dataPoints:N0} data points.");
                        }

                        AlgorithmHandlers.Results.SendFinalResult(job, orders, algorithm.Transactions.TransactionRecord, holdings, algorithm.Portfolio.CashBook, statisticsResults, banner);
                    }
                    catch (Exception err)
                    {
                        Log.Error(err, "Error sending analysis results");
                    }

                    //Before we return, send terminate commands to close up the threads
                    AlgorithmHandlers.Transactions.Exit();
                    AlgorithmHandlers.DataFeed.Exit();
                    AlgorithmHandlers.RealTime.Exit();
                    AlgorithmHandlers.Alphas.Exit();
                    dataManager?.RemoveAllSubscriptions();
                    workerThread?.Dispose();
                }

                //Close result handler:
                AlgorithmHandlers.Results.Exit();

                //Wait for the threads to complete:
                var millisecondInterval  = 10;
                var millisecondTotalWait = 0;
                while ((AlgorithmHandlers.Results.IsActive ||
                        (AlgorithmHandlers.Transactions != null && AlgorithmHandlers.Transactions.IsActive) ||
                        (AlgorithmHandlers.DataFeed != null && AlgorithmHandlers.DataFeed.IsActive) ||
                        (AlgorithmHandlers.RealTime != null && AlgorithmHandlers.RealTime.IsActive) ||
                        (AlgorithmHandlers.Alphas != null && AlgorithmHandlers.Alphas.IsActive)) &&
                       millisecondTotalWait < 30 * 1000)
                {
                    Thread.Sleep(millisecondInterval);
                    if (millisecondTotalWait % (millisecondInterval * 10) == 0)
                    {
                        Log.Trace("Waiting for threads to exit...");
                    }
                    millisecondTotalWait += millisecondInterval;
                }

                //Terminate threads still in active state.
                if (threadResults != null && threadResults.IsAlive)
                {
                    threadResults.Abort();
                }
                if (threadAlphas != null && threadAlphas.IsAlive)
                {
                    threadAlphas.Abort();
                }

                if (brokerage != null)
                {
                    Log.Trace("Engine.Run(): Disconnecting from brokerage...");
                    brokerage.Disconnect();
                    brokerage.Dispose();
                }
                if (AlgorithmHandlers.Setup != null)
                {
                    Log.Trace("Engine.Run(): Disposing of setup handler...");
                    AlgorithmHandlers.Setup.Dispose();
                }
                Log.Trace("Engine.Main(): Analysis Completed and Results Posted.");
            }
            catch (Exception err)
            {
                Log.Error(err, "Error running algorithm");
            }
            finally
            {
                //No matter what for live mode; make sure we've set algorithm status in the API for "not running" conditions:
                if (_liveMode && algorithmManager.State != AlgorithmStatus.Running && algorithmManager.State != AlgorithmStatus.RuntimeError)
                {
                    SystemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, algorithmManager.State);
                }

                AlgorithmHandlers.Results.Exit();
                AlgorithmHandlers.DataFeed.Exit();
                AlgorithmHandlers.Transactions.Exit();
                AlgorithmHandlers.RealTime.Exit();
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Runs a single backtest/live job from the job queue
        /// </summary>
        /// <param name="job">The algorithm job to be processed</param>
        /// <param name="assemblyPath">The path to the algorithm's assembly</param>
        public void Run(AlgorithmNodePacket job, string assemblyPath)
        {
            var algorithm        = default(IAlgorithm);
            var algorithmManager = new AlgorithmManager(_liveMode);

            //Start monitoring the backtest active status:
            var statusPing       = new StateCheck.Ping(algorithmManager, _systemHandlers.Api, _algorithmHandlers.Results, _systemHandlers.Notify, job);
            var statusPingThread = new Thread(statusPing.Run);

            statusPingThread.Start();

            try
            {
                //Reset thread holders.
                var    initializeComplete = false;
                Thread threadFeed         = null;
                Thread threadTransactions = null;
                Thread threadResults      = null;
                Thread threadRealTime     = null;

                //-> Initialize messaging system
                _systemHandlers.Notify.SetChannel(job.Channel);

                //-> Set the result handler type for this algorithm job, and launch the associated result thread.
                _algorithmHandlers.Results.Initialize(job, _systemHandlers.Notify, _systemHandlers.Api, _algorithmHandlers.DataFeed, _algorithmHandlers.Setup, _algorithmHandlers.Transactions);

                threadResults = new Thread(_algorithmHandlers.Results.Run, 0)
                {
                    Name = "Result Thread"
                };
                threadResults.Start();

                IBrokerage brokerage = null;
                try
                {
                    // Save algorithm to cache, load algorithm instance:
                    algorithm = _algorithmHandlers.Setup.CreateAlgorithmInstance(assemblyPath, job.Language);

                    // set the history provider before setting up the algorithm
                    _algorithmHandlers.HistoryProvider.Initialize(job, progress =>
                    {
                        // send progress updates to the result handler only during initialization
                        if (!algorithm.GetLocked() || algorithm.IsWarmingUp)
                        {
                            _algorithmHandlers.Results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.History,
                                                                        string.Format("Processing history {0}%...", progress));
                        }
                    });
                    algorithm.HistoryProvider = _algorithmHandlers.HistoryProvider;

                    // initialize the default brokerage message handler
                    algorithm.BrokerageMessageHandler = new DefaultBrokerageMessageHandler(algorithm, job, _algorithmHandlers.Results, _systemHandlers.Api);

                    //Initialize the internal state of algorithm and job: executes the algorithm.Initialize() method.
                    initializeComplete = _algorithmHandlers.Setup.Setup(algorithm, out brokerage, job, _algorithmHandlers.Results, _algorithmHandlers.Transactions, _algorithmHandlers.RealTime);

                    // set this again now that we've actually added securities
                    _algorithmHandlers.Results.SetAlgorithm(algorithm);

                    //If there are any reasons it failed, pass these back to the IDE.
                    if (!initializeComplete || algorithm.ErrorMessages.Count > 0 || _algorithmHandlers.Setup.Errors.Count > 0)
                    {
                        initializeComplete = false;
                        //Get all the error messages: internal in algorithm and external in setup handler.
                        var errorMessage = String.Join(",", algorithm.ErrorMessages);
                        errorMessage += String.Join(",", _algorithmHandlers.Setup.Errors);
                        _algorithmHandlers.Results.RuntimeError(errorMessage);
                        _systemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, errorMessage);
                    }
                }
                catch (Exception err)
                {
                    var runtimeMessage = "Algorithm.Initialize() Error: " + err.Message + " Stack Trace: " + err.StackTrace;
                    _algorithmHandlers.Results.RuntimeError(runtimeMessage, err.StackTrace);
                    _systemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, runtimeMessage);
                }

                //-> Using the job + initialization: load the designated handlers:
                if (initializeComplete)
                {
                    //-> Reset the backtest stopwatch; we're now running the algorithm.
                    var startTime = DateTime.Now;

                    //Set algorithm as locked; set it to live mode if we're trading live, and set it to locked for no further updates.
                    algorithm.SetAlgorithmId(job.AlgorithmId);
                    algorithm.SetLocked();

                    //Wire up the universe selection event handler before kicking off the data feed
                    var universeSelection = new UniverseSelection(_algorithmHandlers.DataFeed, algorithm, _liveMode);
                    _algorithmHandlers.DataFeed.UniverseSelection += (sender, args) => universeSelection.ApplyUniverseSelection(args);

                    //Load the associated handlers for data, transaction and realtime events:
                    _algorithmHandlers.DataFeed.Initialize(algorithm, job, _algorithmHandlers.Results);
                    _algorithmHandlers.Transactions.Initialize(algorithm, brokerage, _algorithmHandlers.Results);
                    _algorithmHandlers.RealTime.Setup(algorithm, job, _algorithmHandlers.Results, _systemHandlers.Api);

                    // wire up the brokerage message handler
                    brokerage.Message += (sender, message) => algorithm.BrokerageMessageHandler.Handle(message);

                    //Send status to user the algorithm is now executing.
                    _algorithmHandlers.Results.SendStatusUpdate(job.AlgorithmId, AlgorithmStatus.Running);

                    //Launch the data, transaction and realtime handlers into dedicated threads
                    threadFeed = new Thread(_algorithmHandlers.DataFeed.Run)
                    {
                        Name = "DataFeed Thread"
                    };
                    threadTransactions = new Thread(_algorithmHandlers.Transactions.Run)
                    {
                        Name = "Transaction Thread"
                    };
                    threadRealTime = new Thread(_algorithmHandlers.RealTime.Run)
                    {
                        Name = "RealTime Thread"
                    };

                    //Launch the data feed, result sending, and transaction models/handlers in separate threads.
                    threadFeed.Start();         // Data feed pushing data packets into thread bridge;
                    threadTransactions.Start(); // Transaction modeller scanning new order requests
                    threadRealTime.Start();     // RealTime scan time for time based events:

                    // Result manager scanning message queue: (started earlier)
                    _algorithmHandlers.Results.DebugMessage(string.Format("Launching analysis for {0} with LEAN Engine v{1}", job.AlgorithmId, Constants.Version));

                    try
                    {
                        //Create a new engine isolator class
                        var isolator = new Isolator();

                        // Execute the Algorithm Code:
                        var complete = isolator.ExecuteWithTimeLimit(_algorithmHandlers.Setup.MaximumRuntime, algorithmManager.TimeLoopWithinLimits, () =>
                        {
                            try
                            {
                                //Run Algorithm Job:
                                // -> Using this Data Feed,
                                // -> Send Orders to this TransactionHandler,
                                // -> Send Results to ResultHandler.
                                algorithmManager.Run(job, algorithm, _algorithmHandlers.DataFeed, _algorithmHandlers.Transactions, _algorithmHandlers.Results, _algorithmHandlers.RealTime, isolator.CancellationToken);
                            }
                            catch (Exception err)
                            {
                                //Debugging at this level is difficult, stack trace needed.
                                Log.Error(err);
                                algorithm.RunTimeError = err;
                                algorithmManager.SetStatus(AlgorithmStatus.RuntimeError);
                                return;
                            }

                            Log.Trace("Engine.Run(): Exiting Algorithm Manager");
                        }, job.RamAllocation);

                        if (!complete)
                        {
                            Log.Error("Engine.Main(): Failed to complete in time: " + _algorithmHandlers.Setup.MaximumRuntime.ToString("F"));
                            throw new Exception("Failed to complete algorithm within " + _algorithmHandlers.Setup.MaximumRuntime.ToString("F")
                                                + " seconds. Please make it run faster.");
                        }

                        // Algorithm runtime error:
                        if (algorithm.RunTimeError != null)
                        {
                            throw algorithm.RunTimeError;
                        }
                    }
                    catch (Exception err)
                    {
                        //Error running the user algorithm: purge datafeed, send error messages, set algorithm status to failed.
                        Log.Error("Engine.Run(): Breaking out of parent try-catch: " + err.Message + " " + err.StackTrace);
                        if (_algorithmHandlers.DataFeed != null)
                        {
                            _algorithmHandlers.DataFeed.Exit();
                        }
                        if (_algorithmHandlers.Results != null)
                        {
                            var message = "Runtime Error: " + err.Message;
                            Log.Trace("Engine.Run(): Sending runtime error to user...");
                            _algorithmHandlers.Results.LogMessage(message);
                            _algorithmHandlers.Results.RuntimeError(message, err.StackTrace);
                            _systemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, message + " Stack Trace: " + err.StackTrace);
                        }
                    }

                    //Send result data back: this entire code block could be rewritten.
                    // todo: - Split up statistics class, its enormous.
                    // todo: - Make a dedicated Statistics.Benchmark class.
                    // todo: - Move all creation and transmission of statistics out of primary engine loop.
                    // todo: - Statistics.Generate(algorithm, resulthandler, transactionhandler);

                    try
                    {
                        var trades            = algorithm.TradeBuilder.ClosedTrades;
                        var charts            = new Dictionary <string, Chart>(_algorithmHandlers.Results.Charts);
                        var orders            = new Dictionary <int, Order>(_algorithmHandlers.Transactions.Orders);
                        var holdings          = new Dictionary <string, Holding>();
                        var banner            = new Dictionary <string, string>();
                        var statisticsResults = new StatisticsResults();

                        try
                        {
                            //Generates error when things don't exist (no charting logged, runtime errors in main algo execution)
                            const string strategyEquityKey   = "Strategy Equity";
                            const string equityKey           = "Equity";
                            const string dailyPerformanceKey = "Daily Performance";
                            const string benchmarkKey        = "Benchmark";

                            // make sure we've taken samples for these series before just blindly requesting them
                            if (charts.ContainsKey(strategyEquityKey) &&
                                charts[strategyEquityKey].Series.ContainsKey(equityKey) &&
                                charts[strategyEquityKey].Series.ContainsKey(dailyPerformanceKey))
                            {
                                var equity            = charts[strategyEquityKey].Series[equityKey].Values;
                                var performance       = charts[strategyEquityKey].Series[dailyPerformanceKey].Values;
                                var profitLoss        = new SortedDictionary <DateTime, decimal>(algorithm.Transactions.TransactionRecord);
                                var totalTransactions = algorithm.Transactions.GetOrders(x => x.Status.IsFill()).Count();
                                var benchmark         = charts[benchmarkKey].Series[benchmarkKey].Values;

                                statisticsResults = StatisticsBuilder.Generate(trades, profitLoss, equity, performance, benchmark,
                                                                               _algorithmHandlers.Setup.StartingPortfolioValue, algorithm.Portfolio.TotalFees, totalTransactions);
                            }
                        }
                        catch (Exception err)
                        {
                            Log.Error("Algorithm.Node.Engine(): Error generating statistics packet: " + err.Message);
                        }

                        //Diagnostics Completed, Send Result Packet:
                        var totalSeconds = (DateTime.Now - startTime).TotalSeconds;
                        var dataPoints   = algorithmManager.DataPoints + _algorithmHandlers.HistoryProvider.DataPointCount;
                        _algorithmHandlers.Results.DebugMessage(
                            string.Format("Algorithm Id:({0}) completed in {1} seconds at {2}k data points per second. Processing total of {3} data points.",
                                          job.AlgorithmId, totalSeconds.ToString("F2"), ((dataPoints / (double)1000) / totalSeconds).ToString("F0"),
                                          dataPoints.ToString("N0")));

                        _algorithmHandlers.Results.SendFinalResult(job, orders, algorithm.Transactions.TransactionRecord, holdings, statisticsResults, banner);
                    }
                    catch (Exception err)
                    {
                        Log.Error("Engine.Main(): Error sending analysis result: " + err.Message + "  ST >> " + err.StackTrace);
                    }

                    //Before we return, send terminate commands to close up the threads
                    _algorithmHandlers.Transactions.Exit();
                    _algorithmHandlers.DataFeed.Exit();
                    _algorithmHandlers.RealTime.Exit();
                }

                //Close result handler:
                _algorithmHandlers.Results.Exit();
                statusPing.Exit();

                //Wait for the threads to complete:
                var ts = Stopwatch.StartNew();
                while ((_algorithmHandlers.Results.IsActive ||
                        (_algorithmHandlers.Transactions != null && _algorithmHandlers.Transactions.IsActive) ||
                        (_algorithmHandlers.DataFeed != null && _algorithmHandlers.DataFeed.IsActive) ||
                        (_algorithmHandlers.RealTime != null && _algorithmHandlers.RealTime.IsActive)) &&
                       ts.ElapsedMilliseconds < 30 * 1000)
                {
                    Thread.Sleep(100);
                    Log.Trace("Waiting for threads to exit...");
                }

                //Terminate threads still in active state.
                if (threadFeed != null && threadFeed.IsAlive)
                {
                    threadFeed.Abort();
                }
                if (threadTransactions != null && threadTransactions.IsAlive)
                {
                    threadTransactions.Abort();
                }
                if (threadResults != null && threadResults.IsAlive)
                {
                    threadResults.Abort();
                }
                if (statusPingThread != null && statusPingThread.IsAlive)
                {
                    statusPingThread.Abort();
                }

                if (brokerage != null)
                {
                    brokerage.Disconnect();
                }
                if (_algorithmHandlers.Setup != null)
                {
                    _algorithmHandlers.Setup.Dispose();
                }
                Log.Trace("Engine.Main(): Analysis Completed and Results Posted.");
            }
            catch (Exception err)
            {
                Log.Error("Engine.Main(): Error running algorithm: " + err.Message + " >> " + err.StackTrace);
            }
            finally
            {
                //No matter what for live mode; make sure we've set algorithm status in the API for "not running" conditions:
                if (_liveMode && algorithmManager.State != AlgorithmStatus.Running && algorithmManager.State != AlgorithmStatus.RuntimeError)
                {
                    _systemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, algorithmManager.State);
                }

                _algorithmHandlers.Results.Exit();
                _algorithmHandlers.DataFeed.Exit();
                _algorithmHandlers.Transactions.Exit();
                _algorithmHandlers.RealTime.Exit();
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Runs a single backtest/live job from the job queue
        /// </summary>
        /// <param name="job">The algorithm job to be processed</param>
        /// <param name="manager"></param>
        /// <param name="assemblyPath">The path to the algorithm's assembly</param>
        public void Run(AlgorithmNodePacket job, AlgorithmManager manager, string assemblyPath)
        {
            var algorithm        = default(IAlgorithm);
            var algorithmManager = manager;

            try
            {
                //Reset thread holders.
                var    initializeComplete = false;
                Thread threadFeed         = null;
                Thread threadTransactions = null;
                Thread threadResults      = null;
                Thread threadRealTime     = null;

                //-> Initialize messaging system
                _systemHandlers.Notify.SetAuthentication(job);

                //-> Set the result handler type for this algorithm job, and launch the associated result thread.
                _algorithmHandlers.Results.Initialize(job, _systemHandlers.Notify, _systemHandlers.Api, _algorithmHandlers.DataFeed, _algorithmHandlers.Setup, _algorithmHandlers.Transactions);

                threadResults = new Thread(_algorithmHandlers.Results.Run, 0)
                {
                    IsBackground = true, Name = "Result Thread"
                };
                threadResults.Start();

                IBrokerage brokerage = null;
                try
                {
                    // Save algorithm to cache, load algorithm instance:
                    algorithm = _algorithmHandlers.Setup.CreateAlgorithmInstance(job, assemblyPath);

                    // Set algorithm in ILeanManager
                    _systemHandlers.LeanManager.SetAlgorithm(algorithm);

                    // Initialize the brokerage
                    IBrokerageFactory factory;
                    brokerage = _algorithmHandlers.Setup.CreateBrokerage(job, algorithm, out factory);

                    // Initialize the data feed before we initialize so he can intercept added securities/universes via events
                    _algorithmHandlers.DataFeed.Initialize(algorithm, job, _algorithmHandlers.Results, _algorithmHandlers.MapFileProvider, _algorithmHandlers.FactorFileProvider, _algorithmHandlers.DataProvider);

                    // set the order processor on the transaction manager (needs to be done before initializing BrokerageHistoryProvider)
                    algorithm.Transactions.SetOrderProcessor(_algorithmHandlers.Transactions);

                    // set the history provider before setting up the algorithm
                    var historyProvider = GetHistoryProvider(job.HistoryProvider);
                    if (historyProvider is BrokerageHistoryProvider)
                    {
                        (historyProvider as BrokerageHistoryProvider).SetBrokerage(brokerage);
                    }

                    var historyDataCacheProvider = new ZipDataCacheProvider(_algorithmHandlers.DataProvider);
                    historyProvider.Initialize(job, _algorithmHandlers.DataProvider, historyDataCacheProvider, _algorithmHandlers.MapFileProvider, _algorithmHandlers.FactorFileProvider, progress =>
                    {
                        // send progress updates to the result handler only during initialization
                        if (!algorithm.GetLocked() || algorithm.IsWarmingUp)
                        {
                            _algorithmHandlers.Results.SendStatusUpdate(AlgorithmStatus.History,
                                                                        string.Format("Processing history {0}%...", progress));
                        }
                    });

                    algorithm.HistoryProvider = historyProvider;

                    // initialize the default brokerage message handler
                    algorithm.BrokerageMessageHandler = factory.CreateBrokerageMessageHandler(algorithm, job, _systemHandlers.Api);

                    //Initialize the internal state of algorithm and job: executes the algorithm.Initialize() method.
                    initializeComplete = _algorithmHandlers.Setup.Setup(algorithm, brokerage, job, _algorithmHandlers.Results, _algorithmHandlers.Transactions, _algorithmHandlers.RealTime);

                    // set this again now that we've actually added securities
                    _algorithmHandlers.Results.SetAlgorithm(algorithm);

                    //If there are any reasons it failed, pass these back to the IDE.
                    if (!initializeComplete || algorithm.ErrorMessages.Count > 0 || _algorithmHandlers.Setup.Errors.Count > 0)
                    {
                        initializeComplete = false;
                        //Get all the error messages: internal in algorithm and external in setup handler.
                        var errorMessage = String.Join(",", algorithm.ErrorMessages);
                        errorMessage += String.Join(",", _algorithmHandlers.Setup.Errors);
                        Log.Error("Engine.Run(): " + errorMessage);
                        _algorithmHandlers.Results.RuntimeError(errorMessage);
                        _systemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, errorMessage);
                    }
                }
                catch (Exception err)
                {
                    Log.Error(err);
                    var runtimeMessage = "Algorithm.Initialize() Error: " + err.Message + " Stack Trace: " + err.StackTrace;
                    _algorithmHandlers.Results.RuntimeError(runtimeMessage, err.StackTrace);
                    _systemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, AlgorithmStatus.RuntimeError, runtimeMessage);
                }


                // log the job endpoints
                Log.Trace("JOB HANDLERS: ");
                Log.Trace("         DataFeed:     " + _algorithmHandlers.DataFeed.GetType().FullName);
                Log.Trace("         Setup:        " + _algorithmHandlers.Setup.GetType().FullName);
                Log.Trace("         RealTime:     " + _algorithmHandlers.RealTime.GetType().FullName);
                Log.Trace("         Results:      " + _algorithmHandlers.Results.GetType().FullName);
                Log.Trace("         Transactions: " + _algorithmHandlers.Transactions.GetType().FullName);
                if (algorithm != null && algorithm.HistoryProvider != null)
                {
                    Log.Trace("         History Provider:     " + algorithm.HistoryProvider.GetType().FullName);
                }
                if (job is LiveNodePacket)
                {
                    Log.Trace("         Brokerage:      " + brokerage.GetType().FullName);
                }

                //-> Using the job + initialization: load the designated handlers:
                if (initializeComplete)
                {
                    //-> Reset the backtest stopwatch; we're now running the algorithm.
                    var startTime = DateTime.Now;

                    //Set algorithm as locked; set it to live mode if we're trading live, and set it to locked for no further updates.
                    algorithm.SetAlgorithmId(job.AlgorithmId);
                    algorithm.SetLocked();

                    //Load the associated handlers for transaction and realtime events:
                    _algorithmHandlers.Transactions.Initialize(algorithm, brokerage, _algorithmHandlers.Results);
                    _algorithmHandlers.RealTime.Setup(algorithm, job, _algorithmHandlers.Results, _systemHandlers.Api);

                    // wire up the brokerage message handler
                    brokerage.Message += (sender, message) =>
                    {
                        algorithm.BrokerageMessageHandler.Handle(message);

                        // fire brokerage message events
                        algorithm.OnBrokerageMessage(message);
                        switch (message.Type)
                        {
                        case BrokerageMessageType.Disconnect:
                            algorithm.OnBrokerageDisconnect();
                            break;

                        case BrokerageMessageType.Reconnect:
                            algorithm.OnBrokerageReconnect();
                            break;
                        }
                    };

                    //Send status to user the algorithm is now executing.
                    _algorithmHandlers.Results.SendStatusUpdate(AlgorithmStatus.Running);

                    //Launch the data, transaction and realtime handlers into dedicated threads
                    threadFeed = new Thread(_algorithmHandlers.DataFeed.Run)
                    {
                        IsBackground = true, Name = "DataFeed Thread"
                    };
                    threadTransactions = new Thread(_algorithmHandlers.Transactions.Run)
                    {
                        IsBackground = true, Name = "Transaction Thread"
                    };
                    threadRealTime = new Thread(_algorithmHandlers.RealTime.Run)
                    {
                        IsBackground = true, Name = "RealTime Thread"
                    };

                    //Launch the data feed, result sending, and transaction models/handlers in separate threads.
                    threadFeed.Start();         // Data feed pushing data packets into thread bridge;
                    threadTransactions.Start(); // Transaction modeller scanning new order requests
                    threadRealTime.Start();     // RealTime scan time for time based events:

                    // Result manager scanning message queue: (started earlier)
                    _algorithmHandlers.Results.DebugMessage(string.Format("Launching analysis for {0} with LEAN Engine v{1}", job.AlgorithmId, Globals.Version));

                    try
                    {
                        //Create a new engine isolator class
                        var isolator = new Isolator();

                        // Execute the Algorithm Code:
                        var complete = isolator.ExecuteWithTimeLimit(_algorithmHandlers.Setup.MaximumRuntime, algorithmManager.TimeLoopWithinLimits, () =>
                        {
                            try
                            {
                                //Run Algorithm Job:
                                // -> Using this Data Feed,
                                // -> Send Orders to this TransactionHandler,
                                // -> Send Results to ResultHandler.
                                algorithmManager.Run(job, algorithm, _algorithmHandlers.DataFeed, _algorithmHandlers.Transactions, _algorithmHandlers.Results, _algorithmHandlers.RealTime, _systemHandlers.LeanManager, isolator.CancellationToken);
                            }
                            catch (Exception err)
                            {
                                //Debugging at this level is difficult, stack trace needed.
                                Log.Error(err);
                                algorithm.RunTimeError = err;
                                algorithmManager.SetStatus(AlgorithmStatus.RuntimeError);
                                return;
                            }

                            Log.Trace("Engine.Run(): Exiting Algorithm Manager");
                        }, job.Controls.RamAllocation);

                        if (!complete)
                        {
                            Log.Error("Engine.Main(): Failed to complete in time: " + _algorithmHandlers.Setup.MaximumRuntime.ToString("F"));
                            throw new Exception("Failed to complete algorithm within " + _algorithmHandlers.Setup.MaximumRuntime.ToString("F")
                                                + " seconds. Please make it run faster.");
                        }

                        // Algorithm runtime error:
                        if (algorithm.RunTimeError != null)
                        {
                            HandleAlgorithmError(job, algorithm.RunTimeError);
                        }
                    }
                    catch (Exception err)
                    {
                        //Error running the user algorithm: purge datafeed, send error messages, set algorithm status to failed.
                        HandleAlgorithmError(job, err);
                    }

                    try
                    {
                        var trades            = algorithm.TradeBuilder.ClosedTrades;
                        var charts            = new Dictionary <string, Chart>(_algorithmHandlers.Results.Charts);
                        var orders            = new Dictionary <int, Order>(_algorithmHandlers.Transactions.Orders);
                        var holdings          = new Dictionary <string, Holding>();
                        var banner            = new Dictionary <string, string>();
                        var statisticsResults = new StatisticsResults();

                        var csvTransactionsFileName = Config.Get("transaction-log");
                        if (!string.IsNullOrEmpty(csvTransactionsFileName))
                        {
                            SaveListOfTrades(_algorithmHandlers.Transactions, csvTransactionsFileName);
                        }

                        try
                        {
                            //Generates error when things don't exist (no charting logged, runtime errors in main algo execution)
                            const string strategyEquityKey   = "Strategy Equity";
                            const string equityKey           = "Equity";
                            const string dailyPerformanceKey = "Daily Performance";
                            const string benchmarkKey        = "Benchmark";

                            // make sure we've taken samples for these series before just blindly requesting them
                            if (charts.ContainsKey(strategyEquityKey) &&
                                charts[strategyEquityKey].Series.ContainsKey(equityKey) &&
                                charts[strategyEquityKey].Series.ContainsKey(dailyPerformanceKey) &&
                                charts.ContainsKey(benchmarkKey) &&
                                charts[benchmarkKey].Series.ContainsKey(benchmarkKey)
                                )
                            {
                                var equity            = charts[strategyEquityKey].Series[equityKey].Values;
                                var performance       = charts[strategyEquityKey].Series[dailyPerformanceKey].Values;
                                var profitLoss        = new SortedDictionary <DateTime, decimal>(algorithm.Transactions.TransactionRecord);
                                var totalTransactions = algorithm.Transactions.GetOrders(x => x.Status.IsFill()).Count();
                                var benchmark         = charts[benchmarkKey].Series[benchmarkKey].Values;

                                statisticsResults = StatisticsBuilder.Generate(trades, profitLoss, equity, performance, benchmark,
                                                                               _algorithmHandlers.Setup.StartingPortfolioValue, algorithm.Portfolio.TotalFees, totalTransactions);

                                //Some users have $0 in their brokerage account / starting cash of $0. Prevent divide by zero errors
                                var netReturn = _algorithmHandlers.Setup.StartingPortfolioValue > 0 ?
                                                (algorithm.Portfolio.TotalPortfolioValue - _algorithmHandlers.Setup.StartingPortfolioValue) / _algorithmHandlers.Setup.StartingPortfolioValue
                                                : 0;

                                //Add other fixed parameters.
                                banner.Add("Unrealized", "$" + algorithm.Portfolio.TotalUnrealizedProfit.ToString("N2"));
                                banner.Add("Fees", "-$" + algorithm.Portfolio.TotalFees.ToString("N2"));
                                banner.Add("Net Profit", "$" + algorithm.Portfolio.TotalProfit.ToString("N2"));
                                banner.Add("Return", netReturn.ToString("P"));
                                banner.Add("Equity", "$" + algorithm.Portfolio.TotalPortfolioValue.ToString("N2"));
                            }
                        }
                        catch (Exception err)
                        {
                            Log.Error(err, "Error generating statistics packet");
                        }

                        //Diagnostics Completed, Send Result Packet:
                        var totalSeconds = (DateTime.Now - startTime).TotalSeconds;
                        var dataPoints   = algorithmManager.DataPoints + algorithm.HistoryProvider.DataPointCount;
                        _algorithmHandlers.Results.DebugMessage(
                            string.Format("Algorithm Id:({0}) completed in {1} seconds at {2}k data points per second. Processing total of {3} data points.",
                                          job.AlgorithmId, totalSeconds.ToString("F2"), ((dataPoints / (double)1000) / totalSeconds).ToString("F0"),
                                          dataPoints.ToString("N0")));

                        _algorithmHandlers.Results.SendFinalResult(job, orders, algorithm.Transactions.TransactionRecord, holdings, algorithm.Portfolio.CashBook, statisticsResults, banner);
                    }
                    catch (Exception err)
                    {
                        Log.Error(err, "Error sending analysis results");
                    }

                    //Before we return, send terminate commands to close up the threads
                    _algorithmHandlers.Transactions.Exit();
                    _algorithmHandlers.DataFeed.Exit();
                    _algorithmHandlers.RealTime.Exit();
                }

                //Close result handler:
                _algorithmHandlers.Results.Exit();

                //Wait for the threads to complete:
                var ts = Stopwatch.StartNew();
                while ((_algorithmHandlers.Results.IsActive ||
                        (_algorithmHandlers.Transactions != null && _algorithmHandlers.Transactions.IsActive) ||
                        (_algorithmHandlers.DataFeed != null && _algorithmHandlers.DataFeed.IsActive) ||
                        (_algorithmHandlers.RealTime != null && _algorithmHandlers.RealTime.IsActive)) &&
                       ts.ElapsedMilliseconds < 30 * 1000)
                {
                    Thread.Sleep(100);
                    Log.Trace("Waiting for threads to exit...");
                }

                //Terminate threads still in active state.
                if (threadFeed != null && threadFeed.IsAlive)
                {
                    threadFeed.Abort();
                }
                if (threadTransactions != null && threadTransactions.IsAlive)
                {
                    threadTransactions.Abort();
                }
                if (threadResults != null && threadResults.IsAlive)
                {
                    threadResults.Abort();
                }

                if (brokerage != null)
                {
                    Log.Trace("Engine.Run(): Disconnecting from brokerage...");
                    brokerage.Disconnect();
                    brokerage.Dispose();
                }
                if (_algorithmHandlers.Setup != null)
                {
                    Log.Trace("Engine.Run(): Disposing of setup handler...");
                    _algorithmHandlers.Setup.Dispose();
                }
                Log.Trace("Engine.Main(): Analysis Completed and Results Posted.");
            }
            catch (Exception err)
            {
                Log.Error(err, "Error running algorithm");
            }
            finally
            {
                //No matter what for live mode; make sure we've set algorithm status in the API for "not running" conditions:
                if (_liveMode && algorithmManager.State != AlgorithmStatus.Running && algorithmManager.State != AlgorithmStatus.RuntimeError)
                {
                    _systemHandlers.Api.SetAlgorithmStatus(job.AlgorithmId, algorithmManager.State);
                }

                _algorithmHandlers.Results.Exit();
                _algorithmHandlers.DataFeed.Exit();
                _algorithmHandlers.Transactions.Exit();
                _algorithmHandlers.RealTime.Exit();
            }
        }
Ejemplo n.º 10
0
        public void ShowOutputOfStatisticsInConsole()
        {
            StringBuilder buffer = new StringBuilder();

            System.IO.StreamReader reader = System.IO.File.OpenText(System.IO.Path.Combine(@"resources", @"UnitTestResults2.xml"));
            var buildlog = reader.ReadToEnd();

            reader.Close();

            StatisticsBuilder builder = new StatisticsBuilder();


            Statistic info = new Statistic();

            info.Name  = "Statistic TestsTotalCount no ns";
            info.Xpath = @"//TestRun/ResultSummary/Counters/@total";
            builder.Add(info);


            FirstMatch info2 = new FirstMatch();

            info2.Name  = "FirstMatch TestsTotalCount no ns";
            info2.Xpath = @"//TestRun/ResultSummary/Counters/@total";
            builder.Add(info2);


            FirstMatch info1 = new FirstMatch();

            info1.Name          = "FirstMatch TestsTotalCount with ns";
            info1.Xpath         = @"//mstest:TestRun/mstest:ResultSummary/mstest:Counters/@total";
            info1.NameSpaces    = new StatisticsNamespaceMapping[1];
            info1.NameSpaces[0] = new StatisticsNamespaceMapping("mstest", @"http://microsoft.com/schemas/VisualStudio/TeamTest/2010");
            builder.Add(info1);



            Statistic info3 = new Statistic();

            info3.Name  = "Statistic sum(TestsTotalCount) no ns";
            info3.Xpath = @"sum(//TestRun/ResultSummary/Counters/@total)";
            builder.Add(info3);

            Statistic info4 = new Statistic();

            info4.Name          = "Statistic sum(TestsTotalCount) with ns";
            info4.Xpath         = @"sum(//mstest:TestRun/mstest:ResultSummary/mstest:Counters/@total)";
            info4.NameSpaces    = new StatisticsNamespaceMapping[1];
            info4.NameSpaces[0] = new StatisticsNamespaceMapping("mstest", @"http://microsoft.com/schemas/VisualStudio/TeamTest/2010");
            builder.Add(info4);


            // seems impossible in xsl 1.0
            Statistic imp01 = new Statistic();

            imp01.Name          = "impossible : Statistic TestsExecutedCount xmlns";
            imp01.Xpath         = @"/xmlns:cruisecontrol/mstest:TestRun/mstest:ResultSummary/mstest:Counters/@executed";
            imp01.NameSpaces    = new StatisticsNamespaceMapping[1];
            imp01.NameSpaces[0] = new StatisticsNamespaceMapping("mstest", @"http://microsoft.com/schemas/VisualStudio/TeamTest/2010");

            builder.Add(imp01);

            Statistic imp02 = new Statistic();

            imp02.Name          = "impossible : Statistic TestsExecutedCount2 not namespace";
            imp02.Xpath         = @"/cruisecontrol/mstest:TestRun/mstest:ResultSummary/mstest:Counters/@executed";
            imp02.NameSpaces    = new StatisticsNamespaceMapping[1];
            imp02.NameSpaces[0] = new StatisticsNamespaceMapping("mstest", @"http://microsoft.com/schemas/VisualStudio/TeamTest/2010");

            builder.Add(imp02);



            StatisticsResults results = builder.ProcessBuildResults(buildlog);

            foreach (var x in results)
            {
                Console.WriteLine("Result {0} : {1}", x.StatName, x.Value);
            }
        }
Ejemplo n.º 11
0
 public void SetUp()
 {
     builder = new StatisticsBuilder();
     result  = IntegrationResultMother.CreateSuccessful();
 }