From ffdb615a4d61680191d812bcf3909e074de75fb9 Mon Sep 17 00:00:00 2001 From: Martin-Molinero Date: Tue, 15 Oct 2024 13:38:39 -0300 Subject: [PATCH] Add research node packet (#8360) --- Common/Api/Organization.cs | 5 ++++ Common/Extensions.cs | 29 ++++++++++++++----- Common/Global.cs | 7 ++++- Common/Packets/AlgorithmNodePacket.cs | 4 +++ Common/Packets/Packet.cs | 3 ++ Common/Packets/ResearchNodePacket.cs | 41 +++++++++++++++++++++++++++ Common/Util/Composer.cs | 2 +- Tests/Common/Util/ExtensionsTests.cs | 29 +++++++++++++++++++ 8 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 Common/Packets/ResearchNodePacket.cs diff --git a/Common/Api/Organization.cs b/Common/Api/Organization.cs index 3251cb793a7b..5244ab90d642 100644 --- a/Common/Api/Organization.cs +++ b/Common/Api/Organization.cs @@ -117,6 +117,11 @@ public class ProductItem /// [JsonProperty(PropertyName = "productId")] public int Id { get; set; } + + /// + /// Quantity for this product + /// + public int Quantity { get; set; } } /// diff --git a/Common/Extensions.cs b/Common/Extensions.cs index cbcdb3567729..8a2f2cd443c1 100644 --- a/Common/Extensions.cs +++ b/Common/Extensions.cs @@ -209,21 +209,36 @@ public static MarketHoursDatabase.Entry GetEntry(this MarketHoursDatabase market /// The value to deserialize public static List DeserializeList(this string jsonArray) { - List result = new(); + return DeserializeList(jsonArray); + } + + /// + /// Helper method to deserialize a json array into a list also handling single json values + /// + /// The value to deserialize + public static List DeserializeList(this string jsonArray) + { try { if (string.IsNullOrEmpty(jsonArray)) { - return result; + return new(); } - result = JsonConvert.DeserializeObject>(jsonArray); + return JsonConvert.DeserializeObject>(jsonArray); } - catch(JsonReaderException) + catch (Exception ex) { - result.Add(jsonArray); - } + if (ex is not JsonReaderException && ex is not JsonSerializationException) + { + throw; + } - return result; + if (typeof(T) == typeof(string)) + { + return new List { (T)Convert.ChangeType(jsonArray, typeof(T), CultureInfo.InvariantCulture) }; + } + return new List { JsonConvert.DeserializeObject(jsonArray) }; + } } /// diff --git a/Common/Global.cs b/Common/Global.cs index ad06c0bcaffc..3f90aa8cabfc 100644 --- a/Common/Global.cs +++ b/Common/Global.cs @@ -990,7 +990,12 @@ public enum DeploymentTarget /// /// Local Platform (1) /// - LocalPlatform + LocalPlatform, + + /// + /// Private Cloud Platform (2) + /// + PrivateCloudPlatform } /// diff --git a/Common/Packets/AlgorithmNodePacket.cs b/Common/Packets/AlgorithmNodePacket.cs index 99249d3801cf..e3e3172f807d 100644 --- a/Common/Packets/AlgorithmNodePacket.cs +++ b/Common/Packets/AlgorithmNodePacket.cs @@ -71,6 +71,10 @@ public string AlgorithmId { return ((LiveNodePacket)this).DeployId; } + else if (Type == PacketType.ResearchNode) + { + return ((ResearchNodePacket)this).ResearchId; + } return ((BacktestNodePacket)this).BacktestId; } } diff --git a/Common/Packets/Packet.cs b/Common/Packets/Packet.cs index d3a220586d7f..ef58b047c231 100644 --- a/Common/Packets/Packet.cs +++ b/Common/Packets/Packet.cs @@ -191,5 +191,8 @@ public enum PacketType /// Algorithm tags update AlgorithmTagsUpdate, + + /// Research job packet + ResearchNode, } } diff --git a/Common/Packets/ResearchNodePacket.cs b/Common/Packets/ResearchNodePacket.cs new file mode 100644 index 000000000000..c1a73d30b4f0 --- /dev/null +++ b/Common/Packets/ResearchNodePacket.cs @@ -0,0 +1,41 @@ +/* + * 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. + * +*/ + +namespace QuantConnect.Packets +{ + /// + /// Represents a research node packet + /// + public class ResearchNodePacket : AlgorithmNodePacket + { + /// + /// The research id + /// + public string ResearchId { get; set; } + + /// + /// Associated research token + /// + public string ResearchToken { get; set; } + + /// + /// Creates a new instance + /// + public ResearchNodePacket() : base(PacketType.ResearchNode) + { + } + } +} diff --git a/Common/Util/Composer.cs b/Common/Util/Composer.cs index 0c1bd6377f7c..a0a9ec0b1694 100644 --- a/Common/Util/Composer.cs +++ b/Common/Util/Composer.cs @@ -315,7 +315,7 @@ public T GetExportedValueByTypeName(string typeName, bool forceTypeNameOnExis if (selectedPart == null) { throw new ArgumentException( - $"Unable to locate any exports matching the requested typeName: {typeName}", nameof(typeName)); + $"Unable to locate any exports matching the requested typeName: {typeName}. Type: {type}", nameof(typeName)); } var exportDefinition = diff --git a/Tests/Common/Util/ExtensionsTests.cs b/Tests/Common/Util/ExtensionsTests.cs index 3e7ab6d9a509..a2877f99a1a1 100644 --- a/Tests/Common/Util/ExtensionsTests.cs +++ b/Tests/Common/Util/ExtensionsTests.cs @@ -46,6 +46,35 @@ namespace QuantConnect.Tests.Common.Util [TestFixture] public class ExtensionsTests { + [TestCase("A test", 1)] + [TestCase("[\"A test\"]", 1)] + [TestCase("[\"A test\", \"something else\"]", 2)] + public void DeserializeList(string input, int count) + { + var result = input.DeserializeList(); + Assert.AreEqual(count, result.Count); + Assert.AreEqual("A test", result[0]); + if (count == 2) + { + Assert.AreEqual("something else", result[1]); + } + } + + private class DeserializeListObject { public int Property { get; set; } } + [TestCase("{ \"property\": 10}", 1)] + [TestCase("[{ \"property\": 10}]", 1)] + [TestCase("[{ \"property\": 10}, { \"property\": 20 }]", 2)] + public void DeserializeObjectList(string input, int count) + { + var result = input.DeserializeList(); + Assert.AreEqual(count, result.Count); + Assert.AreEqual(10, result[0].Property); + if (count == 2) + { + Assert.AreEqual(20, result[1].Property); + } + } + [TestCase(true)] [TestCase(false)] public void ConvertPythonSymbolEnumerableSingle(bool useSymbol)