diff --git a/.gitignore b/.gitignore index dc44ceb..8c3c50d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ MarketData/MarketData/*.log MarketData/MarketData/marketdata.log MarketData/MarketData/logs/marketdata_echo.log MarketData/MarketData/logs/marketdata_loadheadlineswatchlist.log +MarketDataUnitTests/bin/** +MarketDataUnitTests/obj/** Translate/Translate/bin/** Translate/Translate/obj/** eNavigator/eNavigatorUI/.vscode/chrome-debug/** diff --git a/.vscode/launch.json b/.vscode/launch.json index e22a232..58d7ac6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -39,6 +39,28 @@ "console": "internalConsole", "stopAtEntry": false }, - + { + "name": ".NET Core Launch (unit tests)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "/usr/local/bin/dotnet", + "args": ["test"], + "cwd": "${workspaceFolder}/MarketDataUnitTests", + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Launch (debug unit tests)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/MarketDataUnitTests/bin/Debug/net8.0/MarketDataUnitTests.dll", + "args": [], + "cwd": "${workspaceFolder}", + "console": "internalConsole", + "stopAtEntry": false, + "internalConsoleOptions": "openOnSessionStart" + } ] -} \ No newline at end of file +} diff --git a/MarketData.sln b/MarketData.sln index 1e1de7d..c538451 100755 --- a/MarketData.sln +++ b/MarketData.sln @@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarketDataServer", "MarketD EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPMonitor", "IPMonitor\IPMonitor.csproj", "{EAC3FB58-9112-4446-98BF-DC33F96357B5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MarketDataUnitTests", "MarketDataUnitTests\MarketDataUnitTests.csproj", "{EAC3FB58-9112-4446-98BF-DC33F96357B5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/MarketData/MarketDataLib/Helper/MarketDataHelper.cs b/MarketData/MarketDataLib/Helper/MarketDataHelper.cs index c2cbb6c..4efd833 100755 --- a/MarketData/MarketDataLib/Helper/MarketDataHelper.cs +++ b/MarketData/MarketDataLib/Helper/MarketDataHelper.cs @@ -333,9 +333,9 @@ namespace MarketData.Helper if(null!=httpNetResponse)httpNetResponse.Dispose(); } } -// *************************************************************************************************************************************************************************************** -// ************************************************************************** S P L I T S F R O M E O D D A T A ********************************************************************** -// *************************************************************************************************************************************************************************************** + // *************************************************************************************************************************************************************************************** + // ************************************************************************** S P L I T S F R O M E O D D A T A ********************************************************************** + // *************************************************************************************************************************************************************************************** public static Splits GetSplits() { HttpNetResponse httpNetResponse = null; @@ -386,7 +386,7 @@ namespace MarketData.Helper if (null != httpNetResponse) httpNetResponse.Dispose(); } } - + // *************************************************************************************************************************************************************************************** // ************************************************************************** G D P P E R C A P I T A D A T A W O R L D B A N K ************************************************* // *************************************************************************************************************************************************************************************** @@ -1916,7 +1916,7 @@ namespace MarketData.Helper WebProxy webProxy=HttpNetRequest.GetProxy("GetConsumerPriceIndices"); strRequest=sb.ToString(); MDTrace.WriteLine(LogLevel.DEBUG, String.Format("GetConsumerPriceIndices: {0}", strRequest)); - httpNetResponse=HttpNetRequest.GetRequestNoEncodingV5C(strRequest,"www.bls.gov",300000,webProxy); + httpNetResponse=HttpNetRequest.GetRequestNoEncodingV5C(strRequest,"www.bls.gov", 300000,webProxy); if(!httpNetResponse.Success) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("GetConsumerPriceIndices Request:{0} failed with status {1}",httpNetResponse.Request,httpNetResponse.StatusCode)); diff --git a/MarketData/MarketDataLib/Utility/FeedParser.cs b/MarketData/MarketDataLib/Utility/FeedParser.cs index b2e06e6..3786722 100755 --- a/MarketData/MarketDataLib/Utility/FeedParser.cs +++ b/MarketData/MarketDataLib/Utility/FeedParser.cs @@ -141,6 +141,7 @@ namespace MarketData.Utils return 0; } } + //"Aug 23, 2013" public static DateTime ParseValueDateTimeMonthFormat(String strText) { @@ -158,6 +159,7 @@ namespace MarketData.Utils return DateTime.Parse("01-01-0001"); } } + // "Apr. 04" // "1:00pm" public static DateTime ParseValueDateTimeMonth(String strText) @@ -195,7 +197,6 @@ namespace MarketData.Utils } } - // Sep. 25, 2022 at 4:31 p.m. ET public static DateTime ParseValueDateTimeMonthFormatTZ(String strText) { @@ -249,6 +250,7 @@ namespace MarketData.Utils return null; } } + public static double ParseValue(String strText) { double value = double.NaN; diff --git a/MarketDataUnitTests/MarketDataUnitTestClass.cs b/MarketDataUnitTests/MarketDataUnitTestClass.cs new file mode 100644 index 0000000..5b54bec --- /dev/null +++ b/MarketDataUnitTests/MarketDataUnitTestClass.cs @@ -0,0 +1,562 @@ +using System.Reflection; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.Extensions.Configuration; +using MarketData.DataAccess; +using MarketData.Generator.CMMomentum; +using MarketData.Helper; +using MarketData.MarketDataModel; +using MarketData.Utils; +using MarketData; +using MarketData.Configuration; +using System.Diagnostics; +using System.Net.Http.Headers; + + +// https://www.google.com/search?q=launch.json+for+debugging+c%23+unit+test&client=firefox-b-1-d&sca_esv=f0447ad3867c1f39&ei=OMQHaYOlB9GFwbkPgJbUiAs&ved=0ahUKEwiDocWOrNSQAxXRQjABHQALFbEQ4dUDCBE&uact=5&oq=launch.json+for+debugging+c%23+unit+test&gs_lp=Egxnd3Mtd2l6LXNlcnAiJmxhdW5jaC5qc29uIGZvciBkZWJ1Z2dpbmcgYyMgdW5pdCB0ZXN0MgUQABjvBTIIEAAYgAQYogQyCBAAGKIEGIkFMgUQABjvBUjvFFDdCFjtDXABeAGQAQCYAX6gAdICqgEDMC4zuAEDyAEA-AEBmAIEoALkAsICChAAGLADGNYEGEfCAgoQIRigARjDBBgKwgIIECEYoAEYwwSYAwCIBgGQBgiSBwMxLjOgB_AHsgcDMC4zuAffAsIHBTAuMi4yyAcJ&sclient=gws-wiz-serp + +namespace MarketDataUnitTests; + +[TestClass] +public class MarketDataUnitTestClass +{ + private IConfigurationBuilder builder; + private IConfiguration configuration; + + public MarketDataUnitTestClass() + { + builder = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + IConfigurationRoot configurationRoot = builder.Build(); + configuration = configurationRoot; + GlobalConfig.Instance.Configuration = configuration; + CreateLogging("unittest"); + } + + private static bool CreateLogging(String task) + { + if (String.IsNullOrEmpty(task)) return false; + task = task.ToLower(); + MDTrace.LogLevel = LogLevel.DEBUG; + String logFolder = "/logs"; + DateTime currentDate = DateTime.Now; + String strLogFile = "marketdata_" + task + ".log"; + String currentWorkingDirectory = Directory.GetCurrentDirectory(); + Console.WriteLine($"Current directory is {currentWorkingDirectory}"); + Utility.EnsureLogFolder(currentWorkingDirectory + logFolder); + Utility.ExpireLogs(currentWorkingDirectory + logFolder, 1); + Trace.Listeners.Remove("Default"); + Console.WriteLine($"Adding Trace Listener :{currentWorkingDirectory + logFolder + "/" + strLogFile}"); + Trace.Listeners.Add(new TextWriterTraceListener(currentWorkingDirectory + logFolder + "/" + strLogFile)); + MDTrace.WriteLine($"Trace Listener added."); + Utility.ShowLogs(currentWorkingDirectory + logFolder); + return true; + } + + + // public static Price GetLatestPriceBarChart(string symbol); + // public static Price GetLatestPriceGoogle(string symbol); + // public static Price GetLatestPriceRobinhood(string symbol); + + [TestMethod] + public void GetDailyPricesYahooRetrieval() + { + String symbol = "MIDD"; + DateTime analysisDate = DateTime.Now; + DateGenerator dateGenerator = new DateGenerator(); + analysisDate = dateGenerator.FindPrevBusinessDay(analysisDate); + Prices prices = MarketDataHelper.GetDailyPrices(symbol, analysisDate, analysisDate); + Assert.IsTrue(null != prices && prices.Count > 0, "No Price"); + } + + [TestMethod] + public void LatestPriceRetrieval() + { + String symbol = "AAPL"; + Price price = MarketDataHelper.GetLatestPrice(symbol); + + Assert.IsTrue(null != price && price.IsValid); + } + + [TestMethod] + public void LatestPriceGoogleRetrieval() + { + String symbol = "AAPL"; + Price price = MarketDataHelper.GetLatestPriceGoogle(symbol); + + Assert.IsTrue(null != price && price.IsValid); + } + + // The GetLatestPriceYahoo feed may return a price that only contains the previous close. + // This can happen after market hours and does not mean that the feed is broken. + [TestMethod] + public void LatestPriceYahooRetrieval() + { + String symbol = "AAPL"; + Price price = MarketDataHelper.GetLatestPriceYahoo(symbol); + + Assert.IsTrue(null != price, "No Price from Yahoo"); + Assert.IsTrue(price.IsValid || !double.IsNaN(price.PrevClose), "The feed is not working."); + } + + [TestMethod] + public void LatestPriceBarChartRetrieval() + { + String symbol = "AAPL"; + Price price = MarketDataHelper.GetLatestPriceBarChart(symbol); + + Assert.IsTrue(null != price, "No Price from BarChart"); + Assert.IsTrue(price.IsValid || !double.IsNaN(price.PrevClose), "The feed is not working."); + } + + [TestMethod] + public void LatestPriceRobinhoodRetrieval() + { + String symbol = "AAPL"; + Price price = MarketDataHelper.GetLatestPriceRobinhood(symbol); + + Assert.IsTrue(null != price, "No Price from Robinhood"); + Assert.IsTrue(price.IsValid || !double.IsNaN(price.PrevClose), "The feed is not working."); + } + + [TestMethod] + public void DailyPricesYahoo() + { + String symbol = "AAPL"; + DateGenerator dateGenerator = new DateGenerator(); + DateTime lastBusinessDate = DateTime.Now; + + lastBusinessDate = dateGenerator.GetPrevBusinessDay(lastBusinessDate); + + DateTime startDate = lastBusinessDate; + DateTime endDate = startDate; + + Prices prices = MarketDataHelper.GetDailyPrices(symbol, startDate, endDate); + Assert.IsTrue(null != prices, "No Price from DailyPricesYahoo"); + } + + [TestMethod] + public void CNNPredictionTest() + { + String cnnHostName = "10.0.0.240"; + CMCandidate cmCandidate = new CMCandidate(); + CMParams cmParams = new CMParams(); + + cmParams.UseCNN = true; + cmParams.UseCNNHost = "http://" + cnnHostName + ":5000"; + cmParams.UseCNNDayCount = 270; + cmParams.UseCNNRewardPercentDecimal = 0.25; + + cmCandidate.Symbol = "MIDD"; + cmCandidate.TradeDate = DateTime.Parse("07-01-2024"); + + bool result = CMMomentumGenerator.PredictCandidate(cmCandidate, cmParams); + + Assert.IsTrue(result); + } + + [TestMethod] + public void PremarketRetrieval() + { + PremarketElements premarketElements = MarketDataHelper.GetPremarketData(); + Assert.IsTrue(null != premarketElements && premarketElements.Count > 0); + } + + [TestMethod] + public void ETFHoldingsYahooRetrieval() + { + String[] etfSymbols = { "JFNNX", "ACWX", "ACES", "BBH" }; + List results = new List(); + + foreach (String etfSymbol in etfSymbols) + { + ETFHoldings etfHoldings = MarketDataHelper.GetETFHoldings(etfSymbol); + if (null != etfHoldings && 0 != etfHoldings.Count) + { + results.Add(MarketDataHelper.GetETFHoldings(etfSymbol)); + } + try { Thread.Sleep(500); } catch (Exception) {; } + } + + bool result = results.Any(x => x != null); + + Assert.IsTrue(result, String.Format("{0} items failed.", etfSymbols.Length)); + } + + [TestMethod] + public void ConsumerPriceIndexBureauOfLaborStatisticsRetrieval() + { + PriceIndices priceIndices = MarketDataHelper.GetConsumerPriceIndices(); + Assert.IsTrue(null != priceIndices && priceIndices.Count > 0); + } + + // Yahoo Fundamental feed is very poor quality and lots of misses. It's a last resort. + [TestMethod] + public void FundamentalYahooRetrieval() + { + String symbol = "AAPL"; + Fundamental fundamental = MarketDataHelper.GetFundamental(symbol); + Assert.IsTrue(null != fundamental); + // Assert.IsTrue(!Utility.IsEpoch(fundamental.NextEarningsDate),"NextEarningsDate"); + // Assert.IsTrue(!double.IsNaN(fundamental.Beta),"Beta"); + Assert.IsTrue(!double.IsNaN(fundamental.Low52), "Low52"); + Assert.IsTrue(!double.IsNaN(fundamental.High52), "High52"); + Assert.IsTrue(!double.IsNaN(fundamental.Volume), "Volume"); + // Assert.IsTrue(!double.IsNaN(fundamental.MarketCap),"MarketCap"); + Assert.IsTrue(!double.IsNaN(fundamental.PE), "PE"); + Assert.IsTrue(!double.IsNaN(fundamental.EPS), "EPS"); + Assert.IsTrue(!double.IsNaN(fundamental.PEG), "PEG"); + Assert.IsTrue(!double.IsNaN(fundamental.ReturnOnAssets), "ReturnOnAssets"); + Assert.IsTrue(!double.IsNaN(fundamental.ReturnOnEquity), "ReturnOnEquity"); + Assert.IsTrue(!double.IsNaN(fundamental.TotalCash), "TotalCash"); + Assert.IsTrue(!double.IsNaN(fundamental.TotalDebt), "TotalDebt"); + Assert.IsTrue(!double.IsNaN(fundamental.SharesOutstanding), "SharesOutstanding"); + Assert.IsTrue(!double.IsNaN(fundamental.Revenue), "Revenue"); + Assert.IsTrue(!double.IsNaN(fundamental.RevenuePerShare), "RevenuePerShare"); + Assert.IsTrue(!double.IsNaN(fundamental.QtrlyRevenueGrowth), "QtrlyRevenueGrowth"); + // Assert.IsTrue(!double.IsNaN(fundamental.GrossProfit),"GrossProfit"); + Assert.IsTrue(!double.IsNaN(fundamental.EBITDA), "EBITDA"); + Assert.IsTrue(!double.IsNaN(fundamental.NetIncomeAvailableToCommon), "NetIncomeAvailableToCommon"); + Assert.IsTrue(!double.IsNaN(fundamental.BookValuePerShare), "BookValuePerShare"); + Assert.IsTrue(!double.IsNaN(fundamental.OperatingCashflow), "OperatingCashflow"); + Assert.IsTrue(!double.IsNaN(fundamental.LeveragedFreeCashflow), "LeveragedFreeCashflow"); + Assert.IsTrue(!double.IsNaN(fundamental.Equity), "Equity"); + Assert.IsTrue(!double.IsNaN(fundamental.TrailingPE), "TrailingPE"); + Assert.IsTrue(!double.IsNaN(fundamental.EnterpriseValue), "EnterpriseValue"); + Assert.IsTrue(!double.IsNaN(fundamental.EBIT), "EBIT"); + Assert.IsTrue(!double.IsNaN(fundamental.DebtToEquity), "DebtToEquity"); + } + + [TestMethod] + public void DividendHistoryRetrieval() + { + Dictionary items = new Dictionary(); + String dividendSymbol1 = "AAPL"; + String dividendSymbol2 = "ZIM"; + String dividendSymbol3 = "IVR"; + + DividendHistory dividendHistory1 = MarketDataHelper.GetDividendHistory(dividendSymbol1); + DividendHistory dividendHistory2 = MarketDataHelper.GetDividendHistory(dividendSymbol2); + DividendHistory dividendHistory3 = MarketDataHelper.GetDividendHistory(dividendSymbol3); + Assert.IsTrue((null != dividendHistory1 && dividendHistory1.Count > 0) || + (null != dividendHistory2 && dividendHistory2.Count > 0) || + (null != dividendHistory3 && dividendHistory3.Count > 0)); + } + + [TestMethod] + public void EarningsAnnouncementsaRetrieval() + { + String symbol = "MIDD"; + EarningsAnnouncements earningsAnnouncements = MarketDataHelper.GetEarningsAnnouncements(symbol); + Assert.IsTrue(null != earningsAnnouncements && earningsAnnouncements.Count > 0); + } + + [TestMethod] + public void ZacksRankRetrieval() + { + String symbol = "MIDD"; + ZacksRank zacksRank = MarketDataHelper.GetZacksRank(symbol); + Assert.IsTrue(null != zacksRank && null != zacksRank.Rank); + } + + [TestMethod] + public void GetSplitsRetrieval() + { + Splits splits = MarketDataHelper.GetSplits(); + Assert.IsTrue(null != splits && splits.Count > 0); + } + + [TestMethod] + public void GDPPerCapitaRetrieval() + { + EconomicIndicators economicIndicators = MarketDataHelper.GetGDPPerCapita(); + Assert.IsTrue(null != economicIndicators && economicIndicators.Count > 0); + } + + [TestMethod] + public void LatestAnalystRatingsRetrieval() + { + AnalystRatings analystRatings = MarketDataHelper.GetLatestAnalystRatings(); + Assert.IsTrue(null != analystRatings && analystRatings.Count > 0); + } + + /// + /// This is not working because the website has changed formats + /// + [TestMethod] + [Ignore] + public void AnalystRatingsMarketBeatRetrieval() + { + String symbol = "AAPL"; + AnalystRatings analystRatings = MarketDataHelper.GetAnalystRatingsMarketBeat(symbol); + Assert.IsTrue(null != analystRatings && analystRatings.Count > 0); + } + + [TestMethod] + public void SECCIKRetrieval() + { + String symbol = "AAPL"; + String strCik = MarketDataHelper.GetCIK(symbol); + Assert.IsTrue(null != strCik); + } + + [TestMethod] + public void SECFilingsRetrieval() + { + String symbol = "AAPL"; + String strCik = MarketDataHelper.GetCIK(symbol); + Assert.IsTrue(null != strCik); + SECFilings secFilings = MarketDataHelper.GetSECFilings(symbol, strCik, 1); + Assert.IsTrue(null != secFilings && secFilings.Count > 0); + } + + [TestMethod] + public void YieldCurveRetrieval() + { + DateGenerator dateGenerator = new DateGenerator(); + DateTime analysisDate = dateGenerator.FindPrevBusinessDay(DateTime.Now); + YieldCurve yieldCurve = MarketDataHelper.GetYieldCurve(analysisDate.Year); + Assert.IsTrue(null != yieldCurve && yieldCurve.Count > 0); + Assert.IsTrue(yieldCurve[yieldCurve.Count - 1].Date.Month.Equals(analysisDate.Month)); + } + + [TestMethod] + public void InsiderTransactionRetrieval() + { + DateTime now = DateTime.Now; + DateGenerator dateGenerator = new DateGenerator(); + InsiderTransactions insiderTransactions = InsiderTransactionDA.GetLatestInsiderTransactions(); + Assert.IsTrue(null != insiderTransactions && insiderTransactions.Count > 0); + InsiderTransaction insiderTransaction = insiderTransactions[0]; + int daysBetween = dateGenerator.DaysBetween(now, insiderTransaction.TransactionDate) + 1; + Assert.IsTrue(daysBetween < 10); + InsiderTransactions latestTransactions = MarketDataHelper.GetInsiderTransactions(insiderTransaction.Symbol, daysBetween); + Assert.IsTrue(null != latestTransactions && latestTransactions.Count > 0); + } + + [TestMethod] + public void CompanyProfileRetrieval() + { + String symbol = "MOD"; + CompanyProfile companyProfile = MarketDataHelper.GetCompanyProfile(symbol); + Assert.IsTrue(null != companyProfile); + } + + // Test all feeds + [TestMethod] + public void HeadlinesRetrieval() + { + String symbol = "AAPL"; + Headlines companyHeadlines = HeadlinesMarketDataHelper.GetHeadlinesEx(symbol); + Assert.IsTrue(null != companyHeadlines && companyHeadlines.Count > 0); + } + + // Test MarketWatch feed + // https://www.marketwatch.com/investing/stock/AAPL?mod=search_symbol + /// + /// MarketWatch/BigCharts is no longer working + /// + [TestMethod] + [Ignore] + public void HeadlinesMarketWatchRetrieval() + { + String symbol = "MIDD"; + Headlines companyHeadlines = MarketDataHelper.GetCompanyHeadlinesMarketWatch(symbol); + Assert.IsTrue(null != companyHeadlines && companyHeadlines.Count > 0); + } + + // Test NASDAQ Headlines feed + [TestMethod] + public void HeadlinesNASDAQRetrieval() + { + String symbol = "AAPL"; + Headlines companyHeadlines = MarketDataHelper.GetCompanyHeadlinesNASDAQ(symbol); + Assert.IsTrue(null != companyHeadlines && companyHeadlines.Count > 0); + } + + // Test SEEKING ALPHA Headlines feed + /// + /// SeekingAlpha headlines feed is not working + /// + [TestMethod] + [Ignore] + public void HeadlinesSeekingAlphaRetrieval() + { + String symbol = "GLD"; + Headlines companyHeadlines = MarketDataHelper.GetCompanyHeadlinesSeekingAlpha(symbol); + Assert.IsTrue(null != companyHeadlines && companyHeadlines.Count > 0); + } + + /// + /// SeekingAlpha feed is not working + /// + [TestMethod] + [Ignore] + public void HeadlinesSeekingAlphaV3Retrieval() + { + String symbol = "MIDD"; + Headlines companyHeadlines = MarketDataHelper.GetCompanyHeadlinesSeekingAlphaV3(symbol, true); + Assert.IsTrue(null != companyHeadlines && companyHeadlines.Count > 0); + } + + [TestMethod] + public void AnalystPriceTargetMarketBeatRetrieval() + { + String symbol = "MGPI"; + AnalystPriceTarget analystPriceTarget = MarketDataHelper.GetAnalystPriceTargetMarketBeat(symbol); + Assert.IsTrue(null != analystPriceTarget); + Assert.IsTrue(!Double.IsNaN(analystPriceTarget.HighTargetPrice)); + Assert.IsTrue(!Double.IsNaN(analystPriceTarget.LowTargetPrice)); + Assert.IsTrue(!Double.IsNaN(analystPriceTarget.MeanTargetPrice)); + Assert.IsTrue(!Double.IsNaN(analystPriceTarget.MedianTargetPrice)); + } + + /// + /// Need to figure out why this is not working + /// + [TestMethod] + public void HistoricalRetrieval() + { + String symbol = "AAPL"; + Dictionary timeSeries = MarketDataHelper.GetHistoricalValues(symbol); + Assert.IsTrue(null != timeSeries); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.ROA), "Missing ROA"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.ROIC), "Missing ROIC"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.BVPS), "Missing BVPS"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.Inventory), "Missing Inventory"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.AccountsReceivable), "Missing AccountsReceivable"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.COGS), "Missing COGS"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.OperatingIncome), "Missing OperatingIncome"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.InterestExpense), "Missing InterestExpense"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.TaxRate), "Missing TaxRate"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.Revenue), "Missing Revenue"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.NetIncomeAvailableToCommonShareholders), "Missing NetIncomeAvailableToCommonShareholders"); + Assert.IsTrue(timeSeries.ContainsKey(TimeSeriesElement.ElementType.OperatingCashflow), "Missing OperatingCashflow"); + } + + [TestMethod] + public void IncomeStatementNASDAQRetrieval() + { + String symbol = "MIDD"; + List incomeStatements = MarketDataHelper.GetIncomeStatementNASDAQ(symbol, IncomeStatement.PeriodType.Annual); + Assert.IsTrue(null != incomeStatements && incomeStatements.Count > 0); + } + + [TestMethod] + public void IncomeStatementFinVizRetrieval() + { + String symbol = "MIDD"; + List incomeStatements = MarketDataHelper.GetIncomeStatementFinViz(symbol, IncomeStatement.PeriodType.Annual); + Assert.IsTrue(null != incomeStatements && incomeStatements.Count > 0); + } + + [TestMethod] + public void BalanceSheetNASDAQRetrieval() + { + String symbol = "MIDD"; + List balanceSheets = MarketDataHelper.GetBalanceSheetNASDAQ(symbol, BalanceSheet.PeriodType.Annual); + Assert.IsTrue(null != balanceSheets && balanceSheets.Count > 0); + BalanceSheet balanceSheet = balanceSheets[0]; + Assert.IsTrue(!double.IsNaN(balanceSheet.CashAndCashEquivalents), "CashAndCashEquivalents"); + Assert.IsTrue(!double.IsNaN(balanceSheet.DeferredLongTermLiabilities), "DeferredLongTermLiabilities"); + Assert.IsTrue(!double.IsNaN(balanceSheet.IntangibleAssets), "IntangibleAssets"); + Assert.IsTrue(!double.IsNaN(balanceSheet.Inventory), "Inventory"); + Assert.IsTrue(!double.IsNaN(balanceSheet.LongTermDebt), "LongTermDebt"); + Assert.IsTrue(!double.IsNaN(balanceSheet.NetCurrentAssetValue), "NetCurrentAssetValue"); + Assert.IsTrue(!double.IsNaN(balanceSheet.NetFixedAssets), "NetFixedAssets"); + Assert.IsTrue(!double.IsNaN(balanceSheet.OtherLiabilities), "OtherLiabilities"); + Assert.IsTrue(!double.IsNaN(balanceSheet.PropertyPlantAndEquipment), "PropertyPlantAndEquipment"); + Assert.IsTrue(!double.IsNaN(balanceSheet.TotalAssets), "TotalAssets"); + Assert.IsTrue(!double.IsNaN(balanceSheet.TotalCurrentAssets), "TotalCurrentAssets"); + Assert.IsTrue(!double.IsNaN(balanceSheet.TotalCurrentLiabilities), "TotalCurrentLiabilities"); + Assert.IsTrue(!double.IsNaN(balanceSheet.TotalLiabilities), "TotalLiabilities"); + } + + /// + /// Need to figure out why this is not working. + /// + [TestMethod] + public void CashflowStatementMorningStarRetrieval() + { + String[] symbols = { "AZEK", "CPRT", "DOCU", "ESTC", "HLNE" }; + + Dictionary> cashflowStatementsDict = new Dictionary>(); + + foreach (String symbol in symbols) + { + List cashflowStatements = MarketDataHelper.GetCashflowStatement(symbol, CashflowStatement.PeriodType.Annual); + if (null == cashflowStatements) continue; + cashflowStatementsDict.Add(symbol, cashflowStatements); + } + + Assert.IsTrue(cashflowStatementsDict.Count != 0, "Error retrieving cashflow statements."); + + List keys = cashflowStatementsDict.Keys.ToList(); + + foreach (String key in keys) + { + List cashflowStatements = cashflowStatementsDict[key]; + CashflowStatement cashflowStatement = cashflowStatements[0]; + Assert.IsTrue(!double.IsNaN(cashflowStatement.DepreciationAndAmortization), $"DepreciationAndAmortization for {key}"); + Assert.IsTrue(!double.IsNaN(cashflowStatement.DeferredIncomeTaxes), $"DeferredIncomeTaxes for {key}"); + Assert.IsTrue(!double.IsNaN(cashflowStatement.StockBasedCompensation), $"StockBasedCompensation for {key}"); + Assert.IsTrue(!double.IsNaN(cashflowStatement.AccountsReceivable), $"AccountsReceivable for {key}"); + Assert.IsTrue(!double.IsNaN(cashflowStatement.Inventory), $"Inventory for {key}"); + Assert.IsTrue(!double.IsNaN(cashflowStatement.AccountsPayable), $"AccountsPayable for {key}"); + Assert.IsTrue(!double.IsNaN(cashflowStatement.AccruedLiabilities), $"AccruedLiabilities for {key}"); + Assert.IsTrue(!double.IsNaN(cashflowStatement.OperatingCashflow), $"OperatingCashflow for {key}"); + Assert.IsTrue(!double.IsNaN(cashflowStatement.FreeCashflow), $"FreeCashflow for {key}"); + } + } + + + [TestMethod] + public void CurrencyConversionXERetrieval() + { + DateGenerator dateGenerator = new DateGenerator(); + String sourceCurrency = "USD"; + DateTime analysisDate = DateTime.Now; + analysisDate = dateGenerator.FindPrevBusinessDay(analysisDate); + CurrencyConversionCollection currencyConversionCollection = MarketDataHelper.GetCurrencyConversion(sourceCurrency, analysisDate); + Assert.IsTrue(null != currencyConversionCollection && currencyConversionCollection.Count > 0); + } + + /// + /// Need to figure out why we are missing EBITDA, OperatingCashflow, LeveragedFreeCashflow + /// + [TestMethod] + public void FundamentalFinVizRetrieval() + { + String symbol = "MIDD"; + Fundamental fundamental = MarketDataHelper.GetFundamentalFinViz(symbol); + Assert.IsTrue(null != fundamental); + Assert.IsTrue(!Utility.IsEpoch(fundamental.NextEarningsDate), "NextEarningsDate"); + Assert.IsTrue(!double.IsNaN(fundamental.Beta), "Beta"); + Assert.IsTrue(!double.IsNaN(fundamental.Low52), "Low52"); + Assert.IsTrue(!double.IsNaN(fundamental.High52), "High52"); + Assert.IsTrue(!double.IsNaN(fundamental.Volume), "Volume"); + Assert.IsTrue(!double.IsNaN(fundamental.MarketCap), "MarketCap"); + Assert.IsTrue(!double.IsNaN(fundamental.PE), "PE"); + Assert.IsTrue(!double.IsNaN(fundamental.EPS), "EPS"); + Assert.IsTrue(!double.IsNaN(fundamental.PEG), "PEG"); + Assert.IsTrue(!double.IsNaN(fundamental.ReturnOnAssets), "ReturnOnAssets"); + Assert.IsTrue(!double.IsNaN(fundamental.ReturnOnEquity), "ReturnOnEquity"); + Assert.IsTrue(!double.IsNaN(fundamental.TotalCash), "TotalCash"); + Assert.IsTrue(!double.IsNaN(fundamental.TotalDebt), "TotalDebt"); + Assert.IsTrue(!double.IsNaN(fundamental.SharesOutstanding), "SharesOutstanding"); + Assert.IsTrue(!double.IsNaN(fundamental.Revenue), "Revenue"); + Assert.IsTrue(!double.IsNaN(fundamental.RevenuePerShare), "RevenuePerShare"); + Assert.IsTrue(!double.IsNaN(fundamental.QtrlyRevenueGrowth), "QtrlyRevenueGrowth"); + Assert.IsTrue(!double.IsNaN(fundamental.GrossProfit), "GrossProfit"); +// Assert.IsTrue(!double.IsNaN(fundamental.EBITDA), "EBITDA"); + Assert.IsTrue(!double.IsNaN(fundamental.NetIncomeAvailableToCommon), "NetIncomeAvailableToCommon"); + Assert.IsTrue(!double.IsNaN(fundamental.BookValuePerShare), "BookValuePerShare"); +// Assert.IsTrue(!double.IsNaN(fundamental.OperatingCashflow), "OperatingCashflow"); +// Assert.IsTrue(!double.IsNaN(fundamental.LeveragedFreeCashflow), "LeveragedFreeCashflow"); + Assert.IsTrue(!double.IsNaN(fundamental.Equity), "Equity"); + Assert.IsTrue(!double.IsNaN(fundamental.TrailingPE), "TrailingPE"); + Assert.IsTrue(!double.IsNaN(fundamental.EnterpriseValue), "EnterpriseValue"); + Assert.IsTrue(!double.IsNaN(fundamental.EBIT), "EBIT"); + Assert.IsTrue(!double.IsNaN(fundamental.DebtToEquity), "DebtToEquity"); + } + + +} \ No newline at end of file diff --git a/MarketDataUnitTests/MarketDataUnitTests.csproj b/MarketDataUnitTests/MarketDataUnitTests.csproj new file mode 100644 index 0000000..951b1b3 --- /dev/null +++ b/MarketDataUnitTests/MarketDataUnitTests.csproj @@ -0,0 +1,37 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/MarketDataUnitTests/appsettings.json b/MarketDataUnitTests/appsettings.json new file mode 100755 index 0000000..2b6a7c1 --- /dev/null +++ b/MarketDataUnitTests/appsettings.json @@ -0,0 +1,17 @@ +{ +"market_data" : "Database=market_data;Datasource=adrastea;Username=guest;Password=guest", +"portfolio_data" : "Database=portfolio_data;Datasource=adrastea;Username=guest;Password=guest", +"user_data" : "Database=user_data;Datasource=adrastea;Username=guest;Password=guest", +"sms_smtpaddress" : "smtp.gmail.com", +"sms_smsusername" : "skessler1964@gmail.com", +"sms_smspassword" : "xjfo isnf gmyi zovr", +"sms_smsrecipients" : "skessler1964@gmail.com", +"proxy_address" : "http://euporie:8182", +"proxy_GetLatestPriceYahoo" : "false", +"proxy_GetLatestPriceBigCharts" : "false", +"proxy_GetETFHoldings" : "false", +"proxy_GetDailyPrices" : "false", +"proxy_GetFundamentalEx" : "false", +"proxy_GetDividendHistory" : "false", +"proxy_GetAnalystPriceTargetMarketBeat" : "false" +} diff --git a/README.md b/README.md index f22d672..68294ff 100644 --- a/README.md +++ b/README.md @@ -168,11 +168,11 @@ Notes: There is a c++ program that performs the file transfer between Isonoe and # Miscellaneous Notes -TO-DO -1) MariaDb online -2) MarketDataServer - dotnet add package Microsoft.AspNet.WebApi.SelfHost --version 5.3.0 - dotnet add package System.ServiceModel.Primitives --version 4.0.0 +To run unit tests we need to enable "Code Lens" so that the "Run Test" "Debug Test" options are visible and clickable in the source file. +So make sure to go to File->Preferences->Settings in VsCode and type "Editor: Code Lense" and sure it's checked. +If so you should see options to debug a single unit test right under the [TestMethod] annotation. +To run unit tests from the CLI go to the unit test project folder in Terminal and run dotnet clean, dotnet build, dotnet test + Git Delete Remote Branch git push --delete