diff --git a/src/lib/components/Table/OptionsFlowTable.svelte b/src/lib/components/Table/OptionsFlowTable.svelte new file mode 100644 index 00000000..ea68ab7c --- /dev/null +++ b/src/lib/components/Table/OptionsFlowTable.svelte @@ -0,0 +1,840 @@ + + +
+
+ +
+ +
sortData("time")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Time + +
+
sortData("ticker")} + class="td cursor-pointer select-none bg-[#1E222D] font-bold text-slate-300 text-xs text-start uppercase" + > + Symbol + +
+
+ Save +
+
sortData("expiry")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Expiry + +
+
sortData("dte")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + DTE + +
+
sortData("strike")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Strike + +
+
sortData("callPut")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + C/P + +
+
sortData("sentiment")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Sent. + +
+
sortData("spot")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Spot + +
+
sortData("price")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Price + +
+
sortData("premium")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Prem + +
+
sortData("type")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Type + +
+
sortData("exec")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Exec + +
+
sortData("size")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Size + +
+
sortData("vol")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + Vol + +
+
sortData("oi")} + class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" + > + OI + +
+
+ +
+ + +
+ {formatTime(displayedData[index]?.time)} +
+
+ +
+ +
+ addToWatchlist(displayedData[index]?.id)} + style="justify-content: center;" + class="td {optionsWatchlist.optionsId?.includes( + displayedData[index]?.id, + ) + ? 'text-[#FBCE3C]' + : 'text-white'}" + > + +
+ +
+ {reformatDate(displayedData[index]?.date_expiration)} +
+ +
+ {displayedData[index]?.dte < 0 + ? "expired" + : displayedData[index]?.dte + "d"} +
+ +
+ {displayedData[index]?.strike_price} +
+ +
+ {displayedData[index]?.put_call} +
+ +
+ {displayedData[index]?.sentiment} +
+ +
+ {displayedData[index]?.underlying_price} +
+ +
+ {displayedData[index]?.price} +
+ +
+ {abbreviateNumber(displayedData[index]?.cost_basis)} +
+ +
+ {displayedData[index]?.option_activity_type} +
+ +
+ {displayedData[index]?.execution_estimate?.replace( + "At Midpoint", + "Midpoint", + )} +
+ +
+ {new Intl.NumberFormat("en", { + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }).format(displayedData[index]?.size)} +
+ +
+ {new Intl.NumberFormat("en", { + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }).format(displayedData[index]?.volume)} +
+ +
+ {new Intl.NumberFormat("en", { + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }).format(displayedData[index]?.open_interest)} +
+
+
+
+
+ + diff --git a/src/routes/options-flow/+page.svelte b/src/routes/options-flow/+page.svelte index bea70c95..b7e85312 100644 --- a/src/routes/options-flow/+page.svelte +++ b/src/routes/options-flow/+page.svelte @@ -11,8 +11,8 @@ import { Button } from "$lib/components/shadcn/button/index.js"; import { Calendar } from "$lib/components/shadcn/calendar/index.js"; 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"; export let data; @@ -24,8 +24,7 @@ let displayRules = []; let filteredData = []; let filterQuery = ""; - let animationClass = ""; - let animationId = ""; + let socket: WebSocket | null = null; // Initialize socket as null 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) { 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]); - } @@ -1843,543 +1663,13 @@ function sendMessage(message) {
{#if displayedData?.length !== 0}
-
-
- -
- -
sortData("time")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Time - -
-
sortData("ticker")} - class="td cursor-pointer select-none bg-[#1E222D] font-bold text-slate-300 text-xs text-start uppercase" - > - Symbol - -
-
- Save -
-
sortData("expiry")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Expiry - -
-
sortData("dte")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - DTE - -
-
sortData("strike")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Strike - -
-
sortData("callPut")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - C/P - -
-
sortData("sentiment")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Sent. - -
-
sortData("spot")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Spot - -
-
sortData("price")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Price - -
-
sortData("premium")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Prem - -
-
sortData("type")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Type - -
-
sortData("exec")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Exec - -
-
sortData("size")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Size - -
-
sortData("vol")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - Vol - -
-
sortData("oi")} - class="td cursor-pointer select-none bg-[#1E222D] text-slate-300 font-bold text-xs text-start uppercase" - > - OI - -
-
- -
handleViewData(displayedData[index])} - slot="item" - let:index - let:style - {style} - class="tr cursor-pointer {index % 2 === 0 - ? 'bg-[#2A2E39]' - : 'bg-[#09090B]'}" - > - - -
- {formatTime(displayedData[index]?.time)} -
-
- -
- -
- addToWatchlist(displayedData[index]?.id)} - style="justify-content: center;" - class="td {optionsWatchlist.optionsId?.includes( - displayedData[index]?.id, - ) - ? 'text-[#FBCE3C]' - : 'text-white'}" - > - -
- -
- {reformatDate(displayedData[index]?.date_expiration)} -
- -
- {displayedData[index]?.dte < 0 - ? "expired" - : displayedData[index]?.dte + "d"} -
- -
- {displayedData[index]?.strike_price} -
- -
- {displayedData[index]?.put_call} -
- -
- {displayedData[index]?.sentiment} -
- -
- {displayedData[index]?.underlying_price} -
- -
- {displayedData[index]?.price} -
- -
- {abbreviateNumber(displayedData[index]?.cost_basis)} -
- -
- {displayedData[index]?.option_activity_type} -
- -
- {displayedData[index]?.execution_estimate?.replace( - "At Midpoint", - "Midpoint", - )} -
- -
- {new Intl.NumberFormat("en", { - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(displayedData[index]?.size)} -
- -
- {new Intl.NumberFormat("en", { - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(displayedData[index]?.volume)} -
- -
- {new Intl.NumberFormat("en", { - minimumFractionDigits: 0, - maximumFractionDigits: 0, - }).format(displayedData[index]?.open_interest)} -
-
-
-
-
+
{:else}
- - - - - - - - -