Lean  $LEAN_TAG$
BaseCommandHandler.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.Linq;
18 using Newtonsoft.Json;
19 using QuantConnect.Logging;
20 using QuantConnect.Packets;
21 using Newtonsoft.Json.Linq;
23 using System.Collections.Generic;
24 
25 namespace QuantConnect.Commands
26 {
27  /// <summary>
28  /// Base algorithm command handler
29  /// </summary>
30  public abstract class BaseCommandHandler : ICommandHandler
31  {
32  /// <summary>
33  /// Command json settings
34  /// </summary>
35  protected static readonly JsonSerializerSettings Settings = new() { TypeNameHandling = TypeNameHandling.All };
36 
37  /// <summary>
38  /// The algorithm instance
39  /// </summary>
40  protected IAlgorithm Algorithm { get; set; }
41 
42  /// <summary>
43  /// Initializes this command queue for the specified job
44  /// </summary>
45  /// <param name="job">The job that defines what queue to bind to</param>
46  /// <param name="algorithm">The algorithm instance</param>
47  public virtual void Initialize(AlgorithmNodePacket job, IAlgorithm algorithm)
48  {
49  Algorithm = algorithm;
50  }
51 
52  /// <summary>
53  /// Get the commands to run
54  /// </summary>
55  protected abstract IEnumerable<ICommand> GetCommands();
56 
57  /// <summary>
58  /// Acknowledge a command that has been executed
59  /// </summary>
60  /// <param name="command">The command that was executed</param>
61  /// <param name="commandResultPacket">The result</param>
62  protected virtual void Acknowledge(ICommand command, CommandResultPacket commandResultPacket)
63  {
64  // nop
65  }
66 
67  /// <summary>
68  /// Will consumer and execute any command in the queue
69  /// </summary>
70  public IEnumerable<CommandResultPacket> ProcessCommands()
71  {
72  List<CommandResultPacket> resultPackets = null;
73  try
74  {
75  foreach (var command in GetCommands().Where(c => c != null))
76  {
77  Log.Trace($"BaseCommandHandler.ProcessCommands(): {Messages.BaseCommandHandler.ExecutingCommand(command)}");
78  CommandResultPacket result;
79  try
80  {
81  result = command.Run(Algorithm);
82  }
83  catch (Exception err)
84  {
85  Log.Error(err);
86  Algorithm.Error($"{command.GetType().Name} Error: {err.Message}");
87  result = new CommandResultPacket(command, false);
88  }
89 
90  Acknowledge(command, result);
91 
92  if(resultPackets == null)
93  {
94  resultPackets = new List<CommandResultPacket>();
95  }
96  resultPackets.Add(result);
97  }
98  }
99  catch (Exception err)
100  {
101  Log.Error(err);
102  }
103 
104  return resultPackets ?? Enumerable.Empty<CommandResultPacket>();
105  }
106 
107  /// <summary>
108  /// Disposes of this instance
109  /// </summary>
110  public virtual void Dispose()
111  {
112  // nop
113  }
114 
115  /// <summary>
116  /// Helper method to create a callback command
117  /// </summary>
118  protected ICommand TryGetCallbackCommand(string payload)
119  {
120  Dictionary<string, JToken> deserialized = new(StringComparer.InvariantCultureIgnoreCase);
121  try
122  {
123  if (!string.IsNullOrEmpty(payload))
124  {
125  var jobject = JObject.Parse(payload);
126  foreach (var kv in jobject)
127  {
128  deserialized[kv.Key] = kv.Value;
129  }
130  }
131  }
132  catch (Exception err)
133  {
134  Log.Error(err, $"Payload: '{payload}'");
135  return null;
136  }
137 
138  if (!deserialized.TryGetValue("id", out var id) || id == null)
139  {
140  id = string.Empty;
141  }
142 
143  if (!deserialized.TryGetValue("$type", out var type) || type == null)
144  {
145  type = string.Empty;
146  }
147 
148  return new CallbackCommand { Id = id.ToString(), Type = type.ToString(), Payload = payload };
149  }
150  }
151 }