} // End Run(); /// <summary> /// Send a backtest update to the browser taking a latest snapshot of the charting data. /// </summary> public void Update() { try { //Sometimes don't run the update, if not ready or we're ending. if (Algorithm?.Transactions == null || _processingFinalPacket) { return; } if (DateTime.UtcNow <= _nextUpdate || _daysProcessed < _daysProcessedFrontier) { return; } //Extract the orders since last update var deltaOrders = new Dictionary <int, Order>(); try { deltaOrders = (from order in TransactionHandler.Orders where order.Value.Time.Date >= _lastUpdate && order.Value.Status == OrderStatus.Filled select order).ToDictionary(t => t.Key, t => t.Value); } catch (Exception err) { Log.Error(err, "Transactions"); } //Limit length of orders we pass back dynamically to avoid flooding. if (deltaOrders.Count > 50) { deltaOrders.Clear(); } //Reset loop variables: try { _lastUpdate = Algorithm.UtcTime.Date; _daysProcessedFrontier = _daysProcessed + 1; _nextUpdate = DateTime.UtcNow.AddSeconds(2); } catch (Exception err) { Log.Error(err, "Can't update variables"); } var deltaCharts = new Dictionary <string, Chart>(); var performanceCharts = new Dictionary <string, Chart>(); lock (ChartLock) { //Get the updates since the last chart foreach (var kvp in Charts) { var chart = kvp.Value; deltaCharts.Add(chart.Name, chart.GetUpdates()); if (AlgorithmPerformanceCharts.Contains(kvp.Key)) { performanceCharts[kvp.Key] = chart.Clone(); } } } //Get the runtime statistics from the user algorithm: var runtimeStatistics = new Dictionary <string, string>(); lock (RuntimeStatistics) { foreach (var pair in RuntimeStatistics) { runtimeStatistics.Add(pair.Key, pair.Value); } } var summary = GenerateStatisticsResults(performanceCharts).Summary; GetAlgorithmRuntimeStatistics(summary, runtimeStatistics); //Profit Loss Changes: var progress = Convert.ToDecimal(_daysProcessed / _jobDays); if (progress > 0.999m) { progress = 0.999m; } //1. Cloud Upload -> Upload the whole packet to S3 Immediately: if (DateTime.UtcNow > _nextS3Update) { // For intermediate backtesting results, we truncate the order list to include only the last 100 orders // The final packet will contain the full list of orders. const int maxOrders = 100; var orderCount = TransactionHandler.Orders.Count; var completeResult = new BacktestResult( Charts, orderCount > maxOrders ? TransactionHandler.Orders.Skip(orderCount - maxOrders).ToDictionary() : TransactionHandler.Orders.ToDictionary(), Algorithm.Transactions.TransactionRecord, new Dictionary <string, string>(), runtimeStatistics, new Dictionary <string, AlgorithmPerformance>()); StoreResult(new BacktestResultPacket(_job, completeResult, progress)); _nextS3Update = DateTime.UtcNow.AddSeconds(30); } //2. Backtest Update -> Send the truncated packet to the backtester: var splitPackets = SplitPackets(deltaCharts, deltaOrders, runtimeStatistics, progress); foreach (var backtestingPacket in splitPackets) { MessagingHandler.Send(backtestingPacket); } } catch (Exception err) { Log.Error(err); } }
} // End Run(); /// <summary> /// Send a backtest update to the browser taking a latest snapshot of the charting data. /// </summary> private void Update() { try { //Sometimes don't run the update, if not ready or we're ending. if (Algorithm?.Transactions == null || ExitTriggered) { return; } var utcNow = DateTime.UtcNow; if (utcNow <= _nextUpdate || _daysProcessed < _daysProcessedFrontier) { return; } var deltaOrders = GetDeltaOrders(LastDeltaOrderPosition, shouldStop: orderCount => orderCount >= 50); // Deliberately skip to the end of order event collection to prevent overloading backtesting UX LastDeltaOrderPosition = TransactionHandler.OrderEvents.Count(); //Reset loop variables: try { _daysProcessedFrontier = _daysProcessed + 1; _nextUpdate = utcNow.AddSeconds(3); } catch (Exception err) { Log.Error(err, "Can't update variables"); } var deltaCharts = new Dictionary <string, Chart>(); var serverStatistics = GetServerStatistics(utcNow); var performanceCharts = new Dictionary <string, Chart>(); lock (ChartLock) { //Get the updates since the last chart foreach (var kvp in Charts) { var chart = kvp.Value; var updates = chart.GetUpdates(); if (!updates.IsEmpty()) { deltaCharts.Add(chart.Name, updates); } if (AlgorithmPerformanceCharts.Contains(kvp.Key)) { performanceCharts[kvp.Key] = chart.Clone(); } } } //Get the runtime statistics from the user algorithm: var runtimeStatistics = new Dictionary <string, string>(); lock (RuntimeStatistics) { foreach (var pair in RuntimeStatistics) { runtimeStatistics.Add(pair.Key, pair.Value); } } var summary = GenerateStatisticsResults(performanceCharts).Summary; GetAlgorithmRuntimeStatistics(summary, runtimeStatistics); //Profit Loss Changes: var progress = Convert.ToDecimal(_daysProcessed / _jobDays); if (progress > 0.999m) { progress = 0.999m; } //1. Cloud Upload -> Upload the whole packet to S3 Immediately: if (utcNow > _nextS3Update) { // For intermediate backtesting results, we truncate the order list to include only the last 100 orders // The final packet will contain the full list of orders. const int maxOrders = 100; var orderCount = TransactionHandler.Orders.Count; var completeResult = new BacktestResult(new BacktestResultParameters( Charts, orderCount > maxOrders ? TransactionHandler.Orders.Skip(orderCount - maxOrders).ToDictionary() : TransactionHandler.Orders.ToDictionary(), Algorithm.Transactions.TransactionRecord, new Dictionary <string, string>(), runtimeStatistics, new Dictionary <string, AlgorithmPerformance>(), // we store the last 100 order events, the final packet will contain the full list TransactionHandler.OrderEvents.Reverse().Take(100).ToList())); StoreResult(new BacktestResultPacket(_job, completeResult, Algorithm.EndDate, Algorithm.StartDate, progress)); _nextS3Update = DateTime.UtcNow.AddSeconds(30); } //2. Backtest Update -> Send the truncated packet to the backtester: var splitPackets = SplitPackets(deltaCharts, deltaOrders, runtimeStatistics, progress, serverStatistics); foreach (var backtestingPacket in splitPackets) { MessagingHandler.Send(backtestingPacket); } // let's re update this value after we finish just in case, so we don't re enter in the next loop _nextUpdate = DateTime.UtcNow.AddSeconds(3); } catch (Exception err) { Log.Error(err); } }