Closed RkNxSR closed 1 month ago
It appears the previous ability to get a CSV style text response has been removed by Yahoo.
This URL previously worked:
But now it returns:
{"finance":{"result":null,"error":{"code":"unauthorized","description":"User is not logged in"}}}
If you adjust it to:
It returns JSON that needs to be parsed to get the prices in a CSV style format you expect.
I will be doing an update to this library soon that should address these new changes that Yahoo has made. This URL info is very handy so please let me know if you have any other examples
On Tue, Sep 17, 2024, 9:56 PM David Clayton @.***> wrote:
It appears the previous ability to get a CSV style text response has been removed by Yahoo.
This URL previously worked:
But now it returns:
{"finance":{"result":null,"error":{"code":"unauthorized","description":"User is not logged in"}}}
If you adjust it to:
It returns JSON that needs to be parsed to get the prices in a CSV style format you expect.
— Reply to this email directly, view it on GitHub https://github.com/ooples/OoplesFinance.YahooFinanceAPI/issues/91#issuecomment-2357332737, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAXO4ZOD4SGGJWBEEYUCS63ZXDMUZAVCNFSM6AAAAABN6EVRBKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNJXGMZTENZTG4 . You are receiving this because you are subscribed to this thread.Message ID: @.***>
I lightly edited some code ChatGPT generated to extract the historical prices and put them in the text CSV format that was previously expected. I'm going to refactor my code to work directly with the JSON, but this is a quick and dirty helper for code that was expecting the previous CSV format.
public static string ParseJSONPrices(string rawJSON) { try { // Parse the JSON response var jsonObject = JObject.Parse(rawJSON);
// Extract dates
var timestamps = jsonObject["chart"]["result"][0]["timestamp"]
.Select(t => DateTimeOffset.FromUnixTimeSeconds(t.Value<long>()).DateTime.ToString("yyyy-MM-dd"))
.ToList();
// Extract different price types
var openPrices = ExtractPrices(jsonObject, "open");
var highPrices = ExtractPrices(jsonObject, "high");
var lowPrices = ExtractPrices(jsonObject, "low");
var closePrices = ExtractPrices(jsonObject, "close");
var adjustedClosePrices = ExtractPrices(jsonObject, "adjclose");
var volumes = ExtractPrices(jsonObject, "volume");
// Build the output string
var lines = new List<string>();
// Header line
lines.Add("Date,Open,High,Low,Close,AdjClose,Volume");
for (int i = 0; i < timestamps.Count; i++)
{
// Create line with date and all prices for that date
string line = $"{timestamps[i]},{openPrices[i]},{highPrices[i]},{lowPrices[i]},{closePrices[i]},{adjustedClosePrices[i]},{volumes[i]}";
lines.Add(line);
}
// Join all lines into a single string separated by newline characters
string result = string.Join("\n", lines);
return result;
}
catch
{
//ToDo: Exception handling
return String.Empty;
}
}
// Helper method to extract prices by type from JSON static List<decimal?> ExtractPrices(JObject jsonObject, string priceType) { try { //All prices except Adjusted Close are in "quote", use "adjclose" for adjusted close if (priceType == "adjclose") { // Extract prices as nullable decimals return jsonObject["chart"]["result"][0]["indicators"]["adjclose"][0]["adjclose"] .Select(p => p.Value<decimal?>()) .ToList(); } else { // Extract prices as nullable decimals return jsonObject["chart"]["result"][0]["indicators"]["quote"][0][priceType] .Select(p => p.Value<decimal?>()) .ToList(); }
}
catch
{
// Return an empty list if the price type is not found
return new List<decimal?>();
}
}
@ooples thanks for your input on this issue. I'm encountering this as well.... just like everyone else (I'm assuming). Can you provide an estimated timeline for the update to the library you were referring to that will have the fix?
@davidclayton just curious how did you figure this out? Are there docs that indicate how to fetch this data from yahoo? If so can you share them?
Thanks @davidclayton and @ooples
`public class StockPriceFetcher { private static readonly HttpClient client = new HttpClient();
public StockPriceFetcher()
{
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3");
}
public static DateTime UnixTimeStampToDateTime(long unixTimeStamp)
{
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(unixTimeStamp);
return dateTimeOffset.DateTime;
}
public static long DateTimeToUnixTimeStamp(DateTime dateTime)
{
DateTimeOffset dateTimeOffset = new DateTimeOffset(dateTime);
return dateTimeOffset.ToUnixTimeSeconds();
}
public async Task<List<StockPriceItem>> FetchStockPrices(DateTime startDate, DateTime endDate, string stockName)
{
long period1 = DateTimeToUnixTimeStamp(startDate);
long period2 = DateTimeToUnixTimeStamp(endDate);
string url = $"https://query2.finance.yahoo.com/v8/finance/chart/{stockName}?period1={period1}&period2={period2}&interval=1d&events=history";
List<StockPriceItem> stockPrices = new List<StockPriceItem>();
try
{
string response = await client.GetStringAsync(url);
JObject json = JObject.Parse(response);
var timestamp = json["chart"]["result"][0]["timestamp"];
var indicators = json["chart"]["result"][0]["indicators"]["quote"][0];
var adjClose = json["chart"]["result"][0]["indicators"]["adjclose"][0]["adjclose"];
for (int i = 0; i < timestamp.Count(); i++)
{
DateTime date = UnixTimeStampToDateTime((long)timestamp[i]);
double? open = indicators["open"][i]?.ToObject<double?>();
double? high = indicators["high"][i]?.ToObject<double?>();
double? low = indicators["low"][i]?.ToObject<double?>();
double? close = indicators["close"][i]?.ToObject<double?>();
double? adjCloseVal = adjClose[i]?.ToObject<double?>();
long? volume = indicators["volume"][i]?.ToObject<long?>();
if (open.HasValue && high.HasValue && low.HasValue && close.HasValue && adjCloseVal.HasValue && volume.HasValue)
{
StockPriceItem stockPrice = new StockPriceItem
{
Symbol = stockName,
Date = date,
Open = open.Value,
High = high.Value,
Low = low.Value,
Close = close.Value,
AdjClose = adjCloseVal.Value,
Volume = volume.Value
};
stockPrices.Add(stockPrice);
}
}
}
catch (HttpRequestException ex)
{
MessageBox.Show($"Error fetching data: {ex.Message}");
}
return stockPrices;
}
}
public class StockPriceItem
{
public string Symbol { get; set; }
public DateTime Date { get; set; }
public double Open { get; set; }
public double High { get; set; }
public double Low { get; set; }
public double Close { get; set; }
public double AdjClose { get; set; }
public double Volume { get; set; }
}`
`private async void btn_fill_list_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(txtB_stocks.Text)) { MessageBox.Show("Empty stock name"); return; }
StockPriceFetcher fetcher = new StockPriceFetcher();
DateTime startDate = date_Start.Value;
DateTime endDate = date_end.Value;
try
{
List<StockPriceItem> stockPrices = await fetcher.FetchStockPrices(startDate, endDate, txtB_stocks.Text);
dgw_stockPriceList.DataSource = stockPrices;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}`
@davidclayton just curious how did you figure this out? Are there docs that indicate how to fetch this data from yahoo? If so can you share them?
I googled the error I was getting, found this redit thread, and then started experimenting with the URL, I too am looking for some kind of official documentation or statement
https://www.reddit.com/r/sheets/comments/1farvxr/broken_yahoo_finance_url/?rdt=46309
@Codepoet77 @davidclayton @RkNxSR I have a new version 1.6.5 that fixes the issues with the 4 csv methods: GetCapitalGainsAsync(), GetStockSplitDataAsync(), GetHistoricalDataAsync(), and GetDividendDataAsync()
If you guys can please help test and let me know if you run into any issues
I can confirm GetHistoricalDataAsync() is working as expected
Great to hear the new version is working for everyone. I will go ahead and close this ticket then
@ooples thank you for your great work. Most of quote work good but some of quote like "BUMI.JK" which volume would overflow. I believe the volume type should change to long instead of integer.
chart.result[0].indicators.quote[0].volume[10]
Can you do me a favor and send me the method you are using? I thought I changed all volumes to long but clearly I missed something
Get Outlook for Androidhttps://aka.ms/AAb9ysg
From: Oscar Iong @.> Sent: Saturday, October 5, 2024 9:49:45 PM To: ooples/OoplesFinance.YahooFinanceAPI @.> Cc: Franklin Moormann @.>; Mention @.> Subject: Re: [ooples/OoplesFinance.YahooFinanceAPI] Not working anymore (Issue #91)
@oopleshttps://github.com/ooples thank you for your great work. Most of quote work good but some of quote like "BUMI.JK" which volume would overflow. I believe the volume type should change to long instead of integer.
chart.result[0].indicators.quote[0].volume[10]
— Reply to this email directly, view it on GitHubhttps://github.com/ooples/OoplesFinance.YahooFinanceAPI/issues/91#issuecomment-2395255487, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAXO4ZPNBXV3DDSNXSSXUFDZ2CJLTAVCNFSM6AAAAABN6EVRBKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGOJVGI2TKNBYG4. You are receiving this because you were mentioned.Message ID: @.***>
@ooples , Here is the same code.
var historicalDataList = await yahooClient.GetHistoricalDataAsync("BUMI.JK", DataFrequency.Daily, startDate, null, true);
Please check out version 1.6.9 and confirm that this version fixes your issue
Works good to me
"Historical Data" has not been returning any results since Monday
Exception Message "Yahoo Finance Authentication Error"