/* * 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.Reflection; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using QuantConnect.Orders.TimeInForces; namespace QuantConnect.Orders { /// /// Provides an implementation of that can deserialize TimeInForce objects /// public class TimeInForceJsonConverter : JsonConverter { /// /// Gets a value indicating whether this can write JSON. /// /// /// true if this can write JSON; otherwise, false. /// public override bool CanWrite => true; /// /// Determines whether this instance can convert the specified object type. /// /// Type of the object. /// /// true if this instance can convert the specified object type; otherwise, false. /// public override bool CanConvert(Type objectType) { return typeof(TimeInForce).IsAssignableFrom(objectType); } /// /// Writes the JSON representation of the object. /// /// The to write to.The value.The calling serializer. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var timeInForce = value as TimeInForce; if (ReferenceEquals(timeInForce, null)) return; var jo = new JObject(); var type = value.GetType(); // don't add if its the default value used by the reader if (type != typeof(GoodTilCanceledTimeInForce)) { jo.Add("$type", type.FullName); } foreach (var property in type.GetProperties()) { if (property.CanRead) { var propertyValue = property.GetValue(value, null); if (propertyValue != null) { jo.Add(property.Name, JToken.FromObject(propertyValue, serializer)); } } } jo.WriteTo(writer); } /// /// Reads the JSON representation of the object. /// /// The to read from.Type of the object.The existing value of object being read.The calling serializer. /// /// The object value. /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jObject = JToken.Load(reader); Type type; var array = jObject as JArray; if (array != null) { if (array.Count != 0) { throw new InvalidOperationException($"Unexpected time in force value: {jObject}"); } // default value if not present. for php [] & {} are the same representation of empty object type = typeof(GoodTilCanceledTimeInForce); } else if (jObject["$type"] != null) { var jToken = jObject["$type"]; var typeName = jToken.ToString(); type = Type.GetType(typeName, throwOnError: false, ignoreCase: true); if (type == null) { throw new InvalidOperationException($"Unable to find the type: {typeName}"); } } else { // default value if not present type = typeof(GoodTilCanceledTimeInForce); } var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null); if (constructor == null) { throw new NotImplementedException($"Unable to find a constructor for type: {type.FullName}"); } var timeInForce = constructor.Invoke(null); foreach (var property in timeInForce.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { var value = jObject[property.Name]; if (value != null) { property.SetValue(timeInForce, value.ToObject(property.PropertyType)); } } return timeInForce; } } }