cache options endpoint

This commit is contained in:
MuslemRahimi 2024-06-23 18:45:56 +02:00
parent 05302bbf96
commit 6b8d0b69c8
4 changed files with 144 additions and 62 deletions

View File

@ -9,12 +9,13 @@ import UpgradeToPro from '$lib/components/UpgradeToPro.svelte';
export let data; export let data;
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
let optionsPlotData = data?.getOptionsPlotData?.plot; let optionsPlotData = data?.getOptionsPlotData?.plot;
let displayData = 'volume'; let displayData = 'volume';
let options; let options;
let rawData = data?.getOptionsFlowData let rawData = data?.getOptionsFlowData
let optionList = rawData?.slice(0,15); let optionList = rawData?.slice(0,30);
let flowSentiment = 'n/a'; let flowSentiment = 'n/a';
let callPercentage; let callPercentage;
let putPercentage; let putPercentage;
@ -23,7 +24,6 @@ let displayPutVolume;
let latestPutCallRatio; let latestPutCallRatio;
const totalPutCallRatio = data?.getOptionsPlotData?.putCallRatio; const totalPutCallRatio = data?.getOptionsPlotData?.putCallRatio;
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const totalVolume = data?.getOptionsPlotData?.totalVolume; const totalVolume = data?.getOptionsPlotData?.totalVolume;
@ -47,31 +47,45 @@ const putOpenInterestList = data?.getOptionsPlotData?.putOpenInterestList;
function formatDate(timestamp) { function formatTime(timestamp) {
// Convert timestamp to milliseconds // Convert timestamp to milliseconds
var date = new Date(timestamp * 1000); var date = new Date(timestamp * 1000);
// Get month, day, hours, minutes, and seconds // hours, minutes, and seconds
var month = date.getMonth() + 1; // Month starts from 0
var day = date.getDate();
var hours = date.getHours(); var hours = date.getHours();
var minutes = date.getMinutes(); var minutes = date.getMinutes();
var seconds = date.getSeconds(); var seconds = date.getSeconds();
// Add leading zeros if necessary
month = (month < 10 ? "0" : "") + month;
day = (day < 10 ? "0" : "") + day;
hours = (hours < 10 ? "0" : "") + hours; hours = (hours < 10 ? "0" : "") + hours;
minutes = (minutes < 10 ? "0" : "") + minutes; minutes = (minutes < 10 ? "0" : "") + minutes;
seconds = (seconds < 10 ? "0" : "") + seconds; seconds = (seconds < 10 ? "0" : "") + seconds;
// Format the date string // Format the date string
var formattedDate = month + "/" + day + " " + hours + ":" + minutes + ":" + seconds; var formattedDate = hours + ":" + minutes + ":" + seconds
//var formattedDate = hours + ":" + minutes + ":" + seconds; //var formattedDate = hours + ":" + minutes + ":" + seconds;
return formattedDate; return formattedDate;
} }
function formatDate(timestamp) {
// Convert timestamp to milliseconds and create a Date object
var date = new Date(timestamp * 1000);
// Get month, day, and year
var month = date.getMonth() + 1; // Month starts from 0
var day = date.getDate();
var year = date.getFullYear();
// Add leading zeros if necessary
month = (month < 10 ? "0" : "") + month;
day = (day < 10 ? "0" : "") + day;
// Format the date string in mm/dd/YYYY
var formattedDate = month + "/" + day + "/" + year;
return formattedDate;
}
function changeStatement(event) function changeStatement(event)
{ {
@ -127,7 +141,6 @@ function plotData(callData, putData) {
} }
], ],
series: [ series: [
{ {
name: 'Call', name: 'Call',
type: 'bar', type: 'bar',
@ -137,9 +150,8 @@ function plotData(callData, putData) {
}, },
data: callData, data: callData,
itemStyle: { itemStyle: {
color: '#0FB307' color: '#00FC50'
}, },
barWidth: '30%'
}, },
{ {
name: 'Put', name: 'Put',
@ -150,10 +162,9 @@ function plotData(callData, putData) {
}, },
data: putData, data: putData,
itemStyle: { itemStyle: {
color: '#FF2F1F' //'#7A1C16' color: '#EE5365' //'#7A1C16'
}, },
}, },
] ]
}; };
return options; return options;
@ -250,7 +261,6 @@ $: {
<!-- Other meta tags --> <!-- Other meta tags -->
<meta property="og:title" content={`${$displayCompanyName} (${$etfTicker}) Options Activity · stocknear`}/> <meta property="og:title" content={`${$displayCompanyName} (${$etfTicker}) Options Activity · stocknear`}/>
<meta property="og:description" content={`Detailed informaton of unusual options activity for ${$displayCompanyName} (${$etfTicker}).`} /> <meta property="og:description" content={`Detailed informaton of unusual options activity for ${$displayCompanyName} (${$etfTicker}).`} />
<meta property="og:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>
<meta property="og:type" content="website"/> <meta property="og:type" content="website"/>
<!-- Add more Open Graph meta tags as needed --> <!-- Add more Open Graph meta tags as needed -->
@ -258,7 +268,6 @@ $: {
<meta name="twitter:card" content="summary_large_image"/> <meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:title" content={`${$displayCompanyName} (${$etfTicker}) Options Activity · stocknear`}/> <meta name="twitter:title" content={`${$displayCompanyName} (${$etfTicker}) Options Activity · stocknear`}/>
<meta name="twitter:description" content={`Detailed informaton of unusual options activity for ${$displayCompanyName} (${$etfTicker}).`} /> <meta name="twitter:description" content={`Detailed informaton of unusual options activity for ${$displayCompanyName} (${$etfTicker}).`} />
<meta name="twitter:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>
<!-- Add more Twitter meta tags as needed --> <!-- Add more Twitter meta tags as needed -->
</svelte:head> </svelte:head>
@ -389,7 +398,7 @@ $: {
<div class="w-full mt-5 mb-10 m-auto flex justify-center items-center"> <div class="w-full mt-5 mb-10 m-auto flex justify-center items-center">
<div class="w-full grid grid-cols-2 lg:grid-cols-3 gap-y-3 lg:gap-y-3 gap-x-3 "> <div class="w-full grid grid-cols-2 lg:grid-cols-3 gap-y-3 lg:gap-y-3 gap-x-3 ">
<!--Start Flow Sentiment--> <!--Start Flow Sentiment-->
<div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-5 bg-[#262626] shadow-lg rounded-lg h-20"> <div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-5 bg-[#262626] shadow-lg rounded-md h-20">
<div class="flex flex-col items-start"> <div class="flex flex-col items-start">
<span class="font-medium text-gray-200 text-sm ">Flow Sentiment</span> <span class="font-medium text-gray-200 text-sm ">Flow Sentiment</span>
<span class="text-start text-[1rem] font-medium {flowSentiment === 'Bullish' ? 'text-[#00FC50]' : 'text-[#FC2120]'}">{flowSentiment}</span> <span class="text-start text-[1rem] font-medium {flowSentiment === 'Bullish' ? 'text-[#00FC50]' : 'text-[#FC2120]'}">{flowSentiment}</span>
@ -398,7 +407,7 @@ $: {
</div> </div>
<!--End Flow Sentiment--> <!--End Flow Sentiment-->
<!--Start Put/Call--> <!--Start Put/Call-->
<div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-5 bg-[#262626] shadow-lg rounded-lg h-20"> <div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-5 bg-[#262626] shadow-lg rounded-md h-20">
<div class="flex flex-col items-start"> <div class="flex flex-col items-start">
<span class="font-medium text-gray-200 text-sm ">Put/Call</span> <span class="font-medium text-gray-200 text-sm ">Put/Call</span>
<span class="text-start text-sm sm:text-[1rem] font-medium text-white"> <span class="text-start text-sm sm:text-[1rem] font-medium text-white">
@ -425,7 +434,7 @@ $: {
</div> </div>
<!--End Put/Call--> <!--End Put/Call-->
<!--Start Call Flow--> <!--Start Call Flow-->
<div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-5 bg-[#262626] shadow-lg rounded-lg h-20"> <div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-5 bg-[#262626] shadow-lg rounded-md h-20">
<div class="flex flex-col items-start"> <div class="flex flex-col items-start">
<span class="font-medium text-gray-200 text-sm ">Call Flow</span> <span class="font-medium text-gray-200 text-sm ">Call Flow</span>
<span class="text-start text-sm sm:text-[1rem] font-medium text-white"> <span class="text-start text-sm sm:text-[1rem] font-medium text-white">
@ -454,7 +463,7 @@ $: {
</div> </div>
<!--End Call Flow--> <!--End Call Flow-->
<!--Start Put Flow--> <!--Start Put Flow-->
<div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-5 bg-[#262626] shadow-lg rounded-lg h-20"> <div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-5 bg-[#262626] shadow-lg rounded-md h-20">
<div class="flex flex-col items-start"> <div class="flex flex-col items-start">
<span class="font-medium text-gray-200 text-sm ">Put Flow</span> <span class="font-medium text-gray-200 text-sm ">Put Flow</span>
<span class="text-start text-sm sm:text-[1rem] font-medium text-white"> <span class="text-start text-sm sm:text-[1rem] font-medium text-white">
@ -499,6 +508,7 @@ $: {
<thead> <thead>
<tr class=""> <tr class="">
<td class="text-slate-200 font-semibold text-sm text-start">Time</td> <td class="text-slate-200 font-semibold text-sm text-start">Time</td>
<td class="text-slate-200 font-semibold text-sm text-start">Date</td>
<td class="text-slate-200 font-semibold text-sm text-end">Expiry</td> <td class="text-slate-200 font-semibold text-sm text-end">Expiry</td>
<td class="text-slate-200 font-semibold text-sm text-end">Strike</td> <td class="text-slate-200 font-semibold text-sm text-end">Strike</td>
<td class="text-slate-200 font-semibold text-sm text-end">C/P</td> <td class="text-slate-200 font-semibold text-sm text-end">C/P</td>
@ -512,10 +522,14 @@ $: {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each optionList as item} {#each (data?.user?.tier === 'Pro' ? optionList : optionList?.slice(0,3)) as item, index}
<!-- row --> <!-- row -->
<tr class="bg-[#0F0F0F] border-b-[#0F0F0F] "> <tr class="odd:bg-[#202020] border-b-[#0F0F0F] {index+1 === optionList?.slice(0,3)?.length && data?.user?.tier !== 'Pro' ? 'opacity-[0.1]' : ''}">
<td class="text-white text-xs sm:text-sm text-start">
{formatTime(item?.updated)}
</td>
<td class="text-white text-xs sm:text-sm text-start"> <td class="text-white text-xs sm:text-sm text-start">
{formatDate(item?.updated)} {formatDate(item?.updated)}
</td> </td>

View File

@ -1,5 +1,19 @@
import { userRegion, getCache, setCache } from '$lib/store';
const usRegion = ['cle1','iad1','pdx1','sfo1']; const usRegion = ['cle1','iad1','pdx1','sfo1'];
let apiURL = import.meta.env.VITE_EU_API_URL; // Set a default API URL
userRegion.subscribe(value => {
if (usRegion.includes(value)) {
apiURL = import.meta.env.VITE_USEAST_API_URL;
} else {
apiURL = import.meta.env.VITE_EU_API_URL;
}
});
function daysLeft(targetDate) { function daysLeft(targetDate) {
const targetTime = new Date(targetDate).getTime(); const targetTime = new Date(targetDate).getTime();
@ -13,19 +27,16 @@ function daysLeft(targetDate) {
} }
export const load = async ({ params, locals }) => { export const load = async ({ params }) => {
const userRegion = locals.region?.split("::")[0];
let apiURL;
if (usRegion?.includes(userRegion)) {
apiURL = import.meta.env.VITE_USEAST_API_URL;
} else {
apiURL = import.meta.env.VITE_EU_API_URL;
};
const getOptionsPlotData = async () => { const getOptionsPlotData = async () => {
let res;
const cachedData = getCache(params.tickerID, 'getOptionsPlotData');
if (cachedData) {
res = cachedData;
} else {
// make the POST request to the endpoint // make the POST request to the endpoint
const postData = { const postData = {
@ -71,13 +82,23 @@ export const load = async ({ params, locals }) => {
const callOpenInterestList = output?.map(item => item?.CALL?.open_interest); const callOpenInterestList = output?.map(item => item?.CALL?.open_interest);
const putOpenInterestList = output?.map(item => item?.PUT?.open_interest); const putOpenInterestList = output?.map(item => item?.PUT?.open_interest);
res = {plot: output, 'dateList': dateList, 'callOpenInterestList': callOpenInterestList, 'putOpenInterestList': putOpenInterestList, 'callVolumeList': callVolumeList, 'putVolumeList': putVolumeList, 'putCallRatio': putCallRatio, 'putCallOpenInterestRatio': putCallOpenInterestRatio,'totalVolume': totalVolume, 'totalOpenInterest': totalOpenInterest };
setCache(params.tickerID, res, 'getOptionsPlotData');
return {plot: output, 'dateList': dateList, 'callOpenInterestList': callOpenInterestList, 'putOpenInterestList': putOpenInterestList, 'callVolumeList': callVolumeList, 'putVolumeList': putVolumeList, 'putCallRatio': putCallRatio, 'putCallOpenInterestRatio': putCallOpenInterestRatio,'totalVolume': totalVolume, 'totalOpenInterest': totalOpenInterest }; }
return res;
}; };
const getOptionsFlowData = async () => { const getOptionsFlowData = async () => {
let output;
const cachedData = getCache(params.tickerID, 'getOptionsFlowData');
if (cachedData) {
output = cachedData;
} else {
const postData = { const postData = {
ticker: params.tickerID ticker: params.tickerID
}; };
@ -91,11 +112,14 @@ export const load = async ({ params, locals }) => {
body: JSON.stringify(postData) body: JSON.stringify(postData)
}); });
const output = await response.json(); output = await response.json();
output?.forEach(item => { output?.forEach(item => {
item.dte = daysLeft(item?.date_expiration); item.dte = daysLeft(item?.date_expiration);
}); });
setCache(params.tickerID, output, 'getOptionsFlowData');
}
return output; return output;
}; };
@ -105,4 +129,5 @@ export const load = async ({ params, locals }) => {
getOptionsPlotData: await getOptionsPlotData(), getOptionsPlotData: await getOptionsPlotData(),
getOptionsFlowData: await getOptionsFlowData() getOptionsFlowData: await getOptionsFlowData()
}; };
}; };

View File

@ -15,7 +15,7 @@ let optionsPlotData = data?.getOptionsPlotData?.plot;
let displayData = 'volume'; let displayData = 'volume';
let options; let options;
let rawData = data?.getOptionsFlowData let rawData = data?.getOptionsFlowData
let optionList = rawData?.slice(0,15); let optionList = rawData?.slice(0,30);
let flowSentiment = 'n/a'; let flowSentiment = 'n/a';
let callPercentage; let callPercentage;
let putPercentage; let putPercentage;
@ -47,31 +47,45 @@ const putOpenInterestList = data?.getOptionsPlotData?.putOpenInterestList;
function formatDate(timestamp) { function formatTime(timestamp) {
// Convert timestamp to milliseconds // Convert timestamp to milliseconds
var date = new Date(timestamp * 1000); var date = new Date(timestamp * 1000);
// Get month, day, hours, minutes, and seconds // hours, minutes, and seconds
var month = date.getMonth() + 1; // Month starts from 0
var day = date.getDate();
var hours = date.getHours(); var hours = date.getHours();
var minutes = date.getMinutes(); var minutes = date.getMinutes();
var seconds = date.getSeconds(); var seconds = date.getSeconds();
// Add leading zeros if necessary
month = (month < 10 ? "0" : "") + month;
day = (day < 10 ? "0" : "") + day;
hours = (hours < 10 ? "0" : "") + hours; hours = (hours < 10 ? "0" : "") + hours;
minutes = (minutes < 10 ? "0" : "") + minutes; minutes = (minutes < 10 ? "0" : "") + minutes;
seconds = (seconds < 10 ? "0" : "") + seconds; seconds = (seconds < 10 ? "0" : "") + seconds;
// Format the date string // Format the date string
var formattedDate = month + "/" + day + " " + hours + ":" + minutes + ":" + seconds; var formattedDate = hours + ":" + minutes + ":" + seconds
//var formattedDate = hours + ":" + minutes + ":" + seconds; //var formattedDate = hours + ":" + minutes + ":" + seconds;
return formattedDate; return formattedDate;
} }
function formatDate(timestamp) {
// Convert timestamp to milliseconds and create a Date object
var date = new Date(timestamp * 1000);
// Get month, day, and year
var month = date.getMonth() + 1; // Month starts from 0
var day = date.getDate();
var year = date.getFullYear();
// Add leading zeros if necessary
month = (month < 10 ? "0" : "") + month;
day = (day < 10 ? "0" : "") + day;
// Format the date string in mm/dd/YYYY
var formattedDate = month + "/" + day + "/" + year;
return formattedDate;
}
function changeStatement(event) function changeStatement(event)
{ {
@ -136,9 +150,8 @@ function plotData(callData, putData) {
}, },
data: callData, data: callData,
itemStyle: { itemStyle: {
color: '#0FB307' color: '#00FC50'
}, },
barWidth: '30%',
}, },
{ {
name: 'Put', name: 'Put',
@ -149,7 +162,7 @@ function plotData(callData, putData) {
}, },
data: putData, data: putData,
itemStyle: { itemStyle: {
color: '#FF2F1F' //'#7A1C16' color: '#EE5365' //'#7A1C16'
}, },
}, },
] ]
@ -495,6 +508,7 @@ $: {
<thead> <thead>
<tr class=""> <tr class="">
<td class="text-slate-200 font-semibold text-sm text-start">Time</td> <td class="text-slate-200 font-semibold text-sm text-start">Time</td>
<td class="text-slate-200 font-semibold text-sm text-start">Date</td>
<td class="text-slate-200 font-semibold text-sm text-end">Expiry</td> <td class="text-slate-200 font-semibold text-sm text-end">Expiry</td>
<td class="text-slate-200 font-semibold text-sm text-end">Strike</td> <td class="text-slate-200 font-semibold text-sm text-end">Strike</td>
<td class="text-slate-200 font-semibold text-sm text-end">C/P</td> <td class="text-slate-200 font-semibold text-sm text-end">C/P</td>
@ -510,8 +524,12 @@ $: {
<tbody> <tbody>
{#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}
<!-- row --> <!-- row -->
<tr class="bg-[#0F0F0F] border-b-[#0F0F0F] {index+1 === optionList?.slice(0,3)?.length && data?.user?.tier !== 'Pro' ? 'opacity-[0.1]' : ''}"> <tr class="odd:bg-[#202020] border-b-[#0F0F0F] {index+1 === optionList?.slice(0,3)?.length && data?.user?.tier !== 'Pro' ? 'opacity-[0.1]' : ''}">
<td class="text-white text-xs sm:text-sm text-start">
{formatTime(item?.updated)}
</td>
<td class="text-white text-xs sm:text-sm text-start"> <td class="text-white text-xs sm:text-sm text-start">
{formatDate(item?.updated)} {formatDate(item?.updated)}
</td> </td>

View File

@ -1,5 +1,19 @@
import { userRegion, getCache, setCache } from '$lib/store';
const usRegion = ['cle1','iad1','pdx1','sfo1']; const usRegion = ['cle1','iad1','pdx1','sfo1'];
let apiURL = import.meta.env.VITE_EU_API_URL; // Set a default API URL
userRegion.subscribe(value => {
if (usRegion.includes(value)) {
apiURL = import.meta.env.VITE_USEAST_API_URL;
} else {
apiURL = import.meta.env.VITE_EU_API_URL;
}
});
function daysLeft(targetDate) { function daysLeft(targetDate) {
const targetTime = new Date(targetDate).getTime(); const targetTime = new Date(targetDate).getTime();
@ -13,19 +27,16 @@ function daysLeft(targetDate) {
} }
export const load = async ({ params, locals }) => { export const load = async ({ params }) => {
const userRegion = locals.region?.split("::")[0];
let apiURL;
if (usRegion?.includes(userRegion)) {
apiURL = import.meta.env.VITE_USEAST_API_URL;
} else {
apiURL = import.meta.env.VITE_EU_API_URL;
};
const getOptionsPlotData = async () => { const getOptionsPlotData = async () => {
let res;
const cachedData = getCache(params.tickerID, 'getOptionsPlotData');
if (cachedData) {
res = cachedData;
} else {
// make the POST request to the endpoint // make the POST request to the endpoint
const postData = { const postData = {
@ -71,13 +82,23 @@ export const load = async ({ params, locals }) => {
const callOpenInterestList = output?.map(item => item?.CALL?.open_interest); const callOpenInterestList = output?.map(item => item?.CALL?.open_interest);
const putOpenInterestList = output?.map(item => item?.PUT?.open_interest); const putOpenInterestList = output?.map(item => item?.PUT?.open_interest);
res = {plot: output, 'dateList': dateList, 'callOpenInterestList': callOpenInterestList, 'putOpenInterestList': putOpenInterestList, 'callVolumeList': callVolumeList, 'putVolumeList': putVolumeList, 'putCallRatio': putCallRatio, 'putCallOpenInterestRatio': putCallOpenInterestRatio,'totalVolume': totalVolume, 'totalOpenInterest': totalOpenInterest };
setCache(params.tickerID, res, 'getOptionsPlotData');
return {plot: output, 'dateList': dateList, 'callOpenInterestList': callOpenInterestList, 'putOpenInterestList': putOpenInterestList, 'callVolumeList': callVolumeList, 'putVolumeList': putVolumeList, 'putCallRatio': putCallRatio, 'putCallOpenInterestRatio': putCallOpenInterestRatio,'totalVolume': totalVolume, 'totalOpenInterest': totalOpenInterest }; }
return res;
}; };
const getOptionsFlowData = async () => { const getOptionsFlowData = async () => {
let output;
const cachedData = getCache(params.tickerID, 'getOptionsFlowData');
if (cachedData) {
output = cachedData;
} else {
const postData = { const postData = {
ticker: params.tickerID ticker: params.tickerID
}; };
@ -91,11 +112,14 @@ export const load = async ({ params, locals }) => {
body: JSON.stringify(postData) body: JSON.stringify(postData)
}); });
const output = await response.json(); output = await response.json();
output?.forEach(item => { output?.forEach(item => {
item.dte = daysLeft(item?.date_expiration); item.dte = daysLeft(item?.date_expiration);
}); });
setCache(params.tickerID, output, 'getOptionsFlowData');
}
return output; return output;
}; };
@ -105,4 +129,5 @@ export const load = async ({ params, locals }) => {
getOptionsPlotData: await getOptionsPlotData(), getOptionsPlotData: await getOptionsPlotData(),
getOptionsFlowData: await getOptionsFlowData() getOptionsFlowData: await getOptionsFlowData()
}; };
}; };