update options page

This commit is contained in:
MuslemRahimi 2024-10-25 20:38:47 +02:00
parent c3ee0843e3
commit 67551ae6b2
4 changed files with 228 additions and 254 deletions

View File

@ -1,181 +1,120 @@
<script lang ='ts'> <script lang="ts">
import { optionsNetFlowComponent, stockTicker, assetType, etfTicker, getCache, setCache} from '$lib/store'; import { onMount } from "svelte";
import InfoModal from '$lib/components/InfoModal.svelte';
import { Chart } from 'svelte-echarts'
import { init, use } from 'echarts/core'
import { BarChart } from 'echarts/charts'
import { GridComponent, TooltipComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
import { monthNames} from '$lib/utils';
export let data; import InfoModal from "$lib/components/InfoModal.svelte";
import { Chart } from "svelte-echarts";
import { init, use } from "echarts/core";
import { BarChart } from "echarts/charts";
import { GridComponent, TooltipComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import { monthNames } from "$lib/utils";
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer]) export let rawData: Array<{
date: string;
price: number;
netCall: number;
netPut: number;
}>;
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer]);
let isLoaded = false; let isLoaded = false;
let rawData = [];
let optionsData; let optionsData;
let sentiment; let sentiment;
function getPlotOptions() { function getPlotOptions() {
let dates = []; const dates = [];
let priceList = []; const priceList = [];
let netCallList = []; const netCallList = [];
let netPutList = []; const netPutList = [];
// Iterate over the data and extract required information
rawData?.forEach(item => {
dates?.push(item?.date);
priceList?.push(item?.price);
netCallList?.push(item?.netCall)
netPutList?.push(item?.netPut)
if (rawData && rawData.length) {
// Populate arrays with data
rawData.forEach((item) => {
dates.push(item.date);
priceList.push(item.price);
netCallList.push(item.netCall);
netPutList.push(item.netPut);
}); });
sentiment = netCallList?.slice(-1)?.at(0) > netPutList?.slice(-1)?.at(0) ? 'bullish' : 'bearish'; // Determine sentiment
sentiment =
netCallList.at(-1) > netPutList.at(-1) ? "bullish" : "bearish";
return {
const option = {
silent: true, silent: true,
tooltip: { tooltip: {
trigger: 'axis', trigger: "axis",
hideDelay: 100, // Set the delay in milliseconds hideDelay: 100, // Tooltip delay in milliseconds
}, },
animation: false, animation: false,
grid: { grid: {
left: '3%', left: "3%",
right: '3%', right: "3%",
bottom: '0%', bottom: "0%",
top: '10%', top: "10%",
containLabel: true containLabel: true,
}, },
xAxis: { xAxis: {
type: 'category', type: "category",
boundaryGap: false, boundaryGap: false,
data: dates, // Use the full dates here data: dates,
axisLabel: { axisLabel: {
color: '#fff', color: "#fff",
formatter: function (value, index) { formatter: (value, index) => {
if (index % 2 === 0) { if (index % 2 === 0) {
const [year, month, day] = value.split("-");
const dateParts = value.split(' ')[0].split('-'); return `${day} ${monthNames[parseInt(month, 10) - 1]}`;
const day = dateParts[2]; // Extracting the day
const monthIndex = parseInt(dateParts[1], 10) - 1; // Zero-indexed months
return `${day} ${monthNames[monthIndex]}`; // Return formatted day and month
} else {
return '';
} }
} return "";
} },
}, },
},
yAxis: [ yAxis: [
{ {
type: 'value', type: "value",
splitLine: { splitLine: { show: false },
show: false, // Disable x-axis grid lines axisLabel: { show: false },
}, },
axisLabel: {
show: false // Hide y-axis labels
}
},
], ],
series: [ series: [
{ {
name: 'Net Call', name: "Net Call",
data: netCallList, data: netCallList,
type: 'bar', type: "bar",
stack: 'NetFlow', stack: "NetFlow",
itemStyle: { itemStyle: { color: "#2256FF" },
color: '#2256FF'
},
showSymbol: false, showSymbol: false,
}, },
{ {
name: 'Net Put', name: "Net Put",
data: netPutList, data: netPutList,
type: 'bar', type: "bar",
stack: 'NetFlow', stack: "NetFlow",
itemStyle: { itemStyle: { color: "#FF2256" },
color: '#FF2256'
},
showSymbol: false, showSymbol: false,
}, },
] ],
}; };
return option;
}
const getOptionsNetFlow = async (ticker) => {
// Get cached data for the specific tickerID
const cachedData = getCache(ticker, 'getOptionsNetFlow');
if (cachedData) {
rawData = cachedData;
} else { } else {
console.warn("No raw data available to populate chart options");
const postData = {'ticker': ticker, path: 'options-net-flow-ticker'}; return {};
// make the POST request to the endpoint }
const response = await fetch('/api/ticker-data', {
method: 'POST',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(postData)
});
rawData = (await response.json());
// Cache the data for this specific tickerID with a specific name 'getOptionsNetFlow'
setCache(ticker, rawData, 'getOptionsNetFlow');
} }
if(rawData?.length !== 0) { onMount(() => {
$optionsNetFlowComponent = true;
} else {
$optionsNetFlowComponent = false;
}
};
$: {
if($assetType === 'stock' ? $stockTicker :$etfTicker && typeof window !== 'undefined') {
isLoaded=false;
const ticker = $assetType === 'stock' ? $stockTicker :$etfTicker
const asyncFunctions = [
getOptionsNetFlow(ticker)
];
Promise.all(asyncFunctions)
.then((results) => {
optionsData = getPlotOptions(); optionsData = getPlotOptions();
})
.catch((error) => {
console.error('An error occurred:', error);
});
isLoaded = true; isLoaded = true;
});
</script>
} <section class="overflow-hidden text-white h-full pb-8">
} <main class="overflow-hidden">
</script>
<section class="overflow-hidden text-white h-full pb-8">
<main class="overflow-hidden ">
<div class="flex flex-row items-center"> <div class="flex flex-row items-center">
<label for="optionsNetFlowInfo" class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold"> <label
for="optionsNetFlowInfo"
class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold"
>
Options Net Flow Options Net Flow
</label> </label>
<InfoModal <InfoModal
@ -186,71 +125,81 @@
</div> </div>
{#if isLoaded} {#if isLoaded}
{#if rawData?.length !== 0} {#if rawData?.length !== 0}
<div class="w-full flex flex-col items-start"> <div class="w-full flex flex-col items-start">
<div class="text-white text-[1rem] mt-2 mb-2 w-full"> <div class="text-white text-[1rem] mt-2 mb-2 w-full">
The options net flow demonstrates a {sentiment} trend in the last 2 trading hours, characterized by the {sentiment === 'bullish' ? 'Net Call Flow exceeding the Net Put Flow' : 'Net Put Flow exceeding the Net Call Flow'}. The options net flow demonstrates a {sentiment} trend in the last 2 trading
hours, characterized by the {sentiment === "bullish"
? "Net Call Flow exceeding the Net Put Flow"
: "Net Put Flow exceeding the Net Call Flow"}.
</div> </div>
</div> </div>
<div class="pb-2 rounded-lg bg-[#09090B]"> <div class="pb-2 rounded-lg bg-[#09090B]">
<div class="app w-full h-[300px] mt-5"> <div class="app w-full h-[300px] mt-5">
<Chart {init} options={optionsData} class="chart" /> <Chart {init} options={optionsData} class="chart" />
</div> </div>
</div> </div>
<div class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12"> <div
class="flex flex-row items-center justify-between mx-auto mt-5 w-full sm:w-11/12"
<div class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"> >
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div> <div
<div class="w-3 h-3 bg-[#2256FF] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div> class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
<span class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"> >
<div
class="h-full transform -translate-x-1/2"
aria-hidden="true"
></div>
<div
class="w-3 h-3 bg-[#2256FF] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
aria-hidden="true"
></div>
<span
class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"
>
Net Call Net Call
</span> </span>
</div> </div>
<div class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"> <div
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div> class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"
<div class="w-3 h-3 bg-[#FF2F1F] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div> >
<span class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"> <div
class="h-full transform -translate-x-1/2"
aria-hidden="true"
></div>
<div
class="w-3 h-3 bg-[#FF2F1F] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2"
aria-hidden="true"
></div>
<span
class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"
>
Net Put Net Put
</span> </span>
</div> </div>
</div> </div>
{/if} {/if}
{:else} {:else}
<div class="flex justify-center items-center h-80"> <div class="flex justify-center items-center h-80">
<div class="relative"> <div class="relative">
<label class="bg-[#09090B] rounded-xl 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"> <label
<span class="loading loading-spinner loading-md text-gray-400"></span> class="bg-[#09090B] rounded-xl 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> </label>
</div> </div>
</div> </div>
{/if} {/if}
</main> </main>
</section> </section>
<style>
<style>
.app { .app {
height: 300px; height: 300px;
max-width: 100%; /* Ensure chart width doesn't exceed the container */ max-width: 100%; /* Ensure chart width doesn't exceed the container */
} }
@media (max-width: 640px) { @media (max-width: 640px) {
@ -262,5 +211,4 @@
.chart { .chart {
width: 100%; width: 100%;
} }
</style>
</style>

View File

@ -1,4 +1,23 @@
export const load = async ({ locals, params }) => { export const load = async ({ locals, params }) => {
const getOptionsNetFlow = async () => {
const postData = {
ticker: params.tickerID,
};
const response = await fetch(locals?.apiURL + "/options-net-flow-ticker", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": locals?.apiKey,
},
body: JSON.stringify(postData),
});
const output = await response.json();
return output;
};
const getOptionsPlotData = async () => { const getOptionsPlotData = async () => {
const postData = { const postData = {
ticker: params.tickerID, ticker: params.tickerID,
@ -33,7 +52,7 @@ export const load = async ({ locals, params }) => {
"X-API-KEY": locals?.apiKey, "X-API-KEY": locals?.apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
} },
); );
const output = await response.json(); const output = await response.json();
@ -56,7 +75,7 @@ export const load = async ({ locals, params }) => {
"X-API-KEY": locals?.apiKey, "X-API-KEY": locals?.apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
} },
); );
const output = await response.json(); const output = await response.json();
@ -86,6 +105,7 @@ export const load = async ({ locals, params }) => {
// Make sure to return a promise // Make sure to return a promise
return { return {
getOptionsNetFlow: await getOptionsNetFlow(),
getOptionsPlotData: await getOptionsPlotData(), getOptionsPlotData: await getOptionsPlotData(),
getOptionsHistoricalData: await getOptionsHistoricalData(), getOptionsHistoricalData: await getOptionsHistoricalData(),
getOptionsChainData: await getOptionsChainData(), getOptionsChainData: await getOptionsChainData(),

View File

@ -561,9 +561,15 @@
> >
<div class="sm:p-7 w-full m-auto mt-2 sm:mt-0"> <div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
<div class="w-full mb-6"> <div class="w-full mb-6">
<h2 class="text-2xl sm:text-3xl text-gray-200 font-bold mb-4"> <div
Unsual Options Activity class="w-full m-auto sm:pb-6 {data?.getOptionsNetFlow?.length === 0
</h2> ? 'hidden'
: ''}"
>
{#await import("$lib/components/OptionsNetFlow.svelte") then { default: Comp }}
<svelte:component this={Comp} rawData={data?.getOptionsNetFlow} />
{/await}
</div>
<div <div
class="w-fit text-white p-3 sm:p-5 mb-5 rounded-lg sm:flex sm:flex-row sm:items-center border border-slate-800 text-sm sm:text-[1rem]" class="w-fit text-white p-3 sm:p-5 mb-5 rounded-lg sm:flex sm:flex-row sm:items-center border border-slate-800 text-sm sm:text-[1rem]"

View File

@ -213,7 +213,7 @@ updateYearRange()
><span>Shares Outstanding</span> ><span>Shares Outstanding</span>
</td> </td>
<td <td
class="px-[5px] py-1.5 text-right font-medium xs:px-2.5 xs:py-2" class="px-[5px] py-1.5 text-right font-semibold xs:px-2.5 xs:py-2"
title="3,194,640,415">3.19B</td title="3,194,640,415">3.19B</td
> >
</tr><tr class="border-y border-gray-600 odd:bg-[#27272A]" </tr><tr class="border-y border-gray-600 odd:bg-[#27272A]"
@ -221,7 +221,7 @@ updateYearRange()
><span>Shares Change (YoY)</span> ><span>Shares Change (YoY)</span>
</td> </td>
<td <td
class="px-[5px] py-1.5 text-right font-medium xs:px-2.5 xs:py-2" class="px-[5px] py-1.5 text-right font-semibold xs:px-2.5 xs:py-2"
title="0.309%">+0.31%</td title="0.309%">+0.31%</td
> >
</tr><tr class="border-y border-gray-600 odd:bg-[#27272A]" </tr><tr class="border-y border-gray-600 odd:bg-[#27272A]"
@ -229,7 +229,7 @@ updateYearRange()
><span>Shares Change (QoQ)</span> ><span>Shares Change (QoQ)</span>
</td> </td>
<td <td
class="px-[5px] py-1.5 text-right font-medium xs:px-2.5 xs:py-2" class="px-[5px] py-1.5 text-right font-semibold xs:px-2.5 xs:py-2"
title="0.460%">+0.46%</td title="0.460%">+0.46%</td
> >
</tr><tr class="border-y border-gray-600 odd:bg-[#27272A]" </tr><tr class="border-y border-gray-600 odd:bg-[#27272A]"
@ -237,7 +237,7 @@ updateYearRange()
><span>Owned by Insiders (%)</span> ><span>Owned by Insiders (%)</span>
</td> </td>
<td <td
class="px-[5px] py-1.5 text-right font-medium xs:px-2.5 xs:py-2" class="px-[5px] py-1.5 text-right font-semibold xs:px-2.5 xs:py-2"
title="12.963%">12.96%</td title="12.963%">12.96%</td
> >
</tr><tr class="border-y border-gray-600 odd:bg-[#27272A]" </tr><tr class="border-y border-gray-600 odd:bg-[#27272A]"
@ -245,7 +245,7 @@ updateYearRange()
><span>Owned by Institutions (%)</span> ><span>Owned by Institutions (%)</span>
</td> </td>
<td <td
class="px-[5px] py-1.5 text-right font-medium xs:px-2.5 xs:py-2" class="px-[5px] py-1.5 text-right font-semibold xs:px-2.5 xs:py-2"
title="45.989%">45.99%</td title="45.989%">45.99%</td
> >
</tr><tr class="border-y border-gray-600 odd:bg-[#27272A]" </tr><tr class="border-y border-gray-600 odd:bg-[#27272A]"
@ -253,7 +253,7 @@ updateYearRange()
><span>Float</span> ><span>Float</span>
</td> </td>
<td <td
class="px-[5px] py-1.5 text-right font-medium xs:px-2.5 xs:py-2" class="px-[5px] py-1.5 text-right font-semibold xs:px-2.5 xs:py-2"
title="2,777,647,654">2.78B</td title="2,777,647,654">2.78B</td
> >
</tr></tbody </tr></tbody