From fc3b7cc75b7145184169fed539709752ad63cb33 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Wed, 28 May 2025 14:26:55 +0200 Subject: [PATCH] Added JsonConverter implementation for SharedQuantity and SharedSymbol types --- .../SystemTextJsonConverterTests.cs | 35 +++++++++++ .../SystemTextJson/SharedQuantityConverter.cs | 60 +++++++++++++++++++ .../SystemTextJson/SharedSymbolConverter.cs | 46 ++++++++++++++ .../SharedApis/SharedQuantity.cs | 13 +++- CryptoExchange.Net/SharedApis/SharedSymbol.cs | 5 +- 5 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 CryptoExchange.Net/Converters/SystemTextJson/SharedQuantityConverter.cs create mode 100644 CryptoExchange.Net/Converters/SystemTextJson/SharedSymbolConverter.cs diff --git a/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs b/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs index 68891d3..5662776 100644 --- a/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs +++ b/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs @@ -7,6 +7,7 @@ using System.Text.Json.Serialization; using NUnit.Framework.Legacy; using CryptoExchange.Net.Converters; using CryptoExchange.Net.Testing.Comparers; +using CryptoExchange.Net.SharedApis; namespace CryptoExchange.Net.UnitTests { @@ -298,6 +299,40 @@ namespace CryptoExchange.Net.UnitTests Assert.That(deserialized.Prop8.Prop31, Is.EqualTo(5)); Assert.That(deserialized.Prop8.Prop32, Is.EqualTo("101")); } + + [TestCase(TradingMode.Spot, "ETH", "USDT", null)] + [TestCase(TradingMode.PerpetualLinear, "ETH", "USDT", null)] + [TestCase(TradingMode.DeliveryLinear, "ETH", "USDT", 1748432430)] + public void TestSharedSymbolConversion(TradingMode tradingMode, string baseAsset, string quoteAsset, int? deliverTime) + { + DateTime? time = deliverTime == null ? null : DateTimeConverter.ParseFromDouble(deliverTime.Value); + var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, time); + + var serialized = JsonSerializer.Serialize(symbol); + var restored = JsonSerializer.Deserialize(serialized); + + Assert.That(restored.TradingMode, Is.EqualTo(symbol.TradingMode)); + Assert.That(restored.BaseAsset, Is.EqualTo(symbol.BaseAsset)); + Assert.That(restored.QuoteAsset, Is.EqualTo(symbol.QuoteAsset)); + Assert.That(restored.DeliverTime, Is.EqualTo(symbol.DeliverTime)); + } + + [TestCase(0.1, null, null)] + [TestCase(0.1, 0.1, null)] + [TestCase(0.1, 0.1, 0.1)] + [TestCase(null, 0.1, null)] + [TestCase(null, 0.1, 0.1)] + public void TestSharedQuantityConversion(double? baseQuantity, double? quoteQuantity, double? contractQuantity) + { + var symbol = new SharedOrderQuantity((decimal?)baseQuantity, (decimal?)quoteQuantity, (decimal?)contractQuantity); + + var serialized = JsonSerializer.Serialize(symbol); + var restored = JsonSerializer.Deserialize(serialized); + + Assert.That(restored.QuantityInBaseAsset, Is.EqualTo(symbol.QuantityInBaseAsset)); + Assert.That(restored.QuantityInQuoteAsset, Is.EqualTo(symbol.QuantityInQuoteAsset)); + Assert.That(restored.QuantityInContracts, Is.EqualTo(symbol.QuantityInContracts)); + } } public class STJDecimalObject diff --git a/CryptoExchange.Net/Converters/SystemTextJson/SharedQuantityConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/SharedQuantityConverter.cs new file mode 100644 index 0000000..bedfebe --- /dev/null +++ b/CryptoExchange.Net/Converters/SystemTextJson/SharedQuantityConverter.cs @@ -0,0 +1,60 @@ +using CryptoExchange.Net.SharedApis; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CryptoExchange.Net.Converters.SystemTextJson +{ + internal class SharedQuantityConverter : SharedQuantityReferenceConverter { } + internal class SharedOrderQuantityConverter : SharedQuantityReferenceConverter { } + + internal class SharedQuantityReferenceConverter : JsonConverter where T: SharedQuantityReference, new() + { + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartArray) + throw new Exception(""); + + reader.Read(); // Start array + var baseQuantity = reader.TokenType == JsonTokenType.Null ? (decimal?)null : reader.GetDecimal(); + reader.Read(); + var quoteQuantity = reader.TokenType == JsonTokenType.Null ? (decimal?)null : reader.GetDecimal(); + reader.Read(); + var contractQuantity = reader.TokenType == JsonTokenType.Null ? (decimal?)null : reader.GetDecimal(); + reader.Read(); + + if (reader.TokenType != JsonTokenType.EndArray) + throw new Exception(""); + + reader.Read(); // End array + + var result = new T(); + result.QuantityInBaseAsset = baseQuantity; + result.QuantityInQuoteAsset = quoteQuantity; + result.QuantityInContracts = contractQuantity; + return result; + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + if (value.QuantityInBaseAsset == null) + writer.WriteNullValue(); + else + writer.WriteNumberValue(value.QuantityInBaseAsset.Value); + + if (value.QuantityInQuoteAsset == null) + writer.WriteNullValue(); + else + writer.WriteNumberValue(value.QuantityInQuoteAsset.Value); + + if (value.QuantityInContracts == null) + writer.WriteNullValue(); + else + writer.WriteNumberValue(value.QuantityInContracts.Value); + writer.WriteEndArray(); + } + } +} diff --git a/CryptoExchange.Net/Converters/SystemTextJson/SharedSymbolConverter.cs b/CryptoExchange.Net/Converters/SystemTextJson/SharedSymbolConverter.cs new file mode 100644 index 0000000..6622305 --- /dev/null +++ b/CryptoExchange.Net/Converters/SystemTextJson/SharedSymbolConverter.cs @@ -0,0 +1,46 @@ +using CryptoExchange.Net.SharedApis; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CryptoExchange.Net.Converters.SystemTextJson +{ + internal class SharedSymbolConverter : JsonConverter + { + public override SharedSymbol? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartArray) + throw new Exception(""); + + reader.Read(); // Start array + var tradingMode = (TradingMode)Enum.Parse(typeof(TradingMode), reader.GetString()!); + reader.Read(); + var baseAsset = reader.GetString()!; + reader.Read(); + var quoteAsset = reader.GetString()!; + reader.Read(); + var timeStr = reader.GetString()!; + var deliverTime = string.IsNullOrEmpty(timeStr) ? (DateTime?)null : DateTime.Parse(timeStr); + reader.Read(); + + if (reader.TokenType != JsonTokenType.EndArray) + throw new Exception(""); + + reader.Read(); // End array + + return new SharedSymbol(tradingMode, baseAsset, quoteAsset, deliverTime); + } + + public override void Write(Utf8JsonWriter writer, SharedSymbol value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + writer.WriteStringValue(value.TradingMode.ToString()); + writer.WriteStringValue(value.BaseAsset); + writer.WriteStringValue(value.QuoteAsset); + writer.WriteStringValue(value.DeliverTime?.ToString()); + writer.WriteEndArray(); + } + } +} diff --git a/CryptoExchange.Net/SharedApis/SharedQuantity.cs b/CryptoExchange.Net/SharedApis/SharedQuantity.cs index ef1ca59..722c1b7 100644 --- a/CryptoExchange.Net/SharedApis/SharedQuantity.cs +++ b/CryptoExchange.Net/SharedApis/SharedQuantity.cs @@ -1,6 +1,8 @@ -using System; +using CryptoExchange.Net.Converters.SystemTextJson; +using System; using System.Collections.Generic; using System.Text; +using System.Text.Json.Serialization; namespace CryptoExchange.Net.SharedApis { @@ -25,7 +27,7 @@ namespace CryptoExchange.Net.SharedApis /// /// ctor /// - protected SharedQuantityReference(decimal? baseAssetQuantity, decimal? quoteAssetQuantity, decimal? contractQuantity) + internal SharedQuantityReference(decimal? baseAssetQuantity, decimal? quoteAssetQuantity, decimal? contractQuantity) { QuantityInBaseAsset = baseAssetQuantity; QuantityInQuoteAsset = quoteAssetQuantity; @@ -36,6 +38,7 @@ namespace CryptoExchange.Net.SharedApis /// /// Quantity for an order /// + [JsonConverter(typeof(SharedQuantityConverter))] public record SharedQuantity : SharedQuantityReference { private SharedQuantity(decimal? baseAssetQuantity, decimal? quoteAssetQuantity, decimal? contractQuantity) @@ -43,6 +46,11 @@ namespace CryptoExchange.Net.SharedApis { } + /// + /// ctor + /// + public SharedQuantity() : base(null, null, null) { } + /// /// Specify quantity in base asset /// @@ -98,6 +106,7 @@ namespace CryptoExchange.Net.SharedApis /// /// Order quantity /// + [JsonConverter(typeof(SharedOrderQuantityConverter))] public record SharedOrderQuantity : SharedQuantityReference { /// diff --git a/CryptoExchange.Net/SharedApis/SharedSymbol.cs b/CryptoExchange.Net/SharedApis/SharedSymbol.cs index 9524c68..92c0e3c 100644 --- a/CryptoExchange.Net/SharedApis/SharedSymbol.cs +++ b/CryptoExchange.Net/SharedApis/SharedSymbol.cs @@ -1,12 +1,15 @@ -using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Converters.SystemTextJson; +using CryptoExchange.Net.Objects; using System; using System.Collections.Generic; +using System.Text.Json.Serialization; namespace CryptoExchange.Net.SharedApis { /// /// A symbol representation based on a base and quote asset /// + [JsonConverter(typeof(SharedSymbolConverter))] public record SharedSymbol { ///