ui fixes && add most shorted stocks page

This commit is contained in:
MuslemRahimi 2024-06-10 14:05:21 +02:00
parent 3cf41bd5fb
commit 11c8634170
9 changed files with 327 additions and 30 deletions

View File

@ -1,7 +1,7 @@
<script lang='ts'>
import { Chart } from 'svelte-echarts'
import { screenWidth, stockTicker, userRegion, getCache, setCache} from '$lib/store';
import { shareholderComponent, screenWidth, stockTicker, userRegion, getCache, setCache} from '$lib/store';
import { formatString } from '$lib/utils';
import { goto } from '$app/navigation';
import { abbreviateNumber } from '$lib/utils';
@ -102,6 +102,13 @@ const getShareholders = async (ticker) => {
// Cache the data for this specific tickerID with a specific name 'getShareholders'
setCache(ticker, shareholderList, 'getShareholders');
}
if(shareholderList?.length !== 0) {
$shareholderComponent = true
}
else {
$shareholderComponent = false;
}
};
@ -266,11 +273,6 @@ $: {
{:else}
<h2 class=" mt-10 justify-center items-center text-3xl font-bold text-slate-700 mb-5 m-auto">
No data available
<svg class="w-10 sm:w-12 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#334155" d="M18.68 12.32a4.49 4.49 0 0 0-6.36.01a4.49 4.49 0 0 0 0 6.36a4.508 4.508 0 0 0 5.57.63L21 22.39L22.39 21l-3.09-3.11c1.13-1.77.87-4.09-.62-5.57m-1.41 4.95c-.98.98-2.56.97-3.54 0c-.97-.98-.97-2.56.01-3.54c.97-.97 2.55-.97 3.53 0c.97.98.97 2.56 0 3.54M10.9 20.1a6.527 6.527 0 0 1-1.48-2.32C6.27 17.25 4 15.76 4 14v3c0 2.21 3.58 4 8 4c-.4-.26-.77-.56-1.1-.9M4 9v3c0 1.68 2.07 3.12 5 3.7v-.2c0-.93.2-1.85.58-2.69C6.34 12.3 4 10.79 4 9m8-6C7.58 3 4 4.79 4 7c0 2 3 3.68 6.85 4h.05c1.2-1.26 2.86-2 4.6-2c.91 0 1.81.19 2.64.56A3.215 3.215 0 0 0 20 7c0-2.21-3.58-4-8-4Z"/></svg>
</h2>
{/if}
{:else}

View File

@ -204,6 +204,7 @@ $: {
</div>
</div>
{#if rawData?.sharesShort !== 0}
<h2 class="mt-10 mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-2xl font-bold mb-3">
Short Selling Information
</h2>
@ -257,6 +258,7 @@ $: {
</tbody>
</table>
</div>
{/if}
{/if}

View File

@ -62,6 +62,7 @@ export const fundamentalAnalysisComponent = writable(<boolean>(false));
export const priceAnalysisComponent = writable(<boolean>(false));
export const revenueSegmentationComponent = writable(<boolean>(false));
export const trendAnalysisComponent = writable(<boolean>(false));
export const shareholderComponent = writable(<boolean>(false));
export const strategyId = writable(<string> (""));

View File

@ -164,11 +164,11 @@ onMount( async() => {
<!-- Start Column -->
<div >
<!--
<div class="text-center mb-5 relative w-fit flex justify-center m-auto">
<a href="/politicians" class="text-white antialiased bg-[#202020] w-full px-3 py-1.5 rounded-xl m-auto font-medium text-sm">
<svg class="w-8 h-8 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72"><path fill="#fff" d="M5 17h62v38H5z"/><path fill="#d22f27" d="M5 17h62v5H5zm0 9h62v4H5zm0 8h62v4H5z"/><path fill="#1e50a0" d="M5 17h32v21H5z"/><path fill="#d22f27" d="M5 42h62v4H5z"/><circle cx="9" cy="22" r="1.75" fill="#fff"/><circle cx="17" cy="22" r="1.75" fill="#fff"/><circle cx="25" cy="22" r="1.75" fill="#fff"/><circle cx="33" cy="22" r="1.75" fill="#fff"/><circle cx="29" cy="26" r="1.75" fill="#fff"/><circle cx="21" cy="26" r="1.75" fill="#fff"/><circle cx="13" cy="26" r="1.75" fill="#fff"/><circle cx="9" cy="30" r="1.75" fill="#fff"/><circle cx="17" cy="30" r="1.75" fill="#fff"/><circle cx="25" cy="30" r="1.75" fill="#fff"/><circle cx="33" cy="30" r="1.75" fill="#fff"/><circle cx="29" cy="34" r="1.75" fill="#fff"/><circle cx="21" cy="34" r="1.75" fill="#fff"/><circle cx="13" cy="34" r="1.75" fill="#fff"/><path fill="#d22f27" d="M5 50h62v5H5z"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 17h62v38H5z"/></svg>
Analyze Congressional Trading using our latest Database.
<a href="/most-shorted-stocks" class="text-white antialiased bg-[#202020] w-full px-4 py-2 rounded-xl m-auto font-medium text-sm flex items-center">
<svg class="w-6 h-6 inline-block mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill="#ffe36c" d="m81.13 29.99l-18.34.18l15.68-8.55l-3.71-13.24l10.41 7.9l10.47-8.01l-2.75 10.78l17.26 1.98l-17.96 7l-7.16 12.5z"/><path fill="#ff8f00" d="m92.27 13.37l-.76 2.96l-1.13 4.45l4.56.52l6.94.79l-9.76 3.81l-1.32.51l-.7 1.23l-4.68 8.17l-1.92-5.2l-.98-2.65l-2.82.04l-8.91.09l7.24-3.95l2.8-1.53l-.86-3.07l-1.67-5.96l4.44 3.37l2.43 1.84l2.42-1.85zm-7.11.39L72.49 4.15c-.41-.31-.98.08-.84.57l4.46 15.91l-19.44 10.6c-.49.27-.3 1.01.26 1L79.74 32l4.5 12.17c.16.43.74.47.97.08l8.37-14.62l22.82-8.9c.52-.2.42-.97-.13-1.03L95.4 17.32l3.22-12.65c.13-.49-.44-.87-.84-.56z"/><path fill="#4d4d4d" d="M94.59 44.29c-1.27-.18-7.6 6.13-12.17 2.17l-.01.01a43.674 43.674 0 0 0-8.72-5.51c-21.75-10.37-47.8-1.15-58.18 20.61c-10.37 21.75-1.15 47.8 20.61 58.18c21.75 10.37 47.8 1.15 58.18-20.61c3.37-7.06 4.67-14.57 4.14-21.85c-.04-.51-.13-1.64.12-2.48c1.71-5.74 7.93-8.6 7.8-8.87c-.13-.28-10.49-21.47-11.77-21.65"/><ellipse cx="100.46" cy="55.12" fill="#757575" rx="5.83" ry="12.33" transform="rotate(-29.923 100.447 55.121)"/><ellipse cx="102.35" cy="55.1" fill="#212121" rx="2.29" ry="3.52" transform="rotate(-30 102.345 55.102)"/><path fill="#757575" d="M53.9 52.57c2.74 7.78-1.27 12.42-6.46 15.39c-2.48 1.42-5.36 2.04-7.87 3.41c-4.88 2.66-7.84 7.79-12.09 11.36c-1.06.89-2.27 1.71-3.65 1.86c-1.84.2-3.64-.88-4.74-2.37c-1.09-1.5-5.56-15.72 10.76-30.27c7.29-6.5 21.05-7.91 24.05.62" opacity="0.9"/><linearGradient id="notoBomb0" x1="42.079" x2="83.812" y1="34.552" y2="48.063" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff9c4" stop-opacity="0.1"/><stop offset=".002" stop-color="#fff9c4" stop-opacity="0.101"/><stop offset=".378" stop-color="#fffca6" stop-opacity="0.263"/><stop offset=".701" stop-color="#fffe94" stop-opacity="0.401"/><stop offset=".93" stop-color="#ffff8d" stop-opacity="0.5"/></linearGradient><path fill="url(#notoBomb0)" d="M41.86 38.72c3.69.12 11.23.17 20.77 3.92c3.21 1.26 5.92 3.02 8.83 4.82c2.35 1.45 5.02 2.66 7.77 2.4c.97-.09 2.04-.47 2.42-1.37c.23-.56.21-1.13.01-1.69c-.24-.66-1.06-1.58-2.32-2.61a44.392 44.392 0 0 0-5.64-3.23c-10.36-4.94-21.69-5.43-31.84-2.24"/><linearGradient id="notoBomb1" x1="102.029" x2="91.139" y1="57.302" y2="42.935" gradientUnits="userSpaceOnUse"><stop offset=".11" stop-color="#fff9c4" stop-opacity="0"/><stop offset="1" stop-color="#ffff8d"/></linearGradient><path fill="url(#notoBomb1)" d="M102.13 47.64c-.05-.05-.1-.11-.15-.16c-.01-.01-.01-.02-.02-.02c-.23-.23-.46-.45-.69-.67c-.03-.03-.07-.06-.1-.1c-2.53-2.29-5.12-3.26-6.86-2.27c-2.79 1.6-2.3 7.69 1.1 13.59a25.56 25.56 0 0 0 2.37 3.43c-.1-.29-3.84-11.52-1.51-14.53c1.99-2.54 5.51.43 5.86.73"/><path fill="#212121" d="M88.16 74.53c-2.42-1.59-4.79-3.75-6.26-9.18c-.19-.69-.83-4.12 1.02-4.67c1.6-.48 2.79 2.15 4.17 4.46c1.5 2.53 3.93 4.72 6.54 6.15c.76.41 4.29 2 1.97 4.22c-1.53 1.45-6.02-.04-7.44-.98"/><path fill="#c69461" d="M100.85 53.44c.1-.04 10.25-4.65 9.37-11.34c-.58-4.42-2.3-6.62-11.4-8.78c-8.9-2.11-13.25-6.24-13.43-6.42c-.89-.86-.92-2.29-.05-3.19c.86-.89 2.28-.92 3.18-.06c.07.06 3.77 3.48 11.35 5.28c8.82 2.09 13.79 4.72 14.83 12.57c1.16 8.78-8.52 14.25-11.29 15.7c-1.72.91-3.7-3.26-2.56-3.76"/><path fill="#f6bc41" d="M88.5 23.66c-.89-.86-2.32-.83-3.18.06c-.86.9-.84 2.32.05 3.19c.13.13 2.5 2.37 7.25 4.39l.95-1.66l3.66-1.43c-5.81-1.86-8.67-4.5-8.73-4.55"/></svg>
<span>Find the Most Shorted Stocks</span>
</a>
<div class="absolute top-[-2.0rem] -right-5 sm:-right-10 rotate-[7deg]">
<span class="bg-[#EF4444] text-white text-sm sm:text-[0.9rem] rounded-xl font-medium sm:me-2 px-2.5 py-0.5 rounded dark:bg-red-900 dark:text-red-300">
@ -176,8 +176,6 @@ onMount( async() => {
</span>
</div>
</div>
-->
@ -237,6 +235,7 @@ onMount( async() => {
</div>
{/if}
<!--
<div class="w-full max-w-64 sm:max-w-3xl m-auto grid grid-cols-1 md:grid-cols-3 gap-y-3 sm:gap-x-5 mt-10 flex justify-center items-center">
<a href="/politicians/61b59ab669" class="px-4 py-3 text-white bg-[#202327] rounded-lg flex flex-row items-center font-medium transition duration-150 ease-in-out group">
<div class="flex flex-row items-center">
@ -272,6 +271,7 @@ onMount( async() => {
</div>
</a>
</div>
-->

View File

@ -1,13 +1,13 @@
import { userRegion, getCache, setCache } from '$lib/store';
const usRegion = ['cle1','iad1','pdx1','sfo1'];
let apiURL;
userRegion.subscribe(value => {
if (usRegion?.includes(value)) {
if (usRegion.includes(value)) {
apiURL = import.meta.env.VITE_USEAST_API_URL;
} else {
apiURL = import.meta.env.VITE_EU_API_URL;
@ -15,17 +15,15 @@ userRegion.subscribe(value => {
});
export const load = async ({locals}) => {
export const load = async ({parent}) => {
const getTopAnalystStocks = async () => {
let apiURL;
let output;
const data = await parent();
if (usRegion?.includes(userRegion)) {
apiURL = import.meta.env.VITE_USEAST_API_URL;
const cachedData = getCache('', 'getTopAnalystStocks');
if (cachedData) {
output = cachedData;
} else {
apiURL = import.meta.env.VITE_EU_API_URL;
};
// make the POST request to the endpoint
const response = await fetch(apiURL + '/top-analysts-stocks', {
method: 'GET',
@ -34,10 +32,13 @@ export const load = async ({locals}) => {
},
});
let output = await response.json();
output = await response.json();
output = locals?.user?.tier !== 'Pro' ? output?.reverse()?.slice(0,6) : output;
setCache('', output, 'getTopAnalystStocksg');
}
output = data?.user?.tier !== 'Pro' ? output?.reverse()?.slice(0,6) : output;
return output;
};

View File

@ -0,0 +1,242 @@
<script lang='ts'>
import { goto } from '$app/navigation';
import { numberOfUnreadNotification, screenWidth } from '$lib/store';
import InfiniteLoading from '$lib/components/InfiniteLoading.svelte';
import { abbreviateNumber } from '$lib/utils.js';
import { onMount } from 'svelte';
export let data;
let cloudFrontUrl = import.meta.env.VITE_IMAGE_URL;
let isLoaded = false;
let rawData = []
let shortedList = [];
async function infiniteHandler({ detail: { loaded, complete } })
{
if (shortedList?.length === rawData?.length) {
complete();
} else {
const nextIndex = shortedList?.length;
const newArticles = rawData?.slice(nextIndex, nextIndex + 5);
shortedList = [...shortedList, ...newArticles];
loaded();
}
}
onMount(() => {
rawData = data?.getMostShortedStocks ?? [];
shortedList = rawData?.slice(0,20) ?? []
isLoaded = true;
})
let charNumber = 40;
$: {
if ($screenWidth < 640)
{
charNumber = 15;
}
else {
charNumber = 40;
}
}
</script>
<svelte:head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ''} High Short Interest Stocks · stocknear
</title>
<meta name="description" content={`Short interest, stock short squeeze, short interest ratio & short selling data positions for NASDAQ, NYSE & AMEX stocks to find shorts in the stock market.`} />
<!-- Other meta tags -->
<meta property="og:title" content={`High Short Interest Stocks · stocknear`}/>
<meta property="og:description" content={`Short interest, stock short squeeze, short interest ratio & short selling data positions for NASDAQ, NYSE & AMEX stocks to find shorts in the stock market.`} />
<meta property="og:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>
<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={`High Short Interest Stocks · stocknear`}/>
<meta name="twitter:description" content={`Short interest, stock short squeeze, short interest ratio & short selling data positions for NASDAQ, NYSE & AMEX stocks to find shorts in the stock market.`} />
<meta name="twitter:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>
<!-- Add more Twitter meta tags as needed -->
</svelte:head>
<section class="w-full max-w-4xl overflow-hidden m-auto min-h-screen pt-5 pb-40">
<div class="text-sm breadcrumbs ml-4">
<ul>
<li><a href="/" class="text-gray-300">Home</a></li>
<li class="text-gray-300">Most Shorted Stocks</li>
</ul>
</div>
<div class="w-full max-w-4xl overflow-hidden m-auto mt-5">
<div class="sm:p-0 flex justify-center w-full m-auto overflow-hidden max-w-4xl">
<div class="relative flex justify-center items-center overflow-hidden w-full">
<main class="w-full">
<div class="w-full max-w-4xl m-auto sm:bg-[#202020] sm:rounded-xl h-auto pl-10 pr-10 pt-5 sm:pb-10 sm:pt-10 mt-3 mb-8">
<div class="grid grid-cols-1 sm:grid-cols-2 gap-10">
<!-- Start Column -->
<div>
<div class="flex flex-row justify-center items-center">
<h1 class="text-3xl sm:text-4xl text-white text-center font-bold mb-5">
Most Shorted Stocks
</h1>
</div>
<span class="text-white text-md font-medium text-center flex justify-center items-center ">
High short interest stocks are often volatile, known for sudden price surges called short squeezes.
</span>
</div>
<!-- End Column -->
<!-- Start Column -->
<div class="hidden sm:block relative m-auto mb-5 mt-5 sm:mb-0 sm:mt-0">
<svg class="w-40 -my-5" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="glow">
<feGaussianBlur stdDeviation="5" result="glow"/>
<feMerge>
<feMergeNode in="glow"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<path fill="#1E40AF" d="M57.6,-58.7C72.7,-42.6,81.5,-21.3,82,0.5C82.5,22.3,74.7,44.6,59.7,60.1C44.6,75.6,22.3,84.3,0,84.3C-22.3,84.2,-44.6,75.5,-61.1,60.1C-77.6,44.6,-88.3,22.3,-87.6,0.7C-86.9,-20.8,-74.7,-41.6,-58.2,-57.7C-41.6,-73.8,-20.8,-85.2,0.2,-85.4C21.3,-85.6,42.6,-74.7,57.6,-58.7Z" transform="translate(100 100)" filter="url(#glow)" />
</svg>
<div class="z-1 absolute -top-3">
<img class="w-28 ml-6" src={cloudFrontUrl+'/assets/short_logo.png'} alt="logo" loading="lazy">
</div>
</div>
<!-- End Column -->
</div>
</div>
{#if isLoaded}
<div class="w-screen sm:w-full m-auto mt-20 sm:mt-10">
<div class="w-screen sm:w-full m-auto rounded-none sm:rounded-lg mb-4 overflow-x-scroll sm:overflow-hidden">
<table class="table table-sm table-compact rounded-none sm:rounded-md w-full bg-[#0F0F0F] border-bg-[#0F0F0F] m-auto">
<thead>
<tr class="bg-[#0F0F0F] border-b border-blue-400">
<th class="text-end bg-[#0F0F0F] text-white text-sm font-semibold">
#
</th>
<th class="text-start bg-[#0F0F0F] text-white text-sm font-semibold">
Symbol
</th>
<th class="hidden sm:table-cell text-start bg-[#0F0F0F] text-white text-sm font-semibold">
Name
</th>
<th class="text-center bg-[#0F0F0F] text-white text-sm font-semibold">
Short Interest
</th>
<th class="text-end bg-[#0F0F0F] text-white text-sm font-semibold">
Float
</th>
<th class="text-end bg-[#0F0F0F] text-white text-sm font-semibold">
Outstd
</th>
<th class="text-end bg-[#0F0F0F] text-white text-sm font-semibold">
Sector
</th>
</tr>
</thead>
<tbody>
{#each shortedList as item, index}
<tr on:click={() => goto(`/stocks/${item?.symbol}`)} class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] {index % 2 === 0 ? 'bg-[#202020]' : 'bg-[#0F0F0F]'} border-b-[#0F0F0F] cursor-pointer">
<td class="text-white text-sm font-medium text-white text-end">
{index+1}
</td>
<td class="text-sm text-start">
<div class="flex flex-col items-start w-32 sm:w-fit">
<span class="text-blue-400">{item?.symbol}</span>
<span class="text-white sm:hidden">
{item?.name?.length > charNumber ? item?.name?.slice(0,charNumber) + "..." : item?.name}
</span>
</div>
</td>
<td class="hidden sm:table-cell text-white text-sm text-white text-start">
{item?.name?.length > charNumber ? item?.name?.slice(0,charNumber) + "..." : item?.name}
</td>
<td class="text-center text-sm font-medium text-white">
{item?.shortOutStandingPercent}%
</td>
<td class="text-end text-sm font-medium text-white">
{abbreviateNumber(item?.latestFloatShares)}
</td>
<td class="text-end text-sm font-medium text-white">
{abbreviateNumber(item?.latestOutstandingShares)}
</td>
<td class="text-end text-sm font-medium text-white">
{item?.sector}
</td>
</tr>
{/each}
</tbody>
</table>
</div>
<InfiniteLoading on:infinite={infiniteHandler} />
</div>
{:else}
<div class="flex justify-center items-center h-80">
<div class="relative">
<label class="bg-[#202020] rounded-xl h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<span class="loading loading-spinner loading-md"></span>
</label>
</div>
</div>
{/if}
</main>
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,48 @@
import { userRegion, getCache, setCache } from '$lib/store';
const usRegion = ['cle1','iad1','pdx1','sfo1'];
let apiURL;
userRegion.subscribe(value => {
if (usRegion.includes(value)) {
apiURL = import.meta.env.VITE_USEAST_API_URL;
} else {
apiURL = import.meta.env.VITE_EU_API_URL;
}
});
export const load = async ({parent}) => {
const getMostShortedStocks = async () => {
let output;
const data = await parent();
const cachedData = getCache('', 'getMostShortedStocks');
if (cachedData) {
output = cachedData;
} else {
// make the POST request to the endpoint
const response = await fetch(apiURL + '/most-shorted-stocks', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
output = await response.json();
setCache('', output, 'getMostShortedStocks');
}
return output;
};
// Make sure to return a promise
return {
getMostShortedStocks: await getMostShortedStocks()
};
};

View File

@ -18,6 +18,7 @@ export const config = {
const pages = [
{title: "/"},
{title: "/most-shorted-stocks"},
{title: "/stocks"},
{title: "/etf"},
{title: "/crypto"},

View File

@ -3,7 +3,7 @@
import {AreaSeries, Chart, PriceLine, CandlestickSeries} from 'svelte-lightweight-charts';
import { TrackingModeExitMode } from 'lightweight-charts';
import {screenWidth, displayCompanyName, numberOfUnreadNotification, globalForm, trendAnalysisComponent, revenueSegmentationComponent, priceAnalysisComponent, fundamentalAnalysisComponent, userRegion, isCrosshairMoveActive, realtimePrice, priceIncrease, currentPortfolioPrice, currentPrice, clientSideCache, stockTicker, isOpen, isBeforeMarketOpen, isWeekend} from '$lib/store';
import {screenWidth, displayCompanyName, numberOfUnreadNotification, globalForm, shareholderComponent, trendAnalysisComponent, revenueSegmentationComponent, priceAnalysisComponent, fundamentalAnalysisComponent, userRegion, isCrosshairMoveActive, realtimePrice, priceIncrease, currentPortfolioPrice, currentPrice, clientSideCache, stockTicker, isOpen, isBeforeMarketOpen, isWeekend} from '$lib/store';
import { onDestroy, onMount } from 'svelte';
import StockKeyInformation from '$lib/components/StockKeyInformation.svelte';
import BullBearSay from '$lib/components/BullBearSay.svelte';
@ -1281,7 +1281,7 @@ function changeChartType() {
<!--Start Shareholders-->
<Lazy>
<div class="w-full sm:pl-6 sm:pb-6 sm:pt-6 m-auto mb-5">
<div class="w-full sm:pl-6 sm:pb-6 sm:pt-6 m-auto mb-5 {!$shareholderComponent ? 'hidden' : ''}">
{#await import('$lib/components/ShareHolders.svelte') then {default: Comp}}
<svelte:component this={Comp} />
{/await}