add chain data

This commit is contained in:
MuslemRahimi 2024-09-08 20:55:26 +02:00
parent 4b26a2ac8b
commit 5ab3a76afa
2 changed files with 155 additions and 165 deletions

View File

@ -23,18 +23,12 @@
let displayData = 'volume'; let displayData = 'volume';
let options; let options;
let optionsGEX; let optionsGEX;
let rawData = data?.getOptionsChain
let rawData = data?.getOptionsHistoricalData;
let optionList = rawData?.slice(0,30); let optionList = rawData?.slice(0,30);
let flowSentiment = 'n/a'; let optionChainList = data?.getOptionsChainData?.at(0)?.chain || [];
let callPercentage;
let putPercentage;
let displayCallVolume;
let displayPutVolume;
let latestPutCallRatio;
let displayOTMRatio;
let totalVolume //= data?.getOptionsPlotData?.totalVolume; let totalVolume //= data?.getOptionsPlotData?.totalVolume;
let totalOpenInterest //= data?.getOptionsPlotData?.totalOpenInterest; let totalOpenInterest //= data?.getOptionsPlotData?.totalOpenInterest;
@ -109,10 +103,6 @@ function normalizer(value) {
return formattedTimeString; return formattedTimeString;
} }
function changeStatement(event)
{
displayData = event.target.value;
}
function changeTimePeriod(event) function changeTimePeriod(event)
{ {
@ -306,55 +296,6 @@ function getGEXPlot() {
return option; return option;
} }
function calculateStats() {
const currentPrice = parseFloat(data?.getStockQuote?.price);
const { callVolumeSum, putVolumeSum, bullishCount, bearishCount, otmVolume, itmVolume } = rawData?.reduce((acc, item) => {
const volume = parseInt(item?.volume);
const strikePrice = parseFloat(item?.strike_price);
if (item?.put_call === "Calls") {
acc.callVolumeSum += volume;
if (strikePrice > currentPrice) {
acc.otmVolume += volume;
} else {
acc.itmVolume += volume;
}
} else if (item?.put_call === "Puts") {
acc.putVolumeSum += volume;
if (strikePrice < currentPrice) {
acc.itmVolume += volume;
} else {
acc.otmVolume += volume;
}
}
if (item?.sentiment === "Bullish") {
acc.bullishCount += 1;
} else if (item?.sentiment === "Bearish") {
acc.bearishCount += 1;
}
return acc;
}, { callVolumeSum: 0, putVolumeSum: 0, bullishCount: 0, bearishCount: 0, otmVolume: 0, itmVolume: 0 });
if (bullishCount > bearishCount) {
flowSentiment = 'Bullish';
} else if (bullishCount < bearishCount) {
flowSentiment = 'Bearish';
} else {
flowSentiment = 'Neutral';
}
latestPutCallRatio = (putVolumeSum / callVolumeSum);
callPercentage = Math.floor((callVolumeSum) / (callVolumeSum + putVolumeSum) * 100);
putPercentage = (100 - callPercentage);
displayCallVolume = callVolumeSum;
displayPutVolume = putVolumeSum;
// Calculate OTM/ITM ratio
displayOTMRatio = otmVolume / (itmVolume+otmVolume) ?? 0;
}
function filterDate(filteredList, displayTimePeriod) { function filterDate(filteredList, displayTimePeriod) {
const now = Date.now(); const now = Date.now();
@ -469,12 +410,28 @@ function handleViewData(optionData) {
optionHistoryList?.forEach((item) => { optionHistoryList?.forEach((item) => {
item.dte = daysLeft(item?.date_expiration); item.dte = daysLeft(item?.date_expiration);
}); });
//const openPopup = $screenWidth < 640 ? document.getElementById("optionDetailsMobileModal") : document.getElementById("optionDetailsDesktopModal");
//openPopup?.dispatchEvent(new MouseEvent('click'))
optionDetailsDesktopModal?.showModal() optionDetailsDesktopModal?.showModal()
} }
function handleMode(i) {
activeIdx = i;
}
const tabs = [
{
title: "Historical Data",
},
{
title: "Chain Data",
},
];
let activeIdx = 0;
function changeStatement(event)
{
optionChainList = (data?.getOptionsChainData?.filter(item => item?.date_expiration === event.target.value))?.at(0)?.chain || [];
}
$: { $: {
if ((displayTimePeriod || displayData) && optionsPlotData?.length !== 0 && typeof window !== 'undefined') { if ((displayTimePeriod || displayData) && optionsPlotData?.length !== 0 && typeof window !== 'undefined') {
@ -611,7 +568,7 @@ $: {
<option value="oneYear">1 Year</option> <option value="oneYear">1 Year</option>
</select> </select>
<select class="ml-auto sm:ml-3 w-40 select select-bordered select-sm p-0 pl-5 bg-[#2A303C]" on:change={changeStatement}> <select class="ml-auto sm:ml-3 w-40 select select-bordered select-sm p-0 pl-5 bg-[#2A303C]">
<option disabled>Choose a category</option> <option disabled>Choose a category</option>
<option value="volume" selected>Volume</option> <option value="volume" selected>Volume</option>
<option value="openInterest">Open Interest</option> <option value="openInterest">Open Interest</option>
@ -637,7 +594,7 @@ $: {
{#if data?.getOptionsGexData?.length !== 0} {#if data?.getOptionsGexData?.length !== 0}
<h3 class="text-2xl sm:text-2xl text-gray-200 font-bold mb-4 text-center sm:text-start"> <h3 class="text-2xl text-gray-200 font-bold mb-4 text-start">
Daily Gamma Exposure (GEX) Daily Gamma Exposure (GEX)
</h3> </h3>
@ -648,21 +605,51 @@ $: {
{/if} {/if}
<h3 class="text-2xl sm:text-3xl text-gray-200 font-bold mb-4 text-center sm:text-start"> <h3 class="text-2xl text-gray-200 font-bold mb-4 text-start">
Historical Option Data {activeIdx === 0 ? 'Historical Option Data' : 'Option Chain Data'}
</h3> </h3>
{#if optionList?.length !== 0} {#if optionList?.length !== 0}
<div class="bg-[#313131] w-fit relative flex flex-wrap items-center justify-center rounded-lg p-1 mt-6 mb-6">
{#each tabs as item, i}
<button
on:click={() => handleMode(i)}
class="group relative z-[1] rounded-full px-6 py-1 {activeIdx === i
? 'z-0'
: ''} "
>
{#if activeIdx === i}
<div
class="absolute inset-0 rounded-lg bg-purple-600"
></div>
{/if}
<span
class="relative text-sm block font-medium duration-200 text-white">
{item.title}
</span>
</button>
{/each}
</div>
{#if activeIdx === 1}
<div class="relative mb-6">
<select class="w-48 select select-bordered select-sm p-0 pl-5 overflow-y-auto bg-[#2A303C]" on:change={changeStatement}>
<option disabled>Choose an Expiration Date</option>
{#each data?.getOptionsChainData as item, index}
<option value={item?.date_expiration} selected={index === 0 ? true : false}>
{new Date(item?.date_expiration)?.toLocaleString('en-US', { month: 'short', day: 'numeric', year: 'numeric', daySuffix: '2-digit' })}
</option>
{/each}
</select>
</div>
{/if}
<div class="flex justify-start items-center m-auto overflow-x-auto"> <div class="flex justify-start items-center m-auto overflow-x-auto">
{#if activeIdx === 0}
<table class="table table-pin-cols table-sm table-compact rounded-none sm:rounded-md w-full border-bg-[#09090B] m-auto mt-4 overflow-x-auto"> <table class="table table-pin-cols table-sm table-compact rounded-none sm:rounded-md w-full border-bg-[#09090B] m-auto mt-4 overflow-x-auto">
<thead> <thead>
<tr class=""> <tr class="">
@ -680,7 +667,6 @@ $: {
{#each (data?.user?.tier === 'Pro' ? optionList : optionList?.slice(0,3)) as item, index} {#each (data?.user?.tier === 'Pro' ? optionList : optionList?.slice(0,3)) as item, index}
<tr on:click={() => handleViewData(item?.history)} class="cursor-pointer sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] border-b-[#09090B] {index+1 === optionList?.slice(0,3)?.length && data?.user?.tier !== 'Pro' ? 'opacity-[0.1]' : ''}"> <tr on:click={() => handleViewData(item?.history)} class="cursor-pointer sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] border-b-[#09090B] {index+1 === optionList?.slice(0,3)?.length && data?.user?.tier !== 'Pro' ? 'opacity-[0.1]' : ''}">
<td class="text-white text-sm sm:text-[1rem] text-start"> <td class="text-white text-sm sm:text-[1rem] text-start">
{formatDate(item?.date)} {formatDate(item?.date)}
</td> </td>
@ -757,6 +743,63 @@ $: {
</tbody> </tbody>
</table> </table>
{:else}
<table class="table table-pin-cols table-sm table-compact rounded-none sm:rounded-md w-full border-bg-[#09090B] m-auto mt-4 overflow-x-auto">
<thead>
<tr class="">
<td class="text-slate-200 font-semibold text-sm text-end">Call Prem</td>
<td class="text-slate-200 font-semibold text-sm text-end">Call OI</td>
<td class="text-slate-200 font-semibold text-sm text-end">Call Volume</td>
<td class="text-slate-200 font-semibold text-sm text-center">Strike Price</td>
<td class="text-slate-200 font-semibold text-sm text-start">Put Volume</td>
<td class="text-slate-200 font-semibold text-sm text-start">Put OI</td>
<td class="text-slate-200 font-semibold text-sm text-start">Put Prem</td>
</tr>
</thead>
<tbody>
{#each (data?.user?.tier === 'Pro' ? optionChainList : optionChainList?.slice(0,3)) as item, index}
<tr class="odd:bg-[#27272A] border-b-[#09090B] {index+1 === optionChainList?.slice(0,3)?.length && data?.user?.tier !== 'Pro' ? 'opacity-[0.1]' : ''}">
<td class="text-white text-sm sm:text-[1rem] text-end">
{abbreviateNumber(item?.total_premium_call,true)}
</td>
<td class="text-sm sm:text-[1rem] text-end text-white">
{item?.total_open_interest_call}
</td>
<td class="text-sm sm:text-[1rem] text-end text-white">
{item?.total_volume_call}
</td>
<td class="whitespace-nowrap text-sm sm:text-[1rem] {item?.put_call === 'Calls' ? 'text-[#00FC50]' : 'text-[#FC2120]'} text-end">
<div class="rounded-lg w-fit px-2 text-center font-semibold badge gap-2 bg-[#FBCE3C] text-black m-auto flex justify-center items-center">
{item?.strike_price}
</div>
</td>
<td class="text-sm sm:text-[1rem] text-start text-white">
{item?.total_volume_put}
</td>
<td class="text-sm sm:text-[1rem] text-start text-white">
{item?.total_open_interest_put}
</td>
<td class="text-white text-sm sm:text-[1rem] text-start">
{abbreviateNumber(item?.total_premium_put,true)}
</td>
</tr>
{/each}
</tbody>
</table>
{/if}
</div> </div>
@ -913,88 +956,6 @@ $: {
<!--End Options Detial Desktop Modal--> <!--End Options Detial Desktop Modal-->
<!--Start Options Detail Modal-->
<!--
<div class="hidden drawer drawer-end z-[999] w-full overflow-hidden">
<input id="optionDetailsMobileModal" type="checkbox" class="drawer-toggle"/>
<div class="drawer-side overflow-hidden z-[999]">
<div class="bg-[#000] min-h-screen w-full border pb-20 overflow-hidden">
<label for="optionDetailsMobileModal" class="absolute left-6 top-6">
<svg class="w-6 h-6 inline-block mb-0.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#fff" d="M9.125 21.1L.7 12.7q-.15-.15-.213-.325T.425 12q0-.2.063-.375T.7 11.3l8.425-8.425q.35-.35.875-.35t.9.375q.375.375.375.875t-.375.875L3.55 12l7.35 7.35q.35.35.35.863t-.375.887q-.375.375-.875.375t-.875-.375Z"/></svg>
</label>
<div class="w-fit border overflow-hidden p-2">
<p class="text-xl font-semibold text-white mt-16 p-3">
<span class="text-xl font-semibold">Order Details:</span>
<br>
{optionSymbol}
</p>
<p class="py-4 text-gray-200 w-full p-3">
<span class="font-semibold text-white">Description:</span>
{optionDescription}
</p>
<table class="table table-sm table-compact w-full mt-5 mb-10 text-white">
<tbody>
<tr class="border-b border-slate-700 odd:bg-[#27272A]">
<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-[#27272A]">
<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-[#27272A]">
<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-[#27272A]">
<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-[#27272A]">
<td class="font-semibold">Price</td>
<td class="">${optionPrice}</td>
<td class="font-semibold">Sentiment</td>
<td class="">{optionSentiment}</td>
</tr>
<tr class="odd:bg-[#27272A]">
<td class="font-semibold">Trade Count</td>
<td class="">{optionTradeCount}</td>
<td class="font-semibold">Exchange</td>
<td class="">{optionExchange}</td>
</tr>
<tr class="border-b border-slate-700 odd:bg-[#27272A]">
<td class="font-semibold">Execution Est.</td>
<td class="">{optionExecutionEstimate}</td>
<td class="font-semibold"></td>
<td class=""></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
-->
<!--End Options Detail Modal-->
<style> <style>
.app { .app {

View File

@ -39,9 +39,9 @@ export const load = async ({ parent, params }) => {
} }
}; };
const getOptionsChain = async () => { const getOptionsHistoricalData = async () => {
let output; let output;
const cachedData = getCache(params.tickerID, "getOptionsChain"); const cachedData = getCache(params.tickerID, "getOptionsHistoricalData");
if (cachedData) { if (cachedData) {
output = cachedData; output = cachedData;
} else { } else {
@ -50,7 +50,7 @@ export const load = async ({ parent, params }) => {
}; };
// make the POST request to the endpoint // make the POST request to the endpoint
const response = await fetch(apiURL + "/options-chain-ticker", { const response = await fetch(apiURL + "/options-historical-data-ticker", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -61,7 +61,35 @@ export const load = async ({ parent, params }) => {
output = await response.json(); output = await response.json();
setCache(params.tickerID, output, "getOptionsChain"); setCache(params.tickerID, output, "getOptionsHistoricalData");
}
return output;
};
const getOptionsChainData = async () => {
let output;
const cachedData = getCache(params.tickerID, "getOptionsChainData");
if (cachedData) {
output = cachedData;
} else {
const postData = {
ticker: params.tickerID,
};
// make the POST request to the endpoint
const response = await fetch(apiURL + "/options-chain-data-ticker", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": apiKey,
},
body: JSON.stringify(postData),
});
output = await response.json();
setCache(params.tickerID, output, "getOptionsChainData");
} }
return output; return output;
@ -98,7 +126,8 @@ export const load = async ({ parent, params }) => {
// Make sure to return a promise // Make sure to return a promise
return { return {
getOptionsPlotData: await getOptionsPlotData(), getOptionsPlotData: await getOptionsPlotData(),
getOptionsChain: await getOptionsChain(), getOptionsHistoricalData: await getOptionsHistoricalData(),
getOptionsChainData: await getOptionsChainData(),
getOptionsGexData: await getOptionsGexData(), getOptionsGexData: await getOptionsGexData(),
}; };
}; };