update ai forecast page
This commit is contained in:
parent
e2987da793
commit
a046f9a904
59
src/routes/stocks/[tickerID]/forecast/ai/+layout.svelte
Normal file
59
src/routes/stocks/[tickerID]/forecast/ai/+layout.svelte
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let data;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="w-full overflow-hidden">
|
||||||
|
<div class="w-full overflow-hidden m-auto">
|
||||||
|
<div class="sm:p-0 flex justify-center w-full m-auto overflow-hidden">
|
||||||
|
<div
|
||||||
|
class="relative flex flex-col lg:flex-row justify-center items-start overflow-hidden w-full"
|
||||||
|
>
|
||||||
|
<main class="w-full lg:w-3/4 lg:pr-10">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<aside class="inline-block relative w-full lg:w-1/4 mt-3">
|
||||||
|
{#if !["Pro", "Plus"]?.includes(data?.user?.tier) || data?.user?.freeTrial}
|
||||||
|
<div
|
||||||
|
class="w-full border border-gray-300 dark:border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer sm:hover:shadow-lg dark:sm:hover:bg-secondary transition ease-out duration-100"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/pricing"
|
||||||
|
class="w-auto lg:w-full p-1 flex flex-col m-auto px-2 sm:px-0"
|
||||||
|
>
|
||||||
|
<div class="w-full flex justify-between items-center p-3 mt-3">
|
||||||
|
<h2 class="text-start text-xl font-semibold sm:ml-3">
|
||||||
|
Pro Subscription
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<span class=" p-3 sm:ml-3 sm:mr-3 -mt-4">
|
||||||
|
Upgrade now for unlimited access to all data and tools.
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md h-fit pb-4 mt-4"
|
||||||
|
>
|
||||||
|
<h3 class="p-2 pt-4 text-xl font-semibold">Revenue Definition</h3>
|
||||||
|
<div class=" p-2">
|
||||||
|
Revenue, also called sales, is the amount of money a company
|
||||||
|
receives from its business activities, such as sales of products
|
||||||
|
or services. Revenue does not take any expenses into account and
|
||||||
|
is therefore different from profits.
|
||||||
|
</div>
|
||||||
|
<div class="px-2">
|
||||||
|
<a
|
||||||
|
href="/blog/article/revenue"
|
||||||
|
class="flex justify-center items-center rounded cursor-pointer w-full py-2 mt-3 text-[1rem] text-center font-semibold text-white dark:text-black m-auto sm:hover:bg-blue-600 dark:sm:hover:bg-gray-300 bg-[#3B82F6] dark:bg-[#fff] transition duration-100"
|
||||||
|
>
|
||||||
|
Full Definition
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@ -23,10 +23,27 @@ export const load = async ({ locals, params }) => {
|
|||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getHistoricalPrice = async () => {
|
||||||
|
const postData = { ticker: params.tickerID, timePeriod: "max" };
|
||||||
|
const response = await fetch(apiURL + "/historical-price", {
|
||||||
|
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
|
// Make sure to return a promise
|
||||||
return {
|
return {
|
||||||
getPriceAnalysis: await getPriceAnalysis(),
|
getPriceAnalysis: await getPriceAnalysis(),
|
||||||
|
getHistoricalPrice: await getHistoricalPrice(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { displayCompanyName, stockTicker, screenWidth } from "$lib/store";
|
import { displayCompanyName, stockTicker, screenWidth } from "$lib/store";
|
||||||
|
import { removeCompanyStrings } from "$lib/utils";
|
||||||
import Infobox from "$lib/components/Infobox.svelte";
|
import Infobox from "$lib/components/Infobox.svelte";
|
||||||
import highcharts from "$lib/highcharts.ts";
|
import highcharts from "$lib/highcharts.ts";
|
||||||
import { mode } from "mode-watcher";
|
import { mode } from "mode-watcher";
|
||||||
@ -39,160 +40,173 @@
|
|||||||
consensusRating = "Hold";
|
consensusRating = "Hold";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPieChart() {
|
function getAIScorePlot() {
|
||||||
let value;
|
// Assume data.getHistoricalPrice contains objects with a "time" field (e.g. "2015-01-02")
|
||||||
// Determine the value based on the consensus rating
|
const historicalData = data?.getHistoricalPrice || [];
|
||||||
switch (consensusRating) {
|
|
||||||
case "Strong Sell":
|
// Pre-defined backtest dates and scores
|
||||||
value = 0.5;
|
const backtestList = [
|
||||||
break;
|
{ date: "2023-03-31", yTest: 1, yPred: 1, score: 9 },
|
||||||
case "Sell":
|
{ date: "2023-06-30", yTest: 0, yPred: 1, score: 9 },
|
||||||
value = 1.5;
|
{ date: "2023-09-30", yTest: 0, yPred: 1, score: 9 },
|
||||||
break;
|
{ date: "2023-12-31", yTest: 0, yPred: 1, score: 7 },
|
||||||
case "Hold":
|
{ date: "2024-03-31", yTest: 1, yPred: 1, score: 9 },
|
||||||
value = 2.5;
|
{ date: "2024-06-30", yTest: 1, yPred: 1, score: 9 },
|
||||||
break;
|
{ date: "2024-09-30", yTest: 1, yPred: 1, score: 9 },
|
||||||
case "Buy":
|
{ date: "2024-12-31", yTest: 0, yPred: 1, score: 9 },
|
||||||
value = 3.5;
|
];
|
||||||
break;
|
|
||||||
case "Strong Buy":
|
// Append the latest historical date (using "time") if available. Note that this entry may not include a score.
|
||||||
value = 4.5;
|
if (historicalData && historicalData.length) {
|
||||||
break;
|
const latest = historicalData.at(-1);
|
||||||
default:
|
backtestList.push({ date: latest.time });
|
||||||
value = 0.5;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For each backtest entry, find the historical price with the closest available time.
|
||||||
|
// Then, if a score exists, attach a marker and data label based on the score.
|
||||||
|
const processedData = backtestList.map((item) => {
|
||||||
|
const dateStr = item.date;
|
||||||
|
const targetTime = new Date(dateStr).getTime();
|
||||||
|
let closestPoint = historicalData[0];
|
||||||
|
let minDiff = Infinity;
|
||||||
|
|
||||||
|
historicalData.forEach((point) => {
|
||||||
|
const pointTime = new Date(point.time).getTime();
|
||||||
|
const diff = Math.abs(pointTime - targetTime);
|
||||||
|
if (diff < minDiff) {
|
||||||
|
minDiff = diff;
|
||||||
|
closestPoint = point;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Base data point with x as the target date timestamp and y as the close price from the closest historical point
|
||||||
|
const dataPoint = { x: targetTime, y: closestPoint.close };
|
||||||
|
|
||||||
|
// If a score is provided, add marker configuration based on its value.
|
||||||
|
if (item.hasOwnProperty("score")) {
|
||||||
|
let markerColor, markerSymbol;
|
||||||
|
if (item.score > 6) {
|
||||||
|
// Bullish: green marker with an upward triangle
|
||||||
|
markerColor = "#2ecc71";
|
||||||
|
markerSymbol = "triangle-up";
|
||||||
|
} else if (item.score < 5) {
|
||||||
|
// Bearish: red marker with a downward triangle
|
||||||
|
markerColor = "#e74c3c";
|
||||||
|
markerSymbol = "triangle-down";
|
||||||
|
} else {
|
||||||
|
// Neutral (score exactly 5): yellow marker with a circle
|
||||||
|
markerColor = "#f1c40f";
|
||||||
|
markerSymbol = "circle";
|
||||||
|
}
|
||||||
|
|
||||||
|
dataPoint.marker = {
|
||||||
|
symbol: markerSymbol,
|
||||||
|
radius: 4,
|
||||||
|
fillColor: markerColor,
|
||||||
|
lineWidth: 2,
|
||||||
|
lineColor: $mode === "light" ? "black" : "white",
|
||||||
|
};
|
||||||
|
|
||||||
|
dataPoint.dataLabels = {
|
||||||
|
enabled: true,
|
||||||
|
format: String(item.score),
|
||||||
|
style: {
|
||||||
|
color: $mode === "light" ? "black" : "white",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "14px",
|
||||||
|
},
|
||||||
|
y: -10,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataPoint;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Highcharts options for plotting the data with markers.
|
||||||
const options = {
|
const options = {
|
||||||
|
chart: {
|
||||||
|
backgroundColor: $mode === "light" ? "#fff" : "#09090B",
|
||||||
|
height: 360,
|
||||||
|
animation: false,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: `<h3 class="mt-3 mb-1 text-[1rem] sm:text-lg">Historical AI Score Performance</h3>`,
|
||||||
|
style: {
|
||||||
|
color: $mode === "light" ? "black" : "white",
|
||||||
|
// Using inline CSS for margin-top and margin-bottom
|
||||||
|
},
|
||||||
|
useHTML: true, // Enable HTML to apply custom class styling
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
gridLineWidth: 1,
|
||||||
|
gridLineColor: $mode === "light" ? "#d1d5dc" : "#111827",
|
||||||
|
type: "datetime",
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: $mode === "light" ? "black" : "white",
|
||||||
|
},
|
||||||
|
formatter: function () {
|
||||||
|
const date = new Date(this.value);
|
||||||
|
return date.toLocaleDateString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
year: "numeric",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
title: {
|
||||||
|
text: "",
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: $mode === "light" ? "black" : "white",
|
||||||
|
},
|
||||||
|
formatter: function () {
|
||||||
|
return `$${this.value.toFixed(0)}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
gridLineWidth: 1,
|
||||||
|
gridLineColor: $mode === "light" ? "#d1d5dc" : "#111827",
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "Close Price",
|
||||||
|
data: processedData,
|
||||||
|
color: $mode === "light" ? "#007050" : "#fff",
|
||||||
|
animation: false,
|
||||||
|
marker: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
lineWidth: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
plotOptions: {
|
||||||
|
series: {
|
||||||
|
enableMouseTracking: false,
|
||||||
|
states: {
|
||||||
|
hover: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
marker: {
|
||||||
|
states: {
|
||||||
|
hover: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
legend: {
|
legend: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
credits: {
|
credits: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
chart: {
|
|
||||||
type: "gauge",
|
|
||||||
backgroundColor: $mode === "light" ? "#fff" : "#09090B",
|
|
||||||
plotBackgroundColor: $mode === "light" ? "#fff" : "#09090B",
|
|
||||||
animation: false,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
text: null,
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
min: 0,
|
|
||||||
max: 5,
|
|
||||||
tickPosition: "inside",
|
|
||||||
tickLength: 20,
|
|
||||||
tickWidth: 0,
|
|
||||||
minorTickInterval: null,
|
|
||||||
lineWidth: 0,
|
|
||||||
// Remove numeric tick labels
|
|
||||||
labels: {
|
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
plotBands: [
|
|
||||||
{
|
|
||||||
from: 0,
|
|
||||||
to: 1,
|
|
||||||
color: "#9E190A",
|
|
||||||
thickness: 40,
|
|
||||||
borderRadius: "0px",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: 1,
|
|
||||||
to: 2,
|
|
||||||
color: "#D9220E",
|
|
||||||
thickness: 40,
|
|
||||||
borderRadius: "0px",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: 2,
|
|
||||||
to: 3,
|
|
||||||
color: "#f5b700",
|
|
||||||
thickness: 40,
|
|
||||||
borderRadius: "0px",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: 3,
|
|
||||||
to: 4,
|
|
||||||
color: "#31B800",
|
|
||||||
thickness: 40,
|
|
||||||
borderRadius: "0px",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: 4,
|
|
||||||
to: 5,
|
|
||||||
color: "#008A00",
|
|
||||||
thickness: 40,
|
|
||||||
borderRadius: "0px",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
pane: {
|
|
||||||
startAngle: -90,
|
|
||||||
endAngle: 89.9,
|
|
||||||
background: null,
|
|
||||||
center: ["50%", "50%"],
|
|
||||||
size: "70%",
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: "Rating",
|
|
||||||
data: [value],
|
|
||||||
animation: false,
|
|
||||||
dataLabels: {
|
|
||||||
enabled: true,
|
|
||||||
useHTML: true,
|
|
||||||
borderWidth: 0,
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
style: {
|
|
||||||
textOutline: "none",
|
|
||||||
fontSize: "16px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
},
|
|
||||||
formatter: function () {
|
|
||||||
const rating = this.y;
|
|
||||||
let ratingText = "";
|
|
||||||
let textColor = "";
|
|
||||||
|
|
||||||
if (rating < 1) {
|
|
||||||
ratingText = "Strong Sell";
|
|
||||||
textColor = "#D9220E";
|
|
||||||
} else if (rating < 2) {
|
|
||||||
ratingText = "Sell";
|
|
||||||
textColor = "#D9220E";
|
|
||||||
} else if (rating < 3) {
|
|
||||||
ratingText = "Hold";
|
|
||||||
textColor = "#f5b700";
|
|
||||||
} else if (rating < 4) {
|
|
||||||
ratingText = "Buy";
|
|
||||||
textColor = "#31B800";
|
|
||||||
} else {
|
|
||||||
ratingText = "Strong Buy";
|
|
||||||
textColor = "#31B800";
|
|
||||||
}
|
|
||||||
|
|
||||||
// "Analyst Consensus:" in white, rating in color
|
|
||||||
return `
|
|
||||||
<span class="text-lg text-muted dark:text-white">Analyst Consensus: </span>
|
|
||||||
<span class="text-lg" style="color:${textColor};">${ratingText}</span>
|
|
||||||
`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dial: {
|
|
||||||
radius: "80%",
|
|
||||||
backgroundColor: "#2A2E39",
|
|
||||||
baseWidth: 12,
|
|
||||||
baseLength: "0%",
|
|
||||||
rearLength: "0%",
|
|
||||||
},
|
|
||||||
pivot: {
|
|
||||||
backgroundColor: "#2A2E39",
|
|
||||||
radius: 8,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
@ -457,13 +471,13 @@
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
let optionsPieChart = null;
|
|
||||||
let config = null;
|
let config = null;
|
||||||
|
let configScore = null;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($mode) {
|
if ($mode) {
|
||||||
optionsPieChart = getPieChart() || null;
|
configScore = getAIScorePlot() || null;
|
||||||
config = getPriceForecastChart() || null;
|
config = getAIScorePlot() || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -473,62 +487,48 @@
|
|||||||
description={`Discover our AI-powered forecast for ${$displayCompanyName} (${$stockTicker}). Get in-depth analyst ratings, price targets, upgrades, and downgrades from top Wall Street experts. Stay ahead of market trends and make smarter investment decisions.`}
|
description={`Discover our AI-powered forecast for ${$displayCompanyName} (${$stockTicker}). Get in-depth analyst ratings, price targets, upgrades, and downgrades from top Wall Street experts. Stay ahead of market trends and make smarter investment decisions.`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<section class="w-full overflow-hidden min-h-screen">
|
<section class="w-full overflow-hidden h-full">
|
||||||
<div class="w-full flex h-full overflow-hidden">
|
<div class="w-full flex justify-center w-full sm-auto h-full overflow-hidden">
|
||||||
<div
|
<div
|
||||||
class="w-full relative flex justify-center items-center overflow-hidden"
|
class="w-full relative flex justify-center items-center overflow-hidden"
|
||||||
>
|
>
|
||||||
<div class="sm:pl-4 sm:pt-4 w-full m-auto mt-2 sm:mt-0">
|
<main class="w-full">
|
||||||
<h1 class="mb-px text-xl sm:text-2xl font-bold bp:text-3xl sm:pl-1">
|
<div class="sm:pl-7 sm:pb-7 sm:pt-7 m-auto mt-2 sm:mt-0">
|
||||||
{$displayCompanyName} AI Forecast
|
<div class="">
|
||||||
|
<h1 class="text-xl sm:text-2xl font-bold">
|
||||||
|
{removeCompanyStrings($displayCompanyName)} Trend Forecast
|
||||||
</h1>
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if Object?.keys(data?.getPriceAnalysis)?.length > 0}
|
{#if Object?.keys(data?.getPriceAnalysis)?.length > 0}
|
||||||
<div class="w-full mb-6 mt-3">
|
<div class="w-full mb-6 mt-3">
|
||||||
<div
|
<Infobox
|
||||||
class="rounded-sm border border-gray-300 dark:border-gray-600 p-0.5 xs:p-1 md:flex md:flex-col md:space-y-4 md:divide-y md:p-4 lg:flex-row lg:space-x-4 lg:space-y-0 lg:divide-x lg:divide-y-0 divide-gray-300 dark:divide-gray-600"
|
text={`Using our AI model trained on historical data, we generated a
|
||||||
>
|
12‑month forecast for ${$displayCompanyName}
|
||||||
<div
|
(${$stockTicker}) stock. The model estimates a median target price
|
||||||
class="p-3 md:flex md:space-x-4 md:p-0 lg:block lg:max-w-[32%] lg:space-x-0"
|
of ${medianPriceTarget}—ranging from a low of {lowPriceTarget}
|
||||||
>
|
to a high of ${highPriceTarget}—which suggests ${
|
||||||
|
medianChange > 0 ? "an increase" : "a decrease"
|
||||||
|
} of ${medianChange}% compared to the current price
|
||||||
|
of ${price}.`}
|
||||||
|
/>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="flex items-baseline justify-between">
|
<div class="grow pt-5">
|
||||||
<h2 class="mb-1 text-xl font-bold">Stock Price Forecast</h2>
|
|
||||||
<span></span>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
Using our AI model trained on historical data, we generated
|
|
||||||
a 12‑month forecast for {$displayCompanyName}
|
|
||||||
({$stockTicker}) stock. The model estimates a median target
|
|
||||||
price of {medianPriceTarget}—ranging from a low of {lowPriceTarget}
|
|
||||||
to a high of {highPriceTarget}—which suggests {medianChange >
|
|
||||||
0
|
|
||||||
? "an increase"
|
|
||||||
: "a decrease"} of {medianChange}% compared to the current
|
|
||||||
price of {price}.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
class="max-h-[225px]"
|
|
||||||
use:highcharts={optionsPieChart}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="grow pt-2 md:pt-4 lg:pl-4 lg:pt-0">
|
|
||||||
<div
|
<div
|
||||||
class="chart mt-5 sm:mt-0 sm:border sm:border-gray-300 dark:border-gray-800 rounded"
|
class="chart mt-5 sm:mt-0 sm:border sm:border-gray-300 dark:border-gray-800 rounded"
|
||||||
use:highcharts={config}
|
use:highcharts={config}
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<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"
|
class="hide-scroll mb-1 mt-2 overflow-x-auto px-1.5 text-center md:mb-0 md:px-0 lg:mt-5"
|
||||||
>
|
>
|
||||||
<table class="w-full text-right text-tiny xs:text-sm">
|
<table class="w-full text-right text-tiny xs:text-sm">
|
||||||
<thead
|
<thead
|
||||||
><tr
|
><tr
|
||||||
class="border-b border-gray-300 dark:border-gray-600 font-normal text-sm sm:text-[1rem]"
|
class="border-b border-gray-300 dark:border-gray-600 font-normal text-sm sm:text-[1rem]"
|
||||||
><th class="py-[3px] text-left font-semibold lg:py-0.5"
|
><th
|
||||||
|
class="py-[3px] text-left font-semibold lg:py-0.5"
|
||||||
>Target</th
|
>Target</th
|
||||||
> <th class="font-semibold">Low</th>
|
> <th class="font-semibold">Low</th>
|
||||||
<th class="font-semibold">Average</th>
|
<th class="font-semibold">Average</th>
|
||||||
@ -541,7 +541,8 @@
|
|||||||
class="border-b border-gray-300 dark:border-gray-600 font-normal text-sm sm:text-[1rem]"
|
class="border-b border-gray-300 dark:border-gray-600 font-normal text-sm sm:text-[1rem]"
|
||||||
><td class="py-[3px] text-left lg:py-0.5">Price</td>
|
><td class="py-[3px] text-left lg:py-0.5">Price</td>
|
||||||
<td>${lowPriceTarget}</td>
|
<td>${lowPriceTarget}</td>
|
||||||
<td>${avgPriceTarget}</td> <td>${medianPriceTarget}</td>
|
<td>${avgPriceTarget}</td>
|
||||||
|
<td>${medianPriceTarget}</td>
|
||||||
<td>${highPriceTarget}</td></tr
|
<td>${highPriceTarget}</td></tr
|
||||||
>
|
>
|
||||||
<tr class="text-sm sm:text-[1rem]"
|
<tr class="text-sm sm:text-[1rem]"
|
||||||
@ -581,6 +582,7 @@
|
|||||||
<Infobox text="No AI Price Forecast available right now" />
|
<Infobox text="No AI Price Forecast available right now" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user