diff --git a/src/routes/stock-screener/+page.server.ts b/src/routes/stock-screener/+page.server.ts index aadfd145..99c18f21 100644 --- a/src/routes/stock-screener/+page.server.ts +++ b/src/routes/stock-screener/+page.server.ts @@ -3,7 +3,16 @@ import { validateData } from "$lib/utils"; import { loginUserSchema, registerUserSchema } from "$lib/schemas"; // 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 const ensureAllEmaParameters = (params) => { const includedEmaParameters = params.filter((param) => diff --git a/src/routes/stock-screener/+page.svelte b/src/routes/stock-screener/+page.svelte index 8470be21..80eb8cd9 100644 --- a/src/routes/stock-screener/+page.svelte +++ b/src/routes/stock-screener/+page.svelte @@ -61,6 +61,7 @@ const allRules = { 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' }, 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 }, 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' }, 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' }, + 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' }, 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' }, @@ -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 }, 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' }, + 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' }, 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' }, @@ -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' }, 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' }, + 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%' }, 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' }, @@ -432,6 +441,7 @@ function handleAddRule() { case 'ema100': case 'ema200': case 'sma20': + case 'grahamNumber': case 'sma50': case 'sma100': case 'sma200': @@ -714,8 +724,7 @@ async function handleChangeValue(value) { checkedItems.set(ruleName, new Set([value])); } - console.log(checkedItems) - if (['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200','analystRating','score','sector','industry','country']?.includes(ruleName)) { + if (['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200','grahamNumber','analystRating','score','sector','industry','country']?.includes(ruleName)) { // Ensure valueMappings[ruleName] is initialized as an array searchQuery = ''; if (!Array.isArray(valueMappings[ruleName])) { @@ -1126,7 +1135,7 @@ function handleInput(event) { - {#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)}
@@ -1156,7 +1165,7 @@ function handleInput(event) {
{/if} - {#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} @@ -1165,7 +1174,7 @@ function handleInput(event) { {/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}
event.preventDefault()}> @@ -1353,11 +1362,7 @@ function handleInput(event) { - {#if item?.symbol?.includes('.DE') || item?.symbol?.includes('.F')} - €{item?.marketCap < 100 ? '< $100' : abbreviateNumber(item?.marketCap)} - {:else} - {item?.marketCap < 100 ? '< $100' : abbreviateNumber(item?.marketCap,true)} - {/if} + {item?.marketCap < 100 ? '< 100' : abbreviateNumber(item?.marketCap)} @@ -1369,7 +1374,7 @@ function handleInput(event) { - {item?.price < 0.01 ? '< $0.01' : item?.price?.toFixed(2)} + {item?.price < 0.01 ? '< 0.01' : item?.price?.toFixed(2)} @@ -1414,7 +1419,7 @@ function handleInput(event) { {item?.name?.length > charNumber ? item?.name?.slice(0, charNumber) + "..." : item?.name} - {abbreviateNumber(item?.marketCap, true)} + {abbreviateNumber(item?.marketCap)} {#each displayRules as row (row?.rule)} {#if row?.rule !== 'marketCap'} diff --git a/src/routes/stock-screener/workers/downloadWorker.ts b/src/routes/stock-screener/workers/downloadWorker.ts index 4a69c41d..49765a0e 100644 --- a/src/routes/stock-screener/workers/downloadWorker.ts +++ b/src/routes/stock-screener/workers/downloadWorker.ts @@ -1,7 +1,7 @@ // Cache to store previous requests let cache = new Map(); -const getStockScreenerData = async (rules, apiKey, apiURL) => { +const getStockScreenerData = async (rules) => { console.log("Checking cache and fetching new data if needed"); // Extract the rule names diff --git a/src/routes/stock-screener/workers/filterWorker.ts b/src/routes/stock-screener/workers/filterWorker.ts index e2a20a50..4c248f1c 100644 --- a/src/routes/stock-screener/workers/filterWorker.ts +++ b/src/routes/stock-screener/workers/filterWorker.ts @@ -37,6 +37,9 @@ const movingAverageConditions = { "SMA200 > SMA50": (item) => item.sma200 > item.sma50, "SMA200 > SMA100": (item) => item.sma200 > item.sma100, // 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 @@ -130,6 +133,7 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) { "sma50", "sma100", "sma200", + "grahamnumber", //grahamNumber into lowerCase form ].includes(ruleName) ) { if (ruleValue === "any") return true; @@ -138,7 +142,7 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) { if (movingAverageConditions[condition]) { if (!movingAverageConditions[condition](item)) return false; } else { - console.warn(`Unknown condition: ${condition}`); + //console.warn(`Unknown condition: ${condition}`); } }