add performance tab

This commit is contained in:
MuslemRahimi 2024-11-19 17:41:50 +01:00
parent 37996119b1
commit 582cb04e49
2 changed files with 158 additions and 42 deletions

View File

@ -47,6 +47,7 @@
let displayRules = []; let displayRules = [];
let selectedPopularStrategy = ""; let selectedPopularStrategy = "";
let displayTableTab = "general"; let displayTableTab = "general";
let otherTabRules = [];
let stockScreenerData = data?.getStockScreenerData?.filter((item) => let stockScreenerData = data?.getStockScreenerData?.filter((item) =>
Object?.values(item)?.every( Object?.values(item)?.every(
@ -217,7 +218,7 @@
step: ["20%", "10%", "5%", "1%", "-1%", "-5%", "-10%", "-20%"], step: ["20%", "10%", "5%", "1%", "-1%", "-5%", "-10%", "-20%"],
category: "ta", category: "ta",
defaultCondition: "over", defaultCondition: "over",
defaultValue: "1%", defaultValue: "any",
}, },
change1M: { change1M: {
label: "Price Change 1M", label: "Price Change 1M",
@ -236,7 +237,7 @@
], ],
category: "ta", category: "ta",
defaultCondition: "over", defaultCondition: "over",
defaultValue: "10%", defaultValue: "any",
}, },
change3M: { change3M: {
label: "Price Change 3M", label: "Price Change 3M",
@ -255,7 +256,7 @@
], ],
category: "ta", category: "ta",
defaultCondition: "over", defaultCondition: "over",
defaultValue: "10%", defaultValue: "any",
}, },
change6M: { change6M: {
label: "Price Change 6M", label: "Price Change 6M",
@ -274,7 +275,7 @@
], ],
category: "ta", category: "ta",
defaultCondition: "over", defaultCondition: "over",
defaultValue: "10%", defaultValue: "any",
}, },
change1Y: { change1Y: {
label: "Price Change 1Y", label: "Price Change 1Y",
@ -293,7 +294,7 @@
], ],
category: "ta", category: "ta",
defaultCondition: "over", defaultCondition: "over",
defaultValue: "10%", defaultValue: "any",
}, },
change3Y: { change3Y: {
label: "Price Change 3Y", label: "Price Change 3Y",
@ -312,7 +313,7 @@
], ],
category: "ta", category: "ta",
defaultCondition: "over", defaultCondition: "over",
defaultValue: "10%", defaultValue: "any",
}, },
marketCap: { marketCap: {
label: "Market Cap", label: "Market Cap",
@ -1478,8 +1479,9 @@
const handleMessage = (event) => { const handleMessage = (event) => {
displayRules = allRows?.filter((row) => displayRules = allRows?.filter((row) =>
ruleOfList.some((rule) => rule.name === row.rule), ruleOfList?.some((rule) => rule.name === row.rule),
); );
filteredData = event.data?.filteredData ?? []; filteredData = event.data?.filteredData ?? [];
displayResults = filteredData?.slice(0, 50); displayResults = filteredData?.slice(0, 50);
}; };
@ -1490,11 +1492,27 @@
}; };
const loadWorker = async () => { const loadWorker = async () => {
syncWorker.postMessage({ stockScreenerData, ruleOfList }); if (displayTableTab === "performance") {
syncWorker.postMessage({
stockScreenerData,
ruleOfList: [...ruleOfList, ...otherTabRules],
});
} else {
syncWorker.postMessage({
stockScreenerData,
ruleOfList,
});
}
}; };
const updateStockScreenerData = async () => { const updateStockScreenerData = async () => {
if (displayTableTab === "performance") {
downloadWorker.postMessage({
ruleOfList: [...ruleOfList, ...otherTabRules],
});
} else {
downloadWorker.postMessage({ ruleOfList: ruleOfList }); downloadWorker.postMessage({ ruleOfList: ruleOfList });
}
}; };
function handleAddRule() { function handleAddRule() {
@ -1988,8 +2006,8 @@ const handleKeyDown = (event) => {
{ key: "symbol", label: "Symbol", align: "left" }, { key: "symbol", label: "Symbol", align: "left" },
{ key: "name", label: "Name", align: "left" }, { key: "name", label: "Name", align: "left" },
{ key: "marketCap", label: "Market Cap", align: "right" }, { key: "marketCap", label: "Market Cap", align: "right" },
{ key: "changesPercentage", label: "% Change", align: "right" },
{ key: "price", label: "Price", align: "right" }, { key: "price", label: "Price", align: "right" },
{ key: "changesPercentage", label: "% Change", align: "right" },
{ key: "volume", label: "Volume", align: "right" }, { key: "volume", label: "Volume", align: "right" },
{ key: "pe", label: "PE Ratio", align: "right" }, { key: "pe", label: "PE Ratio", align: "right" },
]; ];
@ -2004,19 +2022,6 @@ const handleKeyDown = (event) => {
pe: { order: "none", type: "number" }, pe: { order: "none", type: "number" },
}; };
// Initial columns and sort orders for other tabs
const baseColumns = [
{ key: "symbol", label: "Symbol", align: "left" },
{ key: "name", label: "Name", align: "left" },
{ key: "marketCap", label: "Market Cap", align: "right" },
];
const baseSortOrders = {
symbol: { order: "none", type: "string" },
name: { order: "none", type: "string" },
marketCap: { order: "none", type: "number" },
};
const stringTypeRules = [ const stringTypeRules = [
"country", "country",
"industry", "industry",
@ -2032,18 +2037,43 @@ const handleKeyDown = (event) => {
$: { $: {
if (displayTableTab) { if (displayTableTab) {
const baseColumnsMap = {
performance: [
{ key: "symbol", label: "Symbol", align: "left" },
{ key: "name", label: "Name", align: "left" },
{ key: "marketCap", label: "Market Cap", align: "right" },
],
filters: [
{ key: "symbol", label: "Symbol", align: "left" },
{ key: "name", label: "Name", align: "left" },
{ key: "marketCap", label: "Market Cap", align: "right" },
],
};
const baseSortOrdersMap = {
performance: {
symbol: { order: "none", type: "string" },
name: { order: "none", type: "string" },
marketCap: { order: "none", type: "number" },
},
filters: {
symbol: { order: "none", type: "string" },
name: { order: "none", type: "string" },
marketCap: { order: "none", type: "number" },
},
};
if (displayTableTab === "general") { if (displayTableTab === "general") {
// Set columns and sortOrders for the "general" tab
columns = [...generalColumns]; columns = [...generalColumns];
sortOrders = { ...generalSortOrders }; sortOrders = { ...generalSortOrders };
} else { } else {
// Set base columns and sortOrders, then extend with displayRules columns = [...(baseColumnsMap[displayTableTab] || [])];
columns = [...baseColumns]; sortOrders = { ...(baseSortOrdersMap[displayTableTab] || {}) };
sortOrders = { ...baseSortOrders };
displayRules?.forEach((rule) => { const rulesList =
displayTableTab === "performance" ? tabRuleList : displayRules;
rulesList?.forEach((rule) => {
if (rule.rule !== "marketCap") { if (rule.rule !== "marketCap") {
// Ignore "marketCap" if it's present in displayRules
columns.push({ columns.push({
key: rule.rule, key: rule.rule,
label: rule.label, label: rule.label,
@ -2055,6 +2085,26 @@ const handleKeyDown = (event) => {
} }
} }
} }
let tabRuleList = [];
async function changeTab(state) {
displayTableTab = state;
if (displayTableTab === "performance") {
otherTabRules = [
{ name: "marketCap", value: "any" },
{ name: "change1W", value: "any" },
{ name: "change1M", value: "any" },
{ name: "change3M", value: "any" },
{ name: "change1Y", value: "any" },
];
tabRuleList = otherTabRules
.map((rule) => allRows.find((row) => row.rule === rule.name))
.filter(Boolean);
await updateStockScreenerData();
}
}
</script> </script>
<svelte:head> <svelte:head>
@ -2757,9 +2807,9 @@ const handleKeyDown = (event) => {
{filteredData?.length} Stocks {filteredData?.length} Stocks
</h2> </h2>
<div <div
class="hide-scroll col-span-2 flex flex-row items-center border-t border-gray-600 lg:order-2 lg:grow lg:border-0 lg:pl-1 xl:pl-3" class="col-span-2 flex flex-row items-center border-t border-gray-600 lg:order-2 lg:grow lg:border-0 lg:pl-1 xl:pl-3"
> >
<nav class="grow flex flex-row items-center py-2.5 sm:py-3 lg:py-1"> <nav class="w-full flex flex-row items-center py-2.5 sm:py-3 lg:py-1">
<ul <ul
class="flex flex-row items-center space-x-2 whitespace-nowrap text-base" class="flex flex-row items-center space-x-2 whitespace-nowrap text-base"
> >
@ -2794,8 +2844,19 @@ const handleKeyDown = (event) => {
</span> </span>
</button> </button>
</li> </li>
<li>
<button
on:click={() => changeTab("performance")}
class="text-[1rem] sm:text-lg block text-white rounded-md px-2 py-1 focus:outline-none sm:hover:bg-[#27272A] {displayTableTab ===
'performance'
? 'font-semibold bg-[#27272A]'
: ''}"
>
Performance
</button>
</li>
</ul> </ul>
<div class="w-fit ml-auto"> <div class="w-fit ml-auto hidden sm:inline-block">
<DownloadData <DownloadData
{data} {data}
rawData={filteredData} rawData={filteredData}
@ -2847,6 +2908,12 @@ const handleKeyDown = (event) => {
: abbreviateNumber(item?.marketCap)} : abbreviateNumber(item?.marketCap)}
</td> </td>
<td
class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]"
>
{item?.price < 0.01 ? "< 0.01" : item?.price?.toFixed(2)}
</td>
<td <td
class="text-white text-end text-sm sm:text-[1rem] font-medium border-b-[#09090B]" class="text-white text-end text-sm sm:text-[1rem] font-medium border-b-[#09090B]"
> >
@ -2865,12 +2932,6 @@ const handleKeyDown = (event) => {
{/if} {/if}
</td> </td>
<td
class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]"
>
{item?.price < 0.01 ? "< 0.01" : item?.price?.toFixed(2)}
</td>
<td <td
class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]" class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]"
> >
@ -2929,8 +2990,6 @@ const handleKeyDown = (event) => {
> >
{#if ["ema20", "ema50", "ema100", "ema200", "analystRating", "halalStocks", "score", "sector", "industry", "country"]?.includes(row?.rule)} {#if ["ema20", "ema50", "ema100", "ema200", "analystRating", "halalStocks", "score", "sector", "industry", "country"]?.includes(row?.rule)}
{item[row?.rule]} {item[row?.rule]}
{:else if ["fundamentalAnalysis", "trendAnalysis"]?.includes(row?.rule)}
{item[row?.rule]?.accuracy}%
{:else} {:else}
{abbreviateNumber(item[row?.rule])} {abbreviateNumber(item[row?.rule])}
{/if} {/if}
@ -2942,6 +3001,65 @@ const handleKeyDown = (event) => {
</tbody> </tbody>
</table> </table>
</div> </div>
{:else if displayTableTab === "performance"}
<div class="w-full rounded-md overflow-x-scroll">
<table
class="table table-sm table-compact w-full bg-[#09090B] border-bg-[#09090B]"
>
<thead>
<TableHeader {columns} {sortOrders} {sortData} />
</thead>
<tbody>
{#each displayResults as item (item?.symbol)}
<tr
on:click={() => {
handleSave(false);
}}
class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] bg-[#09090B] border-b-[#09090B] odd:bg-[#27272A]"
>
<td class="border-b-[#09090B] whitespace-nowrap">
<a
href={"/stocks/" + item?.symbol}
class="sm:hover:text-white text-blue-400 text-sm sm:text-[1rem]"
>{item?.symbol}</a
>
</td>
<td
class="whitespace-nowrap text-[1rem] text-white border-b-[#09090B]"
>
{item?.name?.length > charNumber
? item?.name?.slice(0, charNumber) + "..."
: item?.name}
</td>
{#each tabRuleList as row (row?.rule)}
<td
class="whitespace-nowrap text-sm sm:text-[1rem] text-end text-white border-b-[#09090B]"
>
{#if row?.rule === "marketCap"}
{abbreviateNumber(item[row?.rule])}
{:else if item[row?.rule] > 0}
<span class="text-[#00FC50]"
>+{abbreviateNumber(
item[row?.rule]?.toFixed(2),
)}%</span
>
{:else if item[row?.rule] < 0}
<span class="text-[#FF2F1F]"
>{abbreviateNumber(
item[row?.rule]?.toFixed(2),
)}%</span
>
{:else}
<span class="text-[#fff]">-</span>
{/if}
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
{/if} {/if}
{:else} {:else}
<div <div

View File

@ -65,7 +65,6 @@ const getStockScreenerData = async (rules) => {
onmessage = async (event) => { onmessage = async (event) => {
const { ruleOfList } = event.data || {}; const { ruleOfList } = event.data || {};
const output = await getStockScreenerData(ruleOfList); const output = await getStockScreenerData(ruleOfList);
const stockScreenerData = output?.filter((item) => const stockScreenerData = output?.filter((item) =>
@ -79,7 +78,6 @@ onmessage = async (event) => {
)) ))
) )
); );
postMessage({ message: "success", stockScreenerData }); postMessage({ message: "success", stockScreenerData });
}; };