private static async Task <Stream> GetResponseStreamAsync(string symbol, DateTime?startTime, DateTime?endTime, Period period, string events, CancellationToken token) { bool reset = false; while (true) { try { var(client, crumb) = await YahooClientFactory.GetClientAndCrumbAsync(reset, token).ConfigureAwait(false); return(await _GetResponseStreamAsync(client, crumb, token).ConfigureAwait(false)); } catch (FlurlHttpException ex) when(ex.Call.Response?.StatusCode == (int)HttpStatusCode.NotFound) { throw new Exception($"Invalid ticker or endpoint for symbol '{symbol}'.", ex); } catch (FlurlHttpException ex) when(ex.Call.Response?.StatusCode == (int)HttpStatusCode.Unauthorized) { Debug.WriteLine("GetResponseStreamAsync: Unauthorized."); if (reset) { throw; } reset = true; // try again with a new client } } #region Local Functions Task <Stream> _GetResponseStreamAsync(IFlurlClient?_client, string?_crumb, CancellationToken _token) { // Yahoo expects dates to be "Eastern Standard Time" startTime = startTime?.FromEstToUtc() ?? new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); endTime = endTime? .FromEstToUtc() ?? DateTime.UtcNow; var url = "https://query1.finance.yahoo.com/v7/finance/download" .AppendPathSegment(symbol) .SetQueryParam("period1", startTime.Value.ToUnixTimestamp()) .SetQueryParam("period2", endTime.Value.ToUnixTimestamp()) .SetQueryParam("interval", $"1{period.Name()}") .SetQueryParam("events", events) .SetQueryParam("crumb", _crumb); Debug.WriteLine(url); return(url .WithClient(_client) .GetAsync(_token) .ReceiveStream()); } #endregion }
static async Task <Stream> GetResponseStreamAsync(string symbol, DateTime?startTime, DateTime?endTime, Period period, string events, CancellationToken token) { var(client, crumb) = await _GetClientAndCrumbAsync(); try { return(await _GetResponseStreamAsync(client, crumb).ConfigureAwait(false)); } catch (FlurlHttpException ex) when(ex.Call.Response?.StatusCode == HttpStatusCode.Unauthorized) { YahooClientFactory.Reset(); (client, crumb) = await _GetClientAndCrumbAsync().ConfigureAwait(false); return(await _GetResponseStreamAsync(client, crumb).ConfigureAwait(false)); } catch (FlurlHttpException ex) when(ex.Call.Response?.StatusCode == HttpStatusCode.NotFound) { throw new Exception("You may have used an invalid ticker, or the endpoint is invalidated", ex); } #region Local Functions async Task <(IFlurlClient, string)> _GetClientAndCrumbAsync() { var _client = await YahooClientFactory.GetClientAsync().ConfigureAwait(false); var _crumb = await YahooClientFactory.GetCrumbAsync().ConfigureAwait(false); return(_client, _crumb); } Task <Stream> _GetResponseStreamAsync(IFlurlClient _client, string _crumb) { var url = QueryUrl .AppendPathSegment(symbol) .SetQueryParam(Period1Tag, (startTime ?? new DateTime(1970, 1, 1)).ToUnixTimestamp()) .SetQueryParam(Period2Tag, (endTime ?? DateTime.Now).ToUnixTimestamp()) .SetQueryParam(IntervalTag, $"1{period.Name()}") .SetQueryParam(EventsTag, events) .SetQueryParam(CrumbTag, _crumb); //Debug.WriteLine(url); return(url .WithClient(_client) .GetAsync(token) .ReceiveStream()); } #endregion }