update dark pool page

This commit is contained in:
MuslemRahimi 2024-12-29 13:15:59 +01:00
parent a9093f7882
commit 76af2185b4
7 changed files with 1051 additions and 10 deletions

View File

@ -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>

View 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>

View File

@ -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")}

View 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(),
};
};

View 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>

View 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);
},
};

View 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>