breakup overview => fundamental
This commit is contained in:
parent
ec480afd27
commit
27b294aa03
@ -1,49 +1,38 @@
|
|||||||
<script lang='ts'>
|
<script lang="ts">
|
||||||
|
import { searchBarData, globalForm, screenWidth, openPriceAlert, currentPortfolioPrice, realtimePrice, isCrosshairMoveActive, currentPrice, priceIncrease, displayCompanyName, stockTicker, isOpen } from "$lib/store";
|
||||||
import {searchBarData, globalForm, screenWidth, openPriceAlert, currentPortfolioPrice, realtimePrice, isCrosshairMoveActive, currentPrice, priceIncrease, displayCompanyName, stockTicker, isOpen } from '$lib/store';
|
|
||||||
|
|
||||||
import { onMount, onDestroy, afterUpdate } from "svelte";
|
import { onMount, onDestroy, afterUpdate } from "svelte";
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from "$app/navigation";
|
||||||
import { page } from '$app/stores';
|
import { page } from "$app/stores";
|
||||||
import toast from 'svelte-french-toast';
|
import toast from "svelte-french-toast";
|
||||||
import Sidecard from '$lib/components/Sidecard.svelte';
|
import Sidecard from "$lib/components/Sidecard.svelte";
|
||||||
import Markethour from '$lib/components/Markethour.svelte';
|
import Markethour from "$lib/components/Markethour.svelte";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
|
|
||||||
$: $realtimePrice = data?.getStockQuote?.price?.toFixed(2);
|
$: $realtimePrice = data?.getStockQuote?.price?.toFixed(2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function loadSearchData() {
|
async function loadSearchData() {
|
||||||
|
if ($searchBarData?.length !== 0) {
|
||||||
if($searchBarData?.length !== 0)
|
return;
|
||||||
{
|
} else {
|
||||||
return
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// make the GET request to the endpoint
|
// make the GET request to the endpoint
|
||||||
const response = await fetch(data?.apiURL+'/searchbar-data', {
|
const response = await fetch(data?.apiURL + "/searchbar-data", {
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json","X-API-KEY": data?.apiKey
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": data?.apiKey,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
$searchBarData = await response.json();
|
$searchBarData = await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let previousRealtimePrice = null;
|
let previousRealtimePrice = null;
|
||||||
let previousTicker;
|
let previousTicker;
|
||||||
let socket;
|
let socket;
|
||||||
|
|
||||||
|
|
||||||
let isScrolled = false;
|
let isScrolled = false;
|
||||||
let y;
|
let y;
|
||||||
|
|
||||||
@ -53,31 +42,26 @@ async function loadSearchData() {
|
|||||||
//let holdingShares = 0;
|
//let holdingShares = 0;
|
||||||
//let availableCash = 0;
|
//let availableCash = 0;
|
||||||
|
|
||||||
let displaySection = '';
|
let displaySection = "";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let stockDeck;
|
let stockDeck;
|
||||||
let similarstock = [];
|
let similarstock = [];
|
||||||
let topETFHolder = [];
|
let topETFHolder = [];
|
||||||
|
|
||||||
|
|
||||||
function shareContent(url) {
|
function shareContent(url) {
|
||||||
|
|
||||||
if (navigator.share) {
|
if (navigator.share) {
|
||||||
navigator.share({
|
navigator
|
||||||
|
.share({
|
||||||
title: document.title,
|
title: document.title,
|
||||||
url,
|
url,
|
||||||
})
|
})
|
||||||
.then(() => console.log('Content shared successfully.'))
|
.then(() => console.log("Content shared successfully."))
|
||||||
.catch((error) => console.log('Error sharing content:', error));
|
.catch((error) => console.log("Error sharing content:", error));
|
||||||
} else {
|
} else {
|
||||||
toast.error('Sharing is not supported by your device', {
|
toast.error("Sharing is not supported by your device", {
|
||||||
style: 'background: #333; color: #fff;'
|
style: "background: #333; color: #fff;",
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -97,45 +81,38 @@ function handleTypeOfTrade(state:string)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
function scrollToItem(itemId) {
|
function scrollToItem(itemId) {
|
||||||
const item = document.getElementById(itemId);
|
const item = document.getElementById(itemId);
|
||||||
if (item) {
|
if (item) {
|
||||||
|
item.scrollIntoView({ behavior: "smooth" });
|
||||||
item.scrollIntoView({ behavior: 'smooth' });
|
window.scrollTo(0, 0);
|
||||||
window.scrollTo(0,0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function changeSection(state, item) {
|
function changeSection(state, item) {
|
||||||
scrollToItem(item);
|
scrollToItem(item);
|
||||||
|
|
||||||
const sectionMap = {
|
const sectionMap = {
|
||||||
'insider': '/insider',
|
insider: "/insider",
|
||||||
'options': '/options',
|
options: "/options",
|
||||||
'dividends': '/dividends',
|
dividends: "/dividends",
|
||||||
'stats': '/stats',
|
fundamental: "/stats",
|
||||||
'analyst': '/analyst',
|
analyst: "/analyst",
|
||||||
'news': '/news',
|
news: "/news",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (state !== 'overview' && sectionMap[state]) {
|
if (state !== "overview" && sectionMap[state]) {
|
||||||
displaySection = state;
|
displaySection = state;
|
||||||
//goto(`/stocks/${$stockTicker}${sectionMap[state]}`);
|
//goto(`/stocks/${$stockTicker}${sectionMap[state]}`);
|
||||||
} else {
|
} else {
|
||||||
displaySection = 'overview';
|
displaySection = "overview";
|
||||||
//goto(`/stocks/${$stockTicker}/`);
|
//goto(`/stocks/${$stockTicker}/`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function toggleUserWatchlist(watchListId: string) {
|
async function toggleUserWatchlist(watchListId: string) {
|
||||||
try {
|
try {
|
||||||
const watchlistIndex = userWatchList?.findIndex(item => item?.id === watchListId);
|
const watchlistIndex = userWatchList?.findIndex((item) => item?.id === watchListId);
|
||||||
const postData = {
|
const postData = {
|
||||||
userId: data?.user?.id,
|
userId: data?.user?.id,
|
||||||
watchListId,
|
watchListId,
|
||||||
@ -143,13 +120,13 @@ async function toggleUserWatchlist(watchListId: string) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${data?.fastifyURL}/update-watchlist`, {
|
const response = await fetch(`${data?.fastifyURL}/update-watchlist`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(postData),
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Network response was not ok');
|
throw new Error("Network response was not ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
const output = (await response.json())?.items;
|
const output = (await response.json())?.items;
|
||||||
@ -162,14 +139,12 @@ async function toggleUserWatchlist(watchListId: string) {
|
|||||||
|
|
||||||
userWatchList = [...userWatchList];
|
userWatchList = [...userWatchList];
|
||||||
isTickerIncluded = !isTickerIncluded;
|
isTickerIncluded = !isTickerIncluded;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('An error occurred:', error);
|
console.error("An error occurred:", error);
|
||||||
// Handle the error appropriately (e.g., show an error message to the user)
|
// Handle the error appropriately (e.g., show an error message to the user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
async function fetchPortfolio()
|
async function fetchPortfolio()
|
||||||
{
|
{
|
||||||
@ -188,38 +163,31 @@ async function fetchPortfolio()
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function sendMessage(message) {
|
function sendMessage(message) {
|
||||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||||
socket.send(message);
|
socket.send(message);
|
||||||
} else {
|
} else {
|
||||||
console.error('WebSocket is not open. Unable to send message.');
|
console.error("WebSocket is not open. Unable to send message.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function websocketRealtimeData() {
|
async function websocketRealtimeData() {
|
||||||
|
|
||||||
previousTicker = $stockTicker;
|
previousTicker = $stockTicker;
|
||||||
try {
|
try {
|
||||||
socket = new WebSocket(data?.wsURL + "/realtime-data");
|
socket = new WebSocket(data?.wsURL + "/realtime-data");
|
||||||
|
|
||||||
socket.addEventListener('open', () => {
|
socket.addEventListener("open", () => {
|
||||||
//console.log('WebSocket connection opened');
|
//console.log('WebSocket connection opened');
|
||||||
|
|
||||||
// Send the initial value of stockTicker
|
// Send the initial value of stockTicker
|
||||||
sendMessage($stockTicker?.toLowerCase());
|
sendMessage($stockTicker?.toLowerCase());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.addEventListener("message", (event) => {
|
||||||
socket.addEventListener('message', (event) => {
|
|
||||||
const data = event.data;
|
const data = event.data;
|
||||||
//console.log('Received message:', data);
|
//console.log('Received message:', data);
|
||||||
try {
|
try {
|
||||||
|
$realtimePrice = typeof JSON.parse(data)?.bp !== "undefined" ? JSON.parse(data)?.bp : null;
|
||||||
$realtimePrice = typeof JSON.parse(data)?.bp !== 'undefined' ? JSON.parse(data)?.bp : null;
|
|
||||||
//console.log('Received message:', $realtimePrice);
|
//console.log('Received message:', $realtimePrice);
|
||||||
|
|
||||||
if ($realtimePrice > previousRealtimePrice) {
|
if ($realtimePrice > previousRealtimePrice) {
|
||||||
@ -230,84 +198,63 @@ async function websocketRealtimeData() {
|
|||||||
previousRealtimePrice = $realtimePrice;
|
previousRealtimePrice = $realtimePrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$isCrosshairMoveActive = false;
|
$isCrosshairMoveActive = false;
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
}
|
}
|
||||||
catch(e) {
|
|
||||||
console.log(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.addEventListener("close", (event) => {
|
||||||
|
console.log("WebSocket connection closed:", event.reason);
|
||||||
socket.addEventListener('close', (event) => {
|
|
||||||
console.log('WebSocket connection closed:', event.reason);
|
|
||||||
// Handle disconnection, you might want to attempt to reconnect here
|
// Handle disconnection, you might want to attempt to reconnect here
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('WebSocket connection error:', error);
|
console.error("WebSocket connection error:", error);
|
||||||
// Handle connection errors here
|
// Handle connection errors here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let LoginPopup;
|
let LoginPopup;
|
||||||
let PriceAlert;
|
let PriceAlert;
|
||||||
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
if (!data?.user) {
|
||||||
if(!data?.user)
|
LoginPopup = (await import("$lib/components/LoginPopup.svelte")).default;
|
||||||
{
|
} else {
|
||||||
LoginPopup = (await import('$lib/components/LoginPopup.svelte')).default;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//AddPortfolio = (await import('$lib/components/AddPortfolio.svelte')).default;
|
//AddPortfolio = (await import('$lib/components/AddPortfolio.svelte')).default;
|
||||||
//BuyTrade = (await import('$lib/components/BuyTrade.svelte')).default;
|
//BuyTrade = (await import('$lib/components/BuyTrade.svelte')).default;
|
||||||
//SellTrade = (await import('$lib/components/SellTrade.svelte')).default;
|
//SellTrade = (await import('$lib/components/SellTrade.svelte')).default;
|
||||||
PriceAlert = (await import('$lib/components/PriceAlert.svelte')).default;
|
PriceAlert = (await import("$lib/components/PriceAlert.svelte")).default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($isOpen) {
|
||||||
if ($isOpen) //&& currentDateTime > startTime && currentDateTime < endTime
|
//&& currentDateTime > startTime && currentDateTime < endTime
|
||||||
{
|
await websocketRealtimeData();
|
||||||
await websocketRealtimeData()
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
afterUpdate(async () => {
|
afterUpdate(async () => {
|
||||||
|
if (previousTicker !== $stockTicker && typeof socket !== "undefined") {
|
||||||
if(previousTicker !== $stockTicker && typeof socket !== 'undefined')
|
|
||||||
{
|
|
||||||
previousTicker = $stockTicker;
|
previousTicker = $stockTicker;
|
||||||
//socket.send('close')
|
//socket.send('close')
|
||||||
socket?.close();
|
socket?.close();
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
socket?.addEventListener('close', resolve);
|
socket?.addEventListener("close", resolve);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(socket?.readyState === WebSocket?.CLOSED)
|
if (socket?.readyState === WebSocket?.CLOSED) {
|
||||||
{
|
await websocketRealtimeData();
|
||||||
await websocketRealtimeData()
|
console.log("connecting again");
|
||||||
console.log('connecting again')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
try {
|
try {
|
||||||
//socket?.send('close')
|
//socket?.send('close')
|
||||||
socket?.close()
|
socket?.close();
|
||||||
}
|
} catch (e) {
|
||||||
catch(e) {
|
console.log(e);
|
||||||
console.log(e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//$displayCompanyName = '';
|
//$displayCompanyName = '';
|
||||||
@ -315,16 +262,11 @@ onDestroy(() => {
|
|||||||
$currentPrice = null;
|
$currentPrice = null;
|
||||||
$priceIncrease = null;
|
$priceIncrease = null;
|
||||||
//$traded = false
|
//$traded = false
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if ($stockTicker && $stockTicker?.length !== 0 && typeof window !== 'undefined') // add a check to see if running on client-side
|
if ($stockTicker && $stockTicker?.length !== 0 && typeof window !== "undefined") {
|
||||||
{
|
// add a check to see if running on client-side
|
||||||
|
|
||||||
stockDeck = data?.getStockDeck;
|
stockDeck = data?.getStockDeck;
|
||||||
similarstock = data?.getSimilarStock;
|
similarstock = data?.getSimilarStock;
|
||||||
topETFHolder = data?.getTopETFHolder;
|
topETFHolder = data?.getTopETFHolder;
|
||||||
@ -332,8 +274,7 @@ $: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: isTickerIncluded = userWatchList?.some(item =>
|
$: isTickerIncluded = userWatchList?.some((item) => item.user === data?.user?.id && item.ticker?.includes($stockTicker));
|
||||||
item.user === data?.user?.id && item.ticker?.includes($stockTicker));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$: {
|
$: {
|
||||||
@ -363,35 +304,30 @@ $: {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
$: charNumber = $screenWidth < 640 ? 12 : 25;
|
$: charNumber = $screenWidth < 640 ? 12 : 25;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if($stockTicker && typeof window !== 'undefined' && $page.url.pathname === `/stocks/${$stockTicker}`)
|
if ($stockTicker && typeof window !== "undefined" && $page.url.pathname === `/stocks/${$stockTicker}`) {
|
||||||
{
|
displaySection = "overview";
|
||||||
displaySection = 'overview';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if($page.url.pathname)
|
if ($page.url.pathname) {
|
||||||
{
|
const parts = $page?.url?.pathname?.split("/");
|
||||||
const parts = $page?.url?.pathname?.split('/');
|
|
||||||
const sectionMap = {
|
const sectionMap = {
|
||||||
'stats': 'stats',
|
stats: "fundamental",
|
||||||
'options': 'options',
|
options: "options",
|
||||||
'insider': 'insider',
|
insider: "insider",
|
||||||
'dividends': 'dividends',
|
dividends: "dividends",
|
||||||
'analyst': 'analyst',
|
analyst: "analyst",
|
||||||
'news': 'news'
|
news: "news",
|
||||||
};
|
};
|
||||||
displaySection = sectionMap[parts?.find(part => Object?.keys(sectionMap)?.includes(part))] || 'overview';
|
displaySection = sectionMap[parts?.find((part) => Object?.keys(sectionMap)?.includes(part))] || "overview";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$: isScrolled = y > 0;
|
$: isScrolled = y > 0;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window bind:scrollY={y} />
|
<svelte:window bind:scrollY={y} />
|
||||||
@ -403,26 +339,26 @@ $: isScrolled = y > 0;
|
|||||||
<section class="w-full">
|
<section class="w-full">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div class="sm:flex sm:justify-start w-full">
|
<div class="sm:flex sm:justify-start w-full">
|
||||||
|
|
||||||
<!--Start Mobile Navbar-->
|
<!--Start Mobile Navbar-->
|
||||||
<div class="fixed top-0 left-0 right-0 z-20 bg-[#09090B] sm:hidden">
|
<div class="fixed top-0 left-0 right-0 z-20 bg-[#09090B] sm:hidden">
|
||||||
<div class="navbar w-full px-4 py-2">
|
<div class="navbar w-full px-4 py-2">
|
||||||
|
|
||||||
<div class="{isScrolled ? 'border-b border-slate-800 ease-in' : 'ease-out'} m-auto w-full">
|
<div class="{isScrolled ? 'border-b border-slate-800 ease-in' : 'ease-out'} m-auto w-full">
|
||||||
|
|
||||||
<div class="flex-1 flex-shrink-0 flex flex-row items-center justify-between -mt-2">
|
<div class="flex-1 flex-shrink-0 flex flex-row items-center justify-between -mt-2">
|
||||||
|
<label on:click={() => goto("/")} class="ml-2 cursor-pointer">
|
||||||
<label on:click={() => goto('/')} class="ml-2 cursor-pointer">
|
<svg class="w-5 h-5 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"
|
||||||
<svg class="w-5 h-5 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><g transform="rotate(-90 512 512)"><path fill="white" d="M104.704 685.248a64 64 0 0 0 90.496 0l316.8-316.8l316.8 316.8a64 64 0 0 0 90.496-90.496L557.248 232.704a64 64 0 0 0-90.496 0L104.704 594.752a64 64 0 0 0 0 90.496z"/></g></svg>
|
><g transform="rotate(-90 512 512)"
|
||||||
|
><path fill="white" d="M104.704 685.248a64 64 0 0 0 90.496 0l316.8-316.8l316.8 316.8a64 64 0 0 0 90.496-90.496L557.248 232.704a64 64 0 0 0-90.496 0L104.704 594.752a64 64 0 0 0 0 90.496z" /></g
|
||||||
|
></svg
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="{!isScrolled ? 'hidden' : 'flex flex-col items-center ml-6 transition-transform ease-in'}">
|
<div class={!isScrolled ? "hidden" : "flex flex-col items-center ml-6 transition-transform ease-in"}>
|
||||||
<span class="text-white text-[0.70rem] font-medium text-opacity-[0.6]">
|
<span class="text-white text-[0.70rem] font-medium text-opacity-[0.6]">
|
||||||
{$stockTicker}
|
{$stockTicker}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-white font-medium text-sm">
|
<span class="text-white font-medium text-sm">
|
||||||
{#if $currentPortfolioPrice !== null && $currentPortfolioPrice !== 0}
|
{#if $currentPortfolioPrice !== null && $currentPortfolioPrice !== 0}
|
||||||
{$stockTicker?.includes('.DE') || $stockTicker?.includes('.F') ? `${$currentPortfolioPrice}€` : ` $${$currentPortfolioPrice}`}
|
{$stockTicker?.includes(".DE") || $stockTicker?.includes(".F") ? `${$currentPortfolioPrice}€` : ` $${$currentPortfolioPrice}`}
|
||||||
{:else}
|
{:else}
|
||||||
{data?.getStockQuote?.price}
|
{data?.getStockQuote?.price}
|
||||||
{/if}
|
{/if}
|
||||||
@ -431,19 +367,27 @@ $: isScrolled = y > 0;
|
|||||||
|
|
||||||
<!--Start Search Button-->
|
<!--Start Search Button-->
|
||||||
<label on:click={loadSearchData} class="ml-auto mr-4" for="searchBarModal">
|
<label on:click={loadSearchData} class="ml-auto mr-4" for="searchBarModal">
|
||||||
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m21 21l-4.343-4.343m0 0A8 8 0 1 0 5.343 5.343a8 8 0 0 0 11.314 11.314"/></svg>
|
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
|
><path fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m21 21l-4.343-4.343m0 0A8 8 0 1 0 5.343 5.343a8 8 0 0 0 11.314 11.314" /></svg
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
<!--End Search Button-->
|
<!--End Search Button-->
|
||||||
|
|
||||||
|
|
||||||
<!--Start Share Button-->
|
<!--Start Share Button-->
|
||||||
<label class="mr-4" on:click={() => shareContent('https://stocknear.com/stocks/'+$stockTicker)} >
|
<label class="mr-4" on:click={() => shareContent("https://stocknear.com/stocks/" + $stockTicker)}>
|
||||||
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M336 192h40a40 40 0 0 1 40 40v192a40 40 0 0 1-40 40H136a40 40 0 0 1-40-40V232a40 40 0 0 1 40-40h40m160-64l-80-80l-80 80m80 193V48"/></svg>
|
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"
|
||||||
|
><path
|
||||||
|
fill="none"
|
||||||
|
stroke="white"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="32"
|
||||||
|
d="M336 192h40a40 40 0 0 1 40 40v192a40 40 0 0 1-40 40H136a40 40 0 0 1-40-40V232a40 40 0 0 1 40-40h40m160-64l-80-80l-80 80m80 193V48"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
<!--End Share Button-->
|
<!--End Share Button-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start Watchlist-->
|
<!--Start Watchlist-->
|
||||||
|
|
||||||
{#if data?.user}
|
{#if data?.user}
|
||||||
@ -451,56 +395,74 @@ $: isScrolled = y > 0;
|
|||||||
{#if userWatchList?.length !== 0}
|
{#if userWatchList?.length !== 0}
|
||||||
<label for="addWatchListModal" class="cursor-pointer flex-shrink-0">
|
<label for="addWatchListModal" class="cursor-pointer flex-shrink-0">
|
||||||
{#if isTickerIncluded}
|
{#if isTickerIncluded}
|
||||||
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#FBCE3C" d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/></svg>
|
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="#FBCE3C"
|
||||||
|
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
{:else}
|
{:else}
|
||||||
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="white" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"/></svg>
|
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="white"
|
||||||
|
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{:else if userWatchList?.length === 0}
|
{:else if userWatchList?.length === 0}
|
||||||
<label on:click={() => toggleUserWatchlist('firstList')} class="cursor-pointer flex-shrink-0">
|
<label on:click={() => toggleUserWatchlist("firstList")} class="cursor-pointer flex-shrink-0">
|
||||||
{#if isTickerIncluded}
|
{#if isTickerIncluded}
|
||||||
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#FBCE3C" d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/></svg>
|
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="#FBCE3C"
|
||||||
|
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
{:else}
|
{:else}
|
||||||
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="white" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"/></svg>
|
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="white"
|
||||||
|
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<label for="userLogin" class="cursor-pointer flex-shrink-0 text-white mr-4">
|
<label for="userLogin" class="cursor-pointer flex-shrink-0 text-white mr-4">
|
||||||
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="white" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"/></svg>
|
<svg class="w-6 h-6 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="white"
|
||||||
|
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
{/if}
|
{/if}
|
||||||
<!--End Watchlist-->
|
<!--End Watchlist-->
|
||||||
|
|
||||||
<!--Start Price Alert-->
|
<!--Start Price Alert-->
|
||||||
<label on:click={() => $openPriceAlert = true} for={data?.user ? 'priceAlertModal' : 'userLogin'} class="mr-2">
|
<label on:click={() => ($openPriceAlert = true)} for={data?.user ? "priceAlertModal" : "userLogin"} class="mr-2">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7 inline-block mt-1" viewBox="0 0 24 24"><g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"><path d="M3 5.231L6.15 3M21 5.231L17.85 3"/><circle cx="12" cy="13" r="8"/><path d="M9.5 13h5M12 10.5v5"/></g></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7 inline-block mt-1" viewBox="0 0 24 24"
|
||||||
|
><g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"><path d="M3 5.231L6.15 3M21 5.231L17.85 3" /><circle cx="12" cy="13" r="8" /><path d="M9.5 13h5M12 10.5v5" /></g></svg
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
<!--End Price Alert -->
|
<!--End Price Alert -->
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--End Mobile Navbar-->
|
<!--End Mobile Navbar-->
|
||||||
|
|
||||||
|
|
||||||
<div class="pt-20 sm:pt-0 w-auto max-w-3xl lg:max-w-content 2xl:max-w-6xl px-3 sm:px-0">
|
<div class="pt-20 sm:pt-0 w-auto max-w-3xl lg:max-w-content 2xl:max-w-6xl px-3 sm:px-0">
|
||||||
|
|
||||||
<div class="md:flex md:justify-between md:divide-x md:divide-slate-800">
|
<div class="md:flex md:justify-between md:divide-x md:divide-slate-800">
|
||||||
<!-- Main content -->
|
<!-- Main content -->
|
||||||
<div class="pb-12 md:pb-20 w-full 2xl:max-w-5xl">
|
<div class="pb-12 md:pb-20 w-full 2xl:max-w-5xl">
|
||||||
<div class="md:pr-6 lg:pr-10">
|
<div class="md:pr-6 lg:pr-10">
|
||||||
|
|
||||||
|
|
||||||
<!-----Start-Header-CandleChart-Indicators------>
|
<!-----Start-Header-CandleChart-Indicators------>
|
||||||
|
|
||||||
<div class="m-auto pl-0 sm:pl-4 overflow-hidden mb-5 md:mt-10">
|
<div class="m-auto pl-0 sm:pl-4 overflow-hidden mb-5 md:mt-10">
|
||||||
|
|
||||||
<div class="hidden sm:flex flex-row w-full justify-between items-center pb-10">
|
<div class="hidden sm:flex flex-row w-full justify-between items-center pb-10">
|
||||||
<Markethour />
|
<Markethour />
|
||||||
|
|
||||||
@ -512,30 +474,53 @@ $: isScrolled = y > 0;
|
|||||||
<div class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center">
|
<div class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center">
|
||||||
<label for="addWatchListModal" class="cursor-pointer flex-shrink-0">
|
<label for="addWatchListModal" class="cursor-pointer flex-shrink-0">
|
||||||
{#if isTickerIncluded}
|
{#if isTickerIncluded}
|
||||||
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#FBCE3C" d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/></svg>
|
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="#FBCE3C"
|
||||||
|
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
{:else}
|
{:else}
|
||||||
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="white" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"/></svg>
|
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="white"
|
||||||
|
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else if userWatchList?.length === 0}
|
{:else if userWatchList?.length === 0}
|
||||||
<div class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center">
|
<div class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center">
|
||||||
<label on:click={() => toggleUserWatchlist('firstList')} class="cursor-pointer flex-shrink-0">
|
<label on:click={() => toggleUserWatchlist("firstList")} class="cursor-pointer flex-shrink-0">
|
||||||
{#if isTickerIncluded}
|
{#if isTickerIncluded}
|
||||||
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#FBCE3C" d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/></svg>
|
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="#FBCE3C"
|
||||||
|
d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327l4.898.696c.441.062.612.636.282.95l-3.522 3.356l.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
{:else}
|
{:else}
|
||||||
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="white" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"/></svg>
|
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="white"
|
||||||
|
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex-shrink-0 ml-auto mr-2 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center">
|
<div class="flex-shrink-0 ml-auto mr-2 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center">
|
||||||
<label for="userLogin" class="cursor-pointer flex-shrink-0 text-white">
|
<label for="userLogin" class="cursor-pointer flex-shrink-0 text-white">
|
||||||
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="white" d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"/></svg>
|
<svg class="w-7 h-7 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
|
||||||
|
><path
|
||||||
|
fill="white"
|
||||||
|
d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256l4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73l3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356l-.83 4.73zm4.905-2.767l-3.686 1.894l.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575l-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957l-3.686-1.894a.503.503 0 0 0-.461 0z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -544,14 +529,15 @@ $: isScrolled = y > 0;
|
|||||||
<!--Start Price Alert -->
|
<!--Start Price Alert -->
|
||||||
|
|
||||||
<div class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center">
|
<div class="flex-shrink-0 rounded-full hover:bg-white hover:bg-opacity-[0.02] transition ease-out w-12 h-12 relative bg-[#09090B] flex items-center justify-center">
|
||||||
<label on:click={() => $openPriceAlert = true} for={data?.user ? 'priceAlertModal' : 'userLogin'} class="cursor-pointer flex-shrink-0 text-white">
|
<label on:click={() => ($openPriceAlert = true)} for={data?.user ? "priceAlertModal" : "userLogin"} class="cursor-pointer flex-shrink-0 text-white">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 inline-block" viewBox="0 0 24 24"><g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"><path d="M3 5.231L6.15 3M21 5.231L17.85 3"/><circle cx="12" cy="13" r="8"/><path d="M9.5 13h5M12 10.5v5"/></g></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 inline-block" viewBox="0 0 24 24"
|
||||||
|
><g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"><path d="M3 5.231L6.15 3M21 5.231L17.85 3" /><circle cx="12" cy="13" r="8" /><path d="M9.5 13h5M12 10.5v5" /></g></svg
|
||||||
|
>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<!--End Price Alert -->
|
<!--End Price Alert -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||||
|
|
||||||
@ -572,12 +558,10 @@ $: isScrolled = y > 0;
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="ml-auto sm:hidden">
|
<div class="ml-auto sm:hidden">
|
||||||
<Markethour />
|
<Markethour />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!--Start Trade-->
|
<!--Start Trade-->
|
||||||
<!--
|
<!--
|
||||||
<div class="hidden sm:flex ml-auto">
|
<div class="hidden sm:flex ml-auto">
|
||||||
@ -600,58 +584,86 @@ $: isScrolled = y > 0;
|
|||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
<!--End Trade-->
|
<!--End Trade-->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-----End-Header-CandleChart-Indicators------>
|
<!-----End-Header-CandleChart-Indicators------>
|
||||||
|
|
||||||
|
|
||||||
<!--Start Ticker Section-->
|
<!--Start Ticker Section-->
|
||||||
|
|
||||||
<!--<div class="w-full max-w-3xl sm:max-w-2xl m-auto pt-2 pb-5 sm:pl-3 sticky z-20 bg-[#09090B]" style="top: {$screenWidth < 520 && $isScrollingUp ? '4rem' : '0rem'};">-->
|
<!--<div class="w-full max-w-3xl sm:max-w-2xl m-auto pt-2 pb-5 sm:pl-3 sticky z-20 bg-[#09090B]" style="top: {$screenWidth < 520 && $isScrollingUp ? '4rem' : '0rem'};">-->
|
||||||
<div class="-ml-2 sm:ml-4 w-screen sm:w-full {$screenWidth < 640 ? 'overflow-auto scrollbar' : ''} mb-2">
|
<div class="-ml-2 sm:ml-4 w-screen sm:w-full {$screenWidth < 640 ? 'overflow-auto scrollbar' : ''} mb-2">
|
||||||
<ul class="pr-4 sm:pr-0 w-screen font-medium flex flex-row items-center bg-[#09090B] overflow-x-scroll no-scrollbar space-x-3 rtl:space-x-reverse py-2">
|
<ul class="pr-4 sm:pr-0 w-screen font-medium flex flex-row items-center bg-[#09090B] space-x-3 rtl:space-x-reverse py-2">
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}`} id="item1" on:click={() => (changeSection('overview','item1'))} class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'overview' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}`}
|
||||||
|
id="item1"
|
||||||
|
on:click={() => changeSection("overview", "item1")}
|
||||||
|
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'overview' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
Overview
|
Overview
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySection === 'overview' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4.2rem]" />
|
<div class="{displaySection === 'overview' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4.2rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/stats`} id="item2" on:click={() => (changeSection('stats','item2'))} class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'stats' ? 'text-white ' : 'bg-[#09090B]'}" >Stats</a>
|
<a
|
||||||
<div class="{displaySection === 'stats' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.8rem]" />
|
href={`/stocks/${$stockTicker}/stats`}
|
||||||
|
id="item2"
|
||||||
|
on:click={() => changeSection("fundamental", "item2")}
|
||||||
|
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'fundamental' ? 'text-white ' : 'bg-[#09090B]'}">Fundamental</a
|
||||||
|
>
|
||||||
|
<div class="{displaySection === 'fundamental' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.8rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/options`} id="item3" on:click={() => (changeSection('options','item3'))} class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'options' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}/options`}
|
||||||
|
id="item3"
|
||||||
|
on:click={() => changeSection("options", "item3")}
|
||||||
|
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'options' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
Options
|
Options
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySection === 'options' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
<div class="{displaySection === 'options' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/analyst`} id="item3" on:click={() => (changeSection('analyst','item3'))} class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'analyst' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}/analyst`}
|
||||||
|
id="item3"
|
||||||
|
on:click={() => changeSection("analyst", "item3")}
|
||||||
|
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'analyst' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
Analyst
|
Analyst
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySection === 'analyst' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
<div class="{displaySection === 'analyst' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/insider`} id="item4" on:click={() => (changeSection('insider','item4'))} class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'insider' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}/insider`}
|
||||||
|
id="item4"
|
||||||
|
on:click={() => changeSection("insider", "item4")}
|
||||||
|
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'insider' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
Insider
|
Insider
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySection === 'insider' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
<div class="{displaySection === 'insider' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/dividends`} id="item5" on:click={() => (changeSection('dividends','item5'))} class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'dividends' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}/dividends`}
|
||||||
|
id="item5"
|
||||||
|
on:click={() => changeSection("dividends", "item5")}
|
||||||
|
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'dividends' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
Dividends
|
Dividends
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySection === 'dividends' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4rem]" />
|
<div class="{displaySection === 'dividends' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/news`} id="item7" on:click={() => (changeSection('news','item7'))} class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'news' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}/news`}
|
||||||
|
id="item7"
|
||||||
|
on:click={() => changeSection("news", "item7")}
|
||||||
|
class="px-3 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySection === 'news' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
News
|
News
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySection === 'news' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.8rem]" />
|
<div class="{displaySection === 'news' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.8rem]" />
|
||||||
@ -659,31 +671,17 @@ $: isScrolled = y > 0;
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start-Main Content-->
|
<!--Start-Main Content-->
|
||||||
<slot />
|
<slot />
|
||||||
<!--End Main Content-->
|
<!--End Main Content-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class="hidden lg:block w-fit max-w-xl xl:w-[120px] md:pt-10 pb-12 md:pb-20">
|
<aside class="hidden lg:block w-fit max-w-xl xl:w-[120px] md:pt-10 pb-12 md:pb-20">
|
||||||
<div class="sm:pl-10">
|
<div class="sm:pl-10">
|
||||||
|
|
||||||
<!--Start Company Info -->
|
<!--Start Company Info -->
|
||||||
<Sidecard
|
<Sidecard {stockDeck} lastPrice={data?.getStockQuote?.price} analystRating={data?.getAnalystRating} {similarstock} {topETFHolder} />
|
||||||
stockDeck = {stockDeck}
|
|
||||||
lastPrice = {data?.getStockQuote?.price}
|
|
||||||
analystRating ={data?.getAnalystRating}
|
|
||||||
similarstock = {similarstock}
|
|
||||||
topETFHolder = {topETFHolder}
|
|
||||||
/>
|
|
||||||
<!--End Company Info -->
|
<!--End Company Info -->
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
<!--
|
<!--
|
||||||
@ -699,7 +697,6 @@ $: isScrolled = y > 0;
|
|||||||
{/if}
|
{/if}
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<div class="sm:hidden fixed z-20 bottom-8 sm:bottom-10 right-5">
|
<div class="sm:hidden fixed z-20 bottom-8 sm:bottom-10 right-5">
|
||||||
<div class="h-full mx-auto">
|
<div class="h-full mx-auto">
|
||||||
@ -718,18 +715,15 @@ $: isScrolled = y > 0;
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start Login Modal-->
|
<!--Start Login Modal-->
|
||||||
{#if LoginPopup}
|
{#if LoginPopup}
|
||||||
<LoginPopup form={$globalForm} />
|
<LoginPopup form={$globalForm} />
|
||||||
@ -757,18 +751,13 @@ $: isScrolled = y > 0;
|
|||||||
{/if}
|
{/if}
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
<!--Start SellTrade Modal-->
|
<!--Start SellTrade Modal-->
|
||||||
{#if PriceAlert}
|
{#if PriceAlert}
|
||||||
<PriceAlert
|
<PriceAlert {data} />
|
||||||
data = {data}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!--End SellTrade Modal-->
|
<!--End SellTrade Modal-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start Type of Trade-->
|
<!--Start Type of Trade-->
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@ -838,77 +827,61 @@ $: isScrolled = y > 0;
|
|||||||
-->
|
-->
|
||||||
<!--End Type of Trade-->
|
<!--End Type of Trade-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Start Add Watchlist Modal-->
|
<!--Start Add Watchlist Modal-->
|
||||||
<input type="checkbox" id="addWatchListModal" class="modal-toggle" />
|
<input type="checkbox" id="addWatchListModal" class="modal-toggle" />
|
||||||
|
|
||||||
<dialog id="addWatchListModal" class="modal modal-bottom sm:modal-middle">
|
<dialog id="addWatchListModal" class="modal modal-bottom sm:modal-middle">
|
||||||
|
|
||||||
|
|
||||||
<label id="addWatchListModal" for="addWatchListModal" class="cursor-pointer modal-backdrop bg-[#09090B] bg-opacity-[0.5]"></label>
|
<label id="addWatchListModal" for="addWatchListModal" class="cursor-pointer modal-backdrop bg-[#09090B] bg-opacity-[0.5]"></label>
|
||||||
|
|
||||||
|
|
||||||
<div class="modal-box w-full bg-[#09090B] sm:border sm:border-slate-800">
|
<div class="modal-box w-full bg-[#09090B] sm:border sm:border-slate-800">
|
||||||
|
<label for="addWatchListModal" class="cursor-pointer absolute right-5 top-2 bg-[#09090B] text-[1.8rem] text-white"> ✕ </label>
|
||||||
|
|
||||||
|
|
||||||
<label for="addWatchListModal" class="cursor-pointer absolute right-5 top-2 bg-[#09090B] text-[1.8rem] text-white">
|
|
||||||
✕
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div class="text-white">
|
<div class="text-white">
|
||||||
<h3 class="font-semibold text-lg sm:text-xl mb-10">
|
<h3 class="font-semibold text-lg sm:text-xl mb-10">Add to Watchlist</h3>
|
||||||
Add to Watchlist
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div class="flex flex-col items-center w-full max-w-3xl bg-[#09090B]">
|
<div class="flex flex-col items-center w-full max-w-3xl bg-[#09090B]">
|
||||||
|
|
||||||
{#each userWatchList as item}
|
{#each userWatchList as item}
|
||||||
<label on:click|stopPropagation={() => toggleUserWatchlist(item?.id)} class="cursor-pointer w-full flex flex-row justify-start items-center mb-5">
|
<label on:click|stopPropagation={() => toggleUserWatchlist(item?.id)} class="cursor-pointer w-full flex flex-row justify-start items-center mb-5">
|
||||||
|
|
||||||
<div class="flex flex-row items-center w-full bg-[#313131] p-3 rounded-lg {item?.ticker?.includes($stockTicker) ? 'ring-2 ring-[#04E000]' : ''}">
|
<div class="flex flex-row items-center w-full bg-[#313131] p-3 rounded-lg {item?.ticker?.includes($stockTicker) ? 'ring-2 ring-[#04E000]' : ''}">
|
||||||
|
|
||||||
<div class="flex flex-col items-center w-full">
|
<div class="flex flex-col items-center w-full">
|
||||||
<span class="ml-1 text-white font-medium mr-auto">
|
<span class="ml-1 text-white font-medium mr-auto">
|
||||||
{item?.title}
|
{item?.title}
|
||||||
</span>
|
</span>
|
||||||
<span class="ml-1 text-white text-opacity-40 text-sm font-medium mr-auto">
|
<span class="ml-1 text-white text-opacity-40 text-sm font-medium mr-auto">
|
||||||
{item?.ticker?.length} {item?.ticker?.length !==1 ? 'Companies' : 'Company'}
|
{item?.ticker?.length}
|
||||||
|
{item?.ticker?.length !== 1 ? "Companies" : "Company"}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="rounded-full w-8 h-8 relative border border-[#737373]">
|
<div class="rounded-full w-8 h-8 relative border border-[#737373]">
|
||||||
{#if item?.ticker?.includes($stockTicker)}
|
{#if item?.ticker?.includes($stockTicker)}
|
||||||
<svg class="w-full h-full rounded-full" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#09090B000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> <title>ic_fluent_checkmark_circle_48_filled</title> <desc>Created with Sketch.</desc> <g id="🔍-Product-Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="ic_fluent_checkmark_circle_48_filled" fill="#04E000" fill-rule="nonzero"> <path d="M24,4 C35.045695,4 44,12.954305 44,24 C44,35.045695 35.045695,44 24,44 C12.954305,44 4,35.045695 4,24 C4,12.954305 12.954305,4 24,4 Z M32.6338835,17.6161165 C32.1782718,17.1605048 31.4584514,17.1301307 30.9676119,17.5249942 L30.8661165,17.6161165 L20.75,27.732233 L17.1338835,24.1161165 C16.6457281,23.6279612 15.8542719,23.6279612 15.3661165,24.1161165 C14.9105048,24.5717282 14.8801307,25.2915486 15.2749942,25.7823881 L15.3661165,25.8838835 L19.8661165,30.3838835 C20.3217282,30.8394952 21.0415486,30.8698693 21.5323881,30.4750058 L21.6338835,30.3838835 L32.6338835,19.3838835 C33.1220388,18.8957281 33.1220388,18.1042719 32.6338835,17.6161165 Z" id="🎨-Color"> </path> </g> </g> </g></svg>
|
<svg class="w-full h-full rounded-full" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#09090B000"
|
||||||
|
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier">
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> <title>ic_fluent_checkmark_circle_48_filled</title> <desc>Created with Sketch.</desc>
|
||||||
|
<g id="🔍-Product-Icons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="ic_fluent_checkmark_circle_48_filled" fill="#04E000" fill-rule="nonzero">
|
||||||
|
<path
|
||||||
|
d="M24,4 C35.045695,4 44,12.954305 44,24 C44,35.045695 35.045695,44 24,44 C12.954305,44 4,35.045695 4,24 C4,12.954305 12.954305,4 24,4 Z M32.6338835,17.6161165 C32.1782718,17.1605048 31.4584514,17.1301307 30.9676119,17.5249942 L30.8661165,17.6161165 L20.75,27.732233 L17.1338835,24.1161165 C16.6457281,23.6279612 15.8542719,23.6279612 15.3661165,24.1161165 C14.9105048,24.5717282 14.8801307,25.2915486 15.2749942,25.7823881 L15.3661165,25.8838835 L19.8661165,30.3838835 C20.3217282,30.8394952 21.0415486,30.8698693 21.5323881,30.4750058 L21.6338835,30.3838835 L32.6338835,19.3838835 C33.1220388,18.8957281 33.1220388,18.1042719 32.6338835,17.6161165 Z"
|
||||||
|
id="🎨-Color"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g></svg
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</label>
|
</label>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<!--End Add Watchlist Modal-->
|
<!--End Add Watchlist Modal-->
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style lang='scss'>
|
|
||||||
|
|
||||||
|
|
||||||
.scrollbar {
|
.scrollbar {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: 17px;
|
grid-gap: 17px;
|
||||||
@ -932,17 +905,16 @@ $: isScrolled = y > 0;
|
|||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
height: 7px;
|
height: 7px;
|
||||||
width: 10px;
|
width: 10px;
|
||||||
background: #09090B;
|
background: #09090b;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background: #6B6F79;
|
background: #6b6f79;
|
||||||
-webkit-border-radius: 1ex;
|
-webkit-border-radius: 1ex;
|
||||||
-webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.75);
|
-webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-corner {
|
::-webkit-scrollbar-corner {
|
||||||
background: #09090B;
|
background: #09090b;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
764
src/routes/stocks/[tickerID]/ai-analysis/+page.svelte
Normal file
764
src/routes/stocks/[tickerID]/ai-analysis/+page.svelte
Normal file
@ -0,0 +1,764 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
import {numberOfUnreadNotification, displayCompanyName, screenWidth, stockTicker} from '$lib/store';
|
||||||
|
import { Chart } from 'svelte-echarts'
|
||||||
|
import { abbreviateNumber } from '$lib/utils';
|
||||||
|
import InfoModal from '$lib/components/InfoModal.svelte';
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
import UpgradeToPro from '$lib/components/UpgradeToPro.svelte';
|
||||||
|
import { init, use } from 'echarts/core'
|
||||||
|
import { BarChart } from 'echarts/charts'
|
||||||
|
import { GridComponent, TooltipComponent } from 'echarts/components'
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers'
|
||||||
|
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer])
|
||||||
|
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
|
||||||
|
let rawPlotData = data?.getOptionsPlotData;
|
||||||
|
let filteredList = [];
|
||||||
|
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||||
|
|
||||||
|
let optionsPlotData = data?.getOptionsPlotData?.plot;
|
||||||
|
let displayData = 'volume';
|
||||||
|
let options;
|
||||||
|
let rawData = data?.getOptionsFlowData
|
||||||
|
let optionList = rawData?.slice(0,30);
|
||||||
|
let flowSentiment = 'n/a';
|
||||||
|
let callPercentage;
|
||||||
|
let putPercentage;
|
||||||
|
let displayCallVolume;
|
||||||
|
let displayPutVolume;
|
||||||
|
let latestPutCallRatio;
|
||||||
|
let displayOTMRatio;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let totalVolume //= data?.getOptionsPlotData?.totalVolume;
|
||||||
|
|
||||||
|
let totalOpenInterest //= data?.getOptionsPlotData?.totalOpenInterest;
|
||||||
|
|
||||||
|
|
||||||
|
// Computing the put-call ratio for open interest
|
||||||
|
let putCallOpenInterestRatio //= data?.getOptionsPlotData?.putCallOpenInterestRatio;
|
||||||
|
let putCallRatio;
|
||||||
|
let displayTotalVolume //= new Intl.NumberFormat("en", {minimumFractionDigits: 0, maximumFractionDigits: 0})?.format(totalVolume);
|
||||||
|
let displayTotalOpenInterest //= new Intl.NumberFormat("en", {minimumFractionDigits: 0, maximumFractionDigits: 0})?.format(totalOpenInterest);
|
||||||
|
let displayTotalPutCall
|
||||||
|
let dateList //= data?.getOptionsPlotData?.dateList;
|
||||||
|
|
||||||
|
let callVolumeList //= data?.getOptionsPlotData?.callVolumeList;
|
||||||
|
let putVolumeList //= data?.getOptionsPlotData?.putVolumeList;
|
||||||
|
let callOpenInterestList //= data?.getOptionsPlotData?.callOpenInterestList;
|
||||||
|
let putOpenInterestList //= data?.getOptionsPlotData?.putOpenInterestList;
|
||||||
|
|
||||||
|
|
||||||
|
let displayTimePeriod = 'threeMonths'
|
||||||
|
|
||||||
|
|
||||||
|
function formatDate(dateStr) {
|
||||||
|
// Parse the input date string (YYYY-mm-dd)
|
||||||
|
var date = new Date(dateStr);
|
||||||
|
|
||||||
|
// Get month, day, and year
|
||||||
|
var month = date.getMonth() + 1; // Month starts from 0
|
||||||
|
var day = date.getDate();
|
||||||
|
var year = date.getFullYear();
|
||||||
|
|
||||||
|
// Extract the last two digits of the year
|
||||||
|
var shortYear = year.toString().slice(-2);
|
||||||
|
|
||||||
|
// Add leading zeros if necessary
|
||||||
|
month = (month < 10 ? "0" : "") + month;
|
||||||
|
day = (day < 10 ? "0" : "") + day;
|
||||||
|
|
||||||
|
var formattedDate = month + "/" + day + "/" + year;
|
||||||
|
|
||||||
|
return formattedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(timeString) {
|
||||||
|
// Split the time string into components
|
||||||
|
const [hours, minutes, seconds] = timeString.split(':').map(Number);
|
||||||
|
|
||||||
|
// Determine AM or PM
|
||||||
|
const period = hours >= 12 ? 'PM' : 'AM';
|
||||||
|
|
||||||
|
// Convert hours from 24-hour to 12-hour format
|
||||||
|
const formattedHours = hours % 12 || 12; // Converts 0 to 12 for midnight
|
||||||
|
|
||||||
|
// Format the time string
|
||||||
|
const formattedTimeString = `${formattedHours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')} ${period}`;
|
||||||
|
|
||||||
|
return formattedTimeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeStatement(event)
|
||||||
|
{
|
||||||
|
displayData = event.target.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeTimePeriod(event)
|
||||||
|
{
|
||||||
|
displayTimePeriod = event.target.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function plotData(callData, putData) {
|
||||||
|
const options = {
|
||||||
|
animation: false,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
silent: true,
|
||||||
|
grid: {
|
||||||
|
left: $screenWidth < 640 ? '5%' : '2%',
|
||||||
|
right: $screenWidth < 640 ? '5%' : '2%',
|
||||||
|
bottom: '20%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
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',
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
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'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Put',
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'Put-Call Ratio',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: putData,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#EE5365' //'#7A1C16'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
const now = Date.now();
|
||||||
|
let cutoffDate;
|
||||||
|
|
||||||
|
switch (displayTimePeriod) {
|
||||||
|
case 'oneWeek':
|
||||||
|
cutoffDate = now - 7 * 24 * 60 * 60 * 1000;
|
||||||
|
break;
|
||||||
|
case 'oneMonth':
|
||||||
|
cutoffDate = now - 30 * 24 * 60 * 60 * 1000;
|
||||||
|
break;
|
||||||
|
case 'threeMonths':
|
||||||
|
cutoffDate = now - 90 * 24 * 60 * 60 * 1000;
|
||||||
|
break;
|
||||||
|
case 'sixMonths':
|
||||||
|
cutoffDate = now - 180 * 24 * 60 * 60 * 1000;
|
||||||
|
break;
|
||||||
|
case 'oneYear':
|
||||||
|
cutoffDate = now - 365 * 24 * 60 * 60 * 1000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid time period');
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredList?.filter(item => {
|
||||||
|
// Convert YYYY-MM-DD to a timestamp
|
||||||
|
const [year, month, day] = item?.date?.split('-')?.map(Number);
|
||||||
|
const itemTimestamp = new Date(year, month - 1, day)?.getTime();
|
||||||
|
|
||||||
|
return itemTimestamp >= cutoffDate;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function processPlotData(filteredList: any[]) {
|
||||||
|
const totals = filteredList?.reduce((acc, obj) => {
|
||||||
|
acc.callVolume += obj?.CALL?.volume;
|
||||||
|
acc.putVolume += obj?.PUT?.volume;
|
||||||
|
acc.callOpenInterest += obj?.CALL?.open_interest;
|
||||||
|
acc.putOpenInterest += obj?.PUT?.open_interest;
|
||||||
|
return acc;
|
||||||
|
}, { callVolume: 0, putVolume: 0, callOpenInterest: 0, putOpenInterest: 0 });
|
||||||
|
|
||||||
|
putCallRatio = (totals.putVolume / totals.callVolume)?.toFixed(2);
|
||||||
|
totalVolume = totals.callVolume + totals.putVolume;
|
||||||
|
totalOpenInterest = totals.callOpenInterest + totals.putOpenInterest;
|
||||||
|
putCallOpenInterestRatio = (totals.putOpenInterest / totals.callOpenInterest)?.toFixed(2);
|
||||||
|
|
||||||
|
dateList = filteredList?.map(item => item.date);
|
||||||
|
callVolumeList = filteredList?.map(item => item?.CALL?.volume);
|
||||||
|
putVolumeList = filteredList?.map(item => item?.PUT?.volume);
|
||||||
|
callOpenInterestList = filteredList?.map(item => item?.CALL?.open_interest);
|
||||||
|
putOpenInterestList = filteredList?.map(item => item?.PUT?.open_interest);
|
||||||
|
|
||||||
|
displayTotalVolume = new Intl.NumberFormat("en", {minimumFractionDigits: 0, maximumFractionDigits: 0}).format(totalVolume);
|
||||||
|
displayTotalPutCall = new Intl.NumberFormat("en", {minimumFractionDigits: 0, maximumFractionDigits: 0}).format(putCallRatio);
|
||||||
|
displayTotalOpenInterest = new Intl.NumberFormat("en", {minimumFractionDigits: 0, maximumFractionDigits: 0}).format(totalOpenInterest);
|
||||||
|
|
||||||
|
// Determine the type of plot data to generate based on displayData
|
||||||
|
if (displayData === 'volume') {
|
||||||
|
options = plotData(callVolumeList, putVolumeList);
|
||||||
|
} else if (displayData === 'openInterest') {
|
||||||
|
options = plotData(callOpenInterestList, putOpenInterestList);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleScroll() {
|
||||||
|
const scrollThreshold = document.body.offsetHeight * 0.8; // 80% of the website height
|
||||||
|
const isBottom = window.innerHeight + window.scrollY >= scrollThreshold;
|
||||||
|
if (isBottom && optionList?.length !== rawData?.length) {
|
||||||
|
const nextIndex = optionList?.length;
|
||||||
|
const filteredNewResults = rawData?.slice(nextIndex, nextIndex + 25);
|
||||||
|
optionList = [...optionList, ...filteredNewResults];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
calculateStats();
|
||||||
|
|
||||||
|
if(data?.user?.tier === 'Pro') {
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('scroll', handleScroll);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if ((displayTimePeriod || displayData) && optionsPlotData?.length !== 0 && typeof window !== 'undefined') {
|
||||||
|
// Filter the raw plot data based on the selected time period
|
||||||
|
filteredList = filterDate(rawPlotData, displayTimePeriod);
|
||||||
|
|
||||||
|
// Process the filtered list to generate the plot data
|
||||||
|
processPlotData(filteredList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>
|
||||||
|
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ''} {$displayCompanyName} ({$stockTicker}) Options Activity · stocknear
|
||||||
|
</title>
|
||||||
|
<meta name="description" content={`Detailed informaton of unusual options activity for ${$displayCompanyName} (${$stockTicker}).`} />
|
||||||
|
|
||||||
|
<!-- Other meta tags -->
|
||||||
|
<meta property="og:title" content={`${$displayCompanyName} (${$stockTicker}) Options Activity · stocknear`}/>
|
||||||
|
<meta property="og:description" content={`Detailed informaton of unusual options activity for ${$displayCompanyName} (${$stockTicker}).`} />
|
||||||
|
<meta property="og:type" content="website"/>
|
||||||
|
<!-- Add more Open Graph meta tags as needed -->
|
||||||
|
|
||||||
|
<!-- Twitter specific meta tags -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image"/>
|
||||||
|
<meta name="twitter:title" content={`${$displayCompanyName} (${$stockTicker}) Options Activity · stocknear`}/>
|
||||||
|
<meta name="twitter:description" content={`Detailed informaton of unusual options activity for ${$displayCompanyName} (${$stockTicker}).`} />
|
||||||
|
<!-- Add more Twitter meta tags as needed -->
|
||||||
|
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section class="bg-[#09090B] overflow-hidden text-white h-full mb-40 sm:mb-0 w-full">
|
||||||
|
<div class="flex justify-center m-auto h-full overflow-hidden w-full">
|
||||||
|
<div class="relative flex justify-center items-center overflow-hidden w-full">
|
||||||
|
<div class="sm:p-7 w-full m-auto mt-2 sm:mt-0">
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-2xl sm:text-3xl text-gray-200 font-bold mb-4">
|
||||||
|
Unsual Options Activity
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<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]">
|
||||||
|
<svg class="w-6 h-6 flex-shrink-0 inline-block sm:mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path fill="#a474f6" d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16"/></svg>
|
||||||
|
|
||||||
|
{#if optionsPlotData?.length !== 0}
|
||||||
|
1 Year of options activity involving {$displayCompanyName} by major institutional traders and hedge funds.
|
||||||
|
{:else}
|
||||||
|
There's no data available, indicating that major traders may not be actively betting on {$displayCompanyName}.
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{#if optionsPlotData?.length !== 0}
|
||||||
|
|
||||||
|
<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">
|
||||||
|
<div class="p-4 bp:p-5 sm:p-6">
|
||||||
|
<label for="totaVolume" class="mr-1 cursor-pointer flex flex-row items-center text-white text-[1rem]">
|
||||||
|
Total Volume
|
||||||
|
<InfoModal
|
||||||
|
title={"Total Volume"}
|
||||||
|
content={"The total volume is the combined number of puts and calls traded over the past three months in options trading."}
|
||||||
|
id={"totaVolume"}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="mt-1 break-words font-semibold leading-8 text-light text-lg">
|
||||||
|
{displayTotalVolume}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 bp:p-5 sm:p-6 border-l border-contrast md:border-0">
|
||||||
|
<label for="totalOpenInterest" class="mr-1 cursor-pointer flex flex-row items-center text-white text-[1rem]">
|
||||||
|
Total OI
|
||||||
|
<InfoModal
|
||||||
|
title={"Total OI"}
|
||||||
|
content={"The total open interest reflects the aggregate number of outstanding options contracts in options trading."}
|
||||||
|
id={"totalOpenInterest"}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 break-words font-semibold leading-8 text-light text-lg">
|
||||||
|
{displayTotalOpenInterest}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 bp:p-5 sm:p-6 border-t border-contrast md:border-0">
|
||||||
|
<label for="putCallRatio" class="mr-1 cursor-pointer flex flex-row items-center text-white text-[1rem]">
|
||||||
|
P/C Ratio
|
||||||
|
<InfoModal
|
||||||
|
title={"P/C Ratio"}
|
||||||
|
content={"The put-call ratio assesses market sentiment and potential movements by comparing traded put options to call options."}
|
||||||
|
id={"putCallRatio"}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div class="mt-1 break-words font-semibold leading-8 text-light text-lg">
|
||||||
|
{putCallRatio !== 'Infinity' ? putCallRatio : '> 1'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 bp:p-5 sm:p-6 border-t border-contrast md:border-0 border-l border-contrast md:border-0">
|
||||||
|
<label for="openInteresteRatio" class="mr-1 cursor-pointer flex flex-row items-center text-white text-[1rem]">
|
||||||
|
OI P/C Ratio
|
||||||
|
<InfoModal
|
||||||
|
title={"OI P/C Ratio"}
|
||||||
|
content={"The open interest put-call ratio measures market sentiment in options trading by comparing the total number of outstanding put options contracts to outstanding call options contracts. A higher ratio suggests bearish sentiment, while a lower ratio indicates bullish sentiment."}
|
||||||
|
id={"openInteresteRatio"}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="mt-1 break-words font-semibold leading-8 text-light text-lg">
|
||||||
|
{putCallOpenInterestRatio !== 'Infinity' ? putCallOpenInterestRatio : '> 1'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-row items-center w-full mt-10">
|
||||||
|
<select class="ml-1 w-40 select select-bordered select-sm p-0 pl-5 bg-[#2A303C]" on:change={changeTimePeriod}>
|
||||||
|
<option disabled>Choose a time period</option>
|
||||||
|
<option value="oneWeek">1 Week</option>
|
||||||
|
<option value="oneMonth" selected>1 Month</option>
|
||||||
|
<option value="threeMonths" selected>3 Months</option>
|
||||||
|
<option value="sixMonths">6 Months</option>
|
||||||
|
<option value="oneYear">1 Year</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select class="ml-auto sm:ml-3 w-40 select select-bordered select-sm p-0 pl-5 bg-[#2A303C]" on:change={changeStatement}>
|
||||||
|
<option disabled>Choose a category</option>
|
||||||
|
<option value="volume" selected>Volume</option>
|
||||||
|
<option value="openInterest">Open Interest</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="app w-full bg-[#09090B] rounded-xl">
|
||||||
|
{#if filteredList?.length !== 0}
|
||||||
|
<Chart {init} options={options} class="chart" />
|
||||||
|
{:else}
|
||||||
|
<span class="text-xl text-white m-auto flex justify-center items-center h-full">
|
||||||
|
<div class="text-gray-100 text-sm sm:text-[1rem] sm:rounded-lg h-auto border border-slate-800 p-4">
|
||||||
|
<svg class="w-5 h-5 inline-block sm:mr-2 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path fill="#a474f6" d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16"/></svg>
|
||||||
|
No Options activity found
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 class="text-2xl sm:text-3xl text-gray-200 font-bold mb-4 text-center sm:text-start">
|
||||||
|
Latest Options Activity
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{#if optionList?.length !== 0}
|
||||||
|
<!--Start Widget-->
|
||||||
|
|
||||||
|
<div class="w-full mt-5 mb-10 m-auto flex justify-center items-center">
|
||||||
|
<div class="w-full grid grid-cols-2 xl:grid-cols-3 gap-y-3 lg:gap-y-3 gap-x-3 ">
|
||||||
|
<!--Start Flow Sentiment-->
|
||||||
|
<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">
|
||||||
|
<span class="font-medium text-gray-200 text-[1rem] ">Flow Sentiment</span>
|
||||||
|
<span class="text-start text-[1rem] font-medium {flowSentiment === 'Bullish' ? 'text-[#00FC50]' : 'text-[#FC2120]'}">{flowSentiment}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!--End Flow Sentiment-->
|
||||||
|
<!--Start Put/Call-->
|
||||||
|
<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">
|
||||||
|
<span class="font-medium text-gray-200 text-[1rem] ">Put/Call</span>
|
||||||
|
<span class="text-start text-sm sm:text-[1rem] font-medium text-white">
|
||||||
|
{latestPutCallRatio?.toFixed(3)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- Circular Progress -->
|
||||||
|
<div class="relative size-14 ml-auto">
|
||||||
|
<svg class="size-full w-14 h-14" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!-- Background Circle -->
|
||||||
|
<circle cx="18" cy="18" r="16" fill="none" class="stroke-current text-[#3E3E3E]" stroke-width="3"></circle>
|
||||||
|
<!-- Progress Circle inside a group with rotation -->
|
||||||
|
<g class="origin-center -rotate-90 transform">
|
||||||
|
<circle cx="18" cy="18" r="16" fill="none" class="stroke-current text-blue-500" stroke-width="3" stroke-dasharray="100" stroke-dashoffset={latestPutCallRatio >=1 ? 0 : 100-(latestPutCallRatio*100)?.toFixed(2)}></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<!-- Percentage Text -->
|
||||||
|
<div class="absolute top-1/2 start-1/2 transform -translate-y-1/2 -translate-x-1/2">
|
||||||
|
<span class="text-center text-white text-sm">{latestPutCallRatio?.toFixed(2)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End Circular Progress -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!--End Put/Call-->
|
||||||
|
<!--Start Call Flow-->
|
||||||
|
<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">
|
||||||
|
<span class="font-medium text-gray-200 text-[1rem] ">Call Flow</span>
|
||||||
|
<span class="text-start text-sm sm:text-[1rem] font-medium text-white">
|
||||||
|
{new Intl.NumberFormat("en", {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0
|
||||||
|
}).format(displayCallVolume)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- Circular Progress -->
|
||||||
|
<div class="relative size-14 ml-auto">
|
||||||
|
<svg class="size-full w-14 h-14" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!-- Background Circle -->
|
||||||
|
<circle cx="18" cy="18" r="16" fill="none" class="stroke-current text-[#3E3E3E]" stroke-width="3"></circle>
|
||||||
|
<!-- Progress Circle inside a group with rotation -->
|
||||||
|
<g class="origin-center -rotate-90 transform">
|
||||||
|
<circle cx="18" cy="18" r="16" fill="none" class="stroke-current text-[#00FC50]" stroke-width="3" stroke-dasharray="100" stroke-dashoffset={100-callPercentage?.toFixed(2)}></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<!-- Percentage Text -->
|
||||||
|
<div class="absolute top-1/2 start-1/2 transform -translate-y-1/2 -translate-x-1/2">
|
||||||
|
<span class="text-center text-white text-sm">{callPercentage}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End Circular Progress -->
|
||||||
|
</div>
|
||||||
|
<!--End Call 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-md h-20">
|
||||||
|
<div class="flex flex-col items-start">
|
||||||
|
<span class="font-medium text-gray-200 text-[1rem] ">Put Flow</span>
|
||||||
|
<span class="text-start text-sm sm:text-[1rem] font-medium text-white">
|
||||||
|
{new Intl.NumberFormat("en", {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0
|
||||||
|
}).format(displayPutVolume)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- Circular Progress -->
|
||||||
|
<div class="relative size-14 ml-auto">
|
||||||
|
<svg class="size-full w-14 h-14" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!-- Background Circle -->
|
||||||
|
<circle cx="18" cy="18" r="16" fill="none" class="stroke-current text-[#3E3E3E]" stroke-width="3"></circle>
|
||||||
|
<!-- Progress Circle inside a group with rotation -->
|
||||||
|
<g class="origin-center -rotate-90 transform">
|
||||||
|
<circle cx="18" cy="18" r="16" fill="none" class="stroke-current text-[#EE5365]" stroke-width="3" stroke-dasharray="100" stroke-dashoffset={100-putPercentage?.toFixed(2)}></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<!-- Percentage Text -->
|
||||||
|
<div class="absolute top-1/2 start-1/2 transform -translate-y-1/2 -translate-x-1/2">
|
||||||
|
<span class="text-center text-white text-sm">{putPercentage}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End Circular Progress -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!--End Put Flow-->
|
||||||
|
|
||||||
|
<!--Start Put/Call-->
|
||||||
|
<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">
|
||||||
|
<span class="font-medium text-gray-200 text-[1rem] ">OTM Ratio</span>
|
||||||
|
<span class="text-start text-sm sm:text-[1rem] font-medium text-white">
|
||||||
|
Volume in %
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- Circular Progress -->
|
||||||
|
<div class="relative size-14 ml-auto">
|
||||||
|
<svg class="size-full w-14 h-14" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<!-- Background Circle -->
|
||||||
|
<circle cx="18" cy="18" r="16" fill="none" class="stroke-current text-[#3E3E3E]" stroke-width="3"></circle>
|
||||||
|
<!-- Progress Circle inside a group with rotation -->
|
||||||
|
<g class="origin-center -rotate-90 transform">
|
||||||
|
<circle cx="18" cy="18" r="16" fill="none" class="stroke-current text-[#EE5365]" stroke-width="3" stroke-dasharray="100" stroke-dashoffset={displayOTMRatio >=1 ? 0 : 100-(displayOTMRatio*100)?.toFixed(2)}></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<!-- Percentage Text -->
|
||||||
|
<div class="absolute top-1/2 start-1/2 transform -translate-y-1/2 -translate-x-1/2">
|
||||||
|
<span class="text-center text-white text-sm">{(displayOTMRatio*100)?.toFixed(0)}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End Circular Progress -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!--End Put/Call-->
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--End Widget-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex justify-start items-center m-auto 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>
|
||||||
|
<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">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">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-start">Sent.</td>
|
||||||
|
<td class="text-slate-200 font-semibold text-sm text-end">Spot</td>
|
||||||
|
<td class="text-slate-200 font-semibold text-sm text-end">Price</td>
|
||||||
|
<td class="text-slate-200 font-semibold text-sm text-end">Prem.</td>
|
||||||
|
<td class="text-slate-200 font-semibold text-sm text-start">Type</td>
|
||||||
|
<td class="text-slate-200 font-semibold text-sm text-end">Vol.</td>
|
||||||
|
<td class="text-slate-200 font-semibold text-sm text-end">OI</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each (data?.user?.tier === 'Pro' ? optionList : optionList?.slice(0,3)) as item, index}
|
||||||
|
<!-- row -->
|
||||||
|
<tr class="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 text-start whitespace-nowrap">
|
||||||
|
{formatTime(item?.time)}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-white text-sm sm:text-[1rem] text-start">
|
||||||
|
{formatDate(item?.date)}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-white text-sm sm:text-[1rem] text-end">
|
||||||
|
{item?.dte < 0 ? 'expired' : item?.dte +'d'}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-sm sm:text-[1rem] text-end text-white">
|
||||||
|
{item?.strike_price}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-sm sm:text-[1rem] {item?.put_call === 'Calls' ? 'text-[#00FC50]' : 'text-[#FC2120]'} text-start">
|
||||||
|
{item?.put_call}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-sm sm:text-[1rem] {item?.sentiment === 'Bullish' ? 'text-[#00FC50]' : item?.sentiment === 'Bearish' ? 'text-[#FC2120]' : 'text-[#C6A755]'} text-start">
|
||||||
|
{item?.sentiment}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-sm sm:text-[1rem] text-end text-white">
|
||||||
|
{item?.underlying_price}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-sm sm:text-[1rem] text-end text-white">
|
||||||
|
{item?.price}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-sm sm:text-[1rem] text-end font-medium {item?.put_call === 'Puts' ? 'text-[#CB281C]' : 'text-[#0FB307]'} ">
|
||||||
|
{abbreviateNumber(item?.cost_basis)}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-sm sm:text-[1rem] text-start {item?.type === 'Sweep' ? 'text-[#C6A755]' : 'text-[#976DB7]'}">
|
||||||
|
{item?.type}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<td class="text-white text-end">
|
||||||
|
{new Intl.NumberFormat("en", {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0
|
||||||
|
}).format(item?.volume)}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="text-white text-end">
|
||||||
|
{new Intl.NumberFormat("en", {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0
|
||||||
|
}).format(item?.open_interest)}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<UpgradeToPro data={data} title="Get the recent Options Flow Data from Hedge Funds and major institutional traders to never miss out"/>
|
||||||
|
|
||||||
|
{:else}
|
||||||
|
<div class="flex justify-center items-center m-auto mt-16 mb-6">
|
||||||
|
<div class="text-gray-100 text-sm sm:text-[1rem] rounded-lg h-auto border border-slate-800 p-4">
|
||||||
|
<svg class="w-5 h-5 inline-block sm:mr-2 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path fill="#a474f6" d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16"/></svg>
|
||||||
|
No Options activity found
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.app {
|
||||||
|
height: 420px;
|
||||||
|
max-width: 1500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.app {
|
||||||
|
max-width: 520px;
|
||||||
|
height: 420px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
89
src/routes/stocks/[tickerID]/ai-analysis/+page.ts
Normal file
89
src/routes/stocks/[tickerID]/ai-analysis/+page.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { getCache, setCache } from '$lib/store';
|
||||||
|
|
||||||
|
|
||||||
|
function daysLeft(targetDate) {
|
||||||
|
const targetTime = new Date(targetDate).getTime();
|
||||||
|
const currentTime = new Date().getTime();
|
||||||
|
const difference = targetTime - currentTime;
|
||||||
|
|
||||||
|
const millisecondsPerDay = 1000 * 60 * 60 * 24;
|
||||||
|
const daysLeft = Math?.ceil(difference / millisecondsPerDay);
|
||||||
|
|
||||||
|
return daysLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const load = async ({ parent, params }) => {
|
||||||
|
|
||||||
|
|
||||||
|
const {apiKey, apiURL} = await parent();
|
||||||
|
|
||||||
|
|
||||||
|
const getOptionsPlotData = async () => {
|
||||||
|
|
||||||
|
const cachedData = getCache(params.tickerID, 'getOptionsPlotData');
|
||||||
|
if (cachedData) {
|
||||||
|
return cachedData;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const postData = {
|
||||||
|
ticker: params.tickerID
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(apiURL + '/options-plot-ticker', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json", "X-API-KEY": apiKey
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData)
|
||||||
|
});
|
||||||
|
|
||||||
|
const output = await response.json();
|
||||||
|
|
||||||
|
setCache(params.tickerID, output, 'getOptionsPlotData');
|
||||||
|
return output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOptionsFlowData = async () => {
|
||||||
|
|
||||||
|
let output;
|
||||||
|
const cachedData = getCache(params.tickerID, 'getOptionsFlowData');
|
||||||
|
if (cachedData) {
|
||||||
|
output = cachedData;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const postData = {
|
||||||
|
ticker: params.tickerID
|
||||||
|
};
|
||||||
|
|
||||||
|
// make the POST request to the endpoint
|
||||||
|
const response = await fetch(apiURL + '/options-flow-ticker', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json", "X-API-KEY": apiKey
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData)
|
||||||
|
});
|
||||||
|
|
||||||
|
output = await response.json();
|
||||||
|
|
||||||
|
output?.forEach(item => {
|
||||||
|
item.dte = daysLeft(item?.date_expiration);
|
||||||
|
});
|
||||||
|
|
||||||
|
setCache(params.tickerID, output, 'getOptionsFlowData');
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure to return a promise
|
||||||
|
return {
|
||||||
|
getOptionsPlotData: await getOptionsPlotData(),
|
||||||
|
getOptionsFlowData: await getOptionsFlowData()
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
@ -1,42 +1,36 @@
|
|||||||
<script lang='ts'>
|
<script lang="ts">
|
||||||
import { stockTicker, screenWidth } from "$lib/store";
|
import { stockTicker, screenWidth } from "$lib/store";
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
|
|
||||||
let displaySubSection = 'fundamental';
|
let displaySubSection = "overview";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (displaySubSection) {
|
if (displaySubSection) {
|
||||||
const parts = $page?.url?.pathname.split('/');
|
const parts = $page?.url?.pathname.split("/");
|
||||||
const sectionMap = {
|
const sectionMap = {
|
||||||
'market-cap': 'market-cap',
|
"market-cap": "market-cap",
|
||||||
'employees': 'employees',
|
employees: "employees",
|
||||||
'income': 'income',
|
income: "income",
|
||||||
'balance-sheet': 'balance-sheet',
|
"balance-sheet": "balance-sheet",
|
||||||
'cash-flow': 'cash-flow',
|
"cash-flow": "cash-flow",
|
||||||
'ratios': 'ratios',
|
ratios: "ratios",
|
||||||
};
|
};
|
||||||
|
|
||||||
const foundSection = parts?.find(part => Object?.values(sectionMap)?.includes(part));
|
const foundSection = parts?.find((part) => Object?.values(sectionMap)?.includes(part));
|
||||||
|
|
||||||
displaySubSection = Object?.keys(sectionMap)?.find(key => sectionMap[key] === foundSection) || 'fundamental';
|
|
||||||
|
|
||||||
|
displaySubSection = Object?.keys(sectionMap)?.find((key) => sectionMap[key] === foundSection) || "overview";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function changeSubSection(state) {
|
function changeSubSection(state) {
|
||||||
const subSectionMap = {
|
const subSectionMap = {
|
||||||
'market-cap': '/stats/market-cap',
|
"market-cap": "/stats/market-cap",
|
||||||
'employees': '/stats/employees',
|
employees: "/stats/employees",
|
||||||
'income': '/stats/income',
|
income: "/stats/income",
|
||||||
'balance-sheet': '/stats/balance-sheet',
|
"balance-sheet": "/stats/balance-sheet",
|
||||||
'cash-flow': '/stats/cash-flow',
|
"cash-flow": "/stats/cash-flow",
|
||||||
'ratios': '/stats/ratios',
|
ratios: "/stats/ratios",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (state !== 'fundamental' && subSectionMap[state]) {
|
if (state !== "overview" && subSectionMap[state]) {
|
||||||
displaySubSection = state;
|
displaySubSection = state;
|
||||||
//goto(`/stocks/${$stockTicker}${subSectionMap[state]}`);
|
//goto(`/stocks/${$stockTicker}${subSectionMap[state]}`);
|
||||||
} else {
|
} else {
|
||||||
@ -44,76 +38,93 @@ function changeSubSection(state) {
|
|||||||
//goto(`/stocks/${$stockTicker}/stats`);
|
//goto(`/stocks/${$stockTicker}/stats`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="w-auto max-w-5xl bg-[#09090B] overflow-hidden text-black h-full mb-40">
|
<section class="w-auto max-w-5xl bg-[#09090B] overflow-hidden text-black h-full mb-40">
|
||||||
<div class="m-auto h-full overflow-hidden">
|
<div class="m-auto h-full overflow-hidden">
|
||||||
<main class="w-fit sm:w-full sm:max-w-2xl">
|
<main class="w-fit sm:w-full sm:max-w-2xl">
|
||||||
<div class="m-auto">
|
<div class="m-auto">
|
||||||
|
|
||||||
|
|
||||||
<div class="-ml-2 sm:ml-8 w-screen sm:w-full {$screenWidth < 640 ? 'overflow-auto scrollbar' : 'no-scrollbar'} mb-2">
|
<div class="-ml-2 sm:ml-8 w-screen sm:w-full {$screenWidth < 640 ? 'overflow-auto scrollbar' : 'no-scrollbar'} mb-2">
|
||||||
<ul class="pr-4 sm:pr-0 w-screen flex flex-row items-center bg-[#09090B] overflow-x-scroll sm:overflow-hidden space-x-4 rtl:space-x-reverse py-2">
|
<ul class="pr-4 sm:pr-0 w-screen flex flex-row items-center bg-[#09090B] overflow-x-scroll sm:overflow-hidden space-x-4 rtl:space-x-reverse py-2">
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/stats`} on:click={() => (changeSubSection('fundamental'))} class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'fundamental' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
Fundamental
|
href={`/stocks/${$stockTicker}/stats`}
|
||||||
|
on:click={() => changeSubSection("overview")}
|
||||||
|
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'overview' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
|
Overview
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySubSection === 'fundamental' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4rem]" />
|
<div class="{displaySubSection === 'overview' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[4rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/stats/market-cap`} on:click={() => (changeSubSection('market-cap'))} class="whitespace-nowrap px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'market-cap' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
Market Cap
|
href={`/stocks/${$stockTicker}/stats/ratios`}
|
||||||
|
on:click={() => changeSubSection("ratios")}
|
||||||
|
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'ratios' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
|
Ratios
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySubSection === 'market-cap' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
<div class="{displaySubSection === 'ratios' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/stats/employees`} on:click={() => (changeSubSection('employees'))} class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'employees' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
Employees
|
href={`/stocks/${$stockTicker}/stats/income`}
|
||||||
</a>
|
on:click={() => changeSubSection("income")}
|
||||||
<div class="{displaySubSection === 'employees' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'income' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
</li>
|
>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
|
||||||
<a href={`/stocks/${$stockTicker}/stats/income`} on:click={() => (changeSubSection('income'))} class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'income' ? 'text-white ' : 'bg-[#09090B]'}" >
|
|
||||||
Income
|
Income
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySubSection === 'income' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.5rem]" />
|
<div class="{displaySubSection === 'income' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.5rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/stats/balance-sheet`} on:click={() => (changeSubSection('balance-sheet'))} class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'balance-sheet' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
Balance
|
href={`/stocks/${$stockTicker}/stats/cash-flow`}
|
||||||
</a>
|
on:click={() => changeSubSection("cash-flow")}
|
||||||
<div class="{displaySubSection === 'balance-sheet' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.5rem]" />
|
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'cash-flow' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
</li>
|
>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
|
||||||
<a href={`/stocks/${$stockTicker}/stats/cash-flow`} on:click={() => (changeSubSection('cash-flow'))} class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'cash-flow' ? 'text-white ' : 'bg-[#09090B]'}" >
|
|
||||||
Cashflow
|
Cashflow
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySubSection === 'cash-flow' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.5rem]" />
|
<div class="{displaySubSection === 'cash-flow' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.5rem]" />
|
||||||
</li>
|
</li>
|
||||||
<li class="cursor-pointer flex flex-col items-center">
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
<a href={`/stocks/${$stockTicker}/stats/ratios`} on:click={() => (changeSubSection('ratios'))} class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'ratios' ? 'text-white ' : 'bg-[#09090B]'}" >
|
<a
|
||||||
Ratios
|
href={`/stocks/${$stockTicker}/stats/balance-sheet`}
|
||||||
|
on:click={() => changeSubSection("balance-sheet")}
|
||||||
|
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'balance-sheet' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
|
Balance
|
||||||
</a>
|
</a>
|
||||||
<div class="{displaySubSection === 'ratios' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2rem]" />
|
<div class="{displaySubSection === 'balance-sheet' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[2.5rem]" />
|
||||||
|
</li>
|
||||||
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}/stats/market-cap`}
|
||||||
|
on:click={() => changeSubSection("market-cap")}
|
||||||
|
class="whitespace-nowrap px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'market-cap' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
|
Market Cap
|
||||||
|
</a>
|
||||||
|
<div class="{displaySubSection === 'market-cap' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
||||||
|
</li>
|
||||||
|
<li class="cursor-pointer flex flex-col items-center">
|
||||||
|
<a
|
||||||
|
href={`/stocks/${$stockTicker}/stats/employees`}
|
||||||
|
on:click={() => changeSubSection("employees")}
|
||||||
|
class="px-2 text-sm sm:text-[1rem] font-medium text-gray-400 sm:hover:text-white {displaySubSection === 'employees' ? 'text-white ' : 'bg-[#09090B]'}"
|
||||||
|
>
|
||||||
|
Employees
|
||||||
|
</a>
|
||||||
|
<div class="{displaySubSection === 'employees' ? 'bg-[#75D377]' : 'bg-[#09090B]'} mt-1 h-[3px] rounded-full w-[3.5rem]" />
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.scrollbar {
|
.scrollbar {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user