{"id":5099,"date":"2023-11-01T17:48:15","date_gmt":"2023-11-02T00:48:15","guid":{"rendered":"https:\/\/jeremywhittaker.com\/?p=5099"},"modified":"2023-11-16T14:48:46","modified_gmt":"2023-11-16T21:48:46","slug":"predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python","status":"publish","type":"post","link":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/","title":{"rendered":"Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python"},"content":{"rendered":"\n<p>I started off wanting to analyze the sustainability of mortgage buydowns by home builders. But as it happens, my ADHD had other plans. Three weeks later, here we are with code that looks for trends and anomalies in corporate financials. The code generates detailed HTML profiles for in-depth financial analysis of stocks. <\/p>\n\n\n\n<p> In a series of previous posts, I&#8217;ve explained the extraction of<a href=\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/using-python-to-save-corporate-financial-data-locally-from-eodhd\/\"> corporate financial data<\/a> and <a href=\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/10\/24\/using-python-to-save-open-high-low-close-adjusted-close-and-volume-data-locally-from-eodhd\/\">stock price data<\/a>. Now, let&#8217;s go a step further by utilizing <a href=\"https:\/\/plotly.com\/python\/\">Plotly <\/a>and <a href=\"https:\/\/facebook.github.io\/prophet\/\">Facebook&#8217;s Prophet library <\/a>to predict these financial metrics and stock prices. It&#8217;s crucial to note that the goal here isn&#8217;t to necessarily predict future values but to model the data in such a way that we can quickly spot any anomalies. In this tutorial, we&#8217;ll be extracting data from HDF5 files, which were created in previous posts, so make sure to check those out first.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Generated HTML Output: A Preview of What the Code Produces<\/h1>\n\n\n\n<p>The code generates an in-depth profile of any stock specified. In this example, we take a look at Google. The output is a structured HTML file that includes a variety of information sections. First, it provides basic details such as the company&#8217;s name, ticker symbol, and the date of the most recent update. Next, it lists essential contact information, including the company&#8217;s web URL, phone number, and physical address. The sector and industry in which the company operates, as well as the number of full-time employees, are also displayed. The output then delves into valuation metrics like P\/E ratios, enterprise value, and other financial ratios. Finally, it highlights key financial data points, such as market capitalization, EBITDA, and various earnings and revenue estimates. Overall, the code produces a multi-faceted profile that serves as a valuable resource for anyone looking to understand Alphabet Inc&#8217;s business and financial standing in great detail.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"460\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-1024x460.png\" alt=\"\" class=\"wp-image-5197 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-1024x460.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-300x135.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-768x345.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-1536x689.png 1536w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-500x224.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet.png 1700w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/460;\" \/><\/a><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">Forecasting Future Adjusted Close Prices with Facebook Prophet: A One-Year Outlook<\/h1>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-1.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"161\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-1-1024x161.png\" alt=\"\" class=\"wp-image-5108 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-1-1024x161.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-1-300x47.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-1-768x121.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-1-1536x242.png 1536w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-1-500x79.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-1.png 1785w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/161;\" \/><\/a><\/figure>\n\n\n\n<p>This plot visualizes the historical and predicted adjusted close prices for a particular asset, utilizing the Facebook Prophet algorithm for the forecast. The x-axis represents the timeline, extending from the earliest available historical data to one year into the future. The y-axis shows the adjusted close prices. Historical prices are plotted as solid purple lines. The predicted value is a solid green line with blue dotted lines as the high and low predictions. This predictive model leverages the power of Facebook Prophet to analyze seasonal and trend components in the historical data, providing a one-year outlook on potential price movements.<\/p>\n\n\n\n<p><strong>Forecasting Future Financial Ratios with Facebook Prophet: A One-Year Outlook<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pe_ratio.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"208\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pe_ratio-1024x208.png\" alt=\"\" class=\"wp-image-5199 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pe_ratio-1024x208.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pe_ratio-300x61.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pe_ratio-768x156.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pe_ratio-1536x312.png 1536w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pe_ratio-500x102.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pe_ratio.png 1595w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/208;\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pb_ratio.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"243\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pb_ratio-1024x243.png\" alt=\"\" class=\"wp-image-5201 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pb_ratio-1024x243.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pb_ratio-300x71.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pb_ratio-768x182.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pb_ratio-1536x364.png 1536w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pb_ratio-500x119.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_pb_ratio.png 1551w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/243;\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_roe.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"219\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_roe-1024x219.png\" alt=\"\" class=\"wp-image-5202 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_roe-1024x219.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_roe-300x64.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_roe-768x164.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_roe-500x107.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_roe.png 1524w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/219;\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_earnings_yield.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"197\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_earnings_yield-1024x197.png\" alt=\"\" class=\"wp-image-5203 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_earnings_yield-1024x197.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_earnings_yield-300x58.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_earnings_yield-768x147.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_earnings_yield-1536x295.png 1536w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_earnings_yield-500x96.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_earnings_yield.png 1542w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/197;\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_dividend_yield.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"186\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_dividend_yield-1024x186.png\" alt=\"\" class=\"wp-image-5204 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_dividend_yield-1024x186.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_dividend_yield-300x54.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_dividend_yield-768x139.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_dividend_yield-500x91.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_dividend_yield.png 1532w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/186;\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_current_ratio.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"188\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_current_ratio-1024x188.png\" alt=\"\" class=\"wp-image-5205 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_current_ratio-1024x188.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_current_ratio-300x55.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_current_ratio-768x141.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_current_ratio-1536x281.png 1536w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_current_ratio-500x92.png 500w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/goog_current_ratio.png 1540w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/188;\" \/><\/a><\/figure>\n\n\n\n<p>Financial ratios are key indicators of a company&#8217;s financial health and performance. They offer crucial insights into various aspects like profitability, liquidity, and valuation. In this section, we&#8217;ll leverage the predictive power of Facebook Prophet to forecast these ratios over the next year.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Forecasting Future Earnings and Profitability Metrics from the Income Statement with Facebook Prophet: A One-Year Outlook<\/h1>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-2.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"976\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-2-1024x976.png\" alt=\"\" class=\"wp-image-5109 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-2-1024x976.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-2-300x286.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-2-768x732.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-2-1536x1464.png 1536w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-2-315x300.png 315w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-2.png 1802w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/976;\" \/><\/a><\/figure>\n\n\n\n<p>These plots present a comprehensive visualization of key earnings and profitability metrics extracted from the income statement, including Net Income, Operating Income, Total Revenue, Gross Profit, and Free Cash Flow. The financial numbers are then forward projected using Facebook Prophet. These predictions not only display the expected trends for the next year but also encompass upper and lower bounds, providing a range of possible outcomes. This integration of historical data with advanced forecasting techniques offers a nuanced understanding of the company&#8217;s financial trajectory.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Forecasting Future Balance Sheet Metrics with Facebook Prophet: A One-Year Outlook<\/h1>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-3.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"988\" height=\"1024\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-3-988x1024.png\" alt=\"\" class=\"wp-image-5110 lazyload\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-3-988x1024.png 988w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-3-289x300.png 289w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-3-768x796.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-3-1482x1536.png 1482w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-3.png 1662w\" data-sizes=\"(max-width: 988px) 100vw, 988px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 988px; --smush-placeholder-aspect-ratio: 988\/1024;\" \/><\/a><\/figure>\n\n\n\n<p>These plots offer an in-depth analysis of crucial balance sheet metrics such as Total Assets, Total Stockholder Equity, Retained Earnings, Long-Term Debt, and Total Liabilities. Leveraging the predictive power of Facebook Prophet, these key financial indicators are forecasted into the future. The projections not only illustrate the expected financial posture for the forthcoming year but also include upper and lower prediction intervals, giving a full spectrum of potential financial scenarios. By melding past balance sheet data with sophisticated predictive modeling, the plots provide a multi-dimensional view of the company&#8217;s expected financial stability and risk profile.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Forecasting Future Cash Flow Metrics with Facebook Prophet: A One-Year Outlook<\/h1>\n\n\n\n<figure class=\"wp-block-image is-resized\"><a href=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-4.png\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"646\" data-src=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-4-1024x646.png\" alt=\"\" class=\"wp-image-5111 lazyload\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/646;aspect-ratio:1.585139318885449;width:614px;height:auto\" data-srcset=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-4-1024x646.png 1024w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-4-300x189.png 300w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-4-768x484.png 768w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-4-1536x969.png 1536w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-4-476x300.png 476w, https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/image-4.png 1646w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" \/><\/a><\/figure>\n\n\n\n<p>These plots dive into essential cash flow metrics, specifically Total Cash from Operating Activities, Capital Expenditures, and Dividends Paid. These key figures are also extended into the future using Facebook Prophet&#8217;s forecasting capabilities. The resulting predictions not only map out the anticipated cash flow movements for the next year but are also bracketed by upper and lower confidence intervals, presenting a comprehensive range of financial possibilities. These plots offer a well-rounded perspective on the company&#8217;s future liquidity and capital allocation strategies.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Other Financial Metrics<\/h1>\n\n\n\n<p>In addition to the key financial metrics, the analysis delves into a diverse set of other metrics, plotting each meticulously. These metrics are categorized as follows:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Efficiency and Activity Metrics from Income Statement:<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Research Development<\/li>\n\n\n\n<li>Selling General Administrative<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><br>Stockholder&#8217;s Equity and Capital Structure:<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Common Stock Shares Outstanding<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><br>Additional Important Metrics:<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Net Debt<\/li>\n\n\n\n<li>Net Receivables<\/li>\n\n\n\n<li>Inventory<\/li>\n\n\n\n<li>Accounts Payable<\/li>\n\n\n\n<li>Total Current Assets<\/li>\n\n\n\n<li>Total Current Liabilities<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Less Critical Metrics:<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Income Before Tax<\/li>\n\n\n\n<li>Cost of Revenue<\/li>\n\n\n\n<li>Intangible Assets<\/li>\n\n\n\n<li>Earning Assets<\/li>\n\n\n\n<li>Other Current Assets<\/li>\n\n\n\n<li>Deferred Long-Term Liabilities<\/li>\n\n\n\n<li>Other Current Liabilities<\/li>\n\n\n\n<li>Common Stock<\/li>\n\n\n\n<li>Capital Stock<\/li>\n\n\n\n<li>Other Liabilities<\/li>\n\n\n\n<li>Goodwill<\/li>\n\n\n\n<li>Other Assets<\/li>\n\n\n\n<li>Cash<\/li>\n\n\n\n<li>Cash and Equivalents<\/li>\n\n\n\n<li>Current Deferred Revenue<\/li>\n\n\n\n<li>Short-Term Debt<\/li>\n\n\n\n<li>Short\/Long-Term Debt<\/li>\n\n\n\n<li>Short\/Long-Term Debt Total<\/li>\n\n\n\n<li>Other Stockholder Equity<\/li>\n\n\n\n<li>Property Plant Equipment<\/li>\n\n\n\n<li>Long-Term Investments<\/li>\n\n\n\n<li>Net Tangible Assets<\/li>\n\n\n\n<li>Short-Term Investments<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Other Metrics:<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Effect of Accounting Charges<\/li>\n\n\n\n<li>Income Tax Expense<\/li>\n\n\n\n<li>Non-Operating Income Net Other<\/li>\n\n\n\n<li>Selling and Marketing Expenses<\/li>\n\n\n\n<li>Common Stock Total Equity<\/li>\n\n\n\n<li>Preferred Stock Total Equity<\/li>\n\n\n\n<li>Retained Earnings Total Equity<\/li>\n\n\n\n<li>Treasury Stock<\/li>\n\n\n\n<li>Accumulated Amortization<\/li>\n\n\n\n<li>Non-Current Assets Other<\/li>\n\n\n\n<li>Deferred Long-Term Asset Charges<\/li>\n\n\n\n<li>Non-Current Assets Total<\/li>\n\n\n\n<li>Capital Lease Obligations<\/li>\n\n\n\n<li>Long-Term Debt Total<\/li>\n\n\n\n<li>Non-Current Liabilities Other<\/li>\n\n\n\n<li>Non-Current Liabilities Total<\/li>\n\n\n\n<li>Negative Goodwill<\/li>\n\n\n\n<li>Warrants<\/li>\n\n\n\n<li>Preferred Stock Redeemable<\/li>\n\n\n\n<li>Capital Surpluse<\/li>\n\n\n\n<li>Liabilities And Stockholders Equity<\/li>\n\n\n\n<li>Cash And Short-Term Investments<\/li>\n\n\n\n<li>Property Plant And Equipment Gross<\/li>\n\n\n\n<li>Property Plant And Equipment Net<\/li>\n\n\n\n<li>Accumulated Depreciation<\/li>\n\n\n\n<li>Total Cash Flows From Investing Activities<\/li>\n\n\n\n<li>Total Cash From Financing Activities<\/li>\n\n\n\n<li>Net Borrowings<\/li>\n\n\n\n<li>Issuance Of Capital Stock<\/li>\n\n\n\n<li>Investments<\/li>\n\n\n\n<li>Change To Liabilities<\/li>\n\n\n\n<li>Change To Operating Activities<\/li>\n\n\n\n<li>Change In Cash<\/li>\n\n\n\n<li>Begin Period Cash Flow<\/li>\n\n\n\n<li>End Period Cash Flow<\/li>\n\n\n\n<li>Depreciation<\/li>\n\n\n\n<li>Other Cash Flows From Investing Activities<\/li>\n\n\n\n<li>Change To Inventory<\/li>\n\n\n\n<li>Change To Account Receivables<\/li>\n\n\n\n<li>Sale Purchase Of Stock<\/li>\n\n\n\n<li>Other Cash Flows From Financing Activities<\/li>\n\n\n\n<li>Change To Net Income<\/li>\n\n\n\n<li>Change Receivables<\/li>\n\n\n\n<li>Cash Flows Other Operating<\/li>\n\n\n\n<li>Exchange Rate Changes<\/li>\n\n\n\n<li>Cash And Cash Equivalents Changes<\/li>\n\n\n\n<li>Change In Working Capital<\/li>\n\n\n\n<li>Stock Based Compensation<\/li>\n\n\n\n<li>Other Non-Cash Items<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">Code Overview<\/h1>\n\n\n\n<h1 class=\"wp-block-heading\">Prerequisites<\/h1>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Python 3.x<\/li>\n\n\n\n<li>Pandas<\/li>\n\n\n\n<li>Plotly<\/li>\n\n\n\n<li>Prophet<\/li>\n\n\n\n<li>Logging<\/li>\n\n\n\n<li>Pathlib<\/li>\n\n\n\n<li>os<\/li>\n\n\n\n<li>Collections<\/li>\n\n\n\n<li>bs4 (BeautifulSoup)<\/li>\n\n\n\n<li>time<\/li>\n\n\n\n<li>scikit-learn<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">Helper Functions<\/h1>\n\n\n\n<p>The code includes several helper functions, such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>calculate_mae<\/code>: Calculates the Mean Absolute Error between the actual and predicted data.<\/li>\n\n\n\n<li><code>access_hdf5_with_retries<\/code>: Attempts to read an HDF5 file, retrying up to a specified number of times.<\/li>\n\n\n\n<li><code>read_general_info<\/code>: Reads general company information from an HDF5 file.<\/li>\n\n\n\n<li><code>infer_dtype<\/code>: Infers the data type of a Pandas Series.<\/li>\n\n\n\n<li><code>fetch_data_for_symbol_from_multiple_h5<\/code>: Fetches data for a specific symbol from multiple HDF5 files.<\/li>\n\n\n\n<li><code>get_company_name<\/code>: Gets the company name for a given symbol from an HDF5 file.<\/li>\n\n\n\n<li><code>add_content_before_plot<\/code>: Adds additional content before the plot in an HTML file.<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">Forecasting Function<\/h1>\n\n\n\n<p>The core of this code is the <code>forecast_with_multiple_metrics<\/code> function, which:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Accepts a DataFrame of financial metrics.<\/li>\n\n\n\n<li>Performs time-series forecasting on each metric using Facebook&#8217;s Prophet.<\/li>\n\n\n\n<li>Plots the actual and forecasted metrics using Plotly.<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>def forecast_with_multiple_metrics(df: pd.DataFrame, periods: int = 4, save_dir: str = \"plots\/\", use_all_data: bool = True, eod_price_data: str = 'eod_price_data.h5'):\n    ...\n<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">Code<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>import pandas as pd\nfrom pathlib import Path\nimport logging\nimport os\nfrom plotly.subplots import make_subplots\nfrom prophet import Prophet\nimport plotly.graph_objects as go\nfrom collections import Counter\nfrom pandas.api.types import is_numeric_dtype\nfrom bs4 import BeautifulSoup\nimport time\nfrom sklearn.metrics import mean_absolute_error\nfrom math import log10\n\n\nfrom dictionaries_and_lists import metric_definitions, reordered_columns, homebuilders, sp500, companies_with_treasuries, largest_banks, percentage_metrics\n\ndata_dir = '\/home\/shared\/algos\/data\/'\nplots_dir = '\/home\/shared\/algos\/eodhd_data\/plots\/'\n\nlogging.basicConfig(level=logging.DEBUG)\nlogging.basicConfig(level=logging.INFO)\n\n# Configure Pandas to display all columns\npd.set_option('display.max_columns', None)\npd.set_option('display.expand_frame_repr', False)\n\nsymbol_exchange_map = {}\n\n\ndef wrap_text(text, max_length):\n    \"\"\"\n    Wraps text to a new line at the nearest whitespace of the max_length.\n    \"\"\"\n    wrapped_lines = &#91;]\n    while len(text) &gt; max_length:\n        # Find nearest whitespace of the max_length\n        split_index = text.rfind(' ', 0, max_length + 1)\n        if split_index == -1:  # No whitespace found, force split\n            split_index = max_length\n        wrapped_lines.append(text&#91;:split_index])\n        text = text&#91;split_index:].lstrip()\n    wrapped_lines.append(text)\n    return '&lt;br&gt;'.join(wrapped_lines)\n\ndef format_large_number(num):\n    print('Attempting to plot large number')\n    if num &lt; 1_000:\n        return str(num)\n    magnitude = int(log10(num) \/\/ 3)\n    value = num \/ (10 ** (3 * magnitude))\n    return f\"{value:.2f}{' KMBT'&#91;magnitude]}\"\n\ndef format_percentage(data):\n    try:\n        # Remove any non-numeric characters like commas and percentage signs\n        if isinstance(data, str):\n            data = data.replace(',', '').replace('%', '').strip()\n        # Convert to float and format as a percentage\n        return \"{:.2%}\".format(float(data))\n    except ValueError as e:\n        print(f\"ValueError: Could not convert {data} to a percentage.\")\n        return data  # Return the original data if it cannot be converted\n\n\ndef calculate_mae(actual, predicted):\n    return mean_absolute_error(actual, predicted)\n\ndef access_hdf5_with_retries(hdf5_file_path, mode, max_retries=3, sleep_duration=5):\n    retries = 0\n    while retries &lt; max_retries:\n        try:\n            with pd.HDFStore(hdf5_file_path, mode) as store:\n                return store.keys()  # You can customize this part to return what you need\n            break  # If successful, exit the while loop\n        except Exception as e:  # Replace Exception with a more specific exception if possible\n            if retries &lt; max_retries - 1:\n                logging.info(f\"An exception occurred while reading {hdf5_file_path}: {e}\")\n                logging.info(f\"Retrying in {sleep_duration} seconds...\")\n                time.sleep(sleep_duration)\n                retries += 1\n            else:\n                logging.error(f\"Max retries reached. Could not read {hdf5_file_path}. Exiting...\")\n                raise\n\ndef read_general_info(symbol, h5_general_path, max_retries=3, sleep_duration=5):\n    retries = 0\n    while retries &lt; max_retries:\n        try:\n            with pd.HDFStore(h5_general_path, 'r') as store:\n                key = f'\/{symbol}'\n                if key in store.keys():\n                    general_info = store.get(key)\n                    info_dict = dict(zip(general_info&#91;'SubCategory'], general_info&#91;'Data']))\n                    sector = info_dict.get('Sector', 'N\/A')\n                    industry = info_dict.get('Industry', 'N\/A')\n                    description = info_dict.get('Description', 'N\/A')\n                    full_time_employees = info_dict.get('FullTimeEmployees', 'N\/A')\n                    updated_at = info_dict.get('UpdatedAt', 'N\/A')\n                    web_url = info_dict.get('WebURL', 'N\/A')\n                    phone = info_dict.get('Phone', 'N\/A')\n                    address = info_dict.get('Address', 'N\/A')\n                    name = info_dict.get('Name', 'N\/A')\n                    exchange = info_dict.get('Exchange', 'N\/A')\n                    return sector, industry, description, full_time_employees, updated_at, web_url, phone, address, name, exchange\n                else:\n                    return &#91;'N\/A']*10\n            break\n        except Exception as e:\n            if retries &lt; max_retries - 1:\n                print(f\"An exception occurred while reading {h5_general_path}: {e}\")\n                print(f\"Retrying in {sleep_duration} seconds...\")\n                time.sleep(sleep_duration)\n                retries += 1\n            else:\n                print(f\"Max retries reached. Could not read {h5_general_path}. Exiting...\")\n                raise\n\n\n\ndef infer_dtype(series):\n    sample = series.dropna().head(100)  # Sample the first 100 non-null rows\n\n    # Debugging line\n    print(f\"Sample for {series.name}: {sample}\")\n\n    if sample.empty:\n        return None\n\n    if all(sample.apply(lambda x: isinstance(x, str))):\n        return 'object'\n\n    if is_numeric_dtype(sample) and all(sample.apply(lambda x: x == int(x))):\n        return 'int64'\n\n    if is_numeric_dtype(sample):\n        return 'float64'\n    return None\n\n\ndef fetch_data_for_symbol_from_multiple_h5(h5_filepaths, symbol, max_retries=3, sleep_duration=5):\n    combined_data = None\n    common_keys = &#91;'Symbol', 'date', 'filing_date', 'currency_symbol']\n\n    for h5_filepath in h5_filepaths:\n        h5_path = Path(h5_filepath)\n        if not h5_path.exists():\n            logging.info(f\"The file {h5_filepath} does not exist.\")\n            continue\n\n        retries = 0\n        while retries &lt; max_retries:\n            try:\n                with pd.HDFStore(h5_filepath, 'r') as store:\n                    if f\"\/{symbol}\" in store.keys():\n                        logging.info(f\"Symbol {symbol} found in {h5_filepath}.\")\n                        symbol_data = store.select(symbol)\n\n                        if 'date' not in symbol_data.columns and 'Date' not in symbol_data.columns:\n                            if isinstance(symbol_data.index, pd.DatetimeIndex):\n                                symbol_data.reset_index(inplace=True)\n                                symbol_data.rename(columns={'index': 'date'}, inplace=True)\n                                logging.info(\n                                    f\"'date' and 'Date' columns not found, but datetime index exists in {h5_filepath} for symbol {symbol}.\")\n                                symbol_data = symbol_data.reset_index().rename(columns={'index': 'date'})\n                            else:\n                                logging.warning(\n                                    f\"'date' and 'Date' columns and datetime index not found in {h5_filepath} for symbol {symbol}.\")\n                                break\n                        else:\n                            # Ensure the date column is standardized to 'date'\n                            if 'Date' in symbol_data.columns:\n                                symbol_data.rename(columns={'Date': 'date'}, inplace=True)\n\n\n                        # Rename 'netIncome' if it's present in the dataframe\n                        if 'netIncome' in symbol_data.columns:\n                            # Extract the type of financial statement from the filename\n                            parts = h5_path.stem.split('_')\n                            statement_type = parts&#91;1]\n                            metric_name = parts&#91;2]\n\n                            statement_readable = {\n                                \"Cash\": \"Cash Flow from Operating Activities\",\n                                \"Income\": \"netIncome\",\n                            }.get(statement_type, statement_type)\n\n                            metric_title = f\"{metric_name} ({statement_readable})\"\n\n                            # Ensure statement_type is one of the reports where 'netIncome' appears before renaming\n                            if statement_type in &#91;\"Income\", \"Cash\"]:\n                                symbol_data.rename(columns={'netIncome': metric_title}, inplace=True)\n\n                        if combined_data is None:\n                            combined_data = symbol_data\n                        else:\n                            # Dynamically adjust common keys based on available columns\n                            keys_for_merge = &#91;key for key in common_keys if\n                                              key in symbol_data.columns and key in combined_data.columns]\n                            combined_data = pd.merge(combined_data, symbol_data, on=keys_for_merge, how='outer')\n                        break\n\n                    else:\n                        logging.info(f\"Symbol {symbol} not found in {h5_filepath}.\")\n                        break\n\n            except Exception as e:\n                if retries &lt; max_retries - 1:\n                    logging.info(f\"An exception occurred while reading {h5_filepath}: {e}\")\n                    logging.info(f\"Retrying in {sleep_duration} seconds...\")\n                    time.sleep(sleep_duration)\n                    retries += 1\n                else:\n                    logging.info(f\"Max retries reached. Could not read {h5_filepath}. Exiting...\")\n                    raise\n\n    if combined_data is None:\n        logging.info(f\"Symbol {symbol} not found in any of the HDF5 files.\")\n        return None\n    else:\n        for col in combined_data.select_dtypes(include=&#91;'object']).columns:\n            combined_data&#91;col] = pd.to_numeric(combined_data&#91;col], errors='ignore')\n\n        if 'date' in combined_data.columns:\n            combined_data.sort_values(by='date', inplace=True)\n        else:\n            logging.info(f\"'date' column not found in combined data for symbol {symbol}. Sorting by index instead.\")\n            combined_data.sort_index(inplace=True)\n        logging.info(f\"{symbol}: successfully combined all HDF5 files.\")\n        return combined_data\n\n\n\ndef get_company_name(symbol, h5_file_path, country_code='US'):\n    try:\n        # Read the DataFrame for the entire country from the HDF5 file\n        symbols_df = pd.read_hdf(h5_file_path, key=f'\/{country_code}')\n\n        # Filter by the specific symbol to get the company name\n        company_name_row = symbols_df&#91;symbols_df&#91;'Code'] == symbol]\n        if not company_name_row.empty:\n            return company_name_row&#91;'Name'].iloc&#91;0]\n        else:\n            logging.error(f\"No data for symbol {symbol} in the DataFrame.\")\n            return \"Unknown\"\n    except KeyError:\n        logging.error(f\"No object named {country_code} in the file {h5_file_path}\")\n        return \"Unknown\"\n\n\ndef add_content_before_plot(symbol, max_retries=3, sleep_duration=5):\n    target_filename = f\"{symbol}_quarterly.html\"\n    html_file_path = os.path.join(plots_dir, target_filename)\n\n    if not os.path.exists(html_file_path):\n        print(f\"HTML file for symbol {symbol} not found.\")\n        return\n\n    # Fetch additional info from General.h5\n    exchange = symbol_exchange_map.get(symbol, 'Other')  # Default to 'Other' if exchange is not found\n    h5_general_path = os.path.join(data_dir, f\"{exchange}_General.h5\")\n\n    sector, industry, description, full_time_employees, updated_at, web_url, phone, address, name, exchange = read_general_info(symbol, h5_general_path, max_retries, sleep_duration)\n\n    # Prepare new HTML content\n    new_html_content = f\"\"\"\n    &lt;h1&gt;{symbol} - {name} - {exchange}&lt;\/h1&gt;\n    &lt;p&gt;Updated At: {updated_at}&lt;\/p&gt;\n    &lt;p&gt;&lt;strong style='font-size: larger;'&gt;WebURL:&lt;\/strong&gt; &lt;a href='{web_url}' target='_blank'&gt;{web_url}&lt;\/a&gt;\n    &lt;strong style='font-size: larger;'&gt;Phone:&lt;\/strong&gt; {phone}\n    &lt;strong style='font-size: larger;'&gt;Address:&lt;\/strong&gt; {address}&lt;br&gt;\n    &lt;strong style='font-size: larger;'&gt;Sector:&lt;\/strong&gt; {sector}\n    &lt;strong style='font-size: larger;'&gt;Industry:&lt;\/strong&gt; {industry}&lt;br&gt;\n    &lt;strong style='font-size: larger;'&gt;Full Time Employees:&lt;\/strong&gt; {full_time_employees}&lt;\/p&gt;&lt;br&gt;\n    &lt;strong style='font-size: larger;'&gt;Description:&lt;\/strong&gt; {description}&lt;br&gt;&lt;br&gt;\n    \"\"\"\n\n    # Read valuation.h5 data for the symbol\n    h5_valuation_path = os.path.join(data_dir, f\"{exchange}_Valuation.h5\")\n\n    retries = 0\n    valuation_data = None\n    while retries &lt; max_retries:\n        try:\n            with pd.HDFStore(h5_valuation_path, 'r') as store:\n                if symbol in store:\n                    valuation_data = store.get(symbol)\n                else:\n                    valuation_data = pd.DataFrame(columns=&#91;'SubCategory', 'Data'])\n                    print(f\"The symbol {symbol} valuation data does not exist in {h5_valuation_path}\")\n            break\n        except Exception as e:\n            if retries &lt; max_retries - 1:\n                print(f\"An exception occurred while reading {h5_valuation_path}: {e}\")\n                print(f\"Retrying in {sleep_duration} seconds...\")\n                time.sleep(sleep_duration)\n                retries += 1\n            else:\n                print(f\"Max retries reached. Could not read {h5_valuation_path}. Exiting...\")\n                raise\n\n    # Add valuation_data to new_html_content\n    valuation_html = \"&lt;h2&gt;Valuation&lt;\/h2&gt;&lt;div style='display: flex; flex-wrap: wrap;'&gt;\"\n    if valuation_data is not None:\n        print(f\"valuation_data: {valuation_data}\")\n        valuation_data&#91;'Data'] = pd.to_numeric(valuation_data&#91;'Data'], errors='coerce')\n\n        for index, row in valuation_data.iterrows():\n            data = row&#91;'Data']\n            if pd.notnull(data):  # Check if 'Data' is not NaN\n                if index in percentage_metrics:\n                    formatted_data = \"{:.2%}\".format(float(data))\n                elif isinstance(data, (int, float)) and abs(data) &gt;= 1_000:  # Large numbers\n                    formatted_data = format_large_number(data)\n                elif isinstance(data, (int, float)):\n                    print('formatting numbers with commas in Valuation')\n                    print(f\"data: {data}, type: {type(data)}\")\n                    formatted_data = f\"{data:,.2f}\"  # For other numbers, just format with commas\n                else:\n                    formatted_data = data  # For non-numeric data, leave as is\n            else:\n                # If data is NaN or non-numeric, leave as is\n                formatted_data = row&#91;'Data']\n\n            valuation_html += f\"&lt;div style='flex: 0 0 calc(33.333% - 10px); margin-right: 10px; margin-bottom: 10px;'&gt;\"\n            valuation_html += f\"&lt;strong&gt;{row&#91;'SubCategory']}&lt;\/strong&gt;: {formatted_data}&lt;\/div&gt;\"\n    valuation_html += \"&lt;\/div&gt;\"\n\n    new_html_content += valuation_html  # Append valuation data to new_html_content\n\n\n\n    # Read highlights.h5 data for the symbol\n    h5_highlights_path = os.path.join(data_dir, f\"{exchange}_Highlights.h5\")\n    retries = 0\n    while retries &lt; max_retries:\n        try:\n            with pd.HDFStore(h5_highlights_path, 'r') as store:\n                if symbol in store:\n                    highlights_data = store.get(symbol)\n                else:\n                    highlights_data = pd.DataFrame(columns=&#91;'SubCategory', 'Data'])\n                    print(f\"The symbol {symbol} highlights data does not exist in {h5_highlights_path}\")\n            break\n        except Exception as e:\n            if retries &lt; max_retries - 1:\n                print(f\"An exception occurred while reading {h5_highlights_path}: {e}\")\n                print(f\"Retrying in {sleep_duration} seconds...\")\n                time.sleep(sleep_duration)\n                retries += 1\n            else:\n                print(f\"Max retries reached. Could not read {h5_highlights_path}. Exiting...\")\n                raise\n\n    # Add title before highlights\n    new_html_content += \"&lt;h2&gt;Highlights&lt;\/h2&gt;\"\n    # Add highlights_data to new_html_content\n    highlights_html = \"&lt;div style='display: flex; flex-wrap: wrap;'&gt;\"\n\n    highlights_data&#91;'Data'] = highlights_data&#91;'Data'].apply(pd.to_numeric, errors='ignore')\n\n    for index, row in highlights_data.iterrows():\n        subcategory = row&#91;'SubCategory']\n        data = row&#91;'Data']\n\n        if subcategory in percentage_metrics:\n            formatted_data = format_percentage(data)\n        elif pd.notnull(data) and isinstance(data, (int, float)):\n            if abs(data) &gt;= 1_000:  # Large numbers\n                print(f\"{symbol}: {subcategory} is a large number. Formatting {data} with commas...\")\n                formatted_data = format_large_number(data)\n            else:  # Other numeric data that is not a large number\n                print(f\"{symbol}: {subcategory} is a numeric value. Formatting {data} with commas...\")\n                formatted_data = f\"{data:,.2f}\"\n        else:\n            print(f'{symbol}: {subcategory} is a non-numeric value. Data: {data}')\n            formatted_data = data  # For non-numeric data, leave as is\n\n        highlights_html += f\"\"\"&lt;div style='flex: 0 0 calc(33.333% - 10px); margin-right: 10px; margin-bottom: 10px;'&gt;\n                                &lt;strong&gt;{subcategory}&lt;\/strong&gt;: {formatted_data}\n                               &lt;\/div&gt;\"\"\"\n    highlights_html += \"&lt;\/div&gt;\"\n    new_html_content += highlights_html  # App\n\n    # Add the disclaimer to the end of new_html_content\n    disclaimer = \"&lt;br&gt;&lt;br&gt;&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;\/strong&gt; The last data point has been excluded from the Prophet prediction.&lt;\/p&gt;\"\n    new_html_content += disclaimer\n\n\n    with open(html_file_path, 'r', encoding='utf-8') as f:\n        html_content = f.read()\n\n    # Parse the HTML content with BeautifulSoup\n    soup = BeautifulSoup(html_content, 'html.parser')\n\n    # Find the div that contains the Plotly plot\n    plot_div = soup.find('div', {'class': 'plotly-graph-div'})\n\n    if plot_div:\n        # Create a BeautifulSoup object from the new_content string\n        new_content_soup = BeautifulSoup(new_html_content, 'html.parser')\n\n        # Insert the new content before the Plotly plot\n        plot_div.insert_before(new_content_soup)\n\n        # Save the modified HTML back to disk\n        with open(html_file_path, 'w', encoding='utf-8') as f:\n            f.write(str(soup))\n    else:\n        print(f\"Plotly plot not found in the HTML file {html_file_path}.\")\n\n\ndef forecast_with_multiple_metrics(df: pd.DataFrame, periods: int = 4, save_dir: str = \"plots\/\", use_all_data: bool = True, eod_price_data: str = 'eod_price_data.h5'):\n    def plot_adjusted_close_from_h5(fig, symbol, hdf5_file_path, max_retries=3, sleep_duration=5):\n        hdf5_file_path = data_dir + hdf5_file_path\n        keys = access_hdf5_with_retries(hdf5_file_path, 'r', max_retries, sleep_duration)\n\n        if f'\/{symbol}' in keys:\n            with pd.HDFStore(hdf5_file_path, 'r') as store:\n                stock_data = store.get(symbol)\n\n                # Add actual adjusted_close to the plot\n                fig.add_trace(\n                    go.Scatter(x=stock_data.index, y=stock_data&#91;'Adjusted_close'],\n                               mode='lines+markers',\n                               name='Actual Adjusted_close',\n                               legendgroup='Actual',\n                               line=dict(color='purple'),\n                               showlegend=True),\n                    row=1, col=1\n                )\n\n                prophet_df = stock_data.reset_index()&#91;&#91;'Date', 'Adjusted_close']].rename(\n                    columns={'Date': 'ds', 'Adjusted_close': 'y'})\n\n                best_mae = float('inf')\n                best_forecast = None\n                best_mode = None\n\n                for mode in &#91;'additive', 'multiplicative']:\n                    model = Prophet(\n                        seasonality_mode=mode,\n                        yearly_seasonality=True,\n                        weekly_seasonality=False,\n                        daily_seasonality=False)\n                    model.fit(prophet_df)\n                    future = model.make_future_dataframe(periods=365)  # 1-year prediction\n                    forecast = model.predict(future)\n\n                    mae = calculate_mae(prophet_df&#91;'y'], forecast.loc&#91;:len(prophet_df) - 1, 'yhat'])\n\n                    if mae &lt; best_mae:\n                        best_mae = mae\n                        best_forecast = forecast\n                        best_mode = mode\n\n                # Add the best forecast to the plot\n                fig.add_trace(\n                    go.Scatter(x=best_forecast&#91;'ds'], y=best_forecast&#91;'yhat'],\n                               mode='lines',\n                               name='Adjusted_close Forecast',\n                               legendgroup='Forecast',\n                               line=dict(color='green'),\n                               showlegend=True),\n                    row=1, col=1\n                )\n\n                # Add yhat_upper and yhat_lower to the plot\n                fig.add_trace(\n                    go.Scatter(x=best_forecast&#91;'ds'], y=best_forecast&#91;'yhat_upper'],\n                               mode='lines',\n                               name='Upper Forecast',\n                               legendgroup='Upper Forecast',\n                               line=dict(color='blue', dash='dash'),\n                               showlegend=True),\n                    row=1, col=1\n                )\n\n                fig.add_trace(\n                    go.Scatter(x=best_forecast&#91;'ds'], y=best_forecast&#91;'yhat_lower'],\n                               mode='lines',\n                               name='Lower Forecast',\n                               legendgroup='Lower Forecast',\n                               line=dict(color='blue', dash='dash'),\n                               showlegend=True),\n                    row=1, col=1\n                )\n\n        else:\n            logging.warning(f\"No Adjusted_close data found for symbol: {symbol}\")\n\n    pd.set_option('display.max_columns', None)\n    logging.debug(df.columns.tolist())\n\n    # Get the columns that are both in df.columns and reordered_columns\n    common_columns = &#91;col for col in reordered_columns if col in df.columns]\n\n    # Check if common_columns is not empty\n    if common_columns:\n        # Reorder the DataFrame using the common columns\n        df = df&#91;common_columns + &#91;col for col in df.columns if col not in common_columns]]\n    else:\n        logging.warning(\"No common columns between df and reordered_columns.\")\n\n    metrics = &#91;col for col in df.columns if df&#91;col].dtype in &#91;'int64', 'float64']]\n\n    logging.info(metrics)\n\n    subplot_titles = &#91;]\n    for metric in metrics:\n        definition = metric_definitions.get(metric, 'No definition available')\n        wrapped_definition = wrap_text(definition, 160)  # Adjust the max_length as needed\n        title = f\"&lt;b&gt;{metric}&lt;\/b&gt;&lt;br&gt;&lt;span style='font-size: smaller;'&gt;{wrapped_definition}&lt;\/span&gt;\"\n        subplot_titles.append(title)\n\n    fig = make_subplots(rows=len(subplot_titles) + 1, cols=1, subplot_titles=&#91;'Adjusted_close'] + subplot_titles)\n\n    symbol = df&#91;'Symbol'].iloc&#91;0]\n\n    plot_adjusted_close_from_h5(fig, symbol, eod_price_data)\n\n\n\n\n    # Fetch the company_name\n    h5_symbols = os.path.join(data_dir, \"symbols.h5\")\n    company_name = get_company_name(symbol, h5_symbols)\n\n    if not os.path.exists(save_dir):\n        os.makedirs(save_dir)\n\n    if not use_all_data:\n        disclaimer = \"Disclaimer: The last data point has been excluded from the Prophet prediction. \\n \"\n        disclaimer += \"There may not be enough data points for Prophet to make accurate predictions. \\n\"\n        fig.add_annotation(\n            dict(\n                x=0,\n                y=1.1,\n                xref=\"paper\",\n                yref=\"paper\",\n                text=disclaimer,\n                showarrow=False,\n                font=dict(size=16)\n            )\n        )\n\n\n    for i, metric in enumerate(metrics):\n        row = i + 2\n\n        plotting_df = df&#91;&#91;'date', metric]].copy().dropna()\n        prophet_df = plotting_df.copy()\n\n        # Convert the specified metrics to percentages by multiplying by 100\n        if metric in &#91;'ROE', 'Earnings_Yield', 'Dividend_Yield']:\n            prophet_df&#91;metric] = prophet_df&#91;metric] * 100  # Convert to percentage\n            plotting_df&#91;metric] = plotting_df&#91;metric] * 100  # Convert to percentage\n\n\n        if not use_all_data:\n            prophet_df = prophet_df.iloc&#91;:-1, :]\n\n        prophet_df.rename(columns={'date': 'ds', metric: 'y'}, inplace=True)\n\n        if prophet_df.shape&#91;0] &lt; 2:\n            logging.warning(f\"Skipping {metric} because it has less than 2 non-NaN rows.\")\n            continue\n\n        best_mae = float('inf')\n        best_forecast = None\n        best_mode = None\n\n        for mode in &#91;'additive', 'multiplicative']:\n            model = Prophet(\n                seasonality_mode=mode,\n                yearly_seasonality=True,\n                weekly_seasonality=False,\n                daily_seasonality=False)\n            model.fit(prophet_df)\n            future = model.make_future_dataframe(periods=periods, freq='Q')\n            forecast = model.predict(future)\n\n            mae = calculate_mae(prophet_df&#91;'y'], forecast.loc&#91;:len(prophet_df) - 1, 'yhat'])\n\n            if mae &lt; best_mae:\n                best_mae = mae\n                best_forecast = forecast\n                best_mode = mode\n\n        logging.info(f\"Best seasonality mode for {metric} is {best_mode} with MAE {best_mae}\")\n\n\n        hover_format = '%{x}: %{y:.2f}%' if metric in &#91;'ROE', 'Earnings_Yield', 'Dividend_Yield'] else '%{x}: %{y:,}'\n\n        fig.add_trace(\n            go.Scatter(x=plotting_df&#91;'date'], y=plotting_df&#91;metric],\n                       mode='lines+markers',\n                       name=f'Actual {metric}',\n                       legendgroup='Actual',\n                       line=dict(color='purple'),\n                       showlegend=(i == 0),\n                       hovertemplate=hover_format),\n            row=row, col=1\n        )\n\n        # Plot the forecasted metric data\n        fig.add_trace(\n            go.Scatter(x=best_forecast&#91;'ds'],\n                       y=best_forecast&#91;'yhat'],\n                       mode='lines+markers',\n                       name=f'Forecasted {metric}',\n                       legendgroup='Forecast',\n                       line=dict(color='green'),\n                       showlegend=(i == 0),\n                       hovertemplate=hover_format),\n            row=row, col=1\n        )\n\n        # Plot the upper forecast interval\n        fig.add_trace(\n            go.Scatter(x=best_forecast&#91;'ds'], y=best_forecast&#91;'yhat_upper'],\n                       mode='lines',\n                       name=f'Upper Bound {metric}',\n                       legendgroup='Upper Forecast',\n                       line=dict(color='blue', dash='dash'),\n                       showlegend=(i == 0),\n                       hovertemplate=hover_format),\n            row=row, col=1\n        )\n\n        # Plot the lower forecast interval\n        fig.add_trace(\n            go.Scatter(x=best_forecast&#91;'ds'], y=best_forecast&#91;'yhat_lower'],\n                       mode='lines',\n                       name=f'Lower Bound {metric}',\n                       legendgroup='Lower Forecast',\n                       line=dict(color='blue', dash='dash'),\n                       showlegend=(i == 0),\n                       hovertemplate=hover_format),\n            row=row, col=1\n        )\n\n\n    fig.update_layout(\n        height=350 * len(metrics),\n        width=1800,\n        title_font_size=16  # You can change this value as needed\n    )\n\n    plot_file_path = os.path.join(save_dir, f\"{symbol}_quarterly.html\")\n\n    fig.write_html(plot_file_path)\n    logging.info(f\"Saved Prophet plot for {company_name} to {plot_file_path}\")\n\n    add_content_before_plot(symbol)\n\ndef get_symbols(h5_file_path, key='US'):\n    \"\"\"\n    Open an HDF5 file and populate the global dictionary symbol_exchange_map\n    where the symbol is the key and the exchange is the value.\n\n    Parameters:\n        h5_file_path (str): The path to the HDF5 file.\n        key (str): The key to use when reading the HDF5 file. Default is 'US'.\n\n    Returns:\n        None\n    \"\"\"\n\n    h5_file_path = Path(h5_file_path)\n\n    # Check if the file exists\n    if not h5_file_path.exists():\n        logging.info(f\"The file {h5_file_path} does not exist.\")\n        return\n\n    try:\n        # Read the DataFrame from the HDF5 file\n        df = pd.read_hdf(h5_file_path, key=key)\n\n        # Check if 'Code' and 'Exchange' columns exist\n        if 'Code' not in df.columns or 'Exchange' not in df.columns:\n            logging.info(f\"The 'Code' or 'Exchange' column does not exist in the DataFrame.\")\n            return\n\n        # Populate the global symbol_exchange_map\n        global symbol_exchange_map\n        symbol_exchange_map = dict(zip(df&#91;'Code'], df&#91;'Exchange']))\n        return list(symbol_exchange_map.keys())\n    except Exception as e:\n        logging.error(f\"An error occurred: {e}\")\n        return\n\nsymbols = get_symbols(data_dir + 'symbols.h5', key='US')\n\nsymbols = &#91;'UBER', 'LYFT', 'WE', 'IEP', 'AAPL'] + sp500 + largest_banks + companies_with_treasuries + homebuilders\nsymbols = &#91;'GDHG', 'IEP']\nsymbols = &#91;'GOOG']\n\n\n\nh5_files = set()  # Use a set to automatically handle duplicates\n\nfor symbol in symbols:\n    exchange = symbol_exchange_map.get(symbol, 'Other')  # Default to 'Other' if not found\n    current_h5_files = &#91;\n        f\"{data_dir}\/{exchange}_Cash_Flow_quarterly.h5\",\n        f\"{data_dir}\/{exchange}_Balance_Sheet_quarterly.h5\",\n        f\"{data_dir}\/{exchange}_Income_Statement_quarterly.h5\",\n        f\"{data_dir}\/{exchange}_Ratios.h5\"\n    ]\n    h5_files.update(current_h5_files)  # Update the set with the new file paths\n\n    logging.info(f'Processing {symbol}')\n    try:\n        # Pass only the HDF5 files corresponding to the current symbol's exchange\n        df = fetch_data_for_symbol_from_multiple_h5(list(current_h5_files), symbol, max_retries=3, sleep_duration=5)\n\n\n        if df is None:\n            logging.warning(f\"No data found for symbol {symbol}. Skipping to the next symbol.\")\n            continue  # Skip to the next iteration of the loop    forecast_with_multiple_metrics(df, periods=4, save_dir=\"plots\/\", use_all_data=False)\n\n        logging.info(df.head(20))\n        forecast_with_multiple_metrics(df)\n    except Exception as e:\n        logging.error(f\"An unexpected error occurred while processing symbol {symbol}: {e}\")<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I started off wanting to analyze the sustainability of mortgage buydowns by home builders. But as it happens, my ADHD had other plans. Three weeks later, here we&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5099","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python - Jeremy Whittaker<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Predicting Stock Prices and Corporate Financials with Facebook Prophet Using Python\" \/>\n<meta property=\"og:description\" content=\"I started off wanting to analyze the sustainability of mortgage buydowns by home builders. But as it happens, my ADHD had other plans. Three weeks later, here we are with code that looks for trends and anomalies in corporate financials. The code generates detailed HTML profiles for in-depth financial analysis of stocks. Here&#039;s a glimpse of the HTML output it generates. I think my second phase of this project will be to use a multivariate approach to predicting the close price using the financials as features, perhaps using LGBM. Before I dive into this I&#039;m curious if anyone has done this before. What approach did you use to predict price based on fundamentals?\" \/>\n<meta property=\"og:url\" content=\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/\" \/>\n<meta property=\"og:site_name\" content=\"Jeremy Whittaker\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/WhittakerJeremy\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/WhittakerJeremy\" \/>\n<meta property=\"article:published_time\" content=\"2023-11-02T00:48:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-11-16T21:48:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/preview.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1516\" \/>\n\t<meta property=\"og:image:height\" content=\"1019\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"JeremyWhittaker\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Predicting Stock Prices and Corporate Financials with Facebook Prophet Using Python\" \/>\n<meta name=\"twitter:description\" content=\"I started off wanting to analyze the sustainability of mortgage buydowns by home builders. But as it happens, my ADHD had other plans. Three weeks later, here we are with code that looks for trends and anomalies in corporate financials. The code generates detailed HTML profiles for in-depth financial analysis of stocks. Here&#039;s a glimpse of the HTML output it generates. I think my second phase of this project will be to use a multivariate approach to predicting the close price using the financials as features, perhaps using LGBM. Before I dive into this I&#039;m curious if anyone has done this before. What approach did you use to predict price based on fundamentals?\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/preview.png\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"JeremyWhittaker\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/\"},\"author\":{\"name\":\"JeremyWhittaker\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c\"},\"headline\":\"Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python\",\"datePublished\":\"2023-11-02T00:48:15+00:00\",\"dateModified\":\"2023-11-16T21:48:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/\"},\"wordCount\":1227,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c\"},\"image\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-1024x460.png\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/\",\"url\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/\",\"name\":\"Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python - Jeremy Whittaker\",\"isPartOf\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-1024x460.png\",\"datePublished\":\"2023-11-02T00:48:15+00:00\",\"dateModified\":\"2023-11-16T21:48:46+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#primaryimage\",\"url\":\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet.png\",\"contentUrl\":\"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet.png\",\"width\":1700,\"height\":763},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/new.jeremywhittaker.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/new.jeremywhittaker.com\/#website\",\"url\":\"https:\/\/new.jeremywhittaker.com\/\",\"name\":\"Jeremy Whittaker\",\"description\":\"Research, software, markets, housing, and energy\",\"publisher\":{\"@id\":\"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/new.jeremywhittaker.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c\",\"name\":\"JeremyWhittaker\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g\",\"caption\":\"JeremyWhittaker\"},\"logo\":{\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g\"},\"sameAs\":[\"http:\/\/www.jeremywhittaker.com\",\"https:\/\/www.facebook.com\/WhittakerJeremy\",\"https:\/\/www.linkedin.com\/in\/jeremywhittaker\/\"],\"url\":\"https:\/\/new.jeremywhittaker.com\/index.php\/author\/jeremywhittaker\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python - Jeremy Whittaker","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"en_US","og_type":"article","og_title":"Predicting Stock Prices and Corporate Financials with Facebook Prophet Using Python","og_description":"I started off wanting to analyze the sustainability of mortgage buydowns by home builders. But as it happens, my ADHD had other plans. Three weeks later, here we are with code that looks for trends and anomalies in corporate financials. The code generates detailed HTML profiles for in-depth financial analysis of stocks. Here's a glimpse of the HTML output it generates. I think my second phase of this project will be to use a multivariate approach to predicting the close price using the financials as features, perhaps using LGBM. Before I dive into this I'm curious if anyone has done this before. What approach did you use to predict price based on fundamentals?","og_url":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/","og_site_name":"Jeremy Whittaker","article_publisher":"https:\/\/www.facebook.com\/WhittakerJeremy","article_author":"https:\/\/www.facebook.com\/WhittakerJeremy","article_published_time":"2023-11-02T00:48:15+00:00","article_modified_time":"2023-11-16T21:48:46+00:00","og_image":[{"width":1516,"height":1019,"url":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/preview.png","type":"image\/png"}],"author":"JeremyWhittaker","twitter_card":"summary_large_image","twitter_title":"Predicting Stock Prices and Corporate Financials with Facebook Prophet Using Python","twitter_description":"I started off wanting to analyze the sustainability of mortgage buydowns by home builders. But as it happens, my ADHD had other plans. Three weeks later, here we are with code that looks for trends and anomalies in corporate financials. The code generates detailed HTML profiles for in-depth financial analysis of stocks. Here's a glimpse of the HTML output it generates. I think my second phase of this project will be to use a multivariate approach to predicting the close price using the financials as features, perhaps using LGBM. Before I dive into this I'm curious if anyone has done this before. What approach did you use to predict price based on fundamentals?","twitter_image":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/preview.png","twitter_misc":{"Written by":"JeremyWhittaker","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#article","isPartOf":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/"},"author":{"name":"JeremyWhittaker","@id":"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c"},"headline":"Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python","datePublished":"2023-11-02T00:48:15+00:00","dateModified":"2023-11-16T21:48:46+00:00","mainEntityOfPage":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/"},"wordCount":1227,"commentCount":0,"publisher":{"@id":"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c"},"image":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#primaryimage"},"thumbnailUrl":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-1024x460.png","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/","url":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/","name":"Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python - Jeremy Whittaker","isPartOf":{"@id":"https:\/\/new.jeremywhittaker.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#primaryimage"},"image":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#primaryimage"},"thumbnailUrl":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet-1024x460.png","datePublished":"2023-11-02T00:48:15+00:00","dateModified":"2023-11-16T21:48:46+00:00","breadcrumb":{"@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#primaryimage","url":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet.png","contentUrl":"https:\/\/new.jeremywhittaker.com\/wp-content\/uploads\/2023\/11\/Google_cut_sheet.png","width":1700,"height":763},{"@type":"BreadcrumbList","@id":"https:\/\/new.jeremywhittaker.com\/index.php\/2023\/11\/01\/predicting-future-corporate-financials-and-stock-prices-with-facebook-prophet-and-python\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/new.jeremywhittaker.com\/"},{"@type":"ListItem","position":2,"name":"Predicting Stock Prices and Corporate Financials Ratios with Facebook Prophet Using Python"}]},{"@type":"WebSite","@id":"https:\/\/new.jeremywhittaker.com\/#website","url":"https:\/\/new.jeremywhittaker.com\/","name":"Jeremy Whittaker","description":"Research, software, markets, housing, and energy","publisher":{"@id":"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/new.jeremywhittaker.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/new.jeremywhittaker.com\/#\/schema\/person\/ed0edfdefb3e180693efef453372980c","name":"JeremyWhittaker","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g","caption":"JeremyWhittaker"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/c8ac20e6dfa86b5f27ce9bffee4851099770cbea5ae7338a274865bfbc8c0218?s=96&d=retro&r=g"},"sameAs":["http:\/\/www.jeremywhittaker.com","https:\/\/www.facebook.com\/WhittakerJeremy","https:\/\/www.linkedin.com\/in\/jeremywhittaker\/"],"url":"https:\/\/new.jeremywhittaker.com\/index.php\/author\/jeremywhittaker\/"}]}},"_links":{"self":[{"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/posts\/5099","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/comments?post=5099"}],"version-history":[{"count":16,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/posts\/5099\/revisions"}],"predecessor-version":[{"id":5235,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/posts\/5099\/revisions\/5235"}],"wp:attachment":[{"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/media?parent=5099"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/categories?post=5099"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/new.jeremywhittaker.com\/index.php\/wp-json\/wp\/v2\/tags?post=5099"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}