Lean  $LEAN_TAG$
TimeInForceJsonConverter.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.Reflection;
18 using Newtonsoft.Json;
19 using Newtonsoft.Json.Linq;
21 
22 namespace QuantConnect.Orders
23 {
24  /// <summary>
25  /// Provides an implementation of <see cref="JsonConverter"/> that can deserialize TimeInForce objects
26  /// </summary>
27  public class TimeInForceJsonConverter : JsonConverter
28  {
29  /// <summary>
30  /// Gets a value indicating whether this <see cref="T:Newtonsoft.Json.JsonConverter"/> can write JSON.
31  /// </summary>
32  /// <value>
33  /// <c>true</c> if this <see cref="T:Newtonsoft.Json.JsonConverter"/> can write JSON; otherwise, <c>false</c>.
34  /// </value>
35  public override bool CanWrite => true;
36 
37  /// <summary>
38  /// Determines whether this instance can convert the specified object type.
39  /// </summary>
40  /// <param name="objectType">Type of the object.</param>
41  /// <returns>
42  /// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
43  /// </returns>
44  public override bool CanConvert(Type objectType)
45  {
46  return typeof(TimeInForce).IsAssignableFrom(objectType);
47  }
48 
49  /// <summary>
50  /// Writes the JSON representation of the object.
51  /// </summary>
52  /// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param><param name="value">The value.</param><param name="serializer">The calling serializer.</param>
53  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
54  {
55  var timeInForce = value as TimeInForce;
56  if (ReferenceEquals(timeInForce, null)) return;
57 
58  var jo = new JObject();
59 
60  var type = value.GetType();
61  // don't add if its the default value used by the reader
62  if (type != typeof(GoodTilCanceledTimeInForce))
63  {
64  jo.Add("$type", type.FullName);
65  }
66 
67  foreach (var property in type.GetProperties())
68  {
69  if (property.CanRead)
70  {
71  var propertyValue = property.GetValue(value, null);
72  if (propertyValue != null)
73  {
74  jo.Add(property.Name, JToken.FromObject(propertyValue, serializer));
75  }
76  }
77  }
78 
79  jo.WriteTo(writer);
80  }
81 
82  /// <summary>
83  /// Reads the JSON representation of the object.
84  /// </summary>
85  /// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param><param name="objectType">Type of the object.</param><param name="existingValue">The existing value of object being read.</param><param name="serializer">The calling serializer.</param>
86  /// <returns>
87  /// The object value.
88  /// </returns>
89  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
90  {
91  var jObject = JToken.Load(reader);
92 
93  Type type;
94  var array = jObject as JArray;
95  if (array != null)
96  {
97  if (array.Count != 0)
98  {
99  throw new InvalidOperationException($"Unexpected time in force value: {jObject}");
100  }
101  // default value if not present. for php [] & {} are the same representation of empty object
102  type = typeof(GoodTilCanceledTimeInForce);
103  }
104  else if (jObject["$type"] != null)
105  {
106  var jToken = jObject["$type"];
107  var typeName = jToken.ToString();
108  type = Type.GetType(typeName, throwOnError: false, ignoreCase: true);
109  if (type == null)
110  {
111  throw new InvalidOperationException($"Unable to find the type: {typeName}");
112  }
113  }
114  else
115  {
116  // default value if not present
117  type = typeof(GoodTilCanceledTimeInForce);
118  }
119 
120  var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null);
121  if (constructor == null)
122  {
123  throw new NotImplementedException($"Unable to find a constructor for type: {type.FullName}");
124  }
125 
126  var timeInForce = constructor.Invoke(null);
127 
128  foreach (var property in timeInForce.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
129  {
130  var value = jObject[property.Name];
131  if (value != null)
132  {
133  property.SetValue(timeInForce, value.ToObject(property.PropertyType));
134  }
135  }
136 
137  return timeInForce;
138  }
139  }
140 }