update
This commit is contained in:
parent
46985e413a
commit
a5758649b2
@ -7,10 +7,10 @@
|
|||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import UpgradeToPro from '$lib/components/UpgradeToPro.svelte';
|
import UpgradeToPro from '$lib/components/UpgradeToPro.svelte';
|
||||||
import { init, use } from 'echarts/core'
|
import { init, use } from 'echarts/core'
|
||||||
import { BarChart } from 'echarts/charts'
|
import { BarChart,LineChart } from 'echarts/charts'
|
||||||
import { GridComponent, TooltipComponent } from 'echarts/components'
|
import { GridComponent, TooltipComponent } from 'echarts/components'
|
||||||
import { CanvasRenderer } from 'echarts/renderers'
|
import { CanvasRenderer } from 'echarts/renderers'
|
||||||
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer])
|
use([BarChart,LineChart, GridComponent, TooltipComponent, CanvasRenderer])
|
||||||
|
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
@ -22,6 +22,7 @@
|
|||||||
let optionsPlotData = data?.getOptionsPlotData?.plot;
|
let optionsPlotData = data?.getOptionsPlotData?.plot;
|
||||||
let displayData = 'volume';
|
let displayData = 'volume';
|
||||||
let options;
|
let options;
|
||||||
|
let optionsGEX;
|
||||||
let rawData = data?.getOptionsFlowData
|
let rawData = data?.getOptionsFlowData
|
||||||
let optionList = rawData?.slice(0,30);
|
let optionList = rawData?.slice(0,30);
|
||||||
let flowSentiment = 'n/a';
|
let flowSentiment = 'n/a';
|
||||||
@ -55,7 +56,22 @@
|
|||||||
|
|
||||||
let displayTimePeriod = 'threeMonths'
|
let displayTimePeriod = 'threeMonths'
|
||||||
|
|
||||||
|
function normalizer(value) {
|
||||||
|
if (Math?.abs(value) >= 1e18) {
|
||||||
|
return { unit: 'Q', denominator: 1e18 };
|
||||||
|
} else if (Math?.abs(value) >= 1e12) {
|
||||||
|
return { unit: 'T', denominator: 1e12 };
|
||||||
|
} else if (Math?.abs(value) >= 1e9) {
|
||||||
|
return { unit: 'B', denominator: 1e9 };
|
||||||
|
} else if (Math?.abs(value) >= 1e6) {
|
||||||
|
return { unit: 'M', denominator: 1e6 };
|
||||||
|
} else if (Math?.abs(value) >= 1e5) {
|
||||||
|
return { unit: 'K', denominator: 1e5 };
|
||||||
|
} else {
|
||||||
|
return { unit: '', denominator: 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function formatDate(dateStr) {
|
function formatDate(dateStr) {
|
||||||
// Parse the input date string (YYYY-mm-dd)
|
// Parse the input date string (YYYY-mm-dd)
|
||||||
var date = new Date(dateStr);
|
var date = new Date(dateStr);
|
||||||
@ -105,79 +121,191 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
function plotData(callData, putData) {
|
function plotData(callData, putData) {
|
||||||
const options = {
|
const options = {
|
||||||
animation: false,
|
animation: false,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
type: 'shadow'
|
type: 'shadow'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
silent: true,
|
silent: true,
|
||||||
grid: {
|
grid: {
|
||||||
left: $screenWidth < 640 ? '5%' : '2%',
|
left: $screenWidth < 640 ? '5%' : '2%',
|
||||||
right: $screenWidth < 640 ? '5%' : '2%',
|
right: $screenWidth < 640 ? '5%' : '2%',
|
||||||
bottom: '20%',
|
bottom: '20%',
|
||||||
containLabel: true
|
containLabel: true
|
||||||
},
|
},
|
||||||
xAxis: [
|
xAxis: [
|
||||||
{
|
|
||||||
type: 'category',
|
|
||||||
data: dateList,
|
|
||||||
axisLabel: {
|
|
||||||
formatter: function (value) {
|
|
||||||
// Assuming dates are in the format 'yyyy-mm-dd'
|
|
||||||
const dateParts = value.split('-');
|
|
||||||
const monthIndex = parseInt(dateParts[1]) - 1; // Months are zero-indexed in JavaScript Date objects
|
|
||||||
const year = parseInt(dateParts[0]);
|
|
||||||
const day = parseInt(dateParts[2])
|
|
||||||
return `${day} ${monthNames[monthIndex]} ${year}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
yAxis: [
|
|
||||||
{
|
{
|
||||||
type: 'value',
|
type: 'category',
|
||||||
splitLine: {
|
data: dateList,
|
||||||
show: false,
|
axisLabel: {
|
||||||
},
|
formatter: function (value) {
|
||||||
axisLabel: {
|
// Assuming dates are in the format 'yyyy-mm-dd'
|
||||||
show: false // Hide the y-axis label
|
const dateParts = value.split('-');
|
||||||
}
|
const monthIndex = parseInt(dateParts[1]) - 1; // Months are zero-indexed in JavaScript Date objects
|
||||||
|
const year = parseInt(dateParts[0]);
|
||||||
|
const day = parseInt(dateParts[2])
|
||||||
|
return `${day} ${monthNames[monthIndex]} ${year}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
series: [
|
yAxis: [
|
||||||
{
|
{
|
||||||
name: 'Call',
|
type: 'value',
|
||||||
type: 'bar',
|
splitLine: {
|
||||||
stack: 'Put-Call Ratio',
|
show: false,
|
||||||
emphasis: {
|
},
|
||||||
focus: 'series'
|
axisLabel: {
|
||||||
|
show: false // Hide the y-axis label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Call',
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'Put-Call Ratio',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: callData,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#00FC50'
|
||||||
},
|
},
|
||||||
data: callData,
|
},
|
||||||
itemStyle: {
|
{
|
||||||
color: '#00FC50'
|
name: 'Put',
|
||||||
},
|
type: 'bar',
|
||||||
|
stack: 'Put-Call Ratio',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: putData,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#EE5365' //'#7A1C16'
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
name: 'Put',
|
]
|
||||||
type: 'bar',
|
};
|
||||||
stack: 'Put-Call Ratio',
|
return options;
|
||||||
emphasis: {
|
}
|
||||||
focus: 'series'
|
|
||||||
},
|
function getGEXPlot() {
|
||||||
data: putData,
|
let dates = [];
|
||||||
itemStyle: {
|
let gexList = [];
|
||||||
color: '#EE5365' //'#7A1C16'
|
let priceList = [];
|
||||||
},
|
|
||||||
},
|
data?.getOptionsGexData?.forEach(item => {
|
||||||
]
|
|
||||||
};
|
dates?.push(item?.date);
|
||||||
return options;
|
gexList?.push(item?.gex);
|
||||||
}
|
priceList?.push(item?.close)
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const {unit, denominator } = normalizer(Math.max(...gexList) ?? 0)
|
||||||
|
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
silent: true,
|
||||||
|
animation: false,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
hideDelay: 100, // Set the delay in milliseconds
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '0%',
|
||||||
|
right: '0%',
|
||||||
|
bottom: '0%',
|
||||||
|
top: '5%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: dates,
|
||||||
|
axisLabel: {
|
||||||
|
color: '#fff',
|
||||||
|
formatter: function (value) {
|
||||||
|
// Assuming dates are in the format 'yyyy-mm-dd'
|
||||||
|
// Extract the month and day from the date string and convert the month to its abbreviated name
|
||||||
|
const dateParts = value.split('-');
|
||||||
|
const day = dateParts[2].substring(0); // Extracting the last two digits of the year
|
||||||
|
const monthIndex = parseInt(dateParts[1]) - 1; // Months are zero-indexed in JavaScript Date objects
|
||||||
|
return `${day} ${monthNames[monthIndex]}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
splitLine: {
|
||||||
|
show: false, // Disable x-axis grid lines
|
||||||
|
},
|
||||||
|
position: 'left',
|
||||||
|
axisLabel: {
|
||||||
|
color: '#fff',
|
||||||
|
formatter: function (value, index) {
|
||||||
|
if (index % 2 === 0) {
|
||||||
|
return value?.toFixed(2); // Format the sentiment value
|
||||||
|
} else {
|
||||||
|
return ''; // Hide this tick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: 'right',
|
||||||
|
type: 'value',
|
||||||
|
splitLine: {
|
||||||
|
show: false, // Disable x-axis grid lines
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#fff', // Change label color to white
|
||||||
|
formatter: function (value, index) {
|
||||||
|
// Display every second tick
|
||||||
|
if (index % 2 === 0) {
|
||||||
|
value = Math.max(value, 0);
|
||||||
|
return (value / denominator)?.toFixed(1) + unit; // Format value in millions
|
||||||
|
} else {
|
||||||
|
return ''; // Hide this tick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Price',
|
||||||
|
data: priceList,
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 0,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#fff' // Change bar color to white
|
||||||
|
},
|
||||||
|
showSymbol: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'GEX',
|
||||||
|
data: gexList,
|
||||||
|
type: 'bar',
|
||||||
|
yAxisIndex: 1,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#8e53f4' // Change bar color to white
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
function calculateStats() {
|
function calculateStats() {
|
||||||
const currentPrice = parseFloat(data?.getStockQuote?.price);
|
const currentPrice = parseFloat(data?.getStockQuote?.price);
|
||||||
|
|
||||||
@ -309,7 +437,11 @@ function processPlotData(filteredList: any[]) {
|
|||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
calculateStats();
|
calculateStats();
|
||||||
|
if(data?.getOptionsGexData?.length !== 0) {
|
||||||
|
optionsGEX = getGEXPlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(data?.user?.tier === 'Pro') {
|
if(data?.user?.tier === 'Pro') {
|
||||||
window.addEventListener('scroll', handleScroll);
|
window.addEventListener('scroll', handleScroll);
|
||||||
return () => {
|
return () => {
|
||||||
@ -478,6 +610,17 @@ $: {
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{#if data?.getOptionsGexData?.length !== 0}
|
||||||
|
<h3 class="text-2xl sm:text-2xl text-gray-200 font-bold mb-4 text-center sm:text-start">
|
||||||
|
Daily Gamma Exposure (GEX)
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="app w-full bg-[#09090B] rounded-xl mb-24">
|
||||||
|
|
||||||
|
<Chart {init} options={optionsGEX} class="chart" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
<h3 class="text-2xl sm:text-3xl text-gray-200 font-bold mb-4 text-center sm:text-start">
|
<h3 class="text-2xl sm:text-3xl text-gray-200 font-bold mb-4 text-center sm:text-start">
|
||||||
@ -745,20 +888,20 @@ $: {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.app {
|
||||||
|
height: 400px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
.app {
|
.app {
|
||||||
height: 420px;
|
|
||||||
max-width: 1500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 560px) {
|
|
||||||
.app {
|
|
||||||
max-width: 520px;
|
|
||||||
height: 420px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
}
|
}
|
||||||
</style>
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,80 +1,99 @@
|
|||||||
import { getCache, setCache } from '$lib/store';
|
import { getCache, setCache } from "$lib/store";
|
||||||
|
|
||||||
|
|
||||||
function daysLeft(targetDate) {
|
function daysLeft(targetDate) {
|
||||||
const targetTime = new Date(targetDate).getTime();
|
const targetTime = new Date(targetDate).getTime();
|
||||||
const currentTime = new Date().getTime();
|
const currentTime = new Date().getTime();
|
||||||
const difference = targetTime - currentTime;
|
const difference = targetTime - currentTime;
|
||||||
|
|
||||||
const millisecondsPerDay = 1000 * 60 * 60 * 24;
|
const millisecondsPerDay = 1000 * 60 * 60 * 24;
|
||||||
const daysLeft = Math?.ceil(difference / millisecondsPerDay);
|
const daysLeft = Math?.ceil(difference / millisecondsPerDay);
|
||||||
|
|
||||||
return daysLeft;
|
return daysLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const load = async ({ parent, params }) => {
|
export const load = async ({ parent, params }) => {
|
||||||
|
const { apiKey, apiURL } = await parent();
|
||||||
|
|
||||||
|
|
||||||
const {apiKey, apiURL} = await parent();
|
|
||||||
|
|
||||||
|
|
||||||
const getOptionsPlotData = async () => {
|
const getOptionsPlotData = async () => {
|
||||||
|
const cachedData = getCache(params.tickerID, "getOptionsPlotData");
|
||||||
const cachedData = getCache(params.tickerID, 'getOptionsPlotData');
|
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
return cachedData;
|
return cachedData;
|
||||||
} else {
|
} else {
|
||||||
|
const postData = {
|
||||||
const postData = {
|
ticker: params.tickerID,
|
||||||
ticker: params.tickerID
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const response = await fetch(apiURL + '/options-plot-ticker', {
|
const response = await fetch(apiURL + "/options-plot-ticker", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json", "X-API-KEY": apiKey
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": apiKey,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(postData)
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
|
|
||||||
const output = await response.json();
|
const output = await response.json();
|
||||||
|
|
||||||
setCache(params.tickerID, output, 'getOptionsPlotData');
|
|
||||||
return output;
|
|
||||||
|
|
||||||
|
setCache(params.tickerID, output, "getOptionsPlotData");
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getOptionsFlowData = async () => {
|
const getOptionsFlowData = async () => {
|
||||||
|
|
||||||
let output;
|
let output;
|
||||||
const cachedData = getCache(params.tickerID, 'getOptionsFlowData');
|
const cachedData = getCache(params.tickerID, "getOptionsFlowData");
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
output = cachedData;
|
output = cachedData;
|
||||||
} else {
|
} else {
|
||||||
|
const postData = {
|
||||||
const postData = {
|
ticker: params.tickerID,
|
||||||
ticker: params.tickerID
|
};
|
||||||
};
|
|
||||||
|
|
||||||
// make the POST request to the endpoint
|
// make the POST request to the endpoint
|
||||||
const response = await fetch(apiURL + '/options-flow-ticker', {
|
const response = await fetch(apiURL + "/options-flow-ticker", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json", "X-API-KEY": apiKey
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": apiKey,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(postData)
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
|
|
||||||
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');
|
setCache(params.tickerID, output, "getOptionsFlowData");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOptionsGexData = async () => {
|
||||||
|
let output;
|
||||||
|
const cachedData = getCache(params.tickerID, "getOptionsGexData");
|
||||||
|
if (cachedData) {
|
||||||
|
output = cachedData;
|
||||||
|
} else {
|
||||||
|
const postData = {
|
||||||
|
ticker: params.tickerID,
|
||||||
|
};
|
||||||
|
|
||||||
|
// make the POST request to the endpoint
|
||||||
|
const response = await fetch(apiURL + "/options-gex-ticker", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": apiKey,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData),
|
||||||
|
});
|
||||||
|
|
||||||
|
output = await response.json();
|
||||||
|
|
||||||
|
setCache(params.tickerID, output, "getOptionsGexData");
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -83,7 +102,7 @@ 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(),
|
||||||
getOptionsFlowData: await getOptionsFlowData()
|
getOptionsFlowData: await getOptionsFlowData(),
|
||||||
|
getOptionsGexData: await getOptionsGexData(),
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -887,21 +887,20 @@ $: {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
<style>
|
.app {
|
||||||
|
height: 400px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
.app {
|
.app {
|
||||||
height: 420px;
|
|
||||||
max-width: 1500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 560px) {
|
|
||||||
.app {
|
|
||||||
max-width: 520px;
|
|
||||||
height: 420px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
}
|
}
|
||||||
</style>
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user