Search code examples
c#.netjsoncsvyahoo-finance

Unable to parse JSON string to CSV from Yahoo finance stock data


I have tried to parse the JSON string from Yahoo finance stock data from the below URL to CSV using various tools (JSON.NET, etc.,) available in internet.

MSFT Yahoo Data

I want to parse JSON string to CSV as below format.

Date | Open | High | Low | Close | Volume

Please any one help me to resolve this. Thanks in advance.


Solution

  • 1) You need to define classes for Yahoo JSON schema: (Modified: Some values might be null. So, I have modified them as null-able variables)

    public class Pre
    {
        public string timezone { get; set; }
        public int end { get; set; }
        public int start { get; set; }
        public int gmtoffset { get; set; }
    }
    
    public class Regular
    {
        public string timezone { get; set; }
        public int end { get; set; }
        public int start { get; set; }
        public int gmtoffset { get; set; }
    }
    
    public class Post
    {
        public string timezone { get; set; }
        public int end { get; set; }
        public int start { get; set; }
        public int gmtoffset { get; set; }
    }
    
    public class CurrentTradingPeriod
    {
        public Pre pre { get; set; }
        public Regular regular { get; set; }
        public Post post { get; set; }
    }
    
    public class Meta
    {
        public string currency { get; set; }
        public string symbol { get; set; }
        public string exchangeName { get; set; }
        public string instrumentType { get; set; }
        public int firstTradeDate { get; set; }
        public int gmtoffset { get; set; }
        public string timezone { get; set; }
        public string exchangeTimezoneName { get; set; }
        public CurrentTradingPeriod currentTradingPeriod { get; set; }
        public string dataGranularity { get; set; }
        public List<string> validRanges { get; set; }
    }
    
    public class Quote
    {
        public List<object> volume { get; set; }
        public List<double?> low { get; set; }
        public List<double?> high { get; set; }
        public List<double?> close { get; set; }
        public List<double?> open { get; set; }
    }
    
    public class Unadjclose
    {
        public List<double?> unadjclose { get; set; }
    }
    
    public class Unadjquote
    {
        public List<double?> unadjopen { get; set; }
        public List<double?> unadjclose { get; set; }
        public List<double?> unadjhigh { get; set; }
        public List<double?> unadjlow { get; set; }
    }
    
    public class Indicators
    {
        public List<Quote> quote { get; set; }
        public List<Unadjclose> unadjclose { get; set; }
        public List<Unadjquote> unadjquote { get; set; }
    }
    
    public class Result
    {
        public Meta meta { get; set; }
        public List<int> timestamp { get; set; }
        public Indicators indicators { get; set; }
    }
    
    public class Chart
    {
        public List<Result> result { get; set; }
        public object error { get; set; }
    }
    
    public class RootObject
    {
        public Chart chart { get; set; }
    }
    

    2) You need to deserialize JSON into object

    var str = wc.DownloadString("https://query1.finance.yahoo.com/v7/finance/chart/MSFT?range=25y&interval=1d&indicators=quote&includeTimestamps=true&includePrePost=false&corsDomain=finance.yahoo.com");
    var data = JsonConvert.DeserializeObject<Rootobject>(str);
    

    3) Then, iterate through this object and build your CSV. Working sample: (Modified: Some values might be null. So, I have modified the code to check if that null-able variables preserves value using HasValue property before converting to string)

    var wc = new WebClient();
    var str = wc.DownloadString("https://query1.finance.yahoo.com/v7/finance/chart/MSFT?range=25y&interval=1d&indicators=quote&includeTimestamps=true&includePrePost=false&corsDomain=finance.yahoo.com");
    var data = JsonConvert.DeserializeObject<Rootobject>(str);
    var result = new List<string>();
    var quotesInfo = data.chart.result.First();
    for (var i = 0; i < quotesInfo.timestamp.Count; i++)
    {
        var quotesStr = new List<string>();
        var quoteData = quotesInfo.indicators.quote.First();
        quotesStr.Add(UnixTimeStampToDateTime(quotesInfo.timestamp[i]).ToString(CultureInfo.InvariantCulture));
        quotesStr.Add(quoteData.open[i].HasValue ? quoteData.open[i].ToString() : string.Empty);
        quotesStr.Add(quoteData.high[i].HasValue ? quoteData.high[i].ToString() : string.Empty);
        quotesStr.Add(quoteData.low[i].HasValue ? quoteData.low[i].ToString() : string.Empty);
        quotesStr.Add(quoteData.close[i].HasValue ? quoteData.close[i].ToString() : string.Empty);
        quotesStr.Add(quoteData.volume[i] != null ? quoteData.volume[i].ToString() : string.Empty);
        result.Add(string.Join(",", quotesStr));
    }
    File.WriteAllLines("result.csv",result);
    

    Modified: And, I have added the code to convert the timestamp to DateTime format.

    public static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
    {
        var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToUniversalTime();
        return dtDateTime;
    }
    

    At the end you will receive comma delimeted CSV file