From efde941cf360a76fd1c02e6c495f99a644557012 Mon Sep 17 00:00:00 2001 From: Sean Date: Wed, 18 Mar 2026 13:08:36 -0400 Subject: [PATCH] Fix the Yahoo Fundamental feed. --- .../MarketDataLib/Helper/MarketDataHelper.cs | 91 ++++++++----------- .../MarketDataUnitTestClass.cs | 2 +- 2 files changed, 38 insertions(+), 55 deletions(-) diff --git a/MarketData/MarketDataLib/Helper/MarketDataHelper.cs b/MarketData/MarketDataLib/Helper/MarketDataHelper.cs index 4b831e6..8cbf223 100755 --- a/MarketData/MarketDataLib/Helper/MarketDataHelper.cs +++ b/MarketData/MarketDataLib/Helper/MarketDataHelper.cs @@ -4467,6 +4467,13 @@ namespace MarketData.Helper } return fundamental; } + + /// + /// GetFundamentalEx - Retrieve fundamental data from Yahoo + /// Yahoo continually changes the format of the page. Keep adapting new methodologies while retaining the previous in case they change back + /// + /// + /// private static Fundamental GetFundamentalEx(String symbol) { HttpNetResponse httpNetResponse=null; @@ -4498,19 +4505,35 @@ namespace MarketData.Helper fundamental.Symbol=symbol; fundamental.AsOf=DateTime.Now; fundamental.Source = "YAHOO"; + fundamental.Beta=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">Beta<")); - fundamental.NextEarningsDate=FeedParser.ParseValueDateTimeMonthFormat(Sections.LocateItemAcceptAnyText(httpNetResponse.ResponseString,">Earnings Date<")); - String strText=Sections.LocateFirstItem(httpNetResponse.ResponseString,">52 Week Range<"); + if(double.IsNaN(fundamental.Beta))fundamental.Beta=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">Beta (5Y Monthly) <")); + + fundamental.NextEarningsDate=FeedParser.ParseValueDateTimeMonthFormat(Sections.LocateItemAcceptAnyText(httpNetResponse.ResponseString,">Earnings Date (est.) <")); + if(Utility.IsEpoch(fundamental.NextEarningsDate))fundamental.NextEarningsDate=FeedParser.ParseValueDateTimeMonthFormat(Sections.LocateItemAcceptAnyText(httpNetResponse.ResponseString,">Earnings Date<")); + + String strText=Sections.LocateFirstItem(httpNetResponse.ResponseString,">52 Week Range <"); + if(null==strText)strText=strText=Sections.LocateFirstItem(httpNetResponse.ResponseString,">52 Week Range<"); + if(null!=strText) { String[] strArray = strText.Split('-'); fundamental.Low52 = FeedParser.ParseValue(strArray[0].Trim()); fundamental.High52 = FeedParser.ParseValue(strArray[1].Trim()); } - fundamental.Volume=FeedParser.ParseValueLong(Sections.LocateItem(httpNetResponse.ResponseString,">Volume<")); - fundamental.MarketCap=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">Market Cap<")); - fundamental.PE=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">PE Ratio (TTM)<")); - fundamental.EPS=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">EPS (TTM)<")); + + fundamental.Volume=FeedParser.ParseValueLong(Sections.LocateItem(httpNetResponse.ResponseString,">Volume <")); + if(0==fundamental.Volume)fundamental.Volume=FeedParser.ParseValueLong(Sections.LocateItem(httpNetResponse.ResponseString,">Volume<")); + + fundamental.MarketCap=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">Market Cap <")); + if(double.IsNaN(fundamental.MarketCap))fundamental.MarketCap=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">Market Cap<")); + + fundamental.PE=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">PE Ratio (TTM) <")); + if(double.IsNaN(fundamental.PE))fundamental.PE=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">PE Ratio (TTM)<")); + + fundamental.EPS=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">EPS (TTM) <")); + if(double.IsNaN(fundamental.EPS))fundamental.EPS=FeedParser.ParseValue(Sections.LocateItem(httpNetResponse.ResponseString,">EPS (TTM)<")); + try { Thread.Sleep(250);PopulateKeyStatistics(fundamental,webProxy); } catch (Exception exception) { @@ -4543,6 +4566,13 @@ namespace MarketData.Helper // ************************************************************************************************************************************************************************************* // ***************************************************************** K E Y S T A T I S T I C S - Y A H O O F I N A N C E ********************************************************** // ************************************************************************************************************************************************************************************* + /// + /// PopulateKeyStatistics - PopulateKeyStatistics from Yahoo. + /// Yahoo keeps changing the format of these pages so continue to adapt and retain previous functionality + /// + /// + /// + /// private static bool PopulateKeyStatistics(Fundamental fundamental,WebProxy webProxy=null) { HttpNetResponse httpNetResponse=null; @@ -4550,7 +4580,7 @@ namespace MarketData.Helper { StringBuilder sb = new StringBuilder(); String strRequest; - sb.Append("http://finance.yahoo.com/q/ks?s=").Append(fundamental.Symbol); + sb.Append("https://finance.yahoo.com/quote/").Append(fundamental.Symbol).Append("/key-statistics/"); strRequest = sb.ToString(); httpNetResponse=HttpNetRequest.GetRequestNoEncoding(strRequest,webProxy); if(!httpNetResponse.Success) @@ -5366,53 +5396,6 @@ namespace MarketData.Helper return price; } - // public static Prices GetDailyPrices(String symbol, DateTime startDate, DateTime endDate) - // { - // HttpNetResponse httpNetResponse=null; - // try - // { - // if(symbol==null)return null; - // CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(symbol); - // if(null!=companyProfile && companyProfile.FreezePricing) - // { - // MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Pricing for {0} is frozen.",symbol)); - // return null; - // } - // startDate=startDate.Date; - // endDate=endDate.Date; - // if(startDate>endDate) - // { - // DateTime tempDate=startDate; - // startDate=endDate; - // endDate=tempDate; - // } - - // MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[MarketDataHelper:GetDailyPrices]{0} start:{1} end:{2}",symbol,Utility.DateTimeToStringMMHDDHYYYY(startDate),Utility.DateTimeToStringMMHDDHYYYY(endDate))); - // StringBuilder sb = new StringBuilder(); - // String strRequest; - // Prices prices=null; - // sb.Append("https://query1.finance.yahoo.com/v7/finance/chart/").Append(symbol).Append("?period1=").Append(Utility.DateToUnixDate(startDate)).Append("&period2=").Append(Utility.DateToUnixDate(endDate)).Append("&interval=1d&events=history"); - // strRequest=sb.ToString(); - // MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Query:{0}",strRequest)); - // WebProxy webProxy=HttpNetRequest.GetProxy("GetDailyPrices"); - // CookieCollection cookieCollection=new CookieCollection(); - // httpNetResponse=HttpNetRequest.GetRequestNoEncodingV3B(strRequest,cookieCollection,webProxy); - // if(!httpNetResponse.Success) return null; - // JObject json=JObject.Parse(httpNetResponse.ResponseString); - // prices=GetPricesFromJSONString(json,symbol); - // return prices; - // } - // catch(Exception exception) - // { - // MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString())); - // return null; - // } - // finally - // { - // if(null!=httpNetResponse)httpNetResponse.Dispose(); - // } - // } - public static Prices GetDailyPrices(String symbol, DateTime startDate, DateTime endDate) { HttpNetResponse httpNetResponse=null; diff --git a/MarketDataUnitTests/MarketDataUnitTestClass.cs b/MarketDataUnitTests/MarketDataUnitTestClass.cs index eb86d8a..c4846cd 100644 --- a/MarketDataUnitTests/MarketDataUnitTestClass.cs +++ b/MarketDataUnitTests/MarketDataUnitTestClass.cs @@ -292,7 +292,7 @@ public class MarketDataUnitTestClass { String symbol = "AAPL"; Fundamental fundamental = MarketDataHelper.GetFundamental(symbol); - Assert.IsTrue(null != fundamental); + Assert.IsTrue(null != fundamental,"GetFundamental Failed."); // Assert.IsTrue(!Utility.IsEpoch(fundamental.NextEarningsDate),"NextEarningsDate"); // Assert.IsTrue(!double.IsNaN(fundamental.Beta),"Beta"); Assert.IsTrue(!double.IsNaN(fundamental.Low52), "Low52");