This commit is contained in:
MuslemRahimi 2024-10-31 17:04:04 +01:00
parent 811627f30d
commit edf98dda63
3 changed files with 164 additions and 32 deletions

View File

@ -1,11 +1,9 @@
export const load = async ({ locals, params }) => {
const { apiURL, apiKey } = locals;
const postData = {
ticker: params.tickerID,
};
const getAnalystEstimate = async () => {
const { apiURL, apiKey } = locals;
const postData = {
ticker: params.tickerID,
};
// make the POST request to the endpoint
const response = await fetch(apiURL + "/analyst-estimate", {
method: "POST",
@ -21,8 +19,23 @@ export const load = async ({ locals, params }) => {
return output;
};
const getAnalystInsight = async () => {
const response = await fetch(apiURL + "/analyst-insight", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": apiKey,
},
body: JSON.stringify(postData),
});
const output = await response.json();
return output;
};
// Make sure to return a promise
return {
getAnalystEstimate: await getAnalystEstimate(),
getAnalystInsight: await getAnalystInsight(),
};
};

View File

@ -7,7 +7,17 @@
} from "$lib/store";
import { abbreviateNumber } from "$lib/utils";
import { Chart } from "svelte-echarts";
import { init, use } from "echarts/core";
import { BarChart } from "echarts/charts";
import { GridComponent, TooltipComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import { onMount } from "svelte";
export let data;
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer]);
let index = 0;
let changeRevenue = 0;
let changeNetIncome = 0;
@ -74,6 +84,95 @@
}
};
function getPlotOptions() {
if (!rawAnalystList || rawAnalystList.length === 0) {
return null;
}
// Define categories in the exact order you specified
const categories = ["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"];
const colors = ["#008A00", "#31B800", "#FF9E21", "#D9220E", "#9E190A"];
// Create a consistent mapping for data
const formattedData = rawAnalystList.map((item) =>
categories.map((cat) => item[cat] || 0),
);
// Normalize data to percentages
const normalizedData = formattedData.map((row) => {
const total = row.reduce((sum, val) => sum + val, 0);
return row.map((val) => (total > 0 ? (val / total) * 100 : 0));
});
// Calculate total percentage for each category across all dates
const totalData = [];
for (let i = 0; i < categories.length; ++i) {
let sum = 0;
for (let j = 0; j < normalizedData.length; ++j) {
sum += normalizedData[j][i];
}
totalData.push(sum / normalizedData.length);
}
// Define series based on categories with color mapping
const series = categories.map((name, idx) => ({
name,
type: "bar",
stack: "total",
barWidth: "60%",
data: normalizedData.map((row) => row[idx]),
itemStyle: {
color: colors[idx],
},
tooltip: {
valueFormatter: (value) => `${value.toFixed(2)}%`,
},
}));
// Define chart option
const option = {
grid: {
left: "2%",
right: "2%",
bottom: "10%",
top: "5%",
containLabel: true,
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
legend: {
data: categories,
bottom: 0,
},
xAxis: {
type: "category",
data: rawAnalystList.map((item) => item.date),
axisLabel: {
color: "#fff",
},
},
yAxis: {
type: "value",
max: 100,
axisLabel: {
show: false, // Hide y-axis labels
},
splitLine: {
show: false,
},
},
series,
animation: false,
};
return option;
}
if (data?.getAnalystEstimate?.length !== 0) {
index = findIndex(data?.getAnalystEstimate);
@ -97,6 +196,8 @@
changeEBITDA = calculateChange(estimatedEbitdaAvg, ebitda);
changeEPS = calculateChange(estimatedEpsAvg, eps);
}
let optionsData = getPlotOptions() || null;
</script>
<svelte:head>
@ -258,29 +359,30 @@
class="flex flex-col justify-between p-1 lg:max-w-[32%] text-white"
>
<div>
<h2 class="mb-1 text-xl font-bold">Analyst Ratings</h2>
<p>
According to {numOfAnalyst} stock analyst, the rating for GameStop
is "{consensusRating}". This means that the analyst believes
this stock is likely to lead to {[
"Strong Sell",
"Sell",
]?.includes(consensusRating)
? "lower"
: ["Strong Buy", "Buy"]?.includes(consensusRating)
? "higher"
: "similar"} returns than market as a whole.
</p>
<h2 class="mb-1 text-xl font-bold">Latest Analyst Report</h2>
{#if Object?.keys(data?.getAnalystInsight)?.length > 0}
<p>{data?.getAnalystInsight?.insight}</p>
{:else}
<p>
According to {numOfAnalyst} stock analyst, the rating for GameStop
is "{consensusRating}". This means that the analyst believes
this stock is likely to lead to {[
"Strong Sell",
"Sell",
]?.includes(consensusRating)
? "lower"
: ["Strong Buy", "Buy"]?.includes(consensusRating)
? "higher"
: "similar"} returns than market as a whole.
</p>
{/if}
</div>
</div>
<div class="grow pt-2 md:pt-4 lg:pl-4 lg:pt-0">
<div class="h-[250px] xs:h-[275px]">
<canvas
id="myChart"
style="display: block; box-sizing: border-box; height: 275px; width: 728px;"
width="1092"
height="412"
></canvas>
<div class="app h-[250px] xs:h-[275px]">
{#if optionsData !== null}
<Chart {init} options={optionsData} class="chart" />
{/if}
</div>
<div
class="hide-scroll mb-1 mt-2 overflow-x-auto px-1.5 text-center md:mb-0 md:px-0 lg:mt-2"
@ -563,3 +665,20 @@
</div>
</div>
</section>
<style>
.app {
height: 300px;
max-width: 100%; /* Ensure chart width doesn't exceed the container */
}
@media (max-width: 640px) {
.app {
height: 210px;
}
}
.chart {
width: 100%;
}
</style>

View File

@ -250,23 +250,23 @@
>
<thead class="">
<tr class="border-b border-[#27272A]">
<td class="text-white font-semibold text-[1rem] text-start"
<td class="text-white font-semibold text-sm text-start"
>Analyst</td
>
<td class="text-white font-semibold text-[1rem] text-start"
<td class="text-white font-semibold text-sm text-start"
>Firm</td
>
<td class="text-white font-semibold text-[1rem] text-end"
<td class="text-white font-semibold text-sm text-end"
>Rating</td
>
<td class="text-white font-semibold text-[1rem] text-end"
<td class="text-white font-semibold text-sm text-end"
>Action</td
>
<td class="text-white font-semibold text-[1rem] text-end"
<td class="text-white font-semibold text-sm text-end"
>Price Target</td
>
<td class="text-white font-semibold text-[1rem] text-end"
<td class="text-white font-semibold text-sm text-end"
>Date</td
>
</tr>