update dark pool page
This commit is contained in:
parent
a9093f7882
commit
76af2185b4
@ -1,13 +1,163 @@
|
|||||||
<script lang 'ts'></script>
|
<script lang="ts">
|
||||||
|
import { displayCompanyName, stockTicker, etfTicker } from "$lib/store";
|
||||||
|
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||||
|
import { Chart } from "svelte-echarts";
|
||||||
|
import { abbreviateNumber, formatDateRange } from "$lib/utils";
|
||||||
|
import { init, use } from "echarts/core";
|
||||||
|
import { LineChart } from "echarts/charts";
|
||||||
|
import { GridComponent, TooltipComponent } from "echarts/components";
|
||||||
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
|
|
||||||
|
use([LineChart, GridComponent, TooltipComponent, CanvasRenderer]);
|
||||||
|
|
||||||
|
export let rawData = [];
|
||||||
|
|
||||||
|
let isLoaded = false;
|
||||||
|
let optionsData;
|
||||||
|
let avgVolume = 0;
|
||||||
|
let avgShortVolume = 0;
|
||||||
|
let monthlyVolume = "";
|
||||||
|
let avgMonthlyShort = "";
|
||||||
|
|
||||||
|
function findMonthlyValue(data, lastDateStr) {
|
||||||
|
const lastDate = new Date(lastDateStr);
|
||||||
|
const firstDate = new Date(lastDate.getFullYear(), lastDate.getMonth(), 1);
|
||||||
|
|
||||||
|
const filteredData = data.filter((item) => {
|
||||||
|
const currentDate = new Date(item?.date);
|
||||||
|
return currentDate >= firstDate && currentDate <= lastDate;
|
||||||
|
});
|
||||||
|
|
||||||
|
monthlyVolume = abbreviateNumber(
|
||||||
|
filteredData.reduce((acc, item) => acc + (item?.totalVolume || 0), 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
const totalShortPercent = filteredData.reduce(
|
||||||
|
(acc, item) => acc + (item?.shortPercent || 0),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
avgMonthlyShort =
|
||||||
|
(totalShortPercent / filteredData.length)?.toFixed(2) || "0.00";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPlotOptions() {
|
||||||
|
const dates = rawData.map((item) => item?.date);
|
||||||
|
const totalVolumeList = rawData.map((item) => item?.totalVolume || 0);
|
||||||
|
const shortVolumeList = rawData.map((item) => item?.shortVolume || 0);
|
||||||
|
|
||||||
|
findMonthlyValue(rawData, rawData.at(-1)?.date);
|
||||||
|
|
||||||
|
avgVolume =
|
||||||
|
totalVolumeList.reduce((acc, val) => acc + val, 0) /
|
||||||
|
totalVolumeList.length || 0;
|
||||||
|
avgShortVolume =
|
||||||
|
shortVolumeList.reduce((acc, val) => acc + val, 0) /
|
||||||
|
shortVolumeList.length || 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
silent: true,
|
||||||
|
tooltip: {
|
||||||
|
trigger: "axis",
|
||||||
|
hideDelay: 100,
|
||||||
|
borderColor: "#969696", // Black border color
|
||||||
|
borderWidth: 1, // Border width of 1px
|
||||||
|
backgroundColor: "#313131", // Optional: Set background color for contrast
|
||||||
|
textStyle: {
|
||||||
|
color: "#fff", // Optional: Text color for better visibility
|
||||||
|
},
|
||||||
|
formatter: function (params) {
|
||||||
|
// Get the timestamp from the first parameter
|
||||||
|
const timestamp = params[0].axisValue;
|
||||||
|
|
||||||
|
// Initialize result with timestamp
|
||||||
|
let result = timestamp + "<br/>";
|
||||||
|
|
||||||
|
// Sort params to ensure Vol appears last
|
||||||
|
params.sort((a, b) => {
|
||||||
|
if (a.seriesName === "Vol") return 1;
|
||||||
|
if (b.seriesName === "Vol") return -1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add each series data
|
||||||
|
params?.forEach((param) => {
|
||||||
|
const marker =
|
||||||
|
'<span style="display:inline-block;margin-right:4px;' +
|
||||||
|
"border-radius:10px;width:10px;height:10px;background-color:" +
|
||||||
|
param.color +
|
||||||
|
'"></span>';
|
||||||
|
result +=
|
||||||
|
marker +
|
||||||
|
param.seriesName +
|
||||||
|
": " +
|
||||||
|
abbreviateNumber(param.value) +
|
||||||
|
"<br/>";
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
axisPointer: {
|
||||||
|
lineStyle: {
|
||||||
|
color: "#fff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
animation: false,
|
||||||
|
grid: {
|
||||||
|
left: "3%",
|
||||||
|
right: "3%",
|
||||||
|
bottom: "2%",
|
||||||
|
top: "5%",
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: "category",
|
||||||
|
boundaryGap: false,
|
||||||
|
data: dates,
|
||||||
|
axisLabel: { color: "#fff" },
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: "value",
|
||||||
|
splitLine: { show: false },
|
||||||
|
axisLabel: { show: false },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "Total Volume",
|
||||||
|
data: totalVolumeList,
|
||||||
|
type: "line",
|
||||||
|
itemStyle: { color: "#fff" },
|
||||||
|
showSymbol: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Short Volume",
|
||||||
|
data: shortVolumeList,
|
||||||
|
type: "line",
|
||||||
|
areaStyle: { opacity: 1 },
|
||||||
|
itemStyle: { color: "#E11D48" },
|
||||||
|
showSymbol: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (typeof window !== "undefined" && ($stockTicker || $etfTicker)) {
|
||||||
|
isLoaded = false;
|
||||||
|
optionsData = getPlotOptions();
|
||||||
|
isLoaded = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<section class="overflow-hidden text-white h-full pb-8">
|
<section class="overflow-hidden text-white h-full pb-8">
|
||||||
<main class="overflow-hidden">
|
<main class="overflow-hidden">
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<label
|
<label
|
||||||
for="darkPoolInfo"
|
for="darkPoolInfo"
|
||||||
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold"
|
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-2xl font-bold"
|
||||||
>
|
>
|
||||||
Dark Pool Activity
|
Historical Activity
|
||||||
</label>
|
</label>
|
||||||
<InfoModal
|
<InfoModal
|
||||||
title={"Dark Pool Data"}
|
title={"Dark Pool Data"}
|
||||||
@ -85,7 +235,7 @@
|
|||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="flex justify-start items-center w-full m-auto">
|
<div class="flex justify-start items-center w-full m-auto">
|
||||||
<table class="w-full" data-test="statistics-table">
|
<table class="w-full bg-table border border-gray-800">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="border-y border-gray-800 odd:bg-odd">
|
<tr class="border-y border-gray-800 odd:bg-odd">
|
||||||
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
||||||
@ -97,9 +247,7 @@
|
|||||||
{formatDateRange(rawData?.slice(-1)?.at(0)?.date)}
|
{formatDateRange(rawData?.slice(-1)?.at(0)?.date)}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr
|
<tr class="border-y border-gray-800 whitespace-nowrap odd:bg-odd">
|
||||||
class="border-y border-gray-800 whitespace-nowrap odd:bg-odd"
|
|
||||||
>
|
|
||||||
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
||||||
<span>Total Volume</span>
|
<span>Total Volume</span>
|
||||||
</td>
|
</td>
|
||||||
@ -109,9 +257,7 @@
|
|||||||
{monthlyVolume}
|
{monthlyVolume}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr
|
<tr class="border-y border-gray-800 whitespace-nowrap odd:bg-odd">
|
||||||
class="border-y border-gray-800 whitespace-nowrap odd:bg-odd"
|
|
||||||
>
|
|
||||||
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
||||||
<span>Avg. Short % of Volume</span>
|
<span>Avg. Short % of Volume</span>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
270
src/lib/components/DarkPoolLevel.svelte
Normal file
270
src/lib/components/DarkPoolLevel.svelte
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { stockTicker, etfTicker } from "$lib/store";
|
||||||
|
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||||
|
import { Chart } from "svelte-echarts";
|
||||||
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
|
import { init, use } from "echarts/core";
|
||||||
|
import { BarChart } from "echarts/charts";
|
||||||
|
import { GridComponent, TooltipComponent } from "echarts/components";
|
||||||
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
|
|
||||||
|
let category = "Volume";
|
||||||
|
|
||||||
|
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer]);
|
||||||
|
|
||||||
|
export let rawData = [
|
||||||
|
{ price_level: 31.78, volume: 48562602.0, size: 31490, premium: 1000746.8 },
|
||||||
|
{
|
||||||
|
price_level: 31.67,
|
||||||
|
volume: 46661214.0,
|
||||||
|
size: 28400,
|
||||||
|
premium: 899429.8400000001,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price_level: 31.7,
|
||||||
|
volume: 29795872.0,
|
||||||
|
size: 22798,
|
||||||
|
premium: 722699.5586,
|
||||||
|
},
|
||||||
|
{ price_level: 31.65, volume: 28530280.0, size: 22000, premium: 696289.0 },
|
||||||
|
{ price_level: 31.2, volume: 26279878.0, size: 30516, premium: 952028.3 },
|
||||||
|
{ price_level: 31.24, volume: 19203098.0, size: 27600, premium: 862246.1 },
|
||||||
|
];
|
||||||
|
|
||||||
|
let isLoaded = false;
|
||||||
|
let optionsData;
|
||||||
|
|
||||||
|
function getPlotOptions() {
|
||||||
|
const xAxis = rawData.map((item) => item?.volume); // Convert volume to millions for clarity
|
||||||
|
const yAxis = rawData.map((item) => item?.price_level || 0);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
silent: true,
|
||||||
|
tooltip: {
|
||||||
|
trigger: "axis",
|
||||||
|
hideDelay: 100,
|
||||||
|
borderColor: "#969696",
|
||||||
|
borderWidth: 1,
|
||||||
|
backgroundColor: "#313131",
|
||||||
|
textStyle: {
|
||||||
|
color: "#fff",
|
||||||
|
},
|
||||||
|
formatter: function (params) {
|
||||||
|
const priceLevel = params[0].axisValue;
|
||||||
|
|
||||||
|
let result = `Price Level: ${priceLevel}<br/>`;
|
||||||
|
|
||||||
|
params?.forEach((param) => {
|
||||||
|
const marker =
|
||||||
|
'<span style="display:inline-block;margin-right:4px;' +
|
||||||
|
"border-radius:10px;width:10px;height:10px;background-color:" +
|
||||||
|
param.color +
|
||||||
|
'"></span>';
|
||||||
|
result += `${marker}${param.seriesName}: ${param.value} M<br/>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
axisPointer: {
|
||||||
|
lineStyle: {
|
||||||
|
color: "#fff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
animation: false,
|
||||||
|
grid: {
|
||||||
|
left: "0%", // Adjust to create space for y-axis labels
|
||||||
|
right: "10%",
|
||||||
|
bottom: "5%",
|
||||||
|
top: "5%",
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: "value",
|
||||||
|
name: "",
|
||||||
|
nameTextStyle: { color: "#fff" },
|
||||||
|
splitLine: { show: false },
|
||||||
|
axisLabel: {
|
||||||
|
color: "#fff",
|
||||||
|
interval: 0, // Show all labels
|
||||||
|
rotate: 45, // Rotate labels for better readability
|
||||||
|
fontSize: 12, // Adjust font size if needed
|
||||||
|
margin: 10,
|
||||||
|
formatter: function (value) {
|
||||||
|
return abbreviateNumber(value); // Call your abbreviateNumber function
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: "category",
|
||||||
|
name: "Price Level",
|
||||||
|
nameTextStyle: { color: "#fff" },
|
||||||
|
data: yAxis,
|
||||||
|
axisLabel: { color: "#fff" },
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "Total Volume",
|
||||||
|
data: xAxis,
|
||||||
|
type: "bar",
|
||||||
|
itemStyle: {
|
||||||
|
color: (params) => {
|
||||||
|
// Highlight a specific bar (e.g., the maximum volume)
|
||||||
|
const maxVolumeIndex = xAxis.indexOf(Math.max(...xAxis));
|
||||||
|
return params.dataIndex === maxVolumeIndex
|
||||||
|
? "#3BA272"
|
||||||
|
: "#e2e8f0"; // Green for highlight, blue for others
|
||||||
|
},
|
||||||
|
},
|
||||||
|
showSymbol: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (typeof window !== "undefined" && ($stockTicker || $etfTicker)) {
|
||||||
|
isLoaded = false;
|
||||||
|
optionsData = getPlotOptions();
|
||||||
|
isLoaded = true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="overflow-hidden text-white h-full pb-8">
|
||||||
|
<main class="overflow-hidden">
|
||||||
|
<div class="flex flex-row items-center">
|
||||||
|
<label
|
||||||
|
for="darkPoolLevel"
|
||||||
|
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-2xl font-bold"
|
||||||
|
>
|
||||||
|
Price Level
|
||||||
|
</label>
|
||||||
|
<InfoModal
|
||||||
|
title={"Dark Pool Price Level"}
|
||||||
|
content={"Dark pool data refers to information on trading activities that occur in private, non-public financial exchanges known as dark pools. These venues are used by hedge funds and major institutional traders to buy and sell large blocks of securities without exposing their orders to the public, minimizing market impact and price fluctuations. Currently, nearly 50% of all trades are executed in these dark pools, highlighting their significant role in the trading landscape."}
|
||||||
|
id={"darkPoolLevel"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if isLoaded}
|
||||||
|
{#if rawData?.length !== 0}
|
||||||
|
<!--
|
||||||
|
<div class="w-full flex flex-col items-start">
|
||||||
|
<div class="text-white text-[1rem] mt-2 mb-2 w-full">
|
||||||
|
Over the past 12 months, {$displayCompanyName} has experienced an average
|
||||||
|
dark pool trading volume of
|
||||||
|
<span class="font-semibold">{abbreviateNumber(avgVolume)}</span>
|
||||||
|
shares. Out of this total, an average of
|
||||||
|
<span class="font-semibold">{abbreviateNumber(avgShortVolume)}</span
|
||||||
|
>
|
||||||
|
shares, constituting approximately
|
||||||
|
<span class="font-semibold"
|
||||||
|
>{((avgShortVolume / avgVolume) * 100)?.toFixed(2)}%</span
|
||||||
|
>, were short volume.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
<div class="w-full flex flex-col items-start">
|
||||||
|
Over the past 12 months, GameStop Corp. has experienced an average
|
||||||
|
dark pool trading volume of 8.55M shares. Out of this total, an
|
||||||
|
average of 3.81M shares, constituting approximately 44.52%, were short
|
||||||
|
volume.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pb-2 rounded-md bg-default">
|
||||||
|
<div class="app w-full h-[300px] mt-5 relative">
|
||||||
|
<div
|
||||||
|
class="flex justify-start space-x-2 absolute right-0 top-0 z-10 text-sm"
|
||||||
|
>
|
||||||
|
{#each ["Volume", "Size", "Premium"] as item}
|
||||||
|
<label
|
||||||
|
on:click={() => (category = item)}
|
||||||
|
class="px-4 py-2 {category === item
|
||||||
|
? 'bg-white text-black shadow-xl'
|
||||||
|
: 'text-white bg-table text-opacity-[0.6]'} transition ease-out duration-100 sm:hover:bg-white sm:hover:text-black rounded-md cursor-pointer"
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</label>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Chart {init} options={optionsData} class="chart" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<h2
|
||||||
|
class="mt-10 mr-1 flex flex-row items-center text-white text-xl sm:text-2xl font-bold mb-3"
|
||||||
|
>
|
||||||
|
Latest Information
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="flex justify-start items-center w-full m-auto">
|
||||||
|
<table class="w-full bg-table border border-gray-800">
|
||||||
|
<tbody>
|
||||||
|
<tr class="border-y border-gray-800 odd:bg-odd">
|
||||||
|
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
||||||
|
<span>Date</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-sm sm:text-[1rem] px-[5px] py-1.5 whitespace-nowrap text-right font-medium xs:px-2.5 xs:py-2"
|
||||||
|
>
|
||||||
|
{formatDateRange(rawData?.slice(-1)?.at(0)?.date)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="border-y border-gray-800 whitespace-nowrap odd:bg-odd">
|
||||||
|
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
||||||
|
<span>Total Volume</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="px-[5px] py-1.5 text-right font-medium xs:px-2.5 xs:py-2"
|
||||||
|
>
|
||||||
|
{monthlyVolume}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="border-y border-gray-800 whitespace-nowrap odd:bg-odd">
|
||||||
|
<td class="px-[5px] py-1.5 xs:px-2.5 xs:py-2">
|
||||||
|
<span>Avg. Short % of Volume</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="px-[5px] py-1.5 text-right font-medium xs:px-2.5 xs:py-2"
|
||||||
|
>
|
||||||
|
{avgMonthlyShort}%
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<div class="flex justify-center items-center h-80">
|
||||||
|
<div class="relative">
|
||||||
|
<label
|
||||||
|
class="bg-secondary rounded-md h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
||||||
|
>
|
||||||
|
<span class="loading loading-spinner loading-md text-gray-400"
|
||||||
|
></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</main>
|
||||||
|
</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>
|
||||||
@ -70,6 +70,7 @@
|
|||||||
const sectionMap = {
|
const sectionMap = {
|
||||||
insider: "/insider",
|
insider: "/insider",
|
||||||
options: "/options",
|
options: "/options",
|
||||||
|
"dark-pool": "/dark-pool",
|
||||||
dividends: "/dividends",
|
dividends: "/dividends",
|
||||||
statistics: "/statistics",
|
statistics: "/statistics",
|
||||||
metrics: "metrics",
|
metrics: "metrics",
|
||||||
@ -349,6 +350,7 @@
|
|||||||
statistics: "statistics",
|
statistics: "statistics",
|
||||||
financials: "financials",
|
financials: "financials",
|
||||||
options: "options",
|
options: "options",
|
||||||
|
"dark-pool": "dark-pool",
|
||||||
metrics: "metrics",
|
metrics: "metrics",
|
||||||
insider: "insider",
|
insider: "insider",
|
||||||
dividends: "dividends",
|
dividends: "dividends",
|
||||||
@ -938,6 +940,16 @@
|
|||||||
>
|
>
|
||||||
Options
|
Options
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}/dark-pool`}
|
||||||
|
on:click={() => changeSection("dark-pool")}
|
||||||
|
class="p-2 px-5 cursor-pointer {displaySection ===
|
||||||
|
'dark-pool'
|
||||||
|
? 'text-white bg-secondary sm:hover:bg-opacity-[0.95] font-semibold'
|
||||||
|
: 'text-gray-400 sm:hover:text-white sm:hover:bg-secondary sm:hover:bg-opacity-[0.95]'}"
|
||||||
|
>
|
||||||
|
Dark Pool
|
||||||
|
</a>
|
||||||
<a
|
<a
|
||||||
href={`/stocks/${$stockTicker}/insider`}
|
href={`/stocks/${$stockTicker}/insider`}
|
||||||
on:click={() => changeSection("insider")}
|
on:click={() => changeSection("insider")}
|
||||||
|
|||||||
28
src/routes/stocks/[tickerID]/dark-pool/+layout.server.ts
Normal file
28
src/routes/stocks/[tickerID]/dark-pool/+layout.server.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
export const load = async ({ locals, params }) => {
|
||||||
|
|
||||||
|
const getSimilarStocks = async () => {
|
||||||
|
const { apiKey, apiURL } = locals;
|
||||||
|
const postData = {
|
||||||
|
ticker: params.tickerID,
|
||||||
|
};
|
||||||
|
|
||||||
|
// make the POST request to the endpoint
|
||||||
|
const response = await fetch(apiURL + "/similar-stocks", {
|
||||||
|
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 {
|
||||||
|
getSimilarStocks: await getSimilarStocks(),
|
||||||
|
};
|
||||||
|
};
|
||||||
61
src/routes/stocks/[tickerID]/dark-pool/+layout.svelte
Normal file
61
src/routes/stocks/[tickerID]/dark-pool/+layout.svelte
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
||||||
|
import { stockTicker } from "$lib/store";
|
||||||
|
export let data;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="w-auto overflow-hidden min-h-screen">
|
||||||
|
<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 justify-center items-start overflow-hidden w-full"
|
||||||
|
>
|
||||||
|
<main class="w-full lg:w-3/4">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<aside class="hidden lg:block relative fixed w-1/4 ml-4">
|
||||||
|
{#if data?.user?.tier !== "Pro" || data?.user?.freeTrial}
|
||||||
|
<div
|
||||||
|
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer bg-primary 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 text-white ml-3">
|
||||||
|
Pro Subscription
|
||||||
|
</h2>
|
||||||
|
<ArrowLogo class="w-8 h-8 mr-3 flex-shrink-0" />
|
||||||
|
</div>
|
||||||
|
<span class="text-white p-3 ml-3 mr-3">
|
||||||
|
Upgrade now for unlimited access to all data and tools.
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="w-full text-white border border-gray-600 rounded-md h-fit pb-4 mt-4 cursor-pointer bg-primary sm:hover:bg-secondary transition ease-out duration-100"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={`/dark-pool-flow?query=${$stockTicker}`}
|
||||||
|
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 text-white ml-3">
|
||||||
|
Dark Pool Flow
|
||||||
|
</h2>
|
||||||
|
<ArrowLogo class="w-8 h-8 mr-3 flex-shrink-0" />
|
||||||
|
</div>
|
||||||
|
<span class="text-white p-3 ml-3 mr-3">
|
||||||
|
Follow the dark pool feed in realtime
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
206
src/routes/stocks/[tickerID]/dark-pool/+page.server.ts
Normal file
206
src/routes/stocks/[tickerID]/dark-pool/+page.server.ts
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
import { error, fail, redirect } from "@sveltejs/kit";
|
||||||
|
import { validateData } from "$lib/utils";
|
||||||
|
import { loginUserSchema, registerUserSchema } from "$lib/schemas";
|
||||||
|
|
||||||
|
|
||||||
|
export const load = async ({ params, locals }) => {
|
||||||
|
const { apiURL, apiKey } = locals;
|
||||||
|
|
||||||
|
const postData = {
|
||||||
|
ticker: params.tickerID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStockDividend = async () => {
|
||||||
|
|
||||||
|
|
||||||
|
const response = await fetch(apiURL + "/stock-dividend", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": apiKey,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData),
|
||||||
|
});
|
||||||
|
|
||||||
|
const output = await response.json();
|
||||||
|
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getHistoricalDarkPool = async () => {
|
||||||
|
|
||||||
|
|
||||||
|
// make the POST request to the endpoint
|
||||||
|
const response = await fetch(apiURL + "/historical-dark-pool", {
|
||||||
|
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 {
|
||||||
|
getStockDividend: await getStockDividend(),
|
||||||
|
getHistoricalDarkPool: await getHistoricalDarkPool(),
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
login: async ({ url, request, locals }) => {
|
||||||
|
|
||||||
|
const path = url?.href?.replace("/oauth2","")
|
||||||
|
|
||||||
|
const { formData, errors } = await validateData(
|
||||||
|
await request.formData(),
|
||||||
|
loginUserSchema,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (errors) {
|
||||||
|
return fail(400, {
|
||||||
|
data: formData,
|
||||||
|
errors: errors.fieldErrors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await locals.pb
|
||||||
|
.collection("users")
|
||||||
|
.authWithPassword(formData.email, formData.password);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (!locals.pb?.authStore?.model?.verified) {
|
||||||
|
locals.pb.authStore.clear();
|
||||||
|
return {
|
||||||
|
notVerified: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Error: ", err);
|
||||||
|
error(err.status, err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect(302, path);
|
||||||
|
},
|
||||||
|
|
||||||
|
register: async ({ url, locals, request }) => {
|
||||||
|
const path = url?.href?.replace("/oauth2","")
|
||||||
|
|
||||||
|
const { formData, errors } = await validateData(
|
||||||
|
await request.formData(),
|
||||||
|
registerUserSchema,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (errors) {
|
||||||
|
return fail(400, {
|
||||||
|
data: formData,
|
||||||
|
errors: errors.fieldErrors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let newUser = await locals.pb.collection("users").create(formData);
|
||||||
|
/*
|
||||||
|
await locals.pb?.collection('users').update(
|
||||||
|
newUser?.id, {
|
||||||
|
'freeTrial' : true,
|
||||||
|
'tier': 'Pro', //Give new users a free trial for the Pro Subscription
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
await locals.pb.collection("users")?.requestVerification(formData.email);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Error: ", err);
|
||||||
|
error(err.status, err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await locals.pb
|
||||||
|
.collection("users")
|
||||||
|
.authWithPassword(formData.email, formData.password);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Error: ", err);
|
||||||
|
error(err.status, err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect(303, path);
|
||||||
|
},
|
||||||
|
|
||||||
|
oauth2: async ({ url, locals, request, cookies }) => {
|
||||||
|
|
||||||
|
const path = url?.href?.replace("/oauth2","")
|
||||||
|
const authMethods = (await locals?.pb
|
||||||
|
?.collection("users")
|
||||||
|
?.listAuthMethods())?.oauth2;
|
||||||
|
|
||||||
|
|
||||||
|
const data = await request?.formData();
|
||||||
|
const providerSelected = data?.get("provider");
|
||||||
|
|
||||||
|
if (!authMethods) {
|
||||||
|
return {
|
||||||
|
authProviderRedirect: "",
|
||||||
|
authProviderState: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const redirectURL = `${url.origin}/oauth`;
|
||||||
|
|
||||||
|
const targetItem = authMethods?.providers?.findIndex(
|
||||||
|
(item) => item?.name === providerSelected,
|
||||||
|
);
|
||||||
|
//console.log("==================")
|
||||||
|
//console.log(authMethods.authProviders)
|
||||||
|
//console.log('target item is: ', targetItem)
|
||||||
|
|
||||||
|
const provider = authMethods.providers[targetItem];
|
||||||
|
const authProviderRedirect = `${provider.authUrl}${redirectURL}`;
|
||||||
|
const state = provider.state;
|
||||||
|
const verifier = provider.codeVerifier;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cookies.set("state", state, {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: "lax",
|
||||||
|
secure: true,
|
||||||
|
path: "/",
|
||||||
|
maxAge: 60 * 60,
|
||||||
|
});
|
||||||
|
|
||||||
|
cookies.set("verifier", verifier, {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: "lax",
|
||||||
|
secure: true,
|
||||||
|
path: "/",
|
||||||
|
maxAge: 60 * 60,
|
||||||
|
});
|
||||||
|
|
||||||
|
cookies.set("provider", providerSelected, {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: "lax",
|
||||||
|
secure: true,
|
||||||
|
path: "/",
|
||||||
|
maxAge: 60 * 60,
|
||||||
|
});
|
||||||
|
|
||||||
|
cookies.set("path", path, {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: "lax",
|
||||||
|
secure: true,
|
||||||
|
path: "/",
|
||||||
|
maxAge: 60,
|
||||||
|
});
|
||||||
|
|
||||||
|
redirect(302, authProviderRedirect);
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
318
src/routes/stocks/[tickerID]/dark-pool/+page.svelte
Normal file
318
src/routes/stocks/[tickerID]/dark-pool/+page.svelte
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
numberOfUnreadNotification,
|
||||||
|
displayCompanyName,
|
||||||
|
stockTicker,
|
||||||
|
} from "$lib/store";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { monthNames } from "$lib/utils";
|
||||||
|
import DarkPool from "$lib/components/DarkPool.svelte";
|
||||||
|
import DarkPoolLevel from "$lib/components/DarkPoolLevel.svelte";
|
||||||
|
|
||||||
|
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||||
|
import { Chart } from "svelte-echarts";
|
||||||
|
import { init, use } from "echarts/core";
|
||||||
|
import { LineChart, BarChart } from "echarts/charts";
|
||||||
|
import { GridComponent, TooltipComponent } from "echarts/components";
|
||||||
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
|
import Infobox from "$lib/components/Infobox.svelte";
|
||||||
|
use([LineChart, BarChart, TooltipComponent, GridComponent, CanvasRenderer]);
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
let isLoaded = false;
|
||||||
|
let dateDistance;
|
||||||
|
let rawData = data?.getStockDividend;
|
||||||
|
let historicalDarkPool = data?.getHistoricalDarkPool || [];
|
||||||
|
|
||||||
|
let optionsDividend;
|
||||||
|
|
||||||
|
async function plotDividend() {
|
||||||
|
// Combine the data into an array of objects to keep them linked
|
||||||
|
const combinedData = rawData?.history?.map((item) => ({
|
||||||
|
date: item?.paymentDate,
|
||||||
|
dividend: item?.adjDividend?.toFixed(3),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Sort the combined data array based on the date
|
||||||
|
combinedData.sort((a, b) => new Date(a?.date) - new Date(b?.date));
|
||||||
|
|
||||||
|
// Separate the sorted data back into individual arrays
|
||||||
|
const dates = combinedData.map((item) => item.date);
|
||||||
|
const dividendList = combinedData?.map((item) => item.dividend);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
animation: false,
|
||||||
|
grid: {
|
||||||
|
left: "3%",
|
||||||
|
right: "3%",
|
||||||
|
bottom: "10%",
|
||||||
|
top: "10%",
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: "category",
|
||||||
|
boundaryGap: false,
|
||||||
|
data: dates,
|
||||||
|
axisLabel: {
|
||||||
|
color: "#fff",
|
||||||
|
formatter: function (value) {
|
||||||
|
// Assuming dates are in the format 'yyyy-mm-dd'
|
||||||
|
// Extract the month and day from the date string and convert the month to its abbreviated name
|
||||||
|
const dateParts = value.split("-");
|
||||||
|
const year = dateParts[0].substring(2); // Extracting the last two digits of the year
|
||||||
|
const monthIndex = parseInt(dateParts[1]) - 1; // Months are zero-indexed in JavaScript Date objects
|
||||||
|
return `${monthNames[monthIndex]} '${year} `;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: "value",
|
||||||
|
splitLine: {
|
||||||
|
show: false, // Disable x-axis grid lines
|
||||||
|
},
|
||||||
|
|
||||||
|
axisLabel: {
|
||||||
|
show: false, // Hide y-axis labels
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "Dividend per Share",
|
||||||
|
data: dividendList,
|
||||||
|
type: "bar",
|
||||||
|
smooth: true,
|
||||||
|
itemStyle: {
|
||||||
|
color: "#fff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
trigger: "axis",
|
||||||
|
hideDelay: 100,
|
||||||
|
borderColor: "#969696", // Black border color
|
||||||
|
borderWidth: 1, // Border width of 1px
|
||||||
|
backgroundColor: "#313131", // Optional: Set background color for contrast
|
||||||
|
textStyle: {
|
||||||
|
color: "#fff", // Optional: Text color for better visibility
|
||||||
|
},
|
||||||
|
formatter: function (params) {
|
||||||
|
const date = params[0].name; // Get the date from the x-axis value
|
||||||
|
const dateParts = date.split("-");
|
||||||
|
const year = dateParts[0];
|
||||||
|
const monthIndex = parseInt(dateParts[1]) - 1;
|
||||||
|
const day = dateParts[2];
|
||||||
|
const formattedDate = `${monthNames[monthIndex]} ${day}, ${year}`;
|
||||||
|
|
||||||
|
// Return the tooltip content
|
||||||
|
return `${formattedDate}<br/> Dividend Per Share: ${params[0].value}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
optionsDividend = await plotDividend();
|
||||||
|
isLoaded = true;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>
|
||||||
|
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""}
|
||||||
|
{$displayCompanyName} ({$stockTicker}) Dividend History, Dates & Yield ·
|
||||||
|
stocknear
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content={`Get the latest dividend data for ${$displayCompanyName} (${$stockTicker}) stock price quote with breaking news, financials, statistics, charts and more.`}
|
||||||
|
/>
|
||||||
|
<!-- Other meta tags -->
|
||||||
|
<meta
|
||||||
|
property="og:title"
|
||||||
|
content={`${$displayCompanyName} (${$stockTicker}) Dividend History, Dates & Yield · Stocknear`}
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content={`Get the latest dividend data for ${$displayCompanyName} (${$stockTicker}), including dividend history, yield, key dates, growth and other metrics.`}
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<!-- Add more Open Graph meta tags as needed -->
|
||||||
|
|
||||||
|
<!-- Twitter specific meta tags -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta
|
||||||
|
name="twitter:title"
|
||||||
|
content={`${$displayCompanyName} (${$stockTicker}) Dividend History, Dates & Yield · Stocknear`}
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
name="twitter:description"
|
||||||
|
content={`Get the latest dividend data for ${$displayCompanyName} (${$stockTicker}) stock price quote with breaking news, financials, statistics, charts and more.`}
|
||||||
|
/>
|
||||||
|
<!-- Add more Twitter meta tags as needed -->
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<section class="w-full bg-default overflow-hidden text-white h-full">
|
||||||
|
<div class="w-full flex h-full overflow-hidden">
|
||||||
|
<div
|
||||||
|
class="w-full relative flex justify-center items-center overflow-hidden"
|
||||||
|
>
|
||||||
|
<div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
|
||||||
|
<div class="w-full mb-6">
|
||||||
|
<h1 class="text-xl sm:text-2xl text-white font-bold mb-4 w-full">
|
||||||
|
Dark Pool
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DarkPoolLevel />
|
||||||
|
<DarkPool rawData={historicalDarkPool} />
|
||||||
|
{#if rawData?.history?.length !== 0}
|
||||||
|
<div
|
||||||
|
class="flex flex-col sm:flex-row items-start sm:items-center w-full mt-14 mb-8"
|
||||||
|
>
|
||||||
|
<h3 class="text-xl text-white font-semibold">Dividends History</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if isLoaded}
|
||||||
|
{#if rawData?.history?.length !== 0 && optionsDividend}
|
||||||
|
<div class="app w-full">
|
||||||
|
<Chart {init} options={optionsDividend} class="chart" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="overflow-x-scroll no-scrollbar flex justify-start items-center w-full m-auto rounded-none sm:rounded-md mb-4"
|
||||||
|
>
|
||||||
|
<table
|
||||||
|
class="table table-sm table-compact flex justify-start items-center w-full m-auto"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-default border-b border-gray-800">
|
||||||
|
<th
|
||||||
|
class="text-start bg-default text-white text-sm font-semibold"
|
||||||
|
>
|
||||||
|
Ex-Divid. Date
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="text-end bg-default text-white text-sm font-semibold"
|
||||||
|
>
|
||||||
|
Cash Amount
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="text-end bg-default text-white text-sm font-semibold"
|
||||||
|
>
|
||||||
|
Record Date
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="text-end bg-default text-white text-sm font-semibold"
|
||||||
|
>
|
||||||
|
Pay Date
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="">
|
||||||
|
{#each rawData?.history as item}
|
||||||
|
<tr
|
||||||
|
class="text-white odd:bg-odd border-b border-gray-800"
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
class="text-start text-sm sm:text-[1rem] whitespace-nowrap text-white font-medium"
|
||||||
|
>
|
||||||
|
{new Date(item?.date)?.toLocaleString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
daySuffix: "2-digit",
|
||||||
|
})}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white"
|
||||||
|
>
|
||||||
|
{item?.adjDividend?.toFixed(3)}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white"
|
||||||
|
>
|
||||||
|
{item?.recordDate?.length !== 0
|
||||||
|
? new Date(item?.recordDate)?.toLocaleString(
|
||||||
|
"en-US",
|
||||||
|
{
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
daySuffix: "2-digit",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: "n/a"}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white"
|
||||||
|
>
|
||||||
|
{item?.paymentDate?.length !== 0
|
||||||
|
? new Date(item?.paymentDate)?.toLocaleString(
|
||||||
|
"en-US",
|
||||||
|
{
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
daySuffix: "2-digit",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: "n/a"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<span class="text-white text-sm italic">
|
||||||
|
* Dividend amounts are adjusted for stock splits when
|
||||||
|
applicable.
|
||||||
|
</span>
|
||||||
|
{:else}
|
||||||
|
<h1
|
||||||
|
class="text-xl m-auto flex justify-center text-white mb-4 mt-10"
|
||||||
|
>
|
||||||
|
No history found
|
||||||
|
</h1>
|
||||||
|
{/if}
|
||||||
|
{:else}
|
||||||
|
<div class="flex justify-center items-center h-80">
|
||||||
|
<div class="relative">
|
||||||
|
<label
|
||||||
|
class="bg-secondary rounded-md h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
||||||
|
>
|
||||||
|
<span class="loading loading-spinner loading-md text-gray-400"
|
||||||
|
></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.app {
|
||||||
|
height: 400px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.app {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user