refactor code
This commit is contained in:
parent
249c4f0077
commit
282acde244
840
src/lib/components/Table/OptionsFlowTable.svelte
Normal file
840
src/lib/components/Table/OptionsFlowTable.svelte
Normal file
@ -0,0 +1,840 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { screenWidth } from "$lib/store";
|
||||||
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
|
|
||||||
|
import VirtualList from "svelte-tiny-virtual-list";
|
||||||
|
import HoverStockChart from "$lib/components/HoverStockChart.svelte";
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
export let optionsWatchlist;
|
||||||
|
export let displayedData = [];
|
||||||
|
export let filteredData = [];
|
||||||
|
export let rawData = [];
|
||||||
|
|
||||||
|
let animationClass = "";
|
||||||
|
let animationId = "";
|
||||||
|
|
||||||
|
function formatTime(timeString) {
|
||||||
|
// Split the time string into components
|
||||||
|
const [hours, minutes, seconds] = timeString?.split(":").map(Number);
|
||||||
|
|
||||||
|
// Determine AM or PM
|
||||||
|
const period = hours >= 12 ? "PM" : "AM";
|
||||||
|
|
||||||
|
// Convert hours from 24-hour to 12-hour format
|
||||||
|
const formattedHours = hours % 12 || 12; // Converts 0 to 12 for midnight
|
||||||
|
|
||||||
|
// Format the time string
|
||||||
|
const formattedTimeString = `${formattedHours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")} ${period}`;
|
||||||
|
|
||||||
|
return formattedTimeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reformatDate(dateString) {
|
||||||
|
return (
|
||||||
|
dateString.substring(5, 7) +
|
||||||
|
"/" +
|
||||||
|
dateString.substring(8) +
|
||||||
|
"/" +
|
||||||
|
dateString.substring(2, 4)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addToWatchlist(itemId) {
|
||||||
|
if (data?.user?.tier === "Pro") {
|
||||||
|
try {
|
||||||
|
const postData = {
|
||||||
|
itemIdList: [itemId],
|
||||||
|
id: optionsWatchlist?.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (optionsWatchlist?.optionsId?.includes(itemId)) {
|
||||||
|
// Remove ticker from the watchlist.
|
||||||
|
optionsWatchlist.optionsId = optionsWatchlist?.optionsId.filter(
|
||||||
|
(item) => item !== itemId,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Add ticker to the watchlist.
|
||||||
|
animationId = itemId;
|
||||||
|
animationClass = "heartbeat";
|
||||||
|
const removeAnimation = () => {
|
||||||
|
animationId = "";
|
||||||
|
animationClass = "";
|
||||||
|
};
|
||||||
|
optionsWatchlist.optionsId = [...optionsWatchlist?.optionsId, itemId];
|
||||||
|
const heartbeatElement = document.getElementById(itemId);
|
||||||
|
if (heartbeatElement) {
|
||||||
|
// Only add listener if it's not already present
|
||||||
|
if (!heartbeatElement.classList.contains("animation-added")) {
|
||||||
|
heartbeatElement.addEventListener(
|
||||||
|
"animationend",
|
||||||
|
removeAnimation,
|
||||||
|
);
|
||||||
|
heartbeatElement.classList.add("animation-added"); // Prevent re-adding listener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch("/api/update-options-watchlist", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData),
|
||||||
|
});
|
||||||
|
|
||||||
|
optionsWatchlist.id = await response.json();
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Network response was not ok");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("An error occurred:", error);
|
||||||
|
// Handle the error appropriately (e.g., show an error message to the user)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast.error("Only for Pro Members", {
|
||||||
|
style: "border-radius: 200px; background: #333; color: #fff;",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sortOrders = {
|
||||||
|
time: "none",
|
||||||
|
ticker: "none",
|
||||||
|
expiry: "none",
|
||||||
|
dte: "none",
|
||||||
|
strike: "none",
|
||||||
|
callPut: "none",
|
||||||
|
sentiment: "none",
|
||||||
|
spot: "none",
|
||||||
|
price: "none",
|
||||||
|
premium: "none",
|
||||||
|
type: "none",
|
||||||
|
exec: "none",
|
||||||
|
vol: "none",
|
||||||
|
oi: "none",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generalized sorting function
|
||||||
|
function sortData(key) {
|
||||||
|
// Reset all other keys to 'none' except the current key
|
||||||
|
for (const k in sortOrders) {
|
||||||
|
if (k !== key) {
|
||||||
|
sortOrders[k] = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cycle through 'none', 'asc', 'desc' for the clicked key
|
||||||
|
const orderCycle = ["none", "asc", "desc"];
|
||||||
|
const currentOrderIndex = orderCycle.indexOf(sortOrders[key]);
|
||||||
|
sortOrders[key] = orderCycle[(currentOrderIndex + 1) % orderCycle.length];
|
||||||
|
|
||||||
|
const sortOrder = sortOrders[key];
|
||||||
|
const originalData =
|
||||||
|
filteredData?.length !== 0 ? [...filteredData] : [...rawData];
|
||||||
|
|
||||||
|
// Reset to original data when 'none'
|
||||||
|
if (sortOrder === "none") {
|
||||||
|
displayedData = originalData;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const compareFunctions = {
|
||||||
|
time: (a, b) => {
|
||||||
|
const timeA = new Date("1970-01-01T" + a.time).getTime();
|
||||||
|
const timeB = new Date("1970-01-01T" + b.time).getTime();
|
||||||
|
return sortOrder === "asc" ? timeA - timeB : timeB - timeA;
|
||||||
|
},
|
||||||
|
ticker: (a, b) => {
|
||||||
|
const tickerA = a.ticker.toUpperCase();
|
||||||
|
const tickerB = b.ticker.toUpperCase();
|
||||||
|
return sortOrder === "asc"
|
||||||
|
? tickerA.localeCompare(tickerB)
|
||||||
|
: tickerB.localeCompare(tickerA);
|
||||||
|
},
|
||||||
|
expiry: (a, b) => {
|
||||||
|
const timeA = new Date(a.date_expiration);
|
||||||
|
const timeB = new Date(b.date_expiration);
|
||||||
|
return sortOrder === "asc" ? timeA - timeB : timeB - timeA;
|
||||||
|
},
|
||||||
|
dte: (a, b) => {
|
||||||
|
const timeA = new Date(a.date_expiration);
|
||||||
|
const timeB = new Date(b.date_expiration);
|
||||||
|
return sortOrder === "asc" ? timeA - timeB : timeB - timeA;
|
||||||
|
},
|
||||||
|
strike: (a, b) => {
|
||||||
|
const strikeA = parseFloat(a.strike_price);
|
||||||
|
const strikeB = parseFloat(b.strike_price);
|
||||||
|
return sortOrder === "asc" ? strikeA - strikeB : strikeB - strikeA;
|
||||||
|
},
|
||||||
|
spot: (a, b) => {
|
||||||
|
const spotA = parseFloat(a.underlying_price);
|
||||||
|
const spotB = parseFloat(b.underlying_price);
|
||||||
|
return sortOrder === "asc" ? spotA - spotB : spotB - spotA;
|
||||||
|
},
|
||||||
|
price: (a, b) => {
|
||||||
|
const priceA = parseFloat(a.price);
|
||||||
|
const priceB = parseFloat(b.price);
|
||||||
|
return sortOrder === "asc" ? priceA - priceB : priceB - priceA;
|
||||||
|
},
|
||||||
|
premium: (a, b) => {
|
||||||
|
const premiumA = parseFloat(a.cost_basis);
|
||||||
|
const premiumB = parseFloat(b.cost_basis);
|
||||||
|
return sortOrder === "asc" ? premiumA - premiumB : premiumB - premiumA;
|
||||||
|
},
|
||||||
|
size: (a, b) => {
|
||||||
|
const volA = parseFloat(a?.size);
|
||||||
|
const volB = parseFloat(b?.size);
|
||||||
|
return sortOrder === "asc" ? volA - volB : volB - volA;
|
||||||
|
},
|
||||||
|
vol: (a, b) => {
|
||||||
|
const volA = parseFloat(a.volume);
|
||||||
|
const volB = parseFloat(b.volume);
|
||||||
|
return sortOrder === "asc" ? volA - volB : volB - volA;
|
||||||
|
},
|
||||||
|
oi: (a, b) => {
|
||||||
|
const oiA = parseFloat(a.open_interest);
|
||||||
|
const oiB = parseFloat(b.open_interest);
|
||||||
|
return sortOrder === "asc" ? oiA - oiB : oiB - oiA;
|
||||||
|
},
|
||||||
|
callPut: (a, b) => {
|
||||||
|
const callPutA = a.put_call?.toUpperCase();
|
||||||
|
const callPutB = b.put_call?.toUpperCase();
|
||||||
|
return sortOrder === "asc"
|
||||||
|
? callPutA.localeCompare(callPutB)
|
||||||
|
: callPutB.localeCompare(callPutA);
|
||||||
|
},
|
||||||
|
sentiment: (a, b) => {
|
||||||
|
const sentimentOrder = { BULLISH: 1, NEUTRAL: 2, BEARISH: 3 };
|
||||||
|
const sentimentA = sentimentOrder[a?.sentiment?.toUpperCase()] || 4;
|
||||||
|
const sentimentB = sentimentOrder[b?.sentiment?.toUpperCase()] || 4;
|
||||||
|
return sortOrder === "asc"
|
||||||
|
? sentimentA - sentimentB
|
||||||
|
: sentimentB - sentimentA;
|
||||||
|
},
|
||||||
|
type: (a, b) => {
|
||||||
|
const typeOrder = { SWEEP: 1, TRADE: 2 };
|
||||||
|
const typeA = typeOrder[a.option_activity_type?.toUpperCase()] || 3;
|
||||||
|
const typeB = typeOrder[b.option_activity_type?.toUpperCase()] || 3;
|
||||||
|
return sortOrder === "asc" ? typeA - typeB : typeB - typeA;
|
||||||
|
},
|
||||||
|
exec: (a, b) => {
|
||||||
|
const tickerA = a?.execution_estimate?.toUpperCase();
|
||||||
|
const tickerB = b?.execution_estimate?.toUpperCase();
|
||||||
|
return sortOrder === "asc"
|
||||||
|
? tickerA.localeCompare(tickerB)
|
||||||
|
: tickerB.localeCompare(tickerA);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sort using the appropriate comparison function
|
||||||
|
displayedData = originalData.sort(compareFunctions[key]);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<div class="table">
|
||||||
|
<VirtualList
|
||||||
|
width="100%"
|
||||||
|
height={$screenWidth < 640 ? 550 : 850}
|
||||||
|
itemCount={displayedData.length}
|
||||||
|
itemSize={40}
|
||||||
|
>
|
||||||
|
<div slot="header" class="tr th sticky z-40 top-0">
|
||||||
|
<!-- Table headers -->
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("time")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Time
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['time'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: ''} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("ticker")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] font-bold text-slate-300 text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Symbol
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['ticker'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['ticker'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="td select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("expiry")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Expiry
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['expiry'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['expiry'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("dte")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
DTE
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['dte'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['dte'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("strike")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Strike
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['strike'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['strike'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("callPut")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
C/P
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['callPut'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['callPut'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("sentiment")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Sent.
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
||||||
|
'sentiment'
|
||||||
|
] === 'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['sentiment'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("spot")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Spot
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['spot'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['spot'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("price")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Price
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['price'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['price'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("premium")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Prem
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['premium'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['premium'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("type")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Type
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['type'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['type'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("exec")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Exec
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['exec'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['exec'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("size")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Size
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['size'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['size'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("vol")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
Vol
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['vol'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['vol'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click={() => sortData("oi")}
|
||||||
|
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
||||||
|
>
|
||||||
|
OI
|
||||||
|
<svg
|
||||||
|
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders['oi'] ===
|
||||||
|
'asc'
|
||||||
|
? 'rotate-180'
|
||||||
|
: sortOrders['oi'] === 'desc'
|
||||||
|
? ''
|
||||||
|
: 'hidden'} "
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
style="max-width:50px"
|
||||||
|
><path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
slot="item"
|
||||||
|
let:index
|
||||||
|
let:style
|
||||||
|
{style}
|
||||||
|
class="tr {index % 2 === 0 ? 'bg-secondary' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
|
<!-- Row data -->
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-white text-xs sm:text-sm text-start m-auto whitespace-nowrap"
|
||||||
|
>
|
||||||
|
{formatTime(displayedData[index]?.time)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
on:click|stopPropagation
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:hover:text-white sm:text-[1rem] text-blue-400 font-normal"
|
||||||
|
>
|
||||||
|
<HoverStockChart
|
||||||
|
symbol={displayedData[index]?.ticker}
|
||||||
|
assetType={displayedData[index]?.underlying_type}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={displayedData[index]?.id}
|
||||||
|
on:click|stopPropagation={() =>
|
||||||
|
addToWatchlist(displayedData[index]?.id)}
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td {optionsWatchlist.optionsId?.includes(
|
||||||
|
displayedData[index]?.id,
|
||||||
|
)
|
||||||
|
? 'text-[#FBCE3C]'
|
||||||
|
: 'text-white'}"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="{displayedData[index]?.id === animationId
|
||||||
|
? animationClass
|
||||||
|
: ''} w-4 sm:w-5 sm:h-5 inline-block cursor-pointer flex-shrink-0"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-white text-start"
|
||||||
|
>
|
||||||
|
{reformatDate(displayedData[index]?.date_expiration)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-white text-start"
|
||||||
|
>
|
||||||
|
{displayedData[index]?.dte < 0
|
||||||
|
? "expired"
|
||||||
|
: displayedData[index]?.dte + "d"}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-white text-start"
|
||||||
|
>
|
||||||
|
{displayedData[index]?.strike_price}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] {displayedData[index]?.put_call ===
|
||||||
|
'Calls'
|
||||||
|
? 'text-[#00FC50]'
|
||||||
|
: 'text-[#FF2F1F]'} text-start"
|
||||||
|
>
|
||||||
|
{displayedData[index]?.put_call}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] {displayedData[index]?.sentiment ===
|
||||||
|
'Bullish'
|
||||||
|
? 'text-[#00FC50]'
|
||||||
|
: displayedData[index]?.sentiment === 'Bearish'
|
||||||
|
? 'text-[#FF2F1F]'
|
||||||
|
: 'text-[#C6A755]'} text-start"
|
||||||
|
>
|
||||||
|
{displayedData[index]?.sentiment}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-start text-white"
|
||||||
|
>
|
||||||
|
{displayedData[index]?.underlying_price}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-start text-white"
|
||||||
|
>
|
||||||
|
{displayedData[index]?.price}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-start font-semibold {displayedData[
|
||||||
|
index
|
||||||
|
]?.put_call === 'Puts'
|
||||||
|
? 'text-[#CB281C]'
|
||||||
|
: 'text-[#0FB307]'}"
|
||||||
|
>
|
||||||
|
{abbreviateNumber(displayedData[index]?.cost_basis)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-start {displayedData[index]
|
||||||
|
?.option_activity_type === 'Sweep'
|
||||||
|
? 'text-[#C6A755]'
|
||||||
|
: 'text-[#976DB7]'}"
|
||||||
|
>
|
||||||
|
{displayedData[index]?.option_activity_type}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-start text-[#C6A755]"
|
||||||
|
>
|
||||||
|
{displayedData[index]?.execution_estimate?.replace(
|
||||||
|
"At Midpoint",
|
||||||
|
"Midpoint",
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-white text-end"
|
||||||
|
>
|
||||||
|
{new Intl.NumberFormat("en", {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
}).format(displayedData[index]?.size)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-white text-end"
|
||||||
|
>
|
||||||
|
{new Intl.NumberFormat("en", {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
}).format(displayedData[index]?.volume)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="justify-content: center;"
|
||||||
|
class="td text-sm sm:text-[1rem] text-white text-end"
|
||||||
|
>
|
||||||
|
{new Intl.NumberFormat("en", {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
}).format(displayedData[index]?.open_interest)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VirtualList>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.table-container {
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table :global(.virtual-list-inner) {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.table {
|
||||||
|
width: 1000px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table .virtual-list-inner {
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.th {
|
||||||
|
display: none;
|
||||||
|
font-weight: 700;
|
||||||
|
background-color: #09090b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.th > .td {
|
||||||
|
white-space: nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr.even {
|
||||||
|
background-color: #2a2e39;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr.odd {
|
||||||
|
background-color: #09090b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-basis: 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
min-width: 0px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heartbeat {
|
||||||
|
animation: heartbeat-animation 0.3s;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes heartbeat-animation {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg) scale(0.95);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: rotate(10deg) scale(1.05);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(0deg) scale(1.2);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate(-10deg) scale(1.05);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(0deg) scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -11,8 +11,8 @@
|
|||||||
import { Button } from "$lib/components/shadcn/button/index.js";
|
import { Button } from "$lib/components/shadcn/button/index.js";
|
||||||
import { Calendar } from "$lib/components/shadcn/calendar/index.js";
|
import { Calendar } from "$lib/components/shadcn/calendar/index.js";
|
||||||
import CalendarIcon from "lucide-svelte/icons/calendar";
|
import CalendarIcon from "lucide-svelte/icons/calendar";
|
||||||
import HoverStockChart from "$lib/components/HoverStockChart.svelte";
|
|
||||||
import VirtualList from "svelte-tiny-virtual-list";
|
import OptionsFlowTable from "$lib/components/Table/OptionsFlowTable.svelte";
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
@ -24,8 +24,7 @@
|
|||||||
let displayRules = [];
|
let displayRules = [];
|
||||||
let filteredData = [];
|
let filteredData = [];
|
||||||
let filterQuery = "";
|
let filterQuery = "";
|
||||||
let animationClass = "";
|
|
||||||
let animationId = "";
|
|
||||||
let socket: WebSocket | null = null; // Initialize socket as null
|
let socket: WebSocket | null = null; // Initialize socket as null
|
||||||
|
|
||||||
let syncWorker: Worker | undefined;
|
let syncWorker: Worker | undefined;
|
||||||
@ -504,52 +503,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTime(timeString) {
|
|
||||||
// Split the time string into components
|
|
||||||
const [hours, minutes, seconds] = timeString.split(":").map(Number);
|
|
||||||
|
|
||||||
// Determine AM or PM
|
|
||||||
const period = hours >= 12 ? "PM" : "AM";
|
|
||||||
|
|
||||||
// Convert hours from 24-hour to 12-hour format
|
|
||||||
const formattedHours = hours % 12 || 12; // Converts 0 to 12 for midnight
|
|
||||||
|
|
||||||
// Format the time string
|
|
||||||
const formattedTimeString = `${formattedHours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")} ${period}`;
|
|
||||||
|
|
||||||
return formattedTimeString;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleViewData(optionData) {
|
|
||||||
//optionStart = optionData['Start Date'] === null ? 'n/a' : new Date(optionData['Start Date'])?.toLocaleString('en-US', { month: 'short', day: 'numeric', year: 'numeric', daySuffix: '2-digit' });
|
|
||||||
optionSymbol = optionData?.option_symbol;
|
|
||||||
optionDescription = optionData?.description;
|
|
||||||
optionPremium = abbreviateNumber(optionData?.cost_basis, true);
|
|
||||||
optionExpiry = reformatDate(optionData?.date_expiration);
|
|
||||||
optionContract = optionData?.put_call;
|
|
||||||
optionType = optionData?.option_activity_type;
|
|
||||||
optionStrike = optionData?.strike_price;
|
|
||||||
optionVolume = new Intl.NumberFormat("en", {
|
|
||||||
minimumFractionDigits: 0,
|
|
||||||
maximumFractionDigits: 0,
|
|
||||||
}).format(optionData?.volume);
|
|
||||||
optionSpot = optionData?.underlying_price;
|
|
||||||
optionOpenInterest = new Intl.NumberFormat("en", {
|
|
||||||
minimumFractionDigits: 0,
|
|
||||||
maximumFractionDigits: 0,
|
|
||||||
}).format(optionData?.open_interest);
|
|
||||||
optionSentiment = optionData?.sentiment;
|
|
||||||
optionPrice = optionData?.price;
|
|
||||||
//optionTradeCount = optionData?.tradeCount;
|
|
||||||
optionexecution_estimate = optionData?.execution_estimate;
|
|
||||||
//optionExchange = optionData?.exchange;
|
|
||||||
|
|
||||||
const openPopup =
|
|
||||||
$screenWidth < 640
|
|
||||||
? document.getElementById("optionDetailsMobileModal")
|
|
||||||
: document.getElementById("optionDetailsDesktopModal");
|
|
||||||
openPopup?.dispatchEvent(new MouseEvent("click"));
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
function sendMessage(message) {
|
function sendMessage(message) {
|
||||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||||
@ -925,139 +878,6 @@ function sendMessage(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let sortOrders = {
|
|
||||||
time: "none",
|
|
||||||
ticker: "none",
|
|
||||||
expiry: "none",
|
|
||||||
dte: "none",
|
|
||||||
strike: "none",
|
|
||||||
callPut: "none",
|
|
||||||
sentiment: "none",
|
|
||||||
spot: "none",
|
|
||||||
price: "none",
|
|
||||||
premium: "none",
|
|
||||||
type: "none",
|
|
||||||
exec: "none",
|
|
||||||
vol: "none",
|
|
||||||
oi: "none",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generalized sorting function
|
|
||||||
function sortData(key) {
|
|
||||||
// Reset all other keys to 'none' except the current key
|
|
||||||
for (const k in sortOrders) {
|
|
||||||
if (k !== key) {
|
|
||||||
sortOrders[k] = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cycle through 'none', 'asc', 'desc' for the clicked key
|
|
||||||
const orderCycle = ["none", "asc", "desc"];
|
|
||||||
const currentOrderIndex = orderCycle.indexOf(sortOrders[key]);
|
|
||||||
sortOrders[key] = orderCycle[(currentOrderIndex + 1) % orderCycle.length];
|
|
||||||
|
|
||||||
const sortOrder = sortOrders[key];
|
|
||||||
const originalData =
|
|
||||||
filteredData?.length !== 0 ? [...filteredData] : [...rawData];
|
|
||||||
|
|
||||||
// Reset to original data when 'none'
|
|
||||||
if (sortOrder === "none") {
|
|
||||||
displayedData = originalData;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const compareFunctions = {
|
|
||||||
time: (a, b) => {
|
|
||||||
const timeA = new Date("1970-01-01T" + a.time).getTime();
|
|
||||||
const timeB = new Date("1970-01-01T" + b.time).getTime();
|
|
||||||
return sortOrder === "asc" ? timeA - timeB : timeB - timeA;
|
|
||||||
},
|
|
||||||
ticker: (a, b) => {
|
|
||||||
const tickerA = a.ticker.toUpperCase();
|
|
||||||
const tickerB = b.ticker.toUpperCase();
|
|
||||||
return sortOrder === "asc"
|
|
||||||
? tickerA.localeCompare(tickerB)
|
|
||||||
: tickerB.localeCompare(tickerA);
|
|
||||||
},
|
|
||||||
expiry: (a, b) => {
|
|
||||||
const timeA = new Date(a.date_expiration);
|
|
||||||
const timeB = new Date(b.date_expiration);
|
|
||||||
return sortOrder === "asc" ? timeA - timeB : timeB - timeA;
|
|
||||||
},
|
|
||||||
dte: (a, b) => {
|
|
||||||
const timeA = new Date(a.date_expiration);
|
|
||||||
const timeB = new Date(b.date_expiration);
|
|
||||||
return sortOrder === "asc" ? timeA - timeB : timeB - timeA;
|
|
||||||
},
|
|
||||||
strike: (a, b) => {
|
|
||||||
const strikeA = parseFloat(a.strike_price);
|
|
||||||
const strikeB = parseFloat(b.strike_price);
|
|
||||||
return sortOrder === "asc" ? strikeA - strikeB : strikeB - strikeA;
|
|
||||||
},
|
|
||||||
spot: (a, b) => {
|
|
||||||
const spotA = parseFloat(a.underlying_price);
|
|
||||||
const spotB = parseFloat(b.underlying_price);
|
|
||||||
return sortOrder === "asc" ? spotA - spotB : spotB - spotA;
|
|
||||||
},
|
|
||||||
price: (a, b) => {
|
|
||||||
const priceA = parseFloat(a.price);
|
|
||||||
const priceB = parseFloat(b.price);
|
|
||||||
return sortOrder === "asc" ? priceA - priceB : priceB - priceA;
|
|
||||||
},
|
|
||||||
premium: (a, b) => {
|
|
||||||
const premiumA = parseFloat(a.cost_basis);
|
|
||||||
const premiumB = parseFloat(b.cost_basis);
|
|
||||||
return sortOrder === "asc" ? premiumA - premiumB : premiumB - premiumA;
|
|
||||||
},
|
|
||||||
size: (a, b) => {
|
|
||||||
const volA = parseFloat(a?.size);
|
|
||||||
const volB = parseFloat(b?.size);
|
|
||||||
return sortOrder === "asc" ? volA - volB : volB - volA;
|
|
||||||
},
|
|
||||||
vol: (a, b) => {
|
|
||||||
const volA = parseFloat(a.volume);
|
|
||||||
const volB = parseFloat(b.volume);
|
|
||||||
return sortOrder === "asc" ? volA - volB : volB - volA;
|
|
||||||
},
|
|
||||||
oi: (a, b) => {
|
|
||||||
const oiA = parseFloat(a.open_interest);
|
|
||||||
const oiB = parseFloat(b.open_interest);
|
|
||||||
return sortOrder === "asc" ? oiA - oiB : oiB - oiA;
|
|
||||||
},
|
|
||||||
callPut: (a, b) => {
|
|
||||||
const callPutA = a.put_call?.toUpperCase();
|
|
||||||
const callPutB = b.put_call?.toUpperCase();
|
|
||||||
return sortOrder === "asc"
|
|
||||||
? callPutA.localeCompare(callPutB)
|
|
||||||
: callPutB.localeCompare(callPutA);
|
|
||||||
},
|
|
||||||
sentiment: (a, b) => {
|
|
||||||
const sentimentOrder = { BULLISH: 1, NEUTRAL: 2, BEARISH: 3 };
|
|
||||||
const sentimentA = sentimentOrder[a?.sentiment?.toUpperCase()] || 4;
|
|
||||||
const sentimentB = sentimentOrder[b?.sentiment?.toUpperCase()] || 4;
|
|
||||||
return sortOrder === "asc"
|
|
||||||
? sentimentA - sentimentB
|
|
||||||
: sentimentB - sentimentA;
|
|
||||||
},
|
|
||||||
type: (a, b) => {
|
|
||||||
const typeOrder = { SWEEP: 1, TRADE: 2 };
|
|
||||||
const typeA = typeOrder[a.option_activity_type?.toUpperCase()] || 3;
|
|
||||||
const typeB = typeOrder[b.option_activity_type?.toUpperCase()] || 3;
|
|
||||||
return sortOrder === "asc" ? typeA - typeB : typeB - typeA;
|
|
||||||
},
|
|
||||||
exec: (a, b) => {
|
|
||||||
const tickerA = a?.execution_estimate?.toUpperCase();
|
|
||||||
const tickerB = b?.execution_estimate?.toUpperCase();
|
|
||||||
return sortOrder === "asc"
|
|
||||||
? tickerA.localeCompare(tickerB)
|
|
||||||
: tickerB.localeCompare(tickerA);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sort using the appropriate comparison function
|
|
||||||
displayedData = originalData.sort(compareFunctions[key]);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@ -1843,543 +1663,13 @@ function sendMessage(message) {
|
|||||||
<div class="flex w-full m-auto h-full overflow-hidden">
|
<div class="flex w-full m-auto h-full overflow-hidden">
|
||||||
{#if displayedData?.length !== 0}
|
{#if displayedData?.length !== 0}
|
||||||
<div class="mt-8 w-full overflow-x-auto h-[850px] overflow-hidden">
|
<div class="mt-8 w-full overflow-x-auto h-[850px] overflow-hidden">
|
||||||
<div class="table-container">
|
<OptionsFlowTable
|
||||||
<div class="table">
|
{data}
|
||||||
<VirtualList
|
{optionsWatchlist}
|
||||||
width="100%"
|
{displayedData}
|
||||||
height={$screenWidth < 640 ? 550 : 850}
|
{filteredData}
|
||||||
itemCount={displayedData.length}
|
{rawData}
|
||||||
itemSize={40}
|
/>
|
||||||
>
|
|
||||||
<div slot="header" class="tr th sticky z-40 top-0">
|
|
||||||
<!-- Table headers -->
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("time")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Time
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'time'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: ''} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("ticker")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] font-bold text-slate-300 text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Symbol
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'ticker'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['ticker'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="td select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("expiry")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Expiry
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'expiry'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['expiry'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("dte")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
DTE
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'dte'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['dte'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("strike")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Strike
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'strike'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['strike'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("callPut")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
C/P
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'callPut'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['callPut'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("sentiment")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Sent.
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'sentiment'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['sentiment'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("spot")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Spot
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'spot'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['spot'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("price")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Price
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'price'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['price'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("premium")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Prem
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'premium'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['premium'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("type")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Type
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'type'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['type'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("exec")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Exec
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'exec'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['exec'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("size")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Size
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'size'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['size'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("vol")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
Vol
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'vol'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['vol'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click={() => sortData("oi")}
|
|
||||||
class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase"
|
|
||||||
>
|
|
||||||
OI
|
|
||||||
<svg
|
|
||||||
class="flex-shrink-0 w-4 h-4 inline-block {sortOrders[
|
|
||||||
'oi'
|
|
||||||
] === 'asc'
|
|
||||||
? 'rotate-180'
|
|
||||||
: sortOrders['oi'] === 'desc'
|
|
||||||
? ''
|
|
||||||
: 'hidden'} "
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
style="max-width:50px"
|
|
||||||
><path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
></path></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
on:click={() => handleViewData(displayedData[index])}
|
|
||||||
slot="item"
|
|
||||||
let:index
|
|
||||||
let:style
|
|
||||||
{style}
|
|
||||||
class="tr cursor-pointer {index % 2 === 0
|
|
||||||
? 'bg-[#2A2E39]'
|
|
||||||
: 'bg-[#09090B]'}"
|
|
||||||
>
|
|
||||||
<!-- Row data -->
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-white text-xs sm:text-sm text-start m-auto whitespace-nowrap"
|
|
||||||
>
|
|
||||||
{formatTime(displayedData[index]?.time)}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
on:click|stopPropagation
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:hover:text-white sm:text-[1rem] text-blue-400 font-normal"
|
|
||||||
>
|
|
||||||
<HoverStockChart
|
|
||||||
symbol={displayedData[index]?.ticker}
|
|
||||||
assetType={displayedData[index]?.underlying_type}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
id={displayedData[index]?.id}
|
|
||||||
on:click|stopPropagation={() =>
|
|
||||||
addToWatchlist(displayedData[index]?.id)}
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td {optionsWatchlist.optionsId?.includes(
|
|
||||||
displayedData[index]?.id,
|
|
||||||
)
|
|
||||||
? 'text-[#FBCE3C]'
|
|
||||||
: 'text-white'}"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="{displayedData[index]?.id === animationId
|
|
||||||
? animationClass
|
|
||||||
: ''} w-4 sm:w-5 sm:h-5 inline-block cursor-pointer flex-shrink-0"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
><path
|
|
||||||
fill="currentColor"
|
|
||||||
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-white text-start"
|
|
||||||
>
|
|
||||||
{reformatDate(displayedData[index]?.date_expiration)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-white text-start"
|
|
||||||
>
|
|
||||||
{displayedData[index]?.dte < 0
|
|
||||||
? "expired"
|
|
||||||
: displayedData[index]?.dte + "d"}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-white text-start"
|
|
||||||
>
|
|
||||||
{displayedData[index]?.strike_price}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] {displayedData[index]
|
|
||||||
?.put_call === 'Calls'
|
|
||||||
? 'text-[#00FC50]'
|
|
||||||
: 'text-[#FF2F1F]'} text-start"
|
|
||||||
>
|
|
||||||
{displayedData[index]?.put_call}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] {displayedData[index]
|
|
||||||
?.sentiment === 'Bullish'
|
|
||||||
? 'text-[#00FC50]'
|
|
||||||
: displayedData[index]?.sentiment === 'Bearish'
|
|
||||||
? 'text-[#FF2F1F]'
|
|
||||||
: 'text-[#C6A755]'} text-start"
|
|
||||||
>
|
|
||||||
{displayedData[index]?.sentiment}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-start text-white"
|
|
||||||
>
|
|
||||||
{displayedData[index]?.underlying_price}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-start text-white"
|
|
||||||
>
|
|
||||||
{displayedData[index]?.price}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-start font-semibold {displayedData[
|
|
||||||
index
|
|
||||||
]?.put_call === 'Puts'
|
|
||||||
? 'text-[#CB281C]'
|
|
||||||
: 'text-[#0FB307]'}"
|
|
||||||
>
|
|
||||||
{abbreviateNumber(displayedData[index]?.cost_basis)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-start {displayedData[
|
|
||||||
index
|
|
||||||
]?.option_activity_type === 'Sweep'
|
|
||||||
? 'text-[#C6A755]'
|
|
||||||
: 'text-[#976DB7]'}"
|
|
||||||
>
|
|
||||||
{displayedData[index]?.option_activity_type}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-start text-[#C6A755]"
|
|
||||||
>
|
|
||||||
{displayedData[index]?.execution_estimate?.replace(
|
|
||||||
"At Midpoint",
|
|
||||||
"Midpoint",
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-white text-end"
|
|
||||||
>
|
|
||||||
{new Intl.NumberFormat("en", {
|
|
||||||
minimumFractionDigits: 0,
|
|
||||||
maximumFractionDigits: 0,
|
|
||||||
}).format(displayedData[index]?.size)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-white text-end"
|
|
||||||
>
|
|
||||||
{new Intl.NumberFormat("en", {
|
|
||||||
minimumFractionDigits: 0,
|
|
||||||
maximumFractionDigits: 0,
|
|
||||||
}).format(displayedData[index]?.volume)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style="justify-content: center;"
|
|
||||||
class="td text-sm sm:text-[1rem] text-white text-end"
|
|
||||||
>
|
|
||||||
{new Intl.NumberFormat("en", {
|
|
||||||
minimumFractionDigits: 0,
|
|
||||||
maximumFractionDigits: 0,
|
|
||||||
}).format(displayedData[index]?.open_interest)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</VirtualList>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div
|
<div
|
||||||
@ -2577,169 +1867,3 @@ function sendMessage(message) {
|
|||||||
<!--End Choose Rule Modal-->
|
<!--End Choose Rule Modal-->
|
||||||
|
|
||||||
<!--Start Options Detail Desktop Modal-->
|
<!--Start Options Detail Desktop Modal-->
|
||||||
|
|
||||||
<!-- Put this part before </body> tag -->
|
|
||||||
<input type="checkbox" id="optionDetailsDesktopModal" class="modal-toggle" />
|
|
||||||
|
|
||||||
<label for="optionDetailsDesktopModal" class="modal p-2 sm:p-0">
|
|
||||||
<label
|
|
||||||
for="optionDetailsDesktopModal"
|
|
||||||
class="cursor-pointer modal-backdrop bg-[#000] bg-opacity-[0.8]"
|
|
||||||
></label>
|
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
|
||||||
<label
|
|
||||||
class="modal-box rounded w-full relative bg-primary h-auto max-h-[900px] border border-gray-800 overflow-y-scroll"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
for="optionDetailsDesktopModal"
|
|
||||||
class="cursor-pointer absolute right-5 top-2 bg-primary text-2xl text-white"
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<p class="text-gray-200 mt-10">
|
|
||||||
<span class="text-white text-xl font-semibold">Order Details:</span>
|
|
||||||
<br />
|
|
||||||
{optionSymbol}
|
|
||||||
</p>
|
|
||||||
<p class="py-4 text-gray-200 bg-primary w-full">
|
|
||||||
<span class="font-semibold text-white">Description:</span>
|
|
||||||
<br />
|
|
||||||
{optionDescription}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<table
|
|
||||||
class="table table-sm table-compact bg-primary w-full mt-5 mb-10 text-white"
|
|
||||||
>
|
|
||||||
<tbody>
|
|
||||||
<!-- row 1 -->
|
|
||||||
<tr class="border-b border-slate-700 odd:bg-secondary">
|
|
||||||
<td class="font-semibold">Premium</td>
|
|
||||||
<td class="">{optionPremium}</td>
|
|
||||||
<td class="font-semibold">C/P</td>
|
|
||||||
<td class="">{optionContract}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="border-b border-slate-700 odd:bg-secondary">
|
|
||||||
<td class="font-semibold">Expiry</td>
|
|
||||||
<td class="">{optionExpiry}</td>
|
|
||||||
<td class="font-semibold">Type</td>
|
|
||||||
<td class="">{optionType}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="border-b border-slate-700 odd:bg-secondary">
|
|
||||||
<td class="font-semibold">Strike</td>
|
|
||||||
<td class="">${optionStrike}</td>
|
|
||||||
<td class="font-semibold">Volume</td>
|
|
||||||
<td class="">{optionVolume}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="border-b border-slate-700 odd:bg-secondary">
|
|
||||||
<td class="font-semibold">Spot</td>
|
|
||||||
<td class="">${optionSpot}</td>
|
|
||||||
<td class="font-semibold">Open Interest</td>
|
|
||||||
<td class="">{optionOpenInterest}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="border-b border-slate-700 odd:bg-secondary">
|
|
||||||
<td class="font-semibold">Price</td>
|
|
||||||
<td class="">${optionPrice}</td>
|
|
||||||
<td class="font-semibold">Sentiment</td>
|
|
||||||
<td class="">{optionSentiment}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="border-b border-slate-700 odd:bg-secondary">
|
|
||||||
<td class="font-semibold">Execution Estimate</td>
|
|
||||||
<td class="">{optionexecution_estimate}</td>
|
|
||||||
<td class="font-semibold"></td>
|
|
||||||
<td class=""></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</label>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<!--End Options Detial Desktop Modal-->
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.table-container {
|
|
||||||
width: 100%;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table :global(.virtual-list-inner) {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.table {
|
|
||||||
width: 1000px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.table .virtual-list-inner {
|
|
||||||
flex-flow: column nowrap;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.th {
|
|
||||||
display: none;
|
|
||||||
font-weight: 700;
|
|
||||||
background-color: #09090b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.th > .td {
|
|
||||||
white-space: nowrap;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tr {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tr.even {
|
|
||||||
background-color: #2a2e39;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tr.odd {
|
|
||||||
background-color: #09090b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.td {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row nowrap;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-basis: 0;
|
|
||||||
padding: 0.5em;
|
|
||||||
word-break: break-word;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
min-width: 0px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heartbeat {
|
|
||||||
animation: heartbeat-animation 0.3s;
|
|
||||||
animation-timing-function: ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes heartbeat-animation {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg) scale(0.95);
|
|
||||||
}
|
|
||||||
25% {
|
|
||||||
transform: rotate(10deg) scale(1.05);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: rotate(0deg) scale(1.2);
|
|
||||||
}
|
|
||||||
75% {
|
|
||||||
transform: rotate(-10deg) scale(1.05);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(0deg) scale(0.95);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user