update forecast overview page
This commit is contained in:
parent
f8ed49b3d4
commit
defd8a9283
@ -1,8 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { numberOfUnreadNotification, displayCompanyName, stockTicker, analystEstimateComponent, currentPortfolioPrice } from "$lib/store";
|
import { numberOfUnreadNotification, displayCompanyName, stockTicker, analystEstimateComponent } from "$lib/store";
|
||||||
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
import Lazy from "$lib/components/Lazy.svelte";
|
import Lazy from "$lib/components/Lazy.svelte";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
|
function findIndex(data) {
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
return data.findIndex(item => item.date >= currentYear && item.revenue === null);
|
||||||
|
}
|
||||||
|
const index = findIndex(data?.getAnalystEstimate);
|
||||||
|
const changeRevenue = abbreviateNumber(((data?.getAnalystEstimate[index-1]?.estimatedRevenueAvg/data?.getAnalystEstimate[index-2]?.revenue-1)*100))?.toFixed(1)
|
||||||
|
const changeNetIncome = abbreviateNumber(((data?.getAnalystEstimate[index-1]?.estimatedNetIncomeAvg/data?.getAnalystEstimate[index-2]?.netIncome-1)*100))?.toFixed(1)
|
||||||
|
const changeEBITDA = abbreviateNumber(((data?.getAnalystEstimate[index-1]?.estimatedEbitdaAvg/data?.getAnalystEstimate[index-2]?.ebitda-1)*100)?.toFixed(1))
|
||||||
|
const changeEPS = abbreviateNumber(((data?.getAnalystEstimate[index-1]?.estimatedEpsAvg/data?.getAnalystEstimate[index-2]?.eps-1)*100))?.toFixed(1)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@ -31,6 +43,84 @@
|
|||||||
<div class="flex justify-center m-auto h-full overflow-hidden w-full">
|
<div class="flex justify-center m-auto h-full overflow-hidden w-full">
|
||||||
<div class="relative flex justify-center items-center overflow-hidden w-full">
|
<div class="relative flex justify-center items-center overflow-hidden w-full">
|
||||||
<div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
|
<div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
|
||||||
|
|
||||||
|
<h2 class="mt-5 text-xl sm:text-2xl text-gray-200 font-bold mb-4">
|
||||||
|
Financial Forecast this Year
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="mb-4 grid grid-cols-2 grid-rows-1 divide-gray-500 rounded-lg border border-gray-600 bg-[#272727] shadow md:grid-cols-4 md:grid-rows-1 md:divide-x">
|
||||||
|
<div class="p-4 bp:p-5 sm:p-6">
|
||||||
|
<label class="mr-1 cursor-pointer flex flex-row items-center text-white text-[1rem] font-semibold">
|
||||||
|
Revenue
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 flex flex-col items-baseline justify-start space-y-2 bp:space-y-0">
|
||||||
|
<div class="flex items-baseline text-2xl font-semibold text-white">
|
||||||
|
{abbreviateNumber(data?.getAnalystEstimate[index-1]?.estimatedRevenueAvg,true)}
|
||||||
|
</div>
|
||||||
|
<div class="inline-flex items-baseline rounded-full px-2.5 py-0.5 text-sm font-semibold md:mt-2 lg:mt-0 bg-green-100 text-green-800 dark:bg-green-700 dark:text-dark-100">
|
||||||
|
<svg class="-ml-1 mr-0.5 h-5 w-5 flex-shrink-0 self-center {changeRevenue > 0 ? 'text-green-500' : 'text-red-500 rotate-180'}" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="max-width:40px" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 11l5-5m0 0l5 5m-5-5v12"></path></svg>
|
||||||
|
{changeRevenue}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-0.5 mt-1.5 text-sm font-semibold text-white/60 lg:block">
|
||||||
|
from {abbreviateNumber(data?.getAnalystEstimate[index-2]?.revenue)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 bp:p-5 sm:p-6 border-l border-contrast md:border-0">
|
||||||
|
<label class="mr-1 cursor-pointer flex flex-row items-center text-white text-[1rem] font-semibold">
|
||||||
|
Net Income
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 flex flex-col items-baseline justify-start space-y-2 bp:space-y-0">
|
||||||
|
<div class="flex items-baseline text-2xl font-semibold text-white">
|
||||||
|
{abbreviateNumber(data?.getAnalystEstimate[index-1]?.estimatedNetIncomeAvg,true)}
|
||||||
|
</div>
|
||||||
|
<div class="inline-flex items-baseline rounded-full px-2.5 py-0.5 text-sm font-semibold md:mt-2 lg:mt-0 bg-green-100 text-green-800 dark:bg-green-700 dark:text-dark-100">
|
||||||
|
<svg class="-ml-1 mr-0.5 h-5 w-5 flex-shrink-0 self-center {changeNetIncome > 0 ? 'text-green-500' : 'text-red-500 rotate-180'}" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="max-width:40px" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 11l5-5m0 0l5 5m-5-5v12"></path></svg>
|
||||||
|
{changeNetIncome}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-0.5 mt-1.5 text-sm font-semibold text-white/60 lg:block">
|
||||||
|
from {abbreviateNumber(data?.getAnalystEstimate[index-2]?.netIncome,true)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 bp:p-5 sm:p-6 border-t border-contrast md:border-0">
|
||||||
|
<label class="mr-1 cursor-pointer flex flex-row items-center text-white text-[1rem] font-semibold">
|
||||||
|
EBITDA
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 flex flex-col items-baseline justify-start space-y-2 bp:space-y-0">
|
||||||
|
<div class="flex items-baseline text-2xl font-semibold text-white">
|
||||||
|
{abbreviateNumber(data?.getAnalystEstimate[index-1]?.estimatedEbitdaAvg,true)}
|
||||||
|
</div>
|
||||||
|
<div class="inline-flex items-baseline rounded-full px-2.5 py-0.5 text-sm font-semibold md:mt-2 lg:mt-0 bg-green-100 text-green-800 dark:bg-green-700 dark:text-dark-100">
|
||||||
|
<svg class="-ml-1 mr-0.5 h-5 w-5 flex-shrink-0 self-center {changeEBITDA > 0 ? 'text-green-500' : 'text-red-500 rotate-180'}" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="max-width:40px" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 11l5-5m0 0l5 5m-5-5v12"></path></svg>
|
||||||
|
{changeEBITDA}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-0.5 mt-1.5 text-sm font-semibold text-white/60 lg:block">
|
||||||
|
from {abbreviateNumber(data?.getAnalystEstimate[index-2]?.ebitda,true)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 bp:p-5 sm:p-6 border-t border-contrast md:border-0 border-l border-contrast md:border-0">
|
||||||
|
<label class="mr-1 cursor-pointer flex flex-row items-center text-white text-[1rem] font-semibold">
|
||||||
|
EPS
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 flex flex-col items-baseline justify-start space-y-2 bp:space-y-0">
|
||||||
|
<div class="flex items-baseline text-2xl font-semibold text-white">
|
||||||
|
{data?.getAnalystEstimate[index-1]?.estimatedEpsAvg}
|
||||||
|
</div>
|
||||||
|
<div class="inline-flex items-baseline rounded-full px-2.5 py-0.5 text-sm font-semibold md:mt-2 lg:mt-0 bg-green-100 text-green-800 dark:bg-green-700 dark:text-dark-100">
|
||||||
|
<svg class="-ml-1 mr-0.5 h-5 w-5 flex-shrink-0 self-center {changeEPS > 0 ? 'text-green-500' : 'text-red-500 rotate-180'}" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="max-width:40px" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 11l5-5m0 0l5 5m-5-5v12"></path></svg>
|
||||||
|
{changeEPS}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-0.5 mt-1.5 text-sm font-semibold text-white/60 lg:block">
|
||||||
|
from {data?.getAnalystEstimate[index-2]?.eps}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Lazy>
|
<Lazy>
|
||||||
<div class="w-full m-auto sm:pb-6 sm:pt-6 {!$analystEstimateComponent ? 'hidden' : ''}">
|
<div class="w-full m-auto sm:pb-6 sm:pt-6 {!$analystEstimateComponent ? 'hidden' : ''}">
|
||||||
{#await import("$lib/components/AnalystEstimate.svelte") then { default: Comp }}
|
{#await import("$lib/components/AnalystEstimate.svelte") then { default: Comp }}
|
||||||
|
|||||||
@ -1,36 +1,32 @@
|
|||||||
import { getCache, setCache } from '$lib/store';
|
import { getCache, setCache } from "$lib/store";
|
||||||
|
|
||||||
|
|
||||||
export const load = async ({ parent, params }) => {
|
export const load = async ({ parent, params }) => {
|
||||||
|
const getAnalystEstimate = async () => {
|
||||||
const getAnalystTickerHistory = async () => {
|
|
||||||
|
|
||||||
let output;
|
let output;
|
||||||
|
|
||||||
const cachedData = getCache(params.tickerID, 'getAnalystTickerHistory');
|
const cachedData = getCache(params.tickerID, "getAnalystEstimate");
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
output = cachedData;
|
output = cachedData;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const { apiURL, apiKey } = await parent();
|
const { apiURL, apiKey } = await parent();
|
||||||
|
|
||||||
const postData = {
|
const postData = {
|
||||||
ticker: params.tickerID
|
ticker: params.tickerID,
|
||||||
};
|
};
|
||||||
|
|
||||||
// make the POST request to the endpoint
|
// make the POST request to the endpoint
|
||||||
const response = await fetch(apiURL + '/analyst-ticker-history', {
|
const response = await fetch(apiURL + "/analyst-estimate", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json", "X-API-KEY": apiKey
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": apiKey,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(postData)
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
|
|
||||||
output = await response.json();
|
output = await response.json();
|
||||||
|
|
||||||
setCache(params.tickerID, output, 'getAnalystTickerHistory');
|
setCache(params.tickerID, output, "getAnalystEstimate");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -38,6 +34,6 @@ export const load = async ({ parent, params }) => {
|
|||||||
|
|
||||||
// Make sure to return a promise
|
// Make sure to return a promise
|
||||||
return {
|
return {
|
||||||
getAnalystTickerHistory: await getAnalystTickerHistory()
|
getAnalystEstimate: await getAnalystEstimate(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,21 +3,12 @@
|
|||||||
import ReturnCard from "$lib/components/ReturnCard.svelte";
|
import ReturnCard from "$lib/components/ReturnCard.svelte";
|
||||||
import { numberOfUnreadNotification, displayCompanyName, screenWidth, stockTicker, revenueSegmentationComponent } from "$lib/store";
|
import { numberOfUnreadNotification, displayCompanyName, screenWidth, stockTicker, revenueSegmentationComponent } from "$lib/store";
|
||||||
import { abbreviateNumber } from "$lib/utils";
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
|
import RevenueSegmentation from "$lib/components/RevenueSegmentation.svelte";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
let quantStats = {};
|
let quantStats = {};
|
||||||
let stockQuote;
|
|
||||||
|
|
||||||
let marketCap = "-";
|
|
||||||
|
|
||||||
let currentPrice = 0;
|
|
||||||
let previousClose = "-";
|
|
||||||
let volume = "-";
|
|
||||||
let eps = "-";
|
|
||||||
let pe = "-";
|
|
||||||
let alpha = "-";
|
|
||||||
let beta = "-";
|
|
||||||
|
|
||||||
// Function to check if a date is today or yesterday, adjusting for weekends
|
// Function to check if a date is today or yesterday, adjusting for weekends
|
||||||
function ongoingDD(dateString: string) {
|
function ongoingDD(dateString: string) {
|
||||||
@ -75,7 +66,6 @@ if (progressYearPriceValue < currentPrice) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
stockQuote = data?.getStockQuote;
|
|
||||||
quantStats = data?.getQuantStats ?? {};
|
quantStats = data?.getQuantStats ?? {};
|
||||||
|
|
||||||
|
|
||||||
@ -218,9 +208,7 @@ updateYearRange()
|
|||||||
<!--Start RevenueSegmentation-->
|
<!--Start RevenueSegmentation-->
|
||||||
<Lazy>
|
<Lazy>
|
||||||
<div class="w-full pt-10 sm:pb-6 sm:pt-6 m-auto {!$revenueSegmentationComponent ? 'hidden' : ''}">
|
<div class="w-full pt-10 sm:pb-6 sm:pt-6 m-auto {!$revenueSegmentationComponent ? 'hidden' : ''}">
|
||||||
{#await import("$lib/components/RevenueSegmentation.svelte") then { default: Comp }}
|
<RevenueSegmentation apiURL={data?.apiURL} apiKey={data?.apiKey} userTier={data?.user?.tier} />
|
||||||
<svelte:component this={Comp} apiURL={data?.apiURL} apiKey={data?.apiKey} userTier={data?.user?.tier} />
|
|
||||||
{/await}
|
|
||||||
</div>
|
</div>
|
||||||
</Lazy>
|
</Lazy>
|
||||||
<!--End RevenueSegmentation-->
|
<!--End RevenueSegmentation-->
|
||||||
@ -230,7 +218,7 @@ updateYearRange()
|
|||||||
|
|
||||||
|
|
||||||
{#if $stockTicker in quantStats && Object.keys(quantStats[$stockTicker]).length > 0}
|
{#if $stockTicker in quantStats && Object.keys(quantStats[$stockTicker]).length > 0}
|
||||||
<h3 class="text-start w-full mt-8 mb-2 text-lg sm:text-2xl font-bold text-white">
|
<h3 class="text-start w-full mb-2 text-lg sm:text-2xl font-bold text-white">
|
||||||
Worst 10 Drawdowns of {$stockTicker}
|
Worst 10 Drawdowns of {$stockTicker}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="w-full overflow-x-scroll">
|
<div class="w-full overflow-x-scroll">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user