Skip to content

Commit

Permalink
Merge pull request QuantConnect#4565 from QuantConnect/bug-add-null-c…
Browse files Browse the repository at this point in the history
…heck

Bug add null checks
  • Loading branch information
jaredbroad authored Jul 8, 2020
2 parents 23c3d48 + bab6358 commit 117825b
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 44 deletions.
13 changes: 13 additions & 0 deletions Common/Packets/BacktestResultPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,19 @@ public BacktestResultPacket(BacktestNodePacket job, BacktestResult results, Date
}
}

/// <summary>
/// Creates an empty result packet, useful when the algorithm fails to initialize
/// </summary>
/// <param name="job">The associated job packet</param>
/// <returns>An empty result packet</returns>
public static BacktestResultPacket CreateEmpty(BacktestNodePacket job)
{
return new BacktestResultPacket(job, new BacktestResult(new BacktestResultParameters(
new Dictionary<string, Chart>(), new Dictionary<int, Order>(), new Dictionary<DateTime, decimal>(),
new Dictionary<string, string>(), new Dictionary<string, string>(), new Dictionary<string, AlgorithmPerformance>(),
new List<OrderEvent>(), new AlgorithmPerformance(), new AlphaRuntimeStatistics()
)), DateTime.UtcNow, DateTime.UtcNow);
}
} // End Queue Packet:


Expand Down
15 changes: 15 additions & 0 deletions Common/Packets/LiveResultPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using QuantConnect.Logging;
using QuantConnect.Orders;
using QuantConnect.Securities;

namespace QuantConnect.Packets
Expand Down Expand Up @@ -124,6 +125,20 @@ public LiveResultPacket(LiveNodePacket job, LiveResult results)
Log.Error(err);
}
}

/// <summary>
/// Creates an empty result packet, useful when the algorithm fails to initialize
/// </summary>
/// <param name="job">The associated job packet</param>
/// <returns>An empty result packet</returns>
public static LiveResultPacket CreateEmpty(LiveNodePacket job)
{
return new LiveResultPacket(job, new LiveResult(new LiveResultParameters(
new Dictionary<string, Chart>(), new Dictionary<int, Order>(), new Dictionary<DateTime, decimal>(),
new Dictionary<string, Holding>(), new CashBook(), new Dictionary<string, string>(),
new Dictionary<string, string>(), new List<OrderEvent>(), new Dictionary<string, string>(),
new AlphaRuntimeStatistics())));
}
} // End Queue Packet:


