update dark pool page
This commit is contained in:
parent
76af2185b4
commit
797be0b88b
@ -154,15 +154,15 @@
|
||||
<main class="overflow-hidden">
|
||||
<div class="flex flex-row items-center">
|
||||
<label
|
||||
for="darkPoolInfo"
|
||||
for="historicalDataInfo"
|
||||
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-2xl font-bold"
|
||||
>
|
||||
Historical Activity
|
||||
</label>
|
||||
<InfoModal
|
||||
title={"Dark Pool Data"}
|
||||
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={"darkPoolInfo"}
|
||||
title={"Historical Data"}
|
||||
content={"By analyzing historical dark pool activity, retail investors can gauge market sentiment through total and short volumes. High short volume may indicate bearish sentiment."}
|
||||
id={"historicalDataInfo"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
282
src/lib/components/DarkPool/HottestTrades.svelte
Normal file
282
src/lib/components/DarkPool/HottestTrades.svelte
Normal file
@ -0,0 +1,282 @@
|
||||
<script lang="ts">
|
||||
import { stockTicker, etfTicker } from "$lib/store";
|
||||
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||
import TableHeader from "$lib/components/Table/TableHeader.svelte";
|
||||
|
||||
import { abbreviateNumberWithColor } from "$lib/utils";
|
||||
|
||||
export let rawData = [
|
||||
{
|
||||
date: "2024-12-27T17:52:33Z",
|
||||
price: 31.89,
|
||||
size: 14526,
|
||||
volume: 6937280.0,
|
||||
premium: "463232.6874",
|
||||
sizeVolRatio: 0.21,
|
||||
sizeAvgVolRatio: 0.14,
|
||||
trackingID: 46353769264496,
|
||||
rank: 1,
|
||||
},
|
||||
{
|
||||
date: "2024-12-27T17:52:33Z",
|
||||
price: 31.89,
|
||||
size: 14526,
|
||||
volume: 6937280.0,
|
||||
premium: "463232.6874",
|
||||
sizeVolRatio: 0.21,
|
||||
sizeAvgVolRatio: 0.14,
|
||||
trackingID: 46353769264496,
|
||||
rank: 2,
|
||||
},
|
||||
{
|
||||
date: "2024-12-27T18:03:31Z",
|
||||
price: 32.0,
|
||||
size: 12198,
|
||||
volume: 7146904.0,
|
||||
premium: "390336",
|
||||
sizeVolRatio: 0.17,
|
||||
sizeAvgVolRatio: 0.12,
|
||||
trackingID: 47011633532241,
|
||||
rank: 3,
|
||||
},
|
||||
{
|
||||
date: "2024-12-27T18:03:31Z",
|
||||
price: 32.0,
|
||||
size: 12198,
|
||||
volume: 7146904.0,
|
||||
premium: "390336",
|
||||
sizeVolRatio: 0.17,
|
||||
sizeAvgVolRatio: 0.12,
|
||||
trackingID: 47011633532241,
|
||||
rank: 4,
|
||||
},
|
||||
{
|
||||
date: "2024-12-27T20:00:53Z",
|
||||
price: 31.78,
|
||||
size: 7345,
|
||||
volume: 8220987.0,
|
||||
premium: "233424.10",
|
||||
sizeVolRatio: 0.09,
|
||||
sizeAvgVolRatio: 0.07,
|
||||
trackingID: 54053503366366,
|
||||
rank: 5,
|
||||
},
|
||||
];
|
||||
|
||||
let stockList = [];
|
||||
let isLoaded = false;
|
||||
|
||||
function formatToNewYorkTime(isoString) {
|
||||
const date = new Date(isoString);
|
||||
|
||||
// Get the date components in New York time zone
|
||||
const options = {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
second: "numeric",
|
||||
timeZone: "America/New_York",
|
||||
hour12: true, // Enable AM/PM format
|
||||
};
|
||||
|
||||
// Format date for New York timezone
|
||||
const formatter = new Intl.DateTimeFormat("en-US", options);
|
||||
const parts = formatter.formatToParts(date);
|
||||
|
||||
const year = parts.find((p) => p.type === "year").value;
|
||||
const day = parts.find((p) => p.type === "day").value;
|
||||
const hour = parts.find((p) => p.type === "hour").value.padStart(2, "0");
|
||||
const minute = parts
|
||||
.find((p) => p.type === "minute")
|
||||
.value.padStart(2, "0");
|
||||
|
||||
const ampm = parts.find((p) => p.type === "dayPeriod").value; // AM/PM
|
||||
|
||||
return `${day}/${year} ${hour}:${minute} ${ampm}`;
|
||||
}
|
||||
|
||||
$: columns = [
|
||||
{ key: "rank", label: "Rank", align: "left" },
|
||||
{ key: "date", label: "Time", align: "left" },
|
||||
{ key: "price", label: "Price", align: "right" },
|
||||
{ key: "size", label: "Size", align: "right" },
|
||||
{ key: "volume", label: "Volume", align: "right" },
|
||||
{ key: "sizeVolRatio", label: "Size / Vol", align: "right" },
|
||||
{ key: "sizeAvgVolRatio", label: "Size / Avg Vol", align: "right" },
|
||||
{ key: "premium", label: "Premium", align: "right" },
|
||||
];
|
||||
$: sortOrders = {
|
||||
rank: { order: "none", type: "number" },
|
||||
date: { order: "none", type: "date" },
|
||||
price: { order: "none", type: "number" },
|
||||
size: { order: "none", type: "number" },
|
||||
volume: { order: "none", type: "number" },
|
||||
sizeVolRatio: { order: "none", type: "number" },
|
||||
sizeAvgVolRatio: { order: "none", type: "number" },
|
||||
premium: { order: "none", type: "number" },
|
||||
};
|
||||
|
||||
const sortData = (key) => {
|
||||
// Reset all other keys to 'none' except the current key
|
||||
for (const k in sortOrders) {
|
||||
if (k !== key) {
|
||||
sortOrders[k].order = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// Cycle through 'none', 'asc', 'desc' for the clicked key
|
||||
const orderCycle = ["none", "asc", "desc"];
|
||||
let originalData = rawData;
|
||||
|
||||
const currentOrderIndex = orderCycle.indexOf(sortOrders[key].order);
|
||||
sortOrders[key].order =
|
||||
orderCycle[(currentOrderIndex + 1) % orderCycle.length];
|
||||
const sortOrder = sortOrders[key].order;
|
||||
|
||||
// Reset to original data when 'none' and stop further sorting
|
||||
if (sortOrder === "none") {
|
||||
stockList = originalData?.slice(0, 50); // Reset displayed data
|
||||
return;
|
||||
}
|
||||
|
||||
// Define a generic comparison function
|
||||
const compareValues = (a, b) => {
|
||||
const { type } = sortOrders[key];
|
||||
let valueA, valueB;
|
||||
|
||||
switch (type) {
|
||||
case "date":
|
||||
valueA = new Date(a[key]);
|
||||
valueB = new Date(b[key]);
|
||||
break;
|
||||
case "string":
|
||||
valueA = a[key].toUpperCase();
|
||||
valueB = b[key].toUpperCase();
|
||||
return sortOrder === "asc"
|
||||
? valueA.localeCompare(valueB)
|
||||
: valueB.localeCompare(valueA);
|
||||
case "number":
|
||||
default:
|
||||
valueA = parseFloat(a[key]);
|
||||
valueB = parseFloat(b[key]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sortOrder === "asc") {
|
||||
return valueA < valueB ? -1 : valueA > valueB ? 1 : 0;
|
||||
} else {
|
||||
return valueA > valueB ? -1 : valueA < valueB ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Sort using the generic comparison function
|
||||
stockList = [...originalData].sort(compareValues)?.slice(0, 50);
|
||||
};
|
||||
|
||||
$: if (typeof window !== "undefined" && ($stockTicker || $etfTicker)) {
|
||||
isLoaded = false;
|
||||
stockList = rawData;
|
||||
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="hottestDPTrade"
|
||||
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-2xl font-bold"
|
||||
>
|
||||
Hottest Trades
|
||||
</label>
|
||||
<InfoModal
|
||||
title={"Hottest DP Trades"}
|
||||
content={"Real-time hottest trades highlight significant premium flows, revealing where big players are active and hinting at market trends or sentiment."}
|
||||
id={"hottestDPTrade"}
|
||||
/>
|
||||
</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">
|
||||
Get in realtime the latest hottest trades based on premium.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-full m-auto rounded-none sm:rounded-md mb-4 overflow-x-scroll"
|
||||
>
|
||||
<table
|
||||
class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md text-white w-full bg-table border border-gray-800 m-auto"
|
||||
>
|
||||
<thead>
|
||||
<TableHeader {columns} {sortOrders} {sortData} />
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each stockList as item, index}
|
||||
<tr
|
||||
class="sm:hover:bg-[#245073] border-b border-gray-800 sm:hover:bg-opacity-[0.2] odd:bg-odd"
|
||||
>
|
||||
<td
|
||||
class="text-start text-sm sm:text-[1rem] whitespace-nowrap text-white"
|
||||
>
|
||||
{item?.rank}
|
||||
</td>
|
||||
|
||||
<td
|
||||
class="text-start text-sm sm:text-[1rem] whitespace-nowrap text-white"
|
||||
>
|
||||
{formatToNewYorkTime(item?.date)}
|
||||
</td>
|
||||
|
||||
<td
|
||||
class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white"
|
||||
>
|
||||
{item?.price}
|
||||
</td>
|
||||
|
||||
<td class="text-sm sm:text-[1rem] text-end">
|
||||
{@html abbreviateNumberWithColor(item?.size, false, true)}
|
||||
</td>
|
||||
|
||||
<td class="text-sm sm:text-[1rem] text-end">
|
||||
{@html abbreviateNumberWithColor(item?.volume, false, true)}
|
||||
</td>
|
||||
|
||||
<td class="text-sm sm:text-[1rem] text-end">
|
||||
{item?.sizeVolRatio?.toFixed(2)}%
|
||||
</td>
|
||||
<td class="text-sm sm:text-[1rem] text-end">
|
||||
{item?.sizeAvgVolRatio?.toFixed(2)}%
|
||||
</td>
|
||||
|
||||
<td class="text-sm sm:text-[1rem] text-end">
|
||||
{@html abbreviateNumberWithColor(
|
||||
item?.premium,
|
||||
false,
|
||||
true,
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</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>
|
||||
211
src/lib/components/DarkPool/PriceLevel.svelte
Normal file
211
src/lib/components/DarkPool/PriceLevel.svelte
Normal file
@ -0,0 +1,211 @@
|
||||
<script lang="ts">
|
||||
import { displayCompanyName, stockTicker, etfTicker } from "$lib/store";
|
||||
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||
import { Chart } from "svelte-echarts";
|
||||
import { abbreviateNumber, abbreviateNumberWithColor } 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 = "Size";
|
||||
|
||||
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer]);
|
||||
|
||||
export let rawData = [];
|
||||
export let metrics = {};
|
||||
|
||||
let isLoaded = false;
|
||||
let optionsData;
|
||||
|
||||
function getPlotOptions(category) {
|
||||
const xAxis = rawData.map((item) => item[category?.toLowerCase()]); // 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 += `${param.seriesName}: ${abbreviateNumber(param.value)}<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: "",
|
||||
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: "",
|
||||
data: yAxis,
|
||||
axisLabel: { color: "#fff" },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: `Total ${category}`,
|
||||
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) &&
|
||||
category
|
||||
) {
|
||||
isLoaded = false;
|
||||
optionsData = getPlotOptions(category);
|
||||
isLoaded = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="overflow-hidden text-white h-full pb-8 pt-6">
|
||||
<main class="overflow-hidden">
|
||||
<div class="flex flex-row items-center">
|
||||
<label
|
||||
for="priceLevelInfo"
|
||||
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-2xl font-bold"
|
||||
>
|
||||
Price Level
|
||||
</label>
|
||||
<InfoModal
|
||||
title={"Price Level"}
|
||||
content={"Price levels reveal where significant trading activity occurs, aiding investors in identifying key support and resistance zones."}
|
||||
id={"priceLevelInfo"}
|
||||
/>
|
||||
</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 week, GameStop Corp. has seen an average dark pool
|
||||
trade size of {@html abbreviateNumberWithColor(
|
||||
metrics?.avgTradeSize,
|
||||
false,
|
||||
true,
|
||||
)}, a total volume of {@html abbreviateNumberWithColor(
|
||||
metrics?.totalVolume,
|
||||
false,
|
||||
true,
|
||||
)} and an average premium per trade of {@html abbreviateNumberWithColor(
|
||||
metrics?.avgPremTrade,
|
||||
false,
|
||||
true,
|
||||
)}, with a total premium of {@html abbreviateNumberWithColor(
|
||||
metrics?.totalPrem,
|
||||
false,
|
||||
true,
|
||||
)}
|
||||
</div>
|
||||
</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-8 z-10 text-sm"
|
||||
>
|
||||
{#each ["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>
|
||||
{/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>
|
||||
@ -1,270 +0,0 @@
|
||||
<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>
|
||||
@ -10,10 +10,10 @@ export const load = async ({ params, locals }) => {
|
||||
ticker: params.tickerID,
|
||||
};
|
||||
|
||||
const getStockDividend = async () => {
|
||||
const getPriceLevel = async () => {
|
||||
|
||||
|
||||
const response = await fetch(apiURL + "/stock-dividend", {
|
||||
const response = await fetch(apiURL + "/dark-pool-level", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@ -47,7 +47,7 @@ export const load = async ({ params, locals }) => {
|
||||
|
||||
// Make sure to return a promise
|
||||
return {
|
||||
getStockDividend: await getStockDividend(),
|
||||
getPriceLevel: await getPriceLevel(),
|
||||
getHistoricalDarkPool: await getHistoricalDarkPool(),
|
||||
|
||||
};
|
||||
|
||||
@ -4,120 +4,14 @@
|
||||
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 HistoricalVolume from "$lib/components/DarkPool/HistoricalVolume.svelte";
|
||||
import PriceLevel from "$lib/components/DarkPool/PriceLevel.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]);
|
||||
import HottestTrades from "$lib/components/DarkPool/HottestTrades.svelte";
|
||||
|
||||
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>
|
||||
@ -164,136 +58,31 @@
|
||||
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 class="w-full mb-2">
|
||||
<div class="flex flex-row items-center">
|
||||
<label
|
||||
for="darkPoolInfo"
|
||||
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-2xl font-bold"
|
||||
>
|
||||
Dark Pool Data
|
||||
</label>
|
||||
<InfoModal
|
||||
title={"Dark Pool Data"}
|
||||
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={"darkPoolInfo"}
|
||||
/>
|
||||
</div>
|
||||
<Infobox
|
||||
text="Track the Dark Pool Trades of major whales to monitor hidden trading activity and trends."
|
||||
/>
|
||||
</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}
|
||||
<PriceLevel
|
||||
rawData={data?.getPriceLevel?.priceLevel}
|
||||
metrics={data?.getPriceLevel?.metrics}
|
||||
/>
|
||||
<HottestTrades rawData={data?.getPriceLevel?.hottestTrades} />
|
||||
<HistoricalVolume rawData={historicalDarkPool} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user