/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace QuantConnect.Report { /// /// Removes null values in the object's x,y values so that /// deserialization can occur without exceptions. /// /// Result type to deserialize into public class NullResultValueTypeJsonConverter : JsonConverter where T : Result { private JsonSerializerSettings _settings; /// /// Initialize a new instance of /// public NullResultValueTypeJsonConverter() { _settings = new JsonSerializerSettings { Converters = new List { new OrderTypeNormalizingJsonConverter() }, FloatParseHandling = FloatParseHandling.Decimal }; } /// /// Determine if this converter can convert a given type /// /// Object type to convert /// Always true public override bool CanConvert(Type objectType) { return objectType.IsAssignableTo(typeof(T)); } /// /// Read Json for conversion /// /// Resulting object public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var token = JToken.ReadFrom(reader); if (token.Type == JTokenType.Null) { return null; } foreach (JProperty property in GetProperty(token, "Charts").Children()) { foreach (JProperty seriesProperty in GetProperty(property.Value, "Series")) { var newValues = new List(); foreach (var entry in GetProperty(seriesProperty.Value, "Values")) { if (entry is JObject jobj && (jobj["x"] == null || jobj["x"].Value() == null || jobj["y"] == null || jobj["y"].Value() == null)) { // null chart point continue; } if (entry is JArray jArray && jArray.Any(jToken => jToken.Type == JTokenType.Null)) { // null candlestick continue; } newValues.Add(entry); } var chart = GetProperty(token, "Charts")[property.Name]; var series = GetProperty(chart, "Series")[seriesProperty.Name]; if (series["Values"] != null) { series["Values"] = JArray.FromObject(newValues); } else if (series["values"] != null) { series["values"] = JArray.FromObject(newValues); } } } // Deserialize with OrderJsonConverter, otherwise it will fail. We convert the token back // to its JSON representation and use the `JsonConvert.DeserializeObject(...)` method instead // of using `token.ToObject()` since it can be provided a JsonConverter in its arguments. return JsonConvert.DeserializeObject(token.ToString(), _settings); } /// /// Write Json; Not implemented /// public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } private static JToken GetProperty(JToken jToken, string name) { return jToken[name] ?? jToken[name.ToLower()]; } } }