diff --git a/src/lib/components/AnalystEstimate.svelte b/src/lib/components/AnalystEstimate.svelte index f4e6f934..a818ebdf 100644 --- a/src/lib/components/AnalystEstimate.svelte +++ b/src/lib/components/AnalystEstimate.svelte @@ -13,9 +13,12 @@ let optionsRevenue = null; let optionsEPS = null; let optionsNetIncome = null; + let optionsEbitda = null; + let optionsRevenueGrowth = null; let optionsEPSGrowth = null; let optionsNetIncomeGrowth = null; + let optionsEbitdaGrowth = null; let revenueDateList = []; let avgRevenueList = []; @@ -32,11 +35,15 @@ let lowNetIncomeList = []; let highNetIncomeList = []; + let ebitdaDateList = []; + let avgEbitdaList = []; + let lowEbitdaList = []; + let highEbitdaList = []; + let revenueAvgGrowthList = []; let epsAvgGrowthList = []; let netIncomeAvgGrowthList = []; - - let displayData = "Revenue"; + let ebitdaAvgGrowthList = []; function fillMissingDates(dates, highGrowthList) { // Get the current year @@ -132,17 +139,20 @@ } let tableActualRevenue = []; - let tableActualEPS = []; - let tableForecastRevenue = []; - let tableForecastEPS = []; - let tableForecastNetIncome = []; - let tableCombinedRevenue = []; + + let tableActualEPS = []; + let tableForecastEPS = []; let tableCombinedEPS = []; let tableActualNetIncome = []; let tableCombinedNetIncome = []; + let tableForecastNetIncome = []; + + let tableActualEbitda = []; + let tableCombinedEbitda = []; + let tableForecastEbitda = []; function getPlotOptions(dataType: string) { let dates = []; @@ -180,6 +190,12 @@ isAfterStartIndex ? item.estimatedNetIncomeHigh : null, ); break; + case "Ebitda": + valueList.push(item?.ebitda); + avgList.push(isAfterStartIndex ? item.estimatedEbitdaAvg : null); + lowList.push(isAfterStartIndex ? item.estimatedEbitdaLow : null); + highList.push(isAfterStartIndex ? item.estimatedEbitdaHigh : null); + break; default: break; } @@ -253,6 +269,23 @@ FY: netIncomeDateList[index]?.slice(2), val: val, })) || []; + } else if (dataType === "Ebitda") { + ebitdaDateList = dates?.slice(currentYearIndex) || []; + avgEbitdaList = + avgList?.slice(currentYearIndex)?.map((val, index) => ({ + FY: ebitdaDateList[index]?.slice(2), + val: val, + })) || []; + lowEbitdaList = + lowList?.slice(currentYearIndex)?.map((val, index) => ({ + FY: ebitdaDateList[index]?.slice(2), + val: val, + })) || []; + highEbitdaList = + highList?.slice(currentYearIndex)?.map((val, index) => ({ + FY: ebitdaDateList[index]?.slice(2), + val: val, + })) || []; } const growthList = dates?.map((date) => { @@ -262,7 +295,9 @@ ? revenueAvgGrowthList : dataType === "EPS" ? epsAvgGrowthList - : netIncomeAvgGrowthList; // Select the correct growth list + : dataType === "NetIncome" + ? netIncomeAvgGrowthList + : ebitdaAvgGrowthList; // Select the correct growth list const growth = listToUse?.find((r) => r.FY === fy); // Find matching FY return growth ? growth?.growth : null; // Return growth or null if not found }); @@ -370,6 +405,9 @@ lowNetIncomeList, avgNetIncomeList, ); + } else if (dataType === "Ebitda") { + highGrowthList = computeGrowthSingleList(highEbitdaList, avgEbitdaList); + lowGrowthList = computeGrowthSingleList(lowEbitdaList, avgEbitdaList); } highGrowthList = fillMissingDates(dates, highGrowthList)?.map( @@ -415,7 +453,9 @@ ? "Revenue Growth" : dataType === "EPS" ? "EPS Growth" - : "Net Income Growth", + : dataType === "NetIncome" + ? "Net Income Growth" + : "EBITDA Growth", data: growthList?.map((value) => ({ value, itemStyle: { @@ -544,6 +584,9 @@ } else if (dataType === "NetIncome") { optionsNetIncome = option; optionsNetIncomeGrowth = optionsGrowth; + } else if (dataType === "Ebitda") { + optionsEbitda = option; + optionsEbitdaGrowth = optionsGrowth; } } @@ -561,9 +604,14 @@ tableCombinedNetIncome = []; tableForecastNetIncome = []; + tableActualEbitda = []; + tableCombinedEbitda = []; + tableForecastEbitda = []; + revenueAvgGrowthList = []; epsAvgGrowthList = []; netIncomeAvgGrowthList = []; + ebitdaAvgGrowthList = []; let filteredData = analystEstimateList?.filter((item) => item.date >= 2015) ?? []; @@ -623,6 +671,32 @@ }; }); + //============================// + //Ebitda Data + filteredData?.forEach((item) => { + tableActualEbitda?.push({ + FY: Number(String(item?.date)?.slice(-2)), + val: item?.ebitda, + }); + tableForecastEbitda?.push({ + FY: Number(String(item?.date)?.slice(-2)), + val: item?.estimatedEbitdaAvg, + }); + }); + + tableCombinedEbitda = tableActualEbitda?.map((item1) => { + // Find the corresponding item in data2 based on "FY" + const item2 = tableForecastEbitda?.find( + (item2) => item2?.FY === item1?.FY, + ); + + // If the value in data1 is null, replace it with the value from data2 + return { + FY: item1.FY, + val: item1.val === null ? item2.val : item1.val, + }; + }); + //============================// //EPS Data filteredData?.forEach((item) => { @@ -656,11 +730,16 @@ tableActualNetIncome, tableCombinedNetIncome, ); + + ebitdaAvgGrowthList = computeGrowthList( + tableActualEbitda, + tableCombinedEbitda, + ); epsAvgGrowthList = computeGrowthList(tableActualEPS, tableCombinedEPS); } $: { - if ($stockTicker && displayData && typeof window !== "undefined") { + if ($stockTicker && typeof window !== "undefined") { isLoaded = false; analystEstimateList = []; analystEstimateList = data?.getAnalystEstimate || []; @@ -670,6 +749,7 @@ getPlotOptions("Revenue"); getPlotOptions("EPS"); getPlotOptions("NetIncome"); + getPlotOptions("Ebitda"); } else { $analystEstimateComponent = false; } @@ -867,6 +947,60 @@ {/each} + + + EBITDA + + {#each tableCombinedEbitda as item} + + {item?.val === "0.00" || + item?.val === null || + item?.val === 0 + ? "n/a" + : abbreviateNumber(item?.val.toFixed(2))} + + {/each} + + + + + EBITDA Growth + + {#each computeGrowthList(tableActualEbitda, tableCombinedEbitda) as item, index} + + {#if index === 0 || item?.growth === null} + n/a + {:else if tableActualEbitda[index]?.val === null} + + {item?.growth}%* + + {:else} + 0 + ? "text-[#00FC50] before:content-['+']" + : item?.growth < 0 + ? "text-[#FF2F1F]" + : ""} + > + {item?.growth}% + + {/if} + + {/each} + + + + + + + + + + diff --git a/src/routes/stocks/[tickerID]/forecast/+layout.svelte b/src/routes/stocks/[tickerID]/forecast/+layout.svelte index a6076cab..f063e362 100644 --- a/src/routes/stocks/[tickerID]/forecast/+layout.svelte +++ b/src/routes/stocks/[tickerID]/forecast/+layout.svelte @@ -2,6 +2,7 @@ import { stockTicker, screenWidth } from "$lib/store"; import { onDestroy } from "svelte"; import { page } from "$app/stores"; + import ScrollToTop from "$lib/components/ScrollToTop.svelte"; let displaySubSection = "overview"; @@ -87,6 +88,8 @@ + +