using System.Threading.Tasks;
var requests = new QuoteRequest[]
new DateTime(2004, 1, 1),
new DateTime(2019, 12, 31),
new DateTime(2004, 1, 1),
new DateTime(2019, 12, 31),
new DateTime(2004, 1, 1),
new DateTime(2019, 12, 31),
new DateTime(2004, 12, 1),
new DateTime(2019, 12, 31),
new DateTime(2004, 12, 1),
new DateTime(2019, 12, 31),
foreach(var req in requests)
var csv = await DownloadQuoteFromYahooAsync(req.symbol, req.from, req.to, req.interval, crumb);
Console.WriteLine($"{csv.Length} bytes");
HttpClient newConfiguredHttpClient()
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0");
httpClient.Timeout = TimeSpan.FromSeconds(15);
async Task<string> RevalidateCrumbAsync(string symbol = "GOOG")
var url = $"https://finance.yahoo.com/quote/{symbol}";
HttpClient httpClient = newConfiguredHttpClient();
var response = await httpClient.GetAsync(url);
var html = await response.Content.ReadAsStringAsync();
var pos = html.IndexOf("\"crumb\":\"");
var pos1 = html.IndexOf(":\"", pos) + 2;
var pos2 = html.IndexOf('"', pos1);
if (pos2 <= 0) return "";
return html.Substring(pos1, pos2 - pos1);
async Task<string> DownloadQuoteFromYahooAsync(string symbol, DateTime startDate, DateTime endDate, string interval, string crumb = "")
var period1 = (int)(startDate.Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
var period2 = (int)(endDate.Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
var url = $"https://query1.finance.yahoo.com/v7/finance/download/{symbol}?period1={period1}&period2={period2}&interval={interval}&events=history";
url += "&crumb=" + crumb;
HttpClient httpClient = newConfiguredHttpClient();
var response = await httpClient.GetAsync(url);
Console.WriteLine($"status = {response.StatusCode}");
return await response.Content.ReadAsStringAsync();
internal record QuoteRequest(string symbol, DateTime from, DateTime to, string interval);