This commit is contained in:
MuslemRahimi 2025-02-21 23:36:40 +01:00
parent 5cf8d27ad1
commit e442fb10d5
17 changed files with 170 additions and 75 deletions

View File

@ -163,7 +163,8 @@
<div class="absolute inset-0 rounded-md bg-[#fff]"></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx === i
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"
>

View File

@ -58,23 +58,23 @@
website = info?.website;
snippet = description?.slice(0, 450) + "...";
numOfAnalyst = data?.getAnalystRating?.numOfAnalyst;
buyCount = ((data?.getAnalystRating?.Buy / numOfAnalyst) * 100)?.toFixed(
numOfAnalyst = data?.getAnalystSummary?.numOfAnalyst;
buyCount = ((data?.getAnalystSummary?.Buy / numOfAnalyst) * 100)?.toFixed(
2,
);
holdCount = (
(data?.getAnalystRating?.Hold / numOfAnalyst) *
(data?.getAnalystSummary?.Hold / numOfAnalyst) *
100
)?.toFixed(2);
sellCount = (
(data?.getAnalystRating?.Sell / numOfAnalyst) *
(data?.getAnalystSummary?.Sell / numOfAnalyst) *
100
)?.toFixed(2);
priceTarget =
data?.getAnalystRating?.medianPriceTarget !== ("n/a" && 0)
? data?.getAnalystRating?.medianPriceTarget
data?.getAnalystSummary?.medianPriceTarget !== ("n/a" && 0)
? data?.getAnalystSummary?.medianPriceTarget
: "n/a";
consensusRating = data?.getAnalystRating?.consensusRating;
consensusRating = data?.getAnalystSummary?.consensusRating;
try {
changesPercentage =
@ -165,9 +165,9 @@
</div>
</div>
{#if Object?.keys(data?.getAnalystRating ?? {})?.length !== 0}
{#if Object?.keys(data?.getAnalystSummary ?? {})?.length !== 0}
<div
class="space-y-3 pt-10 sm:pt-5 {Object?.keys(data?.getAnalystRating ?? {})
class="space-y-3 pt-10 sm:pt-5 {Object?.keys(data?.getAnalystSummary ?? {})
?.length !== 0
? ''
: 'hidden'}"

View File

@ -783,7 +783,7 @@
<div class="absolute inset-0 rounded-md bg-[#fff]"></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx ===
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"

View File

@ -96,7 +96,7 @@ export const load = async ({ params, locals }) => {
try {
const [
getStockDeck,
getAnalystRating,
getAnalystSummary,
getStockQuote,
getPrePostQuote,
getWhyPriceMoved,
@ -118,7 +118,7 @@ export const load = async ({ params, locals }) => {
return {
getStockDeck,
getAnalystRating,
getAnalystSummary,
getStockQuote,
getPrePostQuote,
getWhyPriceMoved,

View File

@ -941,7 +941,7 @@
>Metrics</a
>
{#if Object?.keys(data?.getAnalystRating ?? {})?.length > 0}
{#if Object?.keys(data?.getAnalystSummary ?? {})?.length > 0}
<a
href={`/stocks/${$stockTicker}/forecast`}
on:click={() => changeSection("forecast")}

View File

@ -1031,11 +1031,11 @@
><td
class="whitespace-nowrap px-0.5 py-[1px] xs:px-1 sm:py-2 text-[1rem]"
><a
href={data?.getAnalystRating?.consensusRating !==
href={data?.getAnalystSummary?.consensusRating !==
undefined
? `/stocks/${$stockTicker}/forecast`
: ""}
class={data?.getAnalystRating?.consensusRating !==
class={data?.getAnalystSummary?.consensusRating !==
undefined
? "sm:hover:text-blue-400 text-white underline underline-offset-4"
: "text-white cursor-text"}>Analyst</a
@ -1043,10 +1043,10 @@
</td>
<td
class="whitespace-nowrap px-0.5 py-[1px] text-left text-sm font-semibold xs:px-1 sm:py-2 sm:text-right sm:text-[1rem]"
>{data?.getAnalystRating?.consensusRating !== null &&
data?.getAnalystRating?.consensusRating !== "n/a" &&
data?.getAnalystRating?.consensusRating !== undefined
? data?.getAnalystRating?.consensusRating
>{data?.getAnalystSummary?.consensusRating !== null &&
data?.getAnalystSummary?.consensusRating !== "n/a" &&
data?.getAnalystSummary?.consensusRating !== undefined
? data?.getAnalystSummary?.consensusRating
: "n/a"}</td
></tr
>

View File

@ -491,7 +491,7 @@
></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx ===
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"

View File

@ -21,7 +21,6 @@
import Infobox from "$lib/components/Infobox.svelte";
import SEO from "$lib/components/SEO.svelte";
use([LineChart, BarChart, GridComponent, TooltipComponent, CanvasRenderer]);
export let data;
@ -478,8 +477,6 @@
}
</script>
<SEO
title={`${$displayCompanyName} (${$stockTicker}) Balance Sheet · Stocknear`}
description={`Detailed balance sheet for ${$displayCompanyName} (${$stockTicker}), including cash, debt, assets, liabilities, and book value.`}
@ -550,7 +547,7 @@
></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx ===
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"

View File

@ -20,7 +20,6 @@
import Infobox from "$lib/components/Infobox.svelte";
import SEO from "$lib/components/SEO.svelte";
use([LineChart, BarChart, GridComponent, TooltipComponent, CanvasRenderer]);
export let data;
@ -424,8 +423,6 @@
}
</script>
<SEO
title={`${$displayCompanyName} (${$stockTicker}) Cash Flow Statement · Stocknear`}
description={`Detailed cash flow statements for ${$displayCompanyName} (${$stockTicker}), including operating cash flow, capex and free cash flow.`}
@ -494,7 +491,7 @@
></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx ===
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"

View File

@ -478,7 +478,7 @@
></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx ===
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"

View File

@ -50,10 +50,26 @@ export const load = async ({ locals, params }) => {
return output;
};
const getTopAnalystSummary = async () => {
const response = await fetch(apiURL + "/top-analyst-summary-rating", {
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(),
getAnalystTickerHistory: await getAnalystTickerHistory(),
getTopAnalystSummary: await getTopAnalystSummary(),
};
};

View File

@ -2,6 +2,10 @@ import { error, fail, redirect } from "@sveltejs/kit";
import { validateData } from "$lib/utils";
import { loginUserSchema, registerUserSchema } from "$lib/schemas";
export const actions = {
login: async ({ url, request, locals }) => {

View File

@ -16,6 +16,8 @@
import { LineChart, BarChart, GaugeChart } from "echarts/charts";
import { GridComponent, TooltipComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import { goto } from "$app/navigation";
import SEO from "$lib/components/SEO.svelte";
export let data;
@ -37,21 +39,75 @@
const calculatePriceChange = (targetPrice) =>
targetPrice && price ? ((targetPrice / price - 1) * 100)?.toFixed(2) : 0;
const numOfAnalyst = data?.getAnalystRating?.numOfAnalyst || 0;
const avgPriceTarget = data?.getAnalystRating?.avgPriceTarget || 0;
const medianPriceTarget = data?.getAnalystRating?.medianPriceTarget || 0;
const lowPriceTarget = data?.getAnalystRating?.lowPriceTarget || 0;
const highPriceTarget = data?.getAnalystRating?.highPriceTarget || 0;
const consensusRating = data?.getAnalystRating?.consensusRating;
const lowChange = calculatePriceChange(lowPriceTarget);
const medianChange = calculatePriceChange(medianPriceTarget);
const avgChange = calculatePriceChange(avgPriceTarget);
const highChange = calculatePriceChange(highPriceTarget);
const rawAnalystList = data?.getAnalystRating?.recommendationList || [];
const recommendationList =
let numOfAnalyst = data?.getAnalystSummary?.numOfAnalyst || 0;
let avgPriceTarget = data?.getAnalystSummary?.avgPriceTarget || 0;
let medianPriceTarget = data?.getAnalystSummary?.medianPriceTarget || 0;
let lowPriceTarget = data?.getAnalystSummary?.lowPriceTarget || 0;
let highPriceTarget = data?.getAnalystSummary?.highPriceTarget || 0;
let consensusRating = data?.getAnalystSummary?.consensusRating;
let lowChange = calculatePriceChange(lowPriceTarget);
let medianChange = calculatePriceChange(medianPriceTarget);
let avgChange = calculatePriceChange(avgPriceTarget);
let highChange = calculatePriceChange(highPriceTarget);
let rawAnalystList = data?.getAnalystSummary?.recommendationList || [];
let recommendationList =
rawAnalystList?.length > 5 ? rawAnalystList?.slice(-6) : rawAnalystList;
const categories = ["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"];
let categories = ["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"];
const tabs = [
{
title: "All Analysts",
},
{
title: "Top Analysts",
},
];
let activeIdx = 0;
function changeTab(index) {
activeIdx = index;
if (activeIdx === 0) {
numOfAnalyst = data?.getAnalystSummary?.numOfAnalyst || 0;
avgPriceTarget = data?.getAnalystSummary?.avgPriceTarget || 0;
medianPriceTarget = data?.getAnalystSummary?.medianPriceTarget || 0;
lowPriceTarget = data?.getAnalystSummary?.lowPriceTarget || 0;
highPriceTarget = data?.getAnalystSummary?.highPriceTarget || 0;
consensusRating = data?.getAnalystSummary?.consensusRating;
lowChange = calculatePriceChange(lowPriceTarget);
medianChange = calculatePriceChange(medianPriceTarget);
avgChange = calculatePriceChange(avgPriceTarget);
highChange = calculatePriceChange(highPriceTarget);
rawAnalystList = data?.getAnalystSummary?.recommendationList || [];
recommendationList =
rawAnalystList?.length > 5 ? rawAnalystList?.slice(-6) : rawAnalystList;
categories = ["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"];
} else {
numOfAnalyst = data?.getTopAnalystSummary?.numOfAnalyst || 0;
avgPriceTarget = data?.getTopAnalystSummary?.avgPriceTarget || 0;
medianPriceTarget = data?.getTopAnalystSummary?.medianPriceTarget || 0;
lowPriceTarget = data?.getTopAnalystSummary?.lowPriceTarget || 0;
highPriceTarget = data?.getTopAnalystSummary?.highPriceTarget || 0;
consensusRating = data?.getTopAnalystSummary?.consensusRating;
lowChange = calculatePriceChange(lowPriceTarget);
medianChange = calculatePriceChange(medianPriceTarget);
avgChange = calculatePriceChange(avgPriceTarget);
highChange = calculatePriceChange(highPriceTarget);
rawAnalystList = data?.getTopAnalystSummary?.recommendationList || [];
recommendationList =
rawAnalystList?.length > 5 ? rawAnalystList?.slice(-6) : rawAnalystList;
categories = ["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"];
console.log(recommendationList);
}
optionsData = getPlotOptions() || null;
optionsPieChart = getPieChart() || null;
optionsPriceForecast = getPriceForecastChart() || null;
}
function findIndex(data) {
let year = new Date().getFullYear() - 1;
@ -78,8 +134,8 @@
return -1; // Return -1 if no matching index is found
}
function getTotalForDate(index) {
return categories.reduce(
function getTotalForDate(index, recommendationList) {
return categories?.reduce(
(sum, cat) => sum + recommendationList[index][cat],
0,
);
@ -291,7 +347,7 @@
}
function getPriceForecastChart() {
const historicalData = data?.getAnalystRating?.pastPriceList || [];
const historicalData = data?.getAnalystSummary?.pastPriceList || [];
const forecastTargets = {
low: lowPriceTarget,
avg: avgPriceTarget,
@ -472,28 +528,52 @@
{removeCompanyStrings($displayCompanyName)} Forecast
</h1>
<div class="inline-flex justify-center w-full rounded-md sm:w-auto">
<div
class="mb-2 sm:mb-0 mt-2 sm:mt-0 inline-flex w-full rounded-md shadow-sm shadow-[#1E222D] sm:w-auto ml-auto text-sm border border-gray-800"
class="bg-secondary w-full sm:w-fit relative flex flex-wrap items-center justify-center rounded-md p-1 mt-4"
>
{#each tabs as item, i}
{#if data?.user?.tier !== "Pro" && i > 0}
<button
class="w-full text-sm rounded-none rounded-l-md px-2 bp:px-3 sm:w-auto sm:px-4 py-1.5 bg-secondary text-white"
>All Analysts</button
on:click={() => goto("/pricing")}
class="group relative z-[1] rounded-full w-1/2 min-w-24 md:w-auto px-5 py-1"
>
<button
class="text-sm w-full rounded-none rounded-r-md px-2 bp:px-3 sm:w-auto sm:px-4 py-1.5 bg-table sm:hover:bg-secondary transition duration-50 ease-out"
>Top Analysts
<span class="relative text-sm block font-semibold">
{item.title}
<svg
class="w-4 h-4 ml-1 text-icon-faded inline-block"
viewBox="0 0 20 20"
fill="currentColor"
style="max-width:40px"
class="inline-block ml-0.5 -mt-1 w-3.5 h-3.5"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path
fill-rule="evenodd"
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
clip-rule="evenodd"
></path></svg
></button
fill="#A3A3A3"
d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"
/></svg
>
</span>
</button>
{:else}
<button
on:click={() => changeTab(i)}
class="group relative z-[1] rounded-full w-1/2 min-w-24 md:w-auto px-5 py-1 {activeIdx ===
i
? 'z-0'
: ''} "
>
{#if activeIdx === i}
<div class="absolute inset-0 rounded-md bg-[#fff]"></div>
{/if}
<span
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"
>
{item.title}
</span>
</button>
{/if}
{/each}
</div>
</div>
</div>
@ -714,7 +794,7 @@
<td
class="px-1 py-[3px] text-sm sm:text-[1rem] text-right"
>
{getTotalForDate(i)}
{getTotalForDate(i, recommendationList)}
</td>
{/each}
</tr>

View File

@ -134,7 +134,7 @@
}
function getPriceForecastChart() {
const historicalData = data?.getAnalystRating?.pastPriceList || [];
const historicalData = data?.getAnalystSummary?.pastPriceList || [];
const forecastTargets = {
low: lowPriceTarget,
avg: avgPriceTarget,

View File

@ -13,7 +13,7 @@
import SEO from "$lib/components/SEO.svelte";
export let data;
let analystRating = data?.getAnalystRating ?? {};
let analystRating = data?.getAnalystSummary ?? {};
let rawData = data?.getAnalystTickerHistory ?? [];
let historyList = [];
@ -126,8 +126,8 @@
};
const totalRatingScore = recentData
.map((item) => ratingScores[item.rating_current] || 0)
.reduce((sum, score) => sum + score, 0);
?.map((item) => ratingScores[item.rating_current] || 0)
?.reduce((sum, score) => sum + score, 0);
const averageRatingScore = filteredAnalystCount
? totalRatingScore / filteredAnalystCount
@ -262,7 +262,7 @@
></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx ===
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"

View File

@ -659,7 +659,7 @@
></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx ===
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"

View File

@ -398,7 +398,7 @@
></div>
{/if}
<span
class="relative text-sm block font-semibold {activeIdx ===
class="relative text-sm block font-semibold whitespace-nowrap {activeIdx ===
i
? 'text-black'
: 'text-white'}"