/// <summary> /// Retrieves a price quote from Google™ Calculator. /// </summary> /// <param name="security">The security for which to get the quote.</param> /// <param name="currency">The currency in which to express the quote.</param> /// <returns>The requested price quote.</returns> public PriceQuote GetPriceQuote(Security security, Security currency) { if (security == null) { throw new ArgumentNullException(nameof(security)); } if (currency == null) { throw new ArgumentNullException(nameof(currency)); } if (currency.SecurityType != SecurityType.Currency) { throw new ArgumentException("The argument must be a Security with a SecurityType of Currency", nameof(currency)); } if (security.SecurityType != SecurityType.Currency) { throw BuildError(security.Symbol, "Only currencies are supported."); } var client = new WebClient(); string data; try { data = client.DownloadString(string.Format(UrlFormat, security.Symbol, currency.Symbol)); } catch (WebException ex) { throw BuildError(security.Symbol + currency.Symbol, "Check the inner exception for details.", ex); } DateTimeOffset date; decimal price; try { var result = Parse(data).Last(); date = result.Item1; price = result.Item2; } catch (InvalidOperationException ex) { throw BuildError(security.Symbol + currency.Symbol, "Check the inner exception for details.", ex); } checked { var quantity = (long)security.FractionTraded; price *= currency.FractionTraded; var longPrice = (long)Math.Floor(price); while (longPrice != price) { price *= 10; quantity *= 10; longPrice = (long)Math.Floor(price); } var gcd = FinancialMath.GCD(longPrice, quantity / security.FractionTraded); quantity /= gcd; longPrice /= gcd; return(new PriceQuote(Guid.NewGuid(), date.UtcDateTime, security, quantity, currency, longPrice, "Google™ Calculator")); } }
/// <summary> /// Retrieves a price quote from Yahoo!® Finance. /// </summary> /// <param name="security">The security for which to get the quote.</param> /// <param name="currency">The currency in which to express the quote.</param> /// <returns>The requested price quote.</returns> public PriceQuote GetPriceQuote(Security security, Security currency) { if (security == null) { throw new ArgumentNullException(nameof(security)); } if (currency == null) { throw new ArgumentNullException(nameof(currency)); } if (currency.SecurityType != SecurityType.Currency) { throw new ArgumentException("The argument must be a Security with a SecurityType of Currency", nameof(currency)); } if (security.SecurityType != SecurityType.Stock && security.SecurityType != SecurityType.Fund && security.SecurityType != SecurityType.Currency) { throw BuildError(security.Symbol, "Only stocks, funds, and currencies are supported."); } var symbol = security.Symbol; if (security.SecurityType == SecurityType.Currency) { symbol = symbol + currency.Symbol + "=X"; } var client = new WebClient(); string data; try { data = client.DownloadString(string.Format(UrlFormat, symbol)); } catch (WebException ex) { throw BuildError(symbol, "Check the inner exception for details.", ex); } var split = data.Split(','); if (split.Length != 4) { throw BuildError(symbol, "The data returned was not in a recognized format."); } var date = Unquote(split[1]); var time = Unquote(split[2]); var value = Unquote(split[3]); if (date == "N/A") { throw BuildError(symbol, "The symbol could not be found."); } if (!DateTime.TryParse(date, out var utcDate)) { throw BuildError(symbol, "The data returned was not in a recognized format."); } var yahooTimeZone = TimeZoneInfo.FindSystemTimeZoneById(YahooTimeZoneId); var minDate = TimeZoneInfo.ConvertTimeFromUtc(utcDate, yahooTimeZone); if (!DateTime.TryParse(minDate.ToShortDateString() + " " + time, out var dateTime)) { throw BuildError(symbol, "The data returned was not in a recognized format."); } if (dateTime < minDate) { dateTime.AddDays(1); } dateTime = TimeZoneInfo.ConvertTimeToUtc(dateTime, yahooTimeZone); if (!decimal.TryParse(value, out var price)) { throw BuildError(symbol, "The data returned was not in a recognized format."); } checked { var quantity = (long)security.FractionTraded; price *= currency.FractionTraded; var longPrice = (long)Math.Floor(price); while (longPrice != price) { price *= 10; quantity *= 10; longPrice = (long)Math.Floor(price); } var gcd = FinancialMath.GCD(longPrice, quantity / security.FractionTraded); quantity /= gcd; longPrice /= gcd; return(new PriceQuote(Guid.NewGuid(), dateTime, security, quantity, currency, longPrice, "Yahoo!® Finance")); } }