Skip to content

Commit

Permalink
Make Target.MoveAhead() case insensitive (#8382)
Browse files Browse the repository at this point in the history
* First draft of the solution

* Try a different approach

* Nit change

* Add unit tests

* Add edge cases

* Address requests
  • Loading branch information
Marinovsky authored Oct 24, 2024
1 parent 828d923 commit d5b2e4d
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Common/Optimizer/Objectives/Constraint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public bool IsMet(string jsonBacktestResult)
throw new ArgumentNullException(nameof(jsonBacktestResult), $"Constraint.IsMet(): {Messages.OptimizerObjectivesCommon.NullOrEmptyBacktestResult}");
}

var token = JObject.Parse(jsonBacktestResult).SelectToken(Target);
var token = Objectives.Target.GetTokenInJsonBacktest(jsonBacktestResult, Target);
if (token == null)
{
return false;
Expand Down
27 changes: 26 additions & 1 deletion Common/Optimizer/Objectives/Target.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public bool MoveAhead(string jsonBacktestResult)
throw new ArgumentNullException(nameof(jsonBacktestResult), $"Target.MoveAhead(): {Messages.OptimizerObjectivesCommon.NullOrEmptyBacktestResult}");
}

var token = JObject.Parse(jsonBacktestResult).SelectToken(Target);
var token = GetTokenInJsonBacktest(jsonBacktestResult, Target);
if (token == null)
{
return false;
Expand All @@ -103,6 +103,31 @@ public void CheckCompliance()
}
}

public static JToken GetTokenInJsonBacktest(string jsonBacktestResult, string target)
{
var jObject = JObject.Parse(jsonBacktestResult);
var path = target.Replace("[", string.Empty, StringComparison.InvariantCultureIgnoreCase)
.Replace("]", string.Empty, StringComparison.InvariantCultureIgnoreCase)
.Replace("\'", string.Empty, StringComparison.InvariantCultureIgnoreCase).Split(".");
JToken token = null;
foreach (var key in path)
{
if (jObject.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out token))
{
if (token is not JValue)
{
jObject = token.ToObject<JObject>();
}
}
else
{
return null;
}
}

return token;
}

private bool IsComplied() => TargetValue.HasValue && Current.HasValue && (TargetValue.Value == Current.Value || Extremum.Better(TargetValue.Value, Current.Value));
}
}
29 changes: 29 additions & 0 deletions Tests/Optimizer/Objectives/TargetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using QuantConnect.Optimizer.Objectives;
using System;
Expand Down Expand Up @@ -138,5 +139,33 @@ public void RoundTrip()
Assert.AreEqual(origin.Extremum.GetType(), actual.Extremum.GetType());
Assert.AreEqual(origin.TargetValue, actual.TargetValue);
}

[TestCase("['TotalPerformance'].['TradeStatistics'].['ProfitToMaxDrawdownRatio']", "-1")]
[TestCase("['totalPerformance'].['tradeStatistics'].['profitToMaxDrawdownRatio']", "-1")]
[TestCase("['TotalPerformance'].['TradeStatistics'].['lossRate']", "1")]
[TestCase("['totalPerformance'].['tradeStatistics'].['lossRate']", "1")]
[TestCase("['Statistics'].['Start Equity']", "100000")]
[TestCase("['statistics'].['start equity']", "100000")]
[TestCase("['Statistics'].['Sharpe Ratio']", "-5.283")]
[TestCase("['statistics'].['sharpe ratio']", "-5.283")]
[TestCase("['Statistics'].['Sharp Ratio']", null)]
[TestCase("['statistics'].['sharp ratio']", null)]
public void TargetMoveAheadIsCaseInsensitive(string target, string expected)
{
Assert.AreEqual(expected, (Target.GetTokenInJsonBacktest(jsonBacktestResultExample, target))?.Value<string>());
}

private string jsonBacktestResultExample = @"{
""totalPerformance"": {
""tradeStatistics"": {
""lossRate"": ""1"",
""profitToMaxDrawdownRatio"": ""-1"",
}
},
""statistics"": {
""Start Equity"": ""100000"",
""Sharpe Ratio"": ""-5.283"",
}
}";
}
}

0 comments on commit d5b2e4d

Please sign in to comment.