0

I am trying to write C# types and deserialization code for this WEB-API method, using Newtonsoft JSON libs for C#: https://docs.kraken.com/rest/#operation/getTickerInformation

Example JSON looks like this:

{
  "error": [],
  "result": {
    "XXBTZUSD": {
      "a": [
        "52609.60000",
        "1",
        "1.000"
      ],
      "b": [
        "52609.50000",
        "1",
        "1.000"
      ],
      "c": [
        "52641.10000",
        "0.00080000"
      ],
      "v": [
        "1920.83610601",
        "7954.00219674"
      ],
      "p": [
        "52389.94668",
        "54022.90683"
      ],
      "t": [
        23329,
        80463
      ],
      "l": [
        "51513.90000",
        "51513.90000"
      ],
      "h": [
        "53219.90000",
        "57200.00000"
      ],
      "o": "52280.40000"
    }
  }
}

For other API methods I am using direct mapping to my types with code like this:

public static Ticker GetTicker(string pair)
{
    try
    {
        return Deserialize<Ticker>GetJObject($"https://api.kraken.com/0/public/Ticker?pair={pair}");
        
    }
    catch
    {
        throw;
    }
}

private static T Deserialize<T>(JObject jObject)
{
    try
    {
        var err = jObject["error"];
        if (err.HasValues)
        {
            throw new Exception("Kraken Error" + String.Join(',',err.ToObject<string[]>()));
        }
        return jObject["result"].ToObject<T>();
    }
    catch
    {
        throw;
    }
}

But in this case, the JSON returns nameless values in arbitrary arrays - and also Ticker is nested under another element named by pair. Worse, the arrays use mixed types. So I'm resorting (so far) to something like this:

    public class Ticker
    {
        [JsonProperty("a")]
        public float[] ask { get; set; }
        [JsonProperty("b")]
        public float[] bid { get; set; }
        [JsonProperty("c")]
        public float[] close { get; set; }
        [JsonProperty("v")]
        public float[] volume { get; set; }
        [JsonProperty("p")]
        public float[] volumeWeightedPrice { get; set; }
        [JsonProperty("t")]
        public int[] trades { get; set; }
        [JsonProperty("l")]
        public float[] low { get; set; }
        [JsonProperty("h")]
        public float[] high { get; set; }
        [JsonProperty("o")]
        public float opening { get; set; }
    }
}

I am new to NewtonSoft's JSON libraries and wondering if I can get this to work purely on the Ticker class declaration, presumably using annotations? Or if I have to delve into custom deserialization code... and what that might look like?

Mr. Boy
  • 60,845
  • 93
  • 320
  • 589
  • Are the letters `"a"` and so on fixed, or variable? If variable, make `Result` be a `Dictionary>>`. But you will need `SingleOrArrayConverter` from [How to handle both a single item and an array for the same property using JSON.net](https://stackoverflow.com/q/18994685/3744182) to handle the `"o"` property. – dbc May 30 '21 at 22:16
  • @dbc Needs a SingleOrArrayConverter though: `"o": "52280.40000"`. It can then also be seen as a `Dictionary>`. -- Right, now I see the rest of the comment :) – Jimi May 30 '21 at 22:18
  • If fixed, use a `Dictionary`. – dbc May 30 '21 at 22:19
  • I would use `decimal` rather than `float` if these values correspond to monetary values. – dbc May 30 '21 at 22:20
  • Yep, `decimal` is probably better, you might lose the precision otherwise (e,g, `1.000` will probably become just `1`) – Jimi May 30 '21 at 22:22
  • On github you can find some examples, something like this: https://github.com/discosultan/KrakenCore , array converter - `src/Utils/JArrayToObjectConverter.cs`, models - `src/Models/`, search 'kraken api' and filter by c# – Genusatplay May 30 '21 at 22:34
  • https://github.com/jjxtra/ExchangeSharp - active repo – Genusatplay May 30 '21 at 22:38
  • @dbc it's in the linked API, these are fixed. And the number of elements in each array is also fixed... hence I would really love if `ask` could be a POD type whose 3 properties are mapped to index 0,1,2 of the underlying array. Clearly I can write such code but `To.Object` is _such_ a help I wouldn't want to lose it :) – Mr. Boy May 31 '21 at 14:42
  • @Mr.Boy - then see [How to deserialize an array of values with a fixed schema to a strongly typed data class?](https://stackoverflow.com/a/39462464/3744182) which explains how to deserialize an array whose items have some fixed schema into a [POCO](https://en.wikipedia.org/wiki/Plain_old_CLR_object). (Not sure what a POD is.) – dbc May 31 '21 at 14:59

1 Answers1

0

Model:

public class Ticker
{
    [JsonProperty("a")]
    public float[] ask { get; set; }
    [JsonProperty("b")]
    public float[] bid { get; set; }
    [JsonProperty("c")]
    public float[] close { get; set; }
    [JsonProperty("v")]
    public float[] volume { get; set; }
    [JsonProperty("p")]
    public float[] volumeWeightedPrice { get; set; }
    [JsonProperty("t")]
    public int[] trades { get; set; }
    [JsonProperty("l")]
    public float[] low { get; set; }
    [JsonProperty("h")]
    public float[] high { get; set; }
    [JsonProperty("o")]
    public float opening { get; set; }
}

public class Result
{
    [JsonProperty("XXBTZUSD")]
    public Ticker Ticker { get; set; }
}

public class Root
{
    public List<object> error { get; set; }
    public Result result { get; set; }
}

Decerialize:

Root r = JsonConvert.DeserializeObject<Root>(json_text);
Ticker ticker = r.result.Ticker;

Access:
ticker.ask[0] //52609,6

Blackmeser
  • 101
  • 2