Expand Down
5 changes: 3 additions & 2 deletions Engine/AlgorithmManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -713,9 +713,10 @@ public void SetStatus(AlgorithmStatus state)
{
lock (_lock)
{
//We don't want anyone elseto set our internal state to "Running".
//We don't want anyone else to set our internal state to "Running".
//This is controlled by the algorithm private variable only.
if (state != AlgorithmStatus.Running)
//Algorithm could be null after it's initialized and they call Run on us
if (state != AlgorithmStatus.Running && _algorithm != null)
{
_algorithm.Status = state;
}
Expand Down
50 changes: 29 additions & 21 deletions Engine/Results/BacktestingResultHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
Expand Down Expand Up @@ -320,7 +321,7 @@ protected override void StoreResult(Packet packet)
SaveResults(key, results);

// Store Order Events in a separate file
StoreOrderEvents(Algorithm.UtcTime, result.Results.OrderEvents);
StoreOrderEvents(Algorithm?.UtcTime ?? DateTime.UtcNow, result.Results.OrderEvents);
}
else
{
Expand All @@ -340,30 +341,37 @@ protected void SendFinalResult()
{
try
{
//Convert local dictionary:
var charts = new Dictionary<string, Chart>(Charts);
var orders = new Dictionary<int, Order>(TransactionHandler.Orders);
var profitLoss = new SortedDictionary<DateTime, decimal>(Algorithm.Transactions.TransactionRecord);
var statisticsResults = GenerateStatisticsResults(charts, profitLoss);
var runtime = GetAlgorithmRuntimeStatistics(statisticsResults.Summary);
BacktestResultPacket result;
// could happen if algorithm failed to init
if (Algorithm != null)
{
//Convert local dictionary:
var charts = new Dictionary<string, Chart>(Charts);
var orders = new Dictionary<int, Order>(TransactionHandler.Orders);
var profitLoss = new SortedDictionary<DateTime, decimal>(Algorithm.Transactions.TransactionRecord);
var statisticsResults = GenerateStatisticsResults(charts, profitLoss);
var runtime = GetAlgorithmRuntimeStatistics(statisticsResults.Summary);

FinalStatistics = statisticsResults.Summary;
FinalStatistics = statisticsResults.Summary;

// clear the trades collection before placing inside the backtest result
foreach (var ap in statisticsResults.RollingPerformances.Values)
{
ap.ClosedTrades.Clear();
// clear the trades collection before placing inside the backtest result
foreach (var ap in statisticsResults.RollingPerformances.Values)
{
ap.ClosedTrades.Clear();
}
var orderEvents = TransactionHandler.OrderEvents.ToList();
//Create a result packet to send to the browser.
result = new BacktestResultPacket(_job,
new BacktestResult(new BacktestResultParameters(charts, orders, profitLoss, statisticsResults.Summary, runtime, statisticsResults.RollingPerformances, orderEvents, statisticsResults.TotalPerformance, AlphaRuntimeStatistics)),
Algorithm.EndDate, Algorithm.StartDate);
}
var orderEvents = TransactionHandler.OrderEvents.ToList();
//Create a result packet to send to the browser.
var result = new BacktestResultPacket(_job,
new BacktestResult(new BacktestResultParameters(charts, orders, profitLoss, statisticsResults.Summary, runtime, statisticsResults.RollingPerformances, orderEvents, statisticsResults.TotalPerformance, AlphaRuntimeStatistics)),
Algorithm.EndDate, Algorithm.StartDate)
else
{
ProcessingTime = (DateTime.UtcNow - StartTime).TotalSeconds,
DateFinished = DateTime.Now,
Progress = 1
};
result = BacktestResultPacket.CreateEmpty(_job);
}
result.ProcessingTime = (DateTime.UtcNow - StartTime).TotalSeconds;
result.DateFinished = DateTime.Now;
result.Progress = 1;

//Place result into storage.
StoreResult(result);
Expand Down
43 changes: 24 additions & 19 deletions Engine/Results/LiveTradingResultHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -761,32 +761,37 @@ protected void SendFinalResult()
Log.Trace("LiveTradingResultHandler.SendFinalResult(): Starting...");
try
{
//Convert local dictionary:
var charts = new Dictionary<string, Chart>();
lock (ChartLock)
LiveResultPacket result;
// could happen if algorithm failed to init
if (Algorithm != null)
{
foreach (var kvp in Charts)
//Convert local dictionary:
var charts = new Dictionary<string, Chart>();
lock (ChartLock)
{
charts.Add(kvp.Key, kvp.Value.Clone());
foreach (var kvp in Charts)
{
charts.Add(kvp.Key, kvp.Value.Clone());
}
}
}

var orders = new Dictionary<int, Order>(TransactionHandler.Orders);
var profitLoss = new SortedDictionary<DateTime, decimal>(Algorithm.Transactions.TransactionRecord);
var holdings = new Dictionary<string, Holding>();
var statisticsResults = GenerateStatisticsResults(charts, profitLoss);
var runtime = GetAlgorithmRuntimeStatistics(statisticsResults.Summary);
var orders = new Dictionary<int, Order>(TransactionHandler.Orders);
var profitLoss = new SortedDictionary<DateTime, decimal>(Algorithm.Transactions.TransactionRecord);
var holdings = new Dictionary<string, Holding>();
var statisticsResults = GenerateStatisticsResults(charts, profitLoss);
var runtime = GetAlgorithmRuntimeStatistics(statisticsResults.Summary);

StoreStatusFile(runtime, holdings, charts, profitLoss, statistics: statisticsResults);
StoreStatusFile(runtime, holdings, charts, profitLoss, statistics: statisticsResults);

//Create a packet:
var result = new LiveResultPacket(_job,
new LiveResult(new LiveResultParameters(charts, orders, profitLoss, holdings, Algorithm.Portfolio.CashBook, statisticsResults.Summary, runtime, GetOrderEventsToStore())))
//Create a packet:
result = new LiveResultPacket(_job,
new LiveResult(new LiveResultParameters(charts, orders, profitLoss, holdings, Algorithm.Portfolio.CashBook, statisticsResults.Summary, runtime, GetOrderEventsToStore())));
}
else
{
ProcessingTime = (DateTime.UtcNow - StartTime).TotalSeconds
};

//Save the processing time:
result = LiveResultPacket.CreateEmpty(_job);
}
result.ProcessingTime = (DateTime.UtcNow - StartTime).TotalSeconds;

//Store to S3:
StoreResult(result);
Expand Down
5 changes: 3 additions & 2 deletions Engine/Storage/LocalObjectStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,9 @@ public virtual void Dispose()
_persistenceTimer.DisposeSafely();
}

// if the object store was not used, delete the empty storage directory created in Initialize
if (!Directory.EnumerateFileSystemEntries(AlgorithmStorageRoot).Any())
// if the object store was not used, delete the empty storage directory created in Initialize.
// can be null if not initialized
if (AlgorithmStorageRoot != null && !Directory.EnumerateFileSystemEntries(AlgorithmStorageRoot).Any())
{
Directory.Delete(AlgorithmStorageRoot);
}
Expand Down

0 comments on commit 117825b

Please sign in to comment.