Lean  $LEAN_TAG$
OptimizationBacktestJsonConverter.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Globalization;
19 using System.Linq;
20 using Newtonsoft.Json;
21 using Newtonsoft.Json.Linq;
24 using QuantConnect.Util;
25 
26 namespace QuantConnect.Api
27 {
28  /// <summary>
29  /// Json converter for <see cref="OptimizationBacktest"/> which creates a light weight easy to consume serialized version
30  /// </summary>
31  public class OptimizationBacktestJsonConverter : JsonConverter
32  {
33  /// <summary>
34  /// Determines whether this instance can convert the specified object type.
35  /// </summary>
36  /// <param name="objectType">Type of the object.</param>
37  /// <returns>
38  /// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
39  /// </returns>
40  public override bool CanConvert(Type objectType)
41  {
42  return objectType == typeof(OptimizationBacktest);
43  }
44 
45  /// <summary>
46  /// Writes the JSON representation of the object.
47  /// </summary>
48  /// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param>
49  /// <param name="value">The value.</param>
50  /// <param name="serializer">The calling serializer.</param>
51  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
52  {
53  var optimizationBacktest = value as OptimizationBacktest;
54  if (ReferenceEquals(optimizationBacktest, null)) return;
55 
56  writer.WriteStartObject();
57 
58  if (!string.IsNullOrEmpty(optimizationBacktest.Name))
59  {
60  writer.WritePropertyName("name");
61  writer.WriteValue(optimizationBacktest.Name);
62  }
63 
64  if (!string.IsNullOrEmpty(optimizationBacktest.BacktestId))
65  {
66  writer.WritePropertyName("id");
67  writer.WriteValue(optimizationBacktest.BacktestId);
68 
69  writer.WritePropertyName("progress");
70  writer.WriteValue(optimizationBacktest.Progress);
71 
72  writer.WritePropertyName("exitCode");
73  writer.WriteValue(optimizationBacktest.ExitCode);
74  }
75 
76  if (optimizationBacktest.StartDate != default)
77  {
78  writer.WritePropertyName("startDate");
79  writer.WriteValue(optimizationBacktest.StartDate.ToStringInvariant(DateFormat.UI));
80  }
81 
82  if (optimizationBacktest.EndDate != default)
83  {
84  writer.WritePropertyName("endDate");
85  writer.WriteValue(optimizationBacktest.EndDate.ToStringInvariant(DateFormat.UI));
86  }
87 
88  if (optimizationBacktest.OutOfSampleMaxEndDate != null)
89  {
90  writer.WritePropertyName("outOfSampleMaxEndDate");
91  writer.WriteValue(optimizationBacktest.OutOfSampleMaxEndDate.ToStringInvariant(DateFormat.UI));
92 
93  writer.WritePropertyName("outOfSampleDays");
94  writer.WriteValue(optimizationBacktest.OutOfSampleDays);
95  }
96 
97  if (!optimizationBacktest.Statistics.IsNullOrEmpty())
98  {
99  writer.WritePropertyName("statistics");
100  writer.WriteStartArray();
101  foreach (var keyValuePair in optimizationBacktest.Statistics.OrderBy(pair => pair.Key))
102  {
103  switch (keyValuePair.Key)
104  {
109  continue;
110  }
111  var statistic = keyValuePair.Value.Replace("%", string.Empty);
112  if (Currencies.TryParse(statistic, out var result))
113  {
114  writer.WriteValue(result);
115  }
116  }
117  writer.WriteEndArray();
118  }
119 
120  if (optimizationBacktest.ParameterSet != null)
121  {
122  writer.WritePropertyName("parameterSet");
123  serializer.Serialize(writer, optimizationBacktest.ParameterSet.Value);
124  }
125 
126  if (optimizationBacktest.Equity != null)
127  {
128  writer.WritePropertyName("equity");
129 
130  var equity = JsonConvert.SerializeObject(optimizationBacktest.Equity.Values);
131  writer.WriteRawValue(equity);
132  }
133 
134  writer.WriteEndObject();
135  }
136 
137  /// <summary>
138  /// Reads the JSON representation of the object.
139  /// </summary>
140  /// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
141  /// <param name="objectType">Type of the object.</param>
142  /// <param name="existingValue">The existing value of object being read.</param>
143  /// <param name="serializer">The calling serializer.</param>
144  /// <returns>
145  /// The object value.
146  /// </returns>
147  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
148  {
149  var jObject = JObject.Load(reader);
150 
151  var name = jObject["name"].Value<string>();
152  var hostName = jObject["hostName"]?.Value<string>();
153  var backtestId = jObject["id"].Value<string>();
154  var progress = jObject["progress"].Value<decimal>();
155  var exitCode = jObject["exitCode"].Value<int>();
156 
157  var outOfSampleDays = jObject["outOfSampleDays"]?.Value<int>() ?? default;
158  var startDate = jObject["startDate"]?.Value<DateTime?>() ?? default;
159  var endDate = jObject["endDate"]?.Value<DateTime?>() ?? default;
160  var outOfSampleMaxEndDate = jObject["outOfSampleMaxEndDate"]?.Value<DateTime>();
161 
162  var jStatistics = jObject["statistics"];
163  Dictionary<string, string> statistics = default;
164  if (jStatistics != null)
165  {
166  statistics = new Dictionary<string, string>
167  {
168  { PerformanceMetrics.Alpha, jStatistics[0].Value<string>() },
169  { PerformanceMetrics.AnnualStandardDeviation, jStatistics[1].Value<string>() },
170  { PerformanceMetrics.AnnualVariance, jStatistics[2].Value<string>() },
171  { PerformanceMetrics.AverageLoss, jStatistics[3].Value<string>() },
172  { PerformanceMetrics.AverageWin, jStatistics[4].Value<string>() },
173  { PerformanceMetrics.Beta, jStatistics[5].Value<string>() },
174  { PerformanceMetrics.CompoundingAnnualReturn, jStatistics[6].Value<string>() },
175  { PerformanceMetrics.Drawdown, jStatistics[7].Value<string>() },
176  { PerformanceMetrics.EstimatedStrategyCapacity, jStatistics[8].Value<string>() },
177  { PerformanceMetrics.Expectancy, jStatistics[9].Value<string>() },
178  { PerformanceMetrics.InformationRatio, jStatistics[10].Value<string>() },
179  { PerformanceMetrics.LossRate, jStatistics[11].Value<string>() },
180  { PerformanceMetrics.NetProfit, jStatistics[12].Value<string>() },
181  { PerformanceMetrics.ProbabilisticSharpeRatio, jStatistics[13].Value<string>() },
182  { PerformanceMetrics.ProfitLossRatio, jStatistics[14].Value<string>() },
183  { PerformanceMetrics.SharpeRatio, jStatistics[15].Value<string>() },
184  // TODO: Add SortinoRatio
185  // TODO: Add StartingEquity
186  // TODO: Add EndingEquity
187  { PerformanceMetrics.TotalFees, jStatistics[16].Value<string>() },
188  { PerformanceMetrics.TotalOrders, jStatistics[17].Value<string>() },
189  { PerformanceMetrics.TrackingError, jStatistics[18].Value<string>() },
190  { PerformanceMetrics.TreynorRatio, jStatistics[19].Value<string>() },
191  { PerformanceMetrics.WinRate, jStatistics[20].Value<string>() },
192  };
193  }
194 
195  var parameterSet = serializer.Deserialize<ParameterSet>(jObject["parameterSet"].CreateReader());
196 
197  var equity = new CandlestickSeries();
198  if (jObject["equity"] != null)
199  {
200  foreach (var point in JsonConvert.DeserializeObject<List<Candlestick>>(jObject["equity"].ToString()))
201  {
202  equity.AddPoint(point);
203  }
204  }
205 
206  var optimizationBacktest = new OptimizationBacktest(parameterSet, backtestId, name)
207  {
208  HostName = hostName,
209  Progress = progress,
210  ExitCode = exitCode,
211  Statistics = statistics,
212  Equity = equity,
213  EndDate = endDate,
214  StartDate = startDate,
215  OutOfSampleDays = outOfSampleDays,
216  OutOfSampleMaxEndDate = outOfSampleMaxEndDate,
217  };
218 
219  return optimizationBacktest;
220  }
221  }
222 }