question

MattiaFanti-4051 avatar image
0 Votes"
MattiaFanti-4051 asked MattiaFanti-4051 answered

Weird behavior during parsing Json

I'm parsing this JSON

 {"error":null,"result":{"KIBAUSDT":{"limit":100,"offset":0,"total":2,"records":[{"user":2996434,"id":82873069172,"market":"KIBAUSDT","freeze":"100","fee_stock":"","source":"web","type":1,"side":1,"ctime":1645133452.181028,"mtime":1645133452.181028,"price":"0.00002","amount":"100","taker_fee":"0.0035","maker_fee":"-0.003","left":"100","deal_stock":"0","deal_money":"0","deal_fee":"0","alt_fee":"0","deal_fee_alt":"0","status":0},{"user":2996434,"id":82873306723,"market":"KIBAUSDT","freeze":"100","fee_stock":"","source":"web","type":1,"side":1,"ctime":1645133526.563619,"mtime":1645133546.966621,"price":"0.00001124","amount":"200","taker_fee":"0.0035","maker_fee":"-0.003","left":"100","deal_stock":"100","deal_money":"0.001124","deal_fee":"-0.000003372","alt_fee":"0","deal_fee_alt":"0","status":1}]}},"id":300991746}


which is basically the API of one crypto exchange that is showing the orders that I've opened. I'm using quicktype.io to create the code of a new class file

 Imports System
 Imports Newtonsoft.Json
 Imports Newtonsoft.Json.Converters
 Imports System.Runtime.CompilerServices
    
 Namespace OrdiniAperti
     Partial Public Class Openorders
         <JsonProperty("error")>
         Public Property [Error] As Object
         <JsonProperty("result")>
         Public Property Result As Result
         <JsonProperty("id")>
         Public Property Id As Long
     End Class
    
     Partial Public Class Result
         <JsonProperty("KIBAUSDT")>
         Public Property Kibausdt As Kibausdt
     End Class
    
     Partial Public Class Kibausdt
         <JsonProperty("limit")>
         Public Property Limit As Long
         <JsonProperty("offset")>
         Public Property Offset As Long
         <JsonProperty("total")>
         Public Property Total As Long
         <JsonProperty("records")>
         Public Property Records As Record()
     End Class
    
     Partial Public Class Record
         <JsonProperty("user")>
         Public Property User As Long
         <JsonProperty("id")>
         Public Property Id As Long
         <JsonProperty("market")>
         Public Property Market As String
         <JsonProperty("freeze")>
         Public Property Freeze As String
         <JsonProperty("fee_stock")>
         Public Property FeeStock As String
         <JsonProperty("source")>
         Public Property Source As String
         <JsonProperty("type")>
         Public Property Type As Long
         <JsonProperty("side")>
         Public Property Side As Long
         <JsonProperty("ctime")>
         Public Property Ctime As Double
         <JsonProperty("mtime")>
         Public Property Mtime As Double
         <JsonProperty("price")>
         Public Property Price As String
         <JsonProperty("amount")>
         <JsonConverter(GetType(ParseStringConverter))>
         Public Property Amount As Long
         <JsonProperty("taker_fee")>
         Public Property TakerFee As String
         <JsonProperty("maker_fee")>
         Public Property MakerFee As String
         <JsonProperty("left")>
         <JsonConverter(GetType(ParseStringConverter))>
         Public Property Left As Long
         <JsonProperty("deal_stock")>
         <JsonConverter(GetType(ParseStringConverter))>
         Public Property DealStock As Long
         <JsonProperty("deal_money")>
         <JsonConverter(GetType(ParseStringConverter))>
         Public Property DealMoney As Long
         <JsonProperty("deal_fee")>
         <JsonConverter(GetType(ParseStringConverter))>
         Public Property DealFee As Long
         <JsonProperty("alt_fee")>
         <JsonConverter(GetType(ParseStringConverter))>
         Public Property AltFee As Long
         <JsonProperty("deal_fee_alt")>
         <JsonConverter(GetType(ParseStringConverter))>
         Public Property DealFeeAlt As Long
         <JsonProperty("status")>
         Public Property Status As Long
     End Class
    
     Partial Public Class Openorders
         Public Shared Function FromJson(ByVal json As String) As Openorders
             Return JsonConvert.DeserializeObject(Of Openorders)(json, Settings)
         End Function
     End Class
    
     Public Module Serialize
         <Extension()>
         Public Function ToJson(ByVal self As Openorders) As String
             Return JsonConvert.SerializeObject(self, Settings)
         End Function
     End Module
    
     Friend Module Converter
         Public ReadOnly Settings As JsonSerializerSettings = New JsonSerializerSettings With {
             .MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
             .DateParseHandling = DateParseHandling.None
         }
     End Module
    
     Friend Class ParseStringConverter
         Inherits JsonConverter
    
         Public Overrides Function CanConvert(ByVal t As Type) As Boolean
             Return t Is GetType(Long) OrElse t Is GetType(Long?)
         End Function
    
         Public Overrides Function ReadJson(ByVal reader As JsonReader, ByVal t As Type, ByVal existingValue As Object, ByVal serializer As JsonSerializer) As Object
             If reader.TokenType = JsonToken.Null Then Return Nothing
             Dim value = serializer.Deserialize(Of String)(reader)
             Dim l As Long
    
             If Long.TryParse(value, l) Then
                 Return l
             End If
    
             Throw New Exception("Cannot unmarshal type long")
         End Function
    
         Public Overrides Sub WriteJson(ByVal writer As JsonWriter, ByVal untypedValue As Object, ByVal serializer As JsonSerializer)
             If untypedValue Is Nothing Then
                 serializer.Serialize(writer, Nothing)
                 Return
             End If
    
             Dim value = CLng(untypedValue)
             serializer.Serialize(writer, value.ToString())
             Return
         End Sub
    
         Public Shared ReadOnly Singleton As ParseStringConverter = New ParseStringConverter()
     End Class
 End Namespace


and then I'm using the following code in order to parse some of the property I need:

  Dim json = Await wc1.DownloadStringTaskAsync("https://api.hotbit.io/api/v1/order.pending?market=KIBA/USDT&offset=0&limit=100&api_key=44812d8f-66d3-01c0-94c3b29305040b03&sign=F3330B924E1873B9C8FAB40A25D7B851")
                 'deserialize the json
                 Dim rootObj = Openorders.FromJson(json)
                 'navigate to Kibausdt
                 Dim kibausdt = rootObj.Result.Kibausdt
    
                 'check total
                 If kibausdt.Total = 0 Then
                     RichTextBox1.Text = "0 opened orders"
    
                 Else
                     RichTextBox1.Clear()
                     'loop through records
                     For Each record In kibausdt.Records
                         Dim side As String = record.Side.ToString()
                         Dim amount As Long = record.Amount
                         Dim price As String = record.Price.ToString
                         Dim filled As Long = record.Left
                         Dim status As String = record.Status.ToString
                         If side = "1" Then
                             side = "SELL"
                         Else
                             side = ("BUY ")
                         End If
                         If status = "1" Then
                             status = "Hidden order"
                         Else
                             status = "Not hidden order"
                         End If
                         Dim percentage As Double = ((filled * 100) / amount)
                         RichTextBox1.Text &= "    " & side & " - " & "      " & amount & " - " & "            " & price.ToString & " - " & "    " & percentage.tostring & " % " & " - " & "    " & status & vbCr
                     Next
                 End If

As you can see the API lack of filled % property, so I'm calculating it with the formula ((filled * 100)/ whole order amount). The code is working when I have 0 order opened and when an order ( or more) is opened but still not filled, so with 0% filled. The problem starts when the order is starting to be filled, so the % increase. As soon as the % moves from 0 I'm getting the error on the class file at the line Throw New Exception("Cannot unmarshal type long")

System.Exception: 'Cannot unmarshal type long'

So I've been looking at the class file code and sow that "left" and "amount" properties are declared as Long. So I've tried to declare them as Double and even as Decimal, So I changed also Dim filled As Long to Dim filled As Double as well as Dim amount as long to Dim amount as Double into the main form. But now, I'm getting the following error on the line Return JsonConvert.DeserializeObject(Of Openorders)(json, Settings) of the Class File:

Newtonsoft.Json.JsonSerializationException: 'Error setting value to 'Left' on 'HotBit_APIs.OrdiniAperti.Record

How is this behavior possible? What Am I doing wrong? Thanks

















dotnet-visual-basicdotnet-runtime
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


In case of "Cannot unmarshal type long", add additional information to your Throw line:

Throw New Exception("Cannot unmarshal type long: '" & value & "'")

Or use the Debugger and put a breakpoint. Then investigate the value of value and find why it cannot be converted to Long.


0 Votes 0 ·

Since I'm dealing with numbers that can be also decimals, I decided to set everything as decimal ( or double? ) so the error is the second I've posted. Is kind of weird to be honest

0 Votes 0 ·
Viorel-1 avatar image Viorel-1 MattiaFanti-4051 ·

After changing the type of Amount and Left to Decimal, does it work if you remove both of <JsonConverter(GetType(ParseStringConverter))>?


0 Votes 0 ·
Show more comments
JiachenLiMFST-9349 avatar image
0 Votes"
JiachenLiMFST-9349 answered MattiaFanti-4051 edited

Hi @MattiaFanti-4051 ,
I used the code you provided and got the exception Error setting value to 'DealMoney' on 'Deserialize_a_dictionary_json.Record'.
When I changed all long types to Decimal types, there were no exceptions.
And I got the following result.
175648-image.png
Maybe you can try to change all long types to Decimal types.
Best Regards.
Jiachen Li


If the answer is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



image.png (4.0 KiB)
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

did you changg also the properties on the class file?

0 Votes 0 ·

Hi @MattiaFanti-4051 ,
I changed all the Long in the class file to Decimal.
No other changes.

0 Votes 0 ·

That's really weird to me. I've tried what you are suggesting but still getting the error. I changed the long property to decimal and changed the long types on form1 to decimal as well, but it didn't changed the issue. Look gif

p.s. Since I only using the properties: amount and left, I'm leaving the others as they are.
Why you did get "deal money" error if we are not dealing with that property?

0 Votes 0 ·
MattiaFanti-4051 avatar image
0 Votes"
MattiaFanti-4051 answered

I solved changing all "long" types to "Double"

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.