简体   繁体   中英

Conversion of the candles array from the response to List of Historical Object. Additional details in the body

I have following object getting return from one of the API.

{{
  "status": "success",
  "data": {
    "candles": [
      [
        "2020-11-01T18:30:00+00:00",
        1065,
        1079.95,
        1051.1,
        1072.3,
        7183119
      ],
      [
        "2020-11-02T18:30:00+00:00",
        1072,
        1079.4,
        1057.5,
        1062.55,
        7204782
      ],]
  }
}}

I want to convert candle data into List<Historical> Here is what I have tried

foreach (ArrayList item in historicalData["data"]["candles"])
                historicals.Add(new Historical(item));

But this gives me following error:

Cannot convert type 'Newtonsoft.Json.Linq.JArray' to 'System.Collections.ArrayList

I have tried using JsonConvert.DeserializeObject to diretly convert the string into the object using following code:

foreach (var item in historicalData["data"]["candles"]) {
                var historical = JsonConvert.DeserializeObject<Historical>(item.ToString());

But got this error:

Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'QuantConnect.Brokerages.Zerodha.Messages.Historical' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path '', line 1, position 1.

Historical definition:

public struct Historical
    {
        public Historical(dynamic data)
        {
            TimeStamp = Convert.ToDateTime(data[0], CultureInfo.InvariantCulture);
            Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture);
            High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture);
            Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture);
            Close = Convert.ToDecimal(data[4], CultureInfo.InvariantCulture);
            Volume = Convert.ToUInt32(data[5], CultureInfo.InvariantCulture);
            OI = data.Count > 6 ? Convert.ToUInt32(data[6], CultureInfo.InvariantCulture) : 0;
        }

        public DateTime TimeStamp { get; }
        public decimal Open { get; }
        public decimal High { get; }
        public decimal Low { get; }
        public decimal Close { get; }
        public UInt32 Volume { get; }
        public UInt32 OI { get; }
    }

Is there a correct/elegant way to make it work. Also what I am missing something over here?

  1. The main problem is this isn't valid json. However, let's fix it and assume its correct. If this is what you are getting from some resources, I suggest you contact them and complain.
  2. There are a bunch of ways to do this. Since you used JTokens, I will give you a similar answer.

Given

{
   "status":"success",
   "data":{
      "candles":[
         [
            "2020-11-01T18:30:00+00:00",
            1065,
            1079.95,
            1051.1,
            1072.3,
            7183119
         ],
         [
            "2020-11-02T18:30:00+00:00",
            1072,
            1079.4,
            1057.5,
            1062.55,
            7204782
         ]
      ]
   }
}

And

public class Historical
{
   public DateTime TimeStamp { get; set; }
   public decimal Open { get; set; }
   public decimal High { get; set; }
   public decimal Low { get; set; }
   public decimal Close { get; set; }
   public UInt32 Volume { get; set; }
   public UInt32 OI { get; set; }
}

Usage

var jtoken = JToken.Parse(input);

var data = jtoken["data"]["candles"]
    .Select(x => new Historical
    {
       TimeStamp = x[0].Value<DateTime>(),
       Open = x[1].Value<decimal>(),
       Low = x[2].Value<decimal>(),
       High = x[3].Value<decimal>(),
       Close = x[4].Value<decimal>()
       //...
    });

foreach (var item in data)
   Console.WriteLine($"{item.TimeStamp},Open {item.Open},Low {item.Low} ...");

Output

2/11/2020 4:30:00 AM, Open 1065, Low 1079.95 ...
3/11/2020 4:30:00 AM, Open 1072, Low 1079.4 ...

Note : there are also many ways to deal with the datatime and how to configure Json.net or TryParse to give you the results you want. This is example is leaving this up to you and focusing solely on the projection.


If you need this done in the constructor

public struct Historical
{
   public Historical(JToken x)
   {
      TimeStamp = x[0].Value<DateTime>();
      Open = x[1].Value<decimal>();
      Low = x[2].Value<decimal>();
      High = x[3].Value<decimal>();
      Close = x[4].Value<decimal>();
      ...
   }
   public DateTime TimeStamp { get; }
   public decimal Open { get; }
   public decimal High { get; }
   public decimal Low { get; }
   public decimal Close { get; }
   ...     
}

...

var data = jtoken["data"]["candles"].Select(x => new Historical(x));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM