From 9cc6da5f1bae9f7fedb76c7fa888beef197ece7b Mon Sep 17 00:00:00 2001 From: MuslemRahimi Date: Fri, 13 Sep 2024 00:08:20 +0200 Subject: [PATCH] add more rules --- src/lib/utils.ts | 162 ++++++++++++++++++ src/routes/home/+page.svelte | 4 +- .../stock-screener/[strategyId]/+page.svelte | 26 +-- .../[strategyId]/workers/filterWorker.ts | 7 +- 4 files changed, 185 insertions(+), 14 deletions(-) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index a2383b2f..ed50f02a 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1045,3 +1045,165 @@ export const sectorList = [ "Technology", "Utilities", ]; + +export const industryList = [ + "Steel", + "Silver", + "Other Precious Metals", + "Gold", + "Copper", + "Aluminum", + "Paper, Lumber & Forest Products", + "Industrial Materials", + "Construction Materials", + "Chemicals - Specialty", + "Chemicals", + "Agricultural Inputs", + "Telecommunications Services", + "Internet Content & Information", + "Publishing", + "Broadcasting", + "Advertising Agencies", + "Entertainment", + "Travel Lodging", + "Travel Services", + "Specialty Retail", + "Luxury Goods", + "Home Improvement", + "Residential Construction", + "Department Stores", + "Personal Products & Services", + "Leisure", + "Gambling, Resorts & Casinos", + "Furnishings, Fixtures & Appliances", + "Restaurants", + "Auto - Parts", + "Auto - Manufacturers", + "Auto - Recreational Vehicles", + "Auto - Dealerships", + "Apparel - Retail", + "Apparel - Manufacturers", + "Apparel - Footwear & Accessories", + "Packaging & Containers", + "Tobacco", + "Grocery Stores", + "Discount Stores", + "Household & Personal Products", + "Packaged Foods", + "Food Distribution", + "Food Confectioners", + "Agricultural Farm Products", + "Education & Training Services", + "Beverages - Wineries & Distilleries", + "Beverages - Non-Alcoholic", + "Beverages - Alcoholic", + "Uranium", + "Solar", + "Oil & Gas Refining & Marketing", + "Oil & Gas Midstream", + "Oil & Gas Integrated", + "Oil & Gas Exploration & Production", + "Oil & Gas Equipment & Services", + "Oil & Gas Energy", + "Oil & Gas Drilling", + "Coal", + "Shell Companies", + "Investment - Banking & Investment Services", + "Insurance - Specialty", + "Insurance - Reinsurance", + "Insurance - Property & Casualty", + "Insurance - Life", + "Insurance - Diversified", + "Insurance - Brokers", + "Financial - Mortgages", + "Financial - Diversified", + "Financial - Data & Stock Exchanges", + "Financial - Credit Services", + "Financial - Conglomerates", + "Financial - Capital Markets", + "Banks - Regional", + "Banks - Diversified", + "Banks", + "Asset Management", + "Asset Management - Bonds", + "Asset Management - Income", + "Asset Management - Leveraged", + "Asset Management - Cryptocurrency", + "Asset Management - Global", + "Medical - Specialties", + "Medical - Pharmaceuticals", + "Medical - Instruments & Supplies", + "Medical - Healthcare Plans", + "Medical - Healthcare Information Services", + "Medical - Equipment & Services", + "Medical - Distribution", + "Medical - Diagnostics & Research", + "Medical - Devices", + "Medical - Care Facilities", + "Drug Manufacturers - Specialty & Generic", + "Drug Manufacturers - General", + "Biotechnology", + "Waste Management", + "Trucking", + "Railroads", + "Aerospace & Defense", + "Marine Shipping", + "Integrated Freight & Logistics", + "Airlines, Airports & Air Services", + "General Transportation", + "Manufacturing - Tools & Accessories", + "Manufacturing - Textiles", + "Manufacturing - Miscellaneous", + "Manufacturing - Metal Fabrication", + "Industrial - Distribution", + "Industrial - Specialties", + "Industrial - Pollution & Treatment Controls", + "Environmental Services", + "Industrial - Machinery", + "Industrial - Infrastructure Operations", + "Industrial - Capital Goods", + "Consulting Services", + "Business Equipment & Supplies", + "Staffing & Employment Services", + "Rental & Leasing Services", + "Engineering & Construction", + "Security & Protection Services", + "Specialty Business Services", + "Construction", + "Conglomerates", + "Electrical Equipment & Parts", + "Agricultural - Machinery", + "Agricultural - Commodities/Milling", + "REIT - Specialty", + "REIT - Retail", + "REIT - Residential", + "REIT - Office", + "REIT - Mortgage", + "REIT - Industrial", + "REIT - Hotel & Motel", + "REIT - Healthcare Facilities", + "REIT - Diversified", + "Real Estate - Services", + "Real Estate - Diversified", + "Real Estate - Development", + "Real Estate - General", + "Information Technology Services", + "Hardware, Equipment & Parts", + "Computer Hardware", + "Electronic Gaming & Multimedia", + "Software - Services", + "Software - Infrastructure", + "Software - Application", + "Semiconductors", + "Media & Entertainment", + "Communication Equipment", + "Technology Distributors", + "Consumer Electronics", + "Renewable Utilities", + "Regulated Water", + "Regulated Gas", + "Regulated Electric", + "Independent Power Producers", + "Diversified Utilities", + "General Utilities", +]; diff --git a/src/routes/home/+page.svelte b/src/routes/home/+page.svelte index e4ceb2d0..1de7280f 100644 --- a/src/routes/home/+page.svelte +++ b/src/routes/home/+page.svelte @@ -216,8 +216,8 @@ onMount( async() => {
- - US Economic Indicators + + Options Flow Filter
diff --git a/src/routes/stock-screener/[strategyId]/+page.svelte b/src/routes/stock-screener/[strategyId]/+page.svelte index d0debc78..149ba494 100644 --- a/src/routes/stock-screener/[strategyId]/+page.svelte +++ b/src/routes/stock-screener/[strategyId]/+page.svelte @@ -3,7 +3,7 @@ import { goto} from '$app/navigation'; import { screenWidth, strategyId, numberOfUnreadNotification} from '$lib/store'; import toast from 'svelte-french-toast'; - import { abbreviateNumber, sectorList, listOfRelevantCountries } from '$lib/utils'; + import { abbreviateNumber, sectorList, industryList, listOfRelevantCountries } from '$lib/utils'; import * as DropdownMenu from "$lib/components/shadcn/dropdown-menu/index.js"; import { Button } from "$lib/components/shadcn/button/index.js"; //const userConfirmation = confirm('Unsaved changes detected. Leaving now will discard your strategy. Continue?'); @@ -92,6 +92,8 @@ const allRules = { growthTotalLiabilities: { label: 'Total Liabilities Growth', step: ['200%','100%','50%','20%','10%','5%','1%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' }, growthTotalDebt: { label: 'Total Debt Growth', step: ['200%','100%','50%','20%','10%','5%','1%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' }, growthTotalStockholdersEquity: { label: 'Shareholders Equity Growth', step: ['200%','100%','50%','20%','10%','5%','1%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' }, + researchDevelopmentRevenueRatio: { label: 'R&D / Revenue', step: ['20%','10%','5%','1%','0%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' }, + cagr3YearRevenue: { label: 'Revenue CAGR 3Y', step: ['200%','100%','50%','20%','10%','5%','1%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' }, cagr5YearRevenue: { label: 'Revenue CAGR 5Y', step: ['200%','100%','50%','20%','10%','5%','1%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' }, cagr3YearEPS: { label: 'EPS CAGR 3Y', step: ['200%','100%','50%','20%','10%','5%','1%'], category: 'fund', defaultCondition: 'over', defaultValue: '1%' }, @@ -102,6 +104,8 @@ const allRules = { pe: { label: 'PE Ratio', step: [50,40,30,20,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: 1 }, forwardPE: { label: 'Forward PE', step: [50,20,10,5,1,0,-1,-5,-10,-20,-50], category: 'fund', defaultCondition: 'over', defaultValue: 0 }, + forwardPS: { label: 'Forward PS', step: [50,20,10,5,1,0], category: 'fund', defaultCondition: 'over', defaultValue: 5 }, + priceToBookRatio: { label: 'PB Ratio', step: [50,40,30,20,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: 1 }, priceToSalesRatio: { label: 'PS Ratio', step: [50,40,30,20,10,5,1], category: 'fund', defaultCondition: 'over', defaultValue: 1 }, beta: { label: 'Beta', step: [10,5,1,-5,-10], category: 'fund', defaultCondition: 'over', defaultValue: 1 }, @@ -153,6 +157,7 @@ const allRules = { totalLiabilities: { label: 'Total Liabilities', step: ['500B','200B','100B','50B','10B','1B','100M','10M','1M'], category: 'fund', defaultCondition: 'over', defaultValue: '1M' }, analystRating: { label: 'Analyst Rating', step: ['Buy', 'Hold', 'Sell'], category: 'fund', defaultCondition: '', defaultValue: 'any' }, sector: { label: 'Sector', step: sectorList, category: 'fund', defaultCondition: '', defaultValue: 'any' }, + industry: { label: 'Industry', step: industryList, category: 'fund', defaultCondition: '', defaultValue: 'any' }, country: { label: 'Country', step: listOfRelevantCountries, category: 'fund', defaultCondition: '', defaultValue: 'any' }, }; @@ -249,6 +254,7 @@ function handleAddRule() { switch (ruleName) { case 'analystRating': case 'sector': + case 'industry': case 'country': case 'ema20': case 'ema50': @@ -519,7 +525,7 @@ async function handleChangeValue(value) { } else { checkedItems.add(value); } - if (['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200','analystRating','sector','country']?.includes(ruleName)) { + if (['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200','analystRating','sector','industry','country']?.includes(ruleName)) { // Ensure valueMappings[ruleName] is initialized as an array searchQuery = ''; if (!Array.isArray(valueMappings[ruleName])) { @@ -645,7 +651,7 @@ function handleInput(event) { if (searchQuery.length > 0) { - const rawList = ruleName === 'country' ? listOfRelevantCountries : ruleName === 'sector' ? sectorList : ['Buy','Hold','Sell']; + const rawList = ruleName === 'country' ? listOfRelevantCountries : ruleName === 'sector' ? sectorList : ruleName === 'industry' ? industryList : ['Buy','Hold','Sell']; testList = rawList?.filter(item => { const index = item?.toLowerCase(); // Check if country starts with searchQuery @@ -709,7 +715,7 @@ function handleInput(event) { Stock Screener - {ruleOfList?.length !== 0 ? filteredData?.length : 0} Matches Found + {filteredData?.length} Matches Found
@@ -847,7 +853,7 @@ function handleInput(event) { - {#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'analystRating','sector','country']?.includes(row?.rule)} + {#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'analystRating','sector','industry','country']?.includes(row?.rule)}
@@ -870,14 +876,14 @@ function handleInput(event) {
{/if} - {#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'analystRating','sector','country']?.includes(row?.rule)} + {#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'analystRating','sector','industry','country']?.includes(row?.rule)} {#each row?.step as newValue} @@ -891,18 +897,18 @@ function handleInput(event) {
event.preventDefault()}>
{/each} {:else} - {#each (testList.length > 0 && searchQuery?.length > 0 ? testList : searchQuery?.length > 0 && testList?.length === 0 ? [] : (row?.rule === 'country' ? listOfRelevantCountries : row?.rule === 'sector' ? sectorList : ['Buy','Hold','Sell'])) as item} + {#each (testList.length > 0 && searchQuery?.length > 0 ? testList : searchQuery?.length > 0 && testList?.length === 0 ? [] : (row?.rule === 'country' ? listOfRelevantCountries : row?.rule === 'sector' ? sectorList : row?.rule === 'industry' ? industryList : ['Buy','Hold','Sell'])) as item}
event.preventDefault()}>
diff --git a/src/routes/stock-screener/[strategyId]/workers/filterWorker.ts b/src/routes/stock-screener/[strategyId]/workers/filterWorker.ts index 261a1af1..a52d6eef 100644 --- a/src/routes/stock-screener/[strategyId]/workers/filterWorker.ts +++ b/src/routes/stock-screener/[strategyId]/workers/filterWorker.ts @@ -1,4 +1,4 @@ -import { sectorList, listOfRelevantCountries } from "$lib/utils"; +import { sectorList, industryList, listOfRelevantCountries } from "$lib/utils"; const movingAverageConditions = { // EMA conditions @@ -55,6 +55,7 @@ function convertUnitToValue( const nonNumericValues = new Set([ "any", ...sectorList, + ...industryList, ...listOfRelevantCountries, "hold", "sell", @@ -104,7 +105,9 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) { } // Handle categorical data like analyst ratings, sector, country - else if (["analystRating", "sector", "country"].includes(rule.name)) { + else if ( + ["analystRating", "sector", "industry", "country"].includes(rule.name) + ) { if (rule.value === "any") return true; if (Array.isArray(ruleValue) && !ruleValue.includes(itemValue))