add more rules to screener

This commit is contained in:
MuslemRahimi 2024-10-01 23:47:15 +02:00
parent 7ef9794f8d
commit a98588852e
4 changed files with 33 additions and 15 deletions

View File

@ -3,7 +3,16 @@ import { validateData } from "$lib/utils";
import { loginUserSchema, registerUserSchema } from "$lib/schemas"; import { loginUserSchema, registerUserSchema } from "$lib/schemas";
// Define the EMA parameters to check // Define the EMA parameters to check
const emaParameters = ["ema20", "ema50", "ema100", "ema200"]; const emaParameters = [
"sma20",
"sma50",
"sma100",
"sma200",
"ema20",
"ema50",
"ema100",
"ema200",
];
// Function to check and add missing EMA parameters // Function to check and add missing EMA parameters
const ensureAllEmaParameters = (params) => { const ensureAllEmaParameters = (params) => {
const includedEmaParameters = params.filter((param) => const includedEmaParameters = params.filter((param) =>

View File

@ -61,6 +61,7 @@ const allRules = {
ema50: { label: 'EMA50', step: ['Stock Price > EMA50', 'EMA50 > EMA20', 'EMA50 > EMA100', 'EMA50 > EMA200'], category: 'ta', defaultValue: 'any' }, ema50: { label: 'EMA50', step: ['Stock Price > EMA50', 'EMA50 > EMA20', 'EMA50 > EMA100', 'EMA50 > EMA200'], category: 'ta', defaultValue: 'any' },
ema100: { label: 'EMA100', step: ['Stock Price > EMA100', 'EMA100 > EMA20', 'EMA100 > EMA50', 'EMA100 > EMA200'], category: 'ta', defaultValue: 'any' }, ema100: { label: 'EMA100', step: ['Stock Price > EMA100', 'EMA100 > EMA20', 'EMA100 > EMA50', 'EMA100 > EMA200'], category: 'ta', defaultValue: 'any' },
ema200: { label: 'EMA200', step: ['Stock Price > EMA200', 'EMA200 > EMA20', 'EMA200 > EMA50', 'EMA200 > EMA100'], category: 'ta', defaultValue: 'any' }, ema200: { label: 'EMA200', step: ['Stock Price > EMA200', 'EMA200 > EMA20', 'EMA200 > EMA50', 'EMA200 > EMA100'], category: 'ta', defaultValue: 'any' },
grahamNumber: { label: 'Graham Number', step: ['Price > Graham Number','Price < Graham Number'], defaultValue: 'any' },
price: { label: 'Stock Price', step: [1000,500,400,300,200,150,100,80,60,50,20,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: 10 }, price: { label: 'Stock Price', step: [1000,500,400,300,200,150,100,80,60,50,20,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: 10 },
change1W: { label: 'Price Change 1W', step: ['20%','10%','5%','1%','-1%','-5%','-10%','-20%'], category: 'ta', defaultCondition: 'over', defaultValue: '1%' }, change1W: { label: 'Price Change 1W', step: ['20%','10%','5%','1%','-1%','-5%','-10%','-20%'], category: 'ta', defaultCondition: 'over', defaultValue: '1%' },
@ -72,6 +73,7 @@ const allRules = {
marketCap: { label: 'Market Cap', step: ['100B','50B','10B','1B','300M','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: '10M' }, marketCap: { label: 'Market Cap', step: ['100B','50B','10B','1B','300M','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: '10M' },
workingCapital: { label: 'Working Capital', step: ['20B','10B','5B','1B','500M','100M','50M','10M','1M','0'], category: 'fund', defaultCondition: 'over', defaultValue: 'any' }, workingCapital: { label: 'Working Capital', step: ['20B','10B','5B','1B','500M','100M','50M','10M','1M','0'], category: 'fund', defaultCondition: 'over', defaultValue: 'any' },
totalAssets: { label: 'Total Assets', step: ['500B','200B','100B','50B','10B','1B','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: 'any' }, totalAssets: { label: 'Total Assets', step: ['500B','200B','100B','50B','10B','1B','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: 'any' },
tangibleAssetValue: { label: 'Tangible Assets', step: ['500B','200B','100B','50B','10B','1B','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: 'any' },
revenue: { label: 'Revenue', step: ['100B','50B','10B','1B','300M','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: '10M' }, revenue: { label: 'Revenue', step: ['100B','50B','10B','1B','300M','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: '10M' },
growthRevenue: { label: 'Revenue Growth', step: ['200%','100%','50%','20%','10%','5%','1%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' }, growthRevenue: { label: 'Revenue Growth', step: ['200%','100%','50%','20%','10%','5%','1%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' },
costOfRevenue: { label: 'Cost of Revenue', step: ['100B','50B','10B','1B','300M','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: '10M' }, costOfRevenue: { label: 'Cost of Revenue', step: ['100B','50B','10B','1B','300M','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: '10M' },
@ -131,6 +133,7 @@ const allRules = {
debtRatio: { label: 'Debt Ratio', step: [1,0.5,0,-0.5,-1], category: 'fund', defaultCondition: 'over', defaultValue: -0.5 }, debtRatio: { label: 'Debt Ratio', step: [1,0.5,0,-0.5,-1], category: 'fund', defaultCondition: 'over', defaultValue: -0.5 },
returnOnAssets: { label: 'Return on Assets', step: [10,8,6,4,2,1,0,-2,-4,-6,-8,-10], category: 'fund', defaultCondition: 'over', defaultValue: '0' }, returnOnAssets: { label: 'Return on Assets', step: [10,8,6,4,2,1,0,-2,-4,-6,-8,-10], category: 'fund', defaultCondition: 'over', defaultValue: '0' },
returnOnEquity: { label: 'Return on Equity', step: [10,8,6,4,2,1,0,-2,-4,-6,-8,-10], category: 'fund', defaultCondition: 'over', defaultValue: '0' }, returnOnEquity: { label: 'Return on Equity', step: [10,8,6,4,2,1,0,-2,-4,-6,-8,-10], category: 'fund', defaultCondition: 'over', defaultValue: '0' },
returnOnTangibleAssets: { label: 'Return on Tangible Assets', step: [10,8,6,4,2,1,0,-2,-4,-6,-8,-10], category: 'fund', defaultCondition: 'over', defaultValue: '0' },
enterpriseValue: { label: 'Enterprise Value', step: ['100B','50B','10B','1B','300M','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: '10M' }, enterpriseValue: { label: 'Enterprise Value', step: ['100B','50B','10B','1B','300M','100M','10M'], category: 'fund', defaultCondition: 'over', defaultValue: '10M' },
freeCashFlowPerShare: { label: 'FCF / Share', step: [10,8,6,4,2,1,0], category: 'fund', defaultCondition: 'over', defaultValue: '0' }, freeCashFlowPerShare: { label: 'FCF / Share', step: [10,8,6,4,2,1,0], category: 'fund', defaultCondition: 'over', defaultValue: '0' },
cashPerShare: { label: 'Cash / Share', step: [50,20,10,5,1,0,-1,-5,-10,-20,-50], category: 'fund', defaultCondition: 'over', defaultValue: '0' }, cashPerShare: { label: 'Cash / Share', step: [50,20,10,5,1,0,-1,-5,-10,-20,-50], category: 'fund', defaultCondition: 'over', defaultValue: '0' },
@ -145,6 +148,12 @@ const allRules = {
freeCashFlow: { label: 'Free Cash Flow', step: ['50B','10B','1B','100M','10M','1M',0], category: 'fund', defaultCondition: 'over', defaultValue: '0' }, freeCashFlow: { label: 'Free Cash Flow', step: ['50B','10B','1B','100M','10M','1M',0], category: 'fund', defaultCondition: 'over', defaultValue: '0' },
operatingCashFlow: { label: 'Operating Cash Flow', step: ['50B','10B','1B','100M','10M','1M',0], category: 'fund', defaultCondition: 'over', defaultValue: '0' }, operatingCashFlow: { label: 'Operating Cash Flow', step: ['50B','10B','1B','100M','10M','1M',0], category: 'fund', defaultCondition: 'over', defaultValue: '0' },
operatingCashFlowPerShare: { label: 'Operating Cash Flow / Share', step: [50,40,30,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' }, operatingCashFlowPerShare: { label: 'Operating Cash Flow / Share', step: [50,40,30,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' },
revenuePerShare: { label: 'Revenue / Share', step: [50,40,30,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' },
netIncomePerShare: { label: 'Net Income / Share', step: [50,40,30,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' },
shareholdersEquityPerShare: { label: 'Shareholders Equity / Share', step: [50,40,30,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' },
interestDebtPerShare: { label: 'Interest Debt / Share', step: [50,40,30,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' },
capexPerShare: { label: 'CapEx / Share', step: [50,40,30,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' },
freeCashFlowMargin: { label: 'FCF Margin', step: ['80%','50%','20%','10%','5%','0%','-5%','-10%','-20%','-50%'], category: 'fund', defaultCondition: 'over', defaultValue: '0%' }, freeCashFlowMargin: { label: 'FCF Margin', step: ['80%','50%','20%','10%','5%','0%','-5%','-10%','-20%','-50%'], category: 'fund', defaultCondition: 'over', defaultValue: '0%' },
totalDebt: { label: 'Total Debt', step: ['200B','100B','50B','10B','1B','100M','10M','1M'], category: 'fund', defaultCondition: 'over', defaultValue: '1M' }, totalDebt: { label: 'Total Debt', step: ['200B','100B','50B','10B','1B','100M','10M','1M'], category: 'fund', defaultCondition: 'over', defaultValue: '1M' },
cashFlowToDebtRatio: { label: 'Cash Flow / Debt', step: [50,40,30,20,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' }, cashFlowToDebtRatio: { label: 'Cash Flow / Debt', step: [50,40,30,20,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: '1' },
@ -432,6 +441,7 @@ function handleAddRule() {
case 'ema100': case 'ema100':
case 'ema200': case 'ema200':
case 'sma20': case 'sma20':
case 'grahamNumber':
case 'sma50': case 'sma50':
case 'sma100': case 'sma100':
case 'sma200': case 'sma200':
@ -714,8 +724,7 @@ async function handleChangeValue(value) {
checkedItems.set(ruleName, new Set([value])); checkedItems.set(ruleName, new Set([value]));
} }
console.log(checkedItems) if (['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200','grahamNumber','analystRating','score','sector','industry','country']?.includes(ruleName)) {
if (['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200','analystRating','score','sector','industry','country']?.includes(ruleName)) {
// Ensure valueMappings[ruleName] is initialized as an array // Ensure valueMappings[ruleName] is initialized as an array
searchQuery = ''; searchQuery = '';
if (!Array.isArray(valueMappings[ruleName])) { if (!Array.isArray(valueMappings[ruleName])) {
@ -1126,7 +1135,7 @@ function handleInput(event) {
</Button> </Button>
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content class="w-56 h-fit max-h-72 overflow-y-auto scroller"> <DropdownMenu.Content class="w-56 h-fit max-h-72 overflow-y-auto scroller">
{#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'analystRating','score','sector','industry','country']?.includes(row?.rule)} {#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'grahamNumber','analystRating','score','sector','industry','country']?.includes(row?.rule)}
<DropdownMenu.Label class="absolute mt-2 h-11 border-gray-800 border-b -top-1 z-20 fixed sticky bg-[#09090B]"> <DropdownMenu.Label class="absolute mt-2 h-11 border-gray-800 border-b -top-1 z-20 fixed sticky bg-[#09090B]">
<div class="flex items-center justify-start gap-x-1"> <div class="flex items-center justify-start gap-x-1">
<div class="relative inline-block flex flex-row items-center justify-center"> <div class="relative inline-block flex flex-row items-center justify-center">
@ -1156,7 +1165,7 @@ function handleInput(event) {
</div> </div>
{/if} {/if}
<DropdownMenu.Group class="min-h-10 mt-2"> <DropdownMenu.Group class="min-h-10 mt-2">
{#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'analystRating','score','sector','industry','country']?.includes(row?.rule)} {#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'grahamNumber','analystRating','score','sector','industry','country']?.includes(row?.rule)}
{#each row?.step as newValue} {#each row?.step as newValue}
<DropdownMenu.Item class="sm:hover:bg-[#27272A]"> <DropdownMenu.Item class="sm:hover:bg-[#27272A]">
@ -1165,7 +1174,7 @@ function handleInput(event) {
</button> </button>
</DropdownMenu.Item> </DropdownMenu.Item>
{/each} {/each}
{:else if ['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200']?.includes(row?.rule)} {:else if ['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200','grahamNumber']?.includes(row?.rule)}
{#each row?.step as item} {#each row?.step as item}
<DropdownMenu.Item class="sm:hover:bg-[#27272A]"> <DropdownMenu.Item class="sm:hover:bg-[#27272A]">
<div class="flex items-center" on:click|capture={(event) => event.preventDefault()}> <div class="flex items-center" on:click|capture={(event) => event.preventDefault()}>
@ -1353,11 +1362,7 @@ function handleInput(event) {
</td> </td>
<td class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]"> <td class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]">
{#if item?.symbol?.includes('.DE') || item?.symbol?.includes('.F')} {item?.marketCap < 100 ? '< 100' : abbreviateNumber(item?.marketCap)}
{item?.marketCap < 100 ? '< $100' : abbreviateNumber(item?.marketCap)}
{:else}
{item?.marketCap < 100 ? '< $100' : abbreviateNumber(item?.marketCap,true)}
{/if}
</td> </td>
<td class="text-white text-end text-sm sm:text-[1rem] font-medium border-b-[#09090B]"> <td class="text-white text-end text-sm sm:text-[1rem] font-medium border-b-[#09090B]">
@ -1369,7 +1374,7 @@ function handleInput(event) {
</td> </td>
<td class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]"> <td class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]">
{item?.price < 0.01 ? '< $0.01' : item?.price?.toFixed(2)} {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]"> <td class="text-white text-sm sm:text-[1rem] text-end border-b-[#09090B]">
@ -1414,7 +1419,7 @@ function handleInput(event) {
{item?.name?.length > charNumber ? item?.name?.slice(0, charNumber) + "..." : item?.name} {item?.name?.length > charNumber ? item?.name?.slice(0, charNumber) + "..." : item?.name}
</td> </td>
<td class="whitespace-nowrap text-sm sm:text-[1rem] text-end text-white border-b-[#09090B]"> <td class="whitespace-nowrap text-sm sm:text-[1rem] text-end text-white border-b-[#09090B]">
{abbreviateNumber(item?.marketCap, true)} {abbreviateNumber(item?.marketCap)}
</td> </td>
{#each displayRules as row (row?.rule)} {#each displayRules as row (row?.rule)}
{#if row?.rule !== 'marketCap'} {#if row?.rule !== 'marketCap'}

View File

@ -1,7 +1,7 @@
// Cache to store previous requests // Cache to store previous requests
let cache = new Map(); let cache = new Map();
const getStockScreenerData = async (rules, apiKey, apiURL) => { const getStockScreenerData = async (rules) => {
console.log("Checking cache and fetching new data if needed"); console.log("Checking cache and fetching new data if needed");
// Extract the rule names // Extract the rule names

View File

@ -37,6 +37,9 @@ const movingAverageConditions = {
"SMA200 > SMA50": (item) => item.sma200 > item.sma50, "SMA200 > SMA50": (item) => item.sma200 > item.sma50,
"SMA200 > SMA100": (item) => item.sma200 > item.sma100, "SMA200 > SMA100": (item) => item.sma200 > item.sma100,
// Add additional SMA conditions here // Add additional SMA conditions here
"Price > Graham Number": (item) => item.price > item.grahamNumber,
"Price < Graham Number": (item) => item.price < item.grahamNumber,
}; };
// Convert the input to a value or return it as-is if it's already an array // Convert the input to a value or return it as-is if it's already an array
@ -130,6 +133,7 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) {
"sma50", "sma50",
"sma100", "sma100",
"sma200", "sma200",
"grahamnumber", //grahamNumber into lowerCase form
].includes(ruleName) ].includes(ruleName)
) { ) {
if (ruleValue === "any") return true; if (ruleValue === "any") return true;
@ -138,7 +142,7 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) {
if (movingAverageConditions[condition]) { if (movingAverageConditions[condition]) {
if (!movingAverageConditions[condition](item)) return false; if (!movingAverageConditions[condition](item)) return false;
} else { } else {
console.warn(`Unknown condition: ${condition}`); //console.warn(`Unknown condition: ${condition}`);
} }
} }