Skip to content

Commit 3f5eefd

Browse files
authored
Fix IResultHandler.RuntimeError not stopping the algorithm (#9444)
* Fix IResultHandler.RuntimeError not stopping the algorithm * Minor fix
1 parent 779a7c0 commit 3f5eefd

3 files changed

Lines changed: 71 additions & 0 deletions

File tree

Engine/Results/BaseResultsHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
using Newtonsoft.Json;
1818
using Newtonsoft.Json.Serialization;
19+
using QuantConnect;
1920
using QuantConnect.Data.Market;
2021
using QuantConnect.Data.UniverseSelection;
2122
using QuantConnect.Indicators;
@@ -951,6 +952,10 @@ protected void SetAlgorithmState(string error, string stack)
951952
{
952953
State["RuntimeError"] = error;
953954
State["StackTrace"] = stack;
955+
if (Algorithm != null && Algorithm.RunTimeError == null && !string.IsNullOrEmpty(error))
956+
{
957+
Algorithm.SetRuntimeError(new Exception(error), nameof(IResultHandler.RuntimeError));
958+
}
954959
}
955960

956961
/// <summary>

Tests/Engine/AlgorithmManagerTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
using QuantConnect.Scheduling;
4040
using QuantConnect.Securities;
4141
using QuantConnect.Statistics;
42+
using QuantConnect.Util;
4243
using Log = QuantConnect.Logging.Log;
4344

4445
namespace QuantConnect.Tests.Engine
@@ -388,5 +389,35 @@ public override void OnData(Slice data)
388389
SetStatus(AlgorithmStatus);
389390
}
390391
}
392+
393+
[Test]
394+
public void RuntimeErrorFromResultHandlerStopsAlgorithm()
395+
{
396+
ResultHandlerRuntimeErrorTest.Loops = 0;
397+
var parameter = new RegressionTests.AlgorithmStatisticsTestParameters(
398+
"QuantConnect.Tests.Engine.AlgorithmManagerTests+ResultHandlerRuntimeErrorTest",
399+
new Dictionary<string, string>(),
400+
Language.CSharp,
401+
AlgorithmStatus.RuntimeError);
402+
403+
AlgorithmRunner.RunLocalBacktest(parameter.Algorithm,
404+
parameter.Statistics,
405+
parameter.Language,
406+
parameter.ExpectedFinalStatus,
407+
algorithmLocation: "QuantConnect.Tests.dll");
408+
409+
Assert.AreEqual(1, ResultHandlerRuntimeErrorTest.Loops);
410+
}
411+
412+
public class ResultHandlerRuntimeErrorTest : BasicTemplateDailyAlgorithm
413+
{
414+
public static int Loops { get; set; }
415+
416+
public override void OnData(Slice data)
417+
{
418+
++Loops;
419+
Composer.Instance.GetPart<IResultHandler>()?.RuntimeError("Brokerage triggered a fatal error");
420+
}
421+
}
391422
}
392423
}

Tests/Engine/Results/BaseResultsHandlerTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,14 @@ public void SetResultsDestinationFolder(string folder)
199199
ResultsDestinationFolder = folder;
200200
}
201201
public string GetResultsDestinationFolder => ResultsDestinationFolder;
202+
203+
public void SetAlgorithmDirect(IAlgorithm algorithm)
204+
{
205+
Algorithm = algorithm;
206+
}
207+
208+
public void CallSetAlgorithmState(string error, string stack) => SetAlgorithmState(error, stack);
209+
202210
protected override void Run()
203211
{
204212
throw new NotImplementedException();
@@ -224,6 +232,33 @@ protected override void AddToLogStore(string message)
224232
}
225233
}
226234

235+
[Test]
236+
public void RuntimeErrorSetsAlgorithmRunTimeErrorAndStatus()
237+
{
238+
var handler = new BaseResultsHandlerTestable(AlgorithmId);
239+
var algorithm = new QCAlgorithm();
240+
handler.SetAlgorithmDirect(algorithm);
241+
242+
handler.CallSetAlgorithmState("Something went wrong", "stack trace here");
243+
244+
Assert.IsNotNull(algorithm.RunTimeError);
245+
Assert.AreEqual("Something went wrong", algorithm.RunTimeError.Message);
246+
Assert.AreEqual(AlgorithmStatus.RuntimeError, algorithm.Status);
247+
}
248+
249+
[Test]
250+
public void RuntimeErrorDoesNotOverwriteExistingRunTimeError()
251+
{
252+
var handler = new BaseResultsHandlerTestable(AlgorithmId);
253+
var algorithm = new QCAlgorithm();
254+
handler.SetAlgorithmDirect(algorithm);
255+
256+
handler.CallSetAlgorithmState("First error", "");
257+
handler.CallSetAlgorithmState("Second error", "");
258+
259+
Assert.AreEqual("First error", algorithm.RunTimeError.Message);
260+
}
261+
227262
private struct SampleParams
228263
{
229264
public string ChartName { get; set; }

0 commit comments

Comments
 (0)