add implied volatility to plot

This commit is contained in:
MuslemRahimi 2024-11-07 13:50:55 +01:00
parent 4b66e6798d
commit 6bc6146ad1
4 changed files with 134 additions and 87 deletions

View File

@ -1,14 +1,35 @@
export const load = async ({ locals, params }) => { export const load = async ({ locals, params }) => {
const { apiKey, apiURL } = locals;
const getOptionsNetFlow = async () => {
const postData = {
ticker: params.tickerID,
};
const response = await fetch(apiURL + "/options-net-flow-ticker", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": 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,
}; };
const response = await fetch(locals?.apiURL + "/options-plot-ticker", { const response = await fetch(apiURL + "/options-plot-ticker", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
}); });
@ -24,17 +45,14 @@ export const load = async ({ locals, params }) => {
}; };
// make the POST request to the endpoint // make the POST request to the endpoint
const response = await fetch( const response = await fetch(apiURL + "/options-historical-data-ticker", {
locals?.apiURL + "/options-historical-data-ticker",
{
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
} });
);
const output = await response.json(); const output = await response.json();
@ -47,17 +65,14 @@ export const load = async ({ locals, params }) => {
}; };
// make the POST request to the endpoint // make the POST request to the endpoint
const response = await fetch( const response = await fetch(apiURL + "/options-chain-data-ticker", {
locals?.apiURL + "/options-chain-data-ticker",
{
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
} });
);
const output = await response.json(); const output = await response.json();
@ -70,11 +85,11 @@ export const load = async ({ locals, params }) => {
}; };
// make the POST request to the endpoint // make the POST request to the endpoint
const response = await fetch(locals?.apiURL + "/options-gex-ticker", { const response = await fetch(apiURL + "/options-gex-ticker", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
}); });
@ -86,6 +101,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

@ -93,6 +93,7 @@
let putVolumeList; //= data?.getOptionsPlotData?.putVolumeList; let putVolumeList; //= data?.getOptionsPlotData?.putVolumeList;
let callOpenInterestList; //= data?.getOptionsPlotData?.callOpenInterestList; let callOpenInterestList; //= data?.getOptionsPlotData?.callOpenInterestList;
let putOpenInterestList; //= data?.getOptionsPlotData?.putOpenInterestList; let putOpenInterestList; //= data?.getOptionsPlotData?.putOpenInterestList;
let iv60List;
let displayTimePeriod = "threeMonths"; let displayTimePeriod = "threeMonths";
@ -141,7 +142,7 @@
displayData = event.target.value; displayData = event.target.value;
} }
function plotData(callData, putData) { function plotData(callData, putData, ivData) {
const options = { const options = {
animation: false, animation: false,
tooltip: { tooltip: {
@ -162,6 +163,8 @@
type: "category", type: "category",
data: dateList, data: dateList,
axisLabel: { axisLabel: {
color: "#fff",
formatter: function (value) { formatter: function (value) {
// Assuming dates are in the format 'yyyy-mm-dd' // Assuming dates are in the format 'yyyy-mm-dd'
const dateParts = value.split("-"); const dateParts = value.split("-");
@ -179,7 +182,6 @@
splitLine: { splitLine: {
show: false, // Disable x-axis grid lines show: false, // Disable x-axis grid lines
}, },
axisLabel: { axisLabel: {
show: false, // Hide y-axis labels show: false, // Hide y-axis labels
}, },
@ -220,6 +222,19 @@
color: "#EE5365", //'#7A1C16' color: "#EE5365", //'#7A1C16'
}, },
}, },
{
name: "IV60", // Name for the line chart
type: "line", // Type of the chart (line)
yAxisIndex: 1, // Use the second y-axis on the right
data: ivData, // iv60Data (assumed to be passed as ivData)
itemStyle: {
color: "#FFD700", // Choose a color for the line (gold in this case)
},
lineStyle: {
width: 2, // Set the width of the line
},
smooth: true, // Optional: make the line smooth
},
], ],
}; };
return options; return options;
@ -369,6 +384,8 @@
dateList = filteredList?.map((item) => item.date); dateList = filteredList?.map((item) => item.date);
callVolumeList = filteredList?.map((item) => item?.CALL?.volume); callVolumeList = filteredList?.map((item) => item?.CALL?.volume);
putVolumeList = filteredList?.map((item) => item?.PUT?.volume); putVolumeList = filteredList?.map((item) => item?.PUT?.volume);
iv60List = filteredList?.map((item) => item?.iv60);
callOpenInterestList = filteredList?.map( callOpenInterestList = filteredList?.map(
(item) => item?.CALL?.open_interest, (item) => item?.CALL?.open_interest,
); );
@ -389,9 +406,9 @@
// Determine the type of plot data to generate based on displayData // Determine the type of plot data to generate based on displayData
if (displayData === "volume") { if (displayData === "volume") {
options = plotData(callVolumeList, putVolumeList); options = plotData(callVolumeList, putVolumeList, iv60List);
} else if (displayData === "openInterest") { } else if (displayData === "openInterest") {
options = plotData(callOpenInterestList, putOpenInterestList); options = plotData(callOpenInterestList, putOpenInterestList, iv60List);
} }
} }
@ -552,18 +569,22 @@
<!-- Add more Twitter meta tags as needed --> <!-- Add more Twitter meta tags as needed -->
</svelte:head> </svelte:head>
<section <section class="w-full bg-[#09090B] overflow-hidden text-white h-full">
class="bg-[#09090B] overflow-hidden text-white h-full mb-40 sm:mb-0 w-full" <div class="w-full flex h-full overflow-hidden">
>
<div class="flex justify-center m-auto h-full overflow-hidden w-full">
<div <div
class="relative flex justify-center items-center overflow-hidden w-full" class="w-full relative flex justify-center items-center overflow-hidden"
> >
<div class="xl:p-7 w-full m-auto mt-2"> <div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
<div class="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]"
@ -590,7 +611,7 @@
{#if optionsPlotData?.length !== 0} {#if optionsPlotData?.length !== 0}
<div <div
class="mb-4 grid grid-cols-2 grid-rows-2 divide-gray-500 rounded-lg border border-gray-600 bg-[#272727] shadow md:grid-cols-4 md:grid-rows-1 md:divide-x" class="mb-4 grid grid-cols-2 grid-rows-2 divide-gray-600 rounded-md border border-gray-600 md:grid-cols-4 md:grid-rows-1 md:divide-x"
> >
<div class="p-4 bp:p-5 sm:p-6"> <div class="p-4 bp:p-5 sm:p-6">
<label <label
@ -695,7 +716,7 @@
</select> </select>
</div> </div>
<div class="app w-full bg-[#09090B] rounded-xl"> <div class="app w-full bg-[#09090B]">
{#if filteredList?.length !== 0} {#if filteredList?.length !== 0}
<Chart {init} {options} class="chart" /> <Chart {init} {options} class="chart" />
{:else} {:else}
@ -752,7 +773,7 @@
{/each} {/each}
</div> </div>
<div class="app w-full bg-[#09090B] rounded-xl mb-24"> <div class="app w-full bg-[#09090B] mb-24">
<Chart {init} options={optionsEX} class="chart" /> <Chart {init} options={optionsEX} class="chart" />
</div> </div>
{/if} {/if}
@ -817,38 +838,35 @@
<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} {#if activeIdx === 0}
<table <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" class="w-full table table-sm table-compact rounded-none sm:rounded-md border-bg-[#09090B] m-auto mt-4 overflow-x-auto"
> >
<thead> <thead>
<tr class=""> <tr class="border-b border-[#27272A]">
<td <td class="text-white font-semibold text-sm text-start"
class="text-slate-200 font-semibold text-sm text-start"
>Date</td >Date</td
> >
<td class="text-slate-200 font-semibold text-sm text-end" <td class="text-white font-semibold text-sm text-end"
>% Change</td >% Change</td
> >
<td class="text-slate-200 font-semibold text-sm text-end" <td class="text-white font-semibold text-sm text-end"
>P/C</td >P/C</td
> >
<td <td class="text-white font-semibold text-sm text-center"
class="text-slate-200 font-semibold text-sm text-center"
>Bear/Bull</td >Bear/Bull</td
> >
<td <td class="text-white font-semibold text-sm text-center"
class="text-slate-200 font-semibold text-sm text-center"
>Bid/Ask Vol</td >Bid/Ask Vol</td
> >
<td class="text-slate-200 font-semibold text-sm text-end" <td class="text-white font-semibold text-sm text-end"
>% OTM</td >% OTM</td
> >
<td class="text-slate-200 font-semibold text-sm text-end" <td class="text-white font-semibold text-sm text-end"
>Total Volume</td >Total Volume</td
> >
<td class="text-slate-200 font-semibold text-sm text-end" <td class="text-white font-semibold text-sm text-end"
>Total OI</td >Total OI</td
> >
<td class="text-slate-200 font-semibold text-sm text-end" <td class="text-white font-semibold text-sm text-end"
>Total Prem</td >Total Prem</td
> >
</tr> </tr>

View File

@ -1,14 +1,16 @@
export const load = async ({ locals, params }) => { export const load = async ({ locals, params }) => {
const { apiKey, apiURL } = locals;
const getOptionsNetFlow = async () => { const getOptionsNetFlow = async () => {
const postData = { const postData = {
ticker: params.tickerID, ticker: params.tickerID,
}; };
const response = await fetch(locals?.apiURL + "/options-net-flow-ticker", { const response = await fetch(apiURL + "/options-net-flow-ticker", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
}); });
@ -23,11 +25,11 @@ export const load = async ({ locals, params }) => {
ticker: params.tickerID, ticker: params.tickerID,
}; };
const response = await fetch(locals?.apiURL + "/options-plot-ticker", { const response = await fetch(apiURL + "/options-plot-ticker", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
}); });
@ -43,17 +45,14 @@ export const load = async ({ locals, params }) => {
}; };
// make the POST request to the endpoint // make the POST request to the endpoint
const response = await fetch( const response = await fetch(apiURL + "/options-historical-data-ticker", {
locals?.apiURL + "/options-historical-data-ticker",
{
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
}, });
);
const output = await response.json(); const output = await response.json();
@ -66,17 +65,14 @@ export const load = async ({ locals, params }) => {
}; };
// make the POST request to the endpoint // make the POST request to the endpoint
const response = await fetch( const response = await fetch(apiURL + "/options-chain-data-ticker", {
locals?.apiURL + "/options-chain-data-ticker",
{
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
}, });
);
const output = await response.json(); const output = await response.json();
@ -89,11 +85,11 @@ export const load = async ({ locals, params }) => {
}; };
// make the POST request to the endpoint // make the POST request to the endpoint
const response = await fetch(locals?.apiURL + "/options-gex-ticker", { const response = await fetch(apiURL + "/options-gex-ticker", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-API-KEY": locals?.apiKey, "X-API-KEY": apiKey,
}, },
body: JSON.stringify(postData), body: JSON.stringify(postData),
}); });

View File

@ -93,6 +93,7 @@
let putVolumeList; //= data?.getOptionsPlotData?.putVolumeList; let putVolumeList; //= data?.getOptionsPlotData?.putVolumeList;
let callOpenInterestList; //= data?.getOptionsPlotData?.callOpenInterestList; let callOpenInterestList; //= data?.getOptionsPlotData?.callOpenInterestList;
let putOpenInterestList; //= data?.getOptionsPlotData?.putOpenInterestList; let putOpenInterestList; //= data?.getOptionsPlotData?.putOpenInterestList;
let iv60List;
let displayTimePeriod = "threeMonths"; let displayTimePeriod = "threeMonths";
@ -141,7 +142,7 @@
displayData = event.target.value; displayData = event.target.value;
} }
function plotData(callData, putData) { function plotData(callData, putData, ivData) {
const options = { const options = {
animation: false, animation: false,
tooltip: { tooltip: {
@ -162,6 +163,8 @@
type: "category", type: "category",
data: dateList, data: dateList,
axisLabel: { axisLabel: {
color: "#fff",
formatter: function (value) { formatter: function (value) {
// Assuming dates are in the format 'yyyy-mm-dd' // Assuming dates are in the format 'yyyy-mm-dd'
const dateParts = value.split("-"); const dateParts = value.split("-");
@ -179,7 +182,6 @@
splitLine: { splitLine: {
show: false, // Disable x-axis grid lines show: false, // Disable x-axis grid lines
}, },
axisLabel: { axisLabel: {
show: false, // Hide y-axis labels show: false, // Hide y-axis labels
}, },
@ -220,6 +222,19 @@
color: "#EE5365", //'#7A1C16' color: "#EE5365", //'#7A1C16'
}, },
}, },
{
name: "IV60", // Name for the line chart
type: "line", // Type of the chart (line)
yAxisIndex: 1, // Use the second y-axis on the right
data: ivData, // iv60Data (assumed to be passed as ivData)
itemStyle: {
color: "#FFD700", // Choose a color for the line (gold in this case)
},
lineStyle: {
width: 2, // Set the width of the line
},
smooth: true, // Optional: make the line smooth
},
], ],
}; };
return options; return options;
@ -369,6 +384,8 @@
dateList = filteredList?.map((item) => item.date); dateList = filteredList?.map((item) => item.date);
callVolumeList = filteredList?.map((item) => item?.CALL?.volume); callVolumeList = filteredList?.map((item) => item?.CALL?.volume);
putVolumeList = filteredList?.map((item) => item?.PUT?.volume); putVolumeList = filteredList?.map((item) => item?.PUT?.volume);
iv60List = filteredList?.map((item) => item?.iv60);
callOpenInterestList = filteredList?.map( callOpenInterestList = filteredList?.map(
(item) => item?.CALL?.open_interest, (item) => item?.CALL?.open_interest,
); );
@ -389,9 +406,9 @@
// Determine the type of plot data to generate based on displayData // Determine the type of plot data to generate based on displayData
if (displayData === "volume") { if (displayData === "volume") {
options = plotData(callVolumeList, putVolumeList); options = plotData(callVolumeList, putVolumeList, iv60List);
} else if (displayData === "openInterest") { } else if (displayData === "openInterest") {
options = plotData(callOpenInterestList, putOpenInterestList); options = plotData(callOpenInterestList, putOpenInterestList, iv60List);
} }
} }