add more rules

This commit is contained in:
MuslemRahimi 2024-09-13 00:08:20 +02:00
parent 4b2b3b5c0e
commit 9cc6da5f1b
4 changed files with 185 additions and 14 deletions

View File

@ -1045,3 +1045,165 @@ export const sectorList = [
"Technology", "Technology",
"Utilities", "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",
];

View File

@ -216,8 +216,8 @@ onMount( async() => {
<div class="text-center mb-10 relative w-fit flex justify-center m-auto"> <div class="text-center mb-10 relative w-fit flex justify-center m-auto">
<a href="/economic-indicator" class="text-white antialiased bg-[#27272A] w-full px-4 py-2 rounded-lg m-auto font-medium text-[1rem] flex items-center"> <a href="/options-flow" class="text-white antialiased bg-[#27272A] w-full px-4 py-2 rounded-lg m-auto font-medium text-[1rem] flex items-center">
<span class="font-semibold">US Economic Indicators</span> <span class="text-white sm:hover:text-blue-400">Options Flow Filter</span>
</a> </a>
<div class="absolute top-[-1.2rem] -right-5 sm:-right-8 rotate-[7deg]"> <div class="absolute top-[-1.2rem] -right-5 sm:-right-8 rotate-[7deg]">
<span class="bg-[#FBCE3C] text-black text-sm sm:text-[0.9rem] rounded-xl font-semibold sm:me-2 px-2.5 py-0.5 rounded dark:bg-red-900 dark:text-red-300"> <span class="bg-[#FBCE3C] text-black text-sm sm:text-[0.9rem] rounded-xl font-semibold sm:me-2 px-2.5 py-0.5 rounded dark:bg-red-900 dark:text-red-300">

View File

@ -3,7 +3,7 @@
import { goto} from '$app/navigation'; import { goto} from '$app/navigation';
import { screenWidth, strategyId, numberOfUnreadNotification} from '$lib/store'; import { screenWidth, strategyId, numberOfUnreadNotification} from '$lib/store';
import toast from 'svelte-french-toast'; 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 * as DropdownMenu from "$lib/components/shadcn/dropdown-menu/index.js";
import { Button } from "$lib/components/shadcn/button/index.js"; import { Button } from "$lib/components/shadcn/button/index.js";
//const userConfirmation = confirm('Unsaved changes detected. Leaving now will discard your strategy. Continue?'); //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%' }, 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%' }, 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%' }, 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%' }, 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%' }, 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%' }, 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 }, 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 }, 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 }, 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 }, 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 }, 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' }, 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' }, analystRating: { label: 'Analyst Rating', step: ['Buy', 'Hold', 'Sell'], category: 'fund', defaultCondition: '', defaultValue: 'any' },
sector: { label: 'Sector', step: sectorList, 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' }, country: { label: 'Country', step: listOfRelevantCountries, category: 'fund', defaultCondition: '', defaultValue: 'any' },
}; };
@ -249,6 +254,7 @@ function handleAddRule() {
switch (ruleName) { switch (ruleName) {
case 'analystRating': case 'analystRating':
case 'sector': case 'sector':
case 'industry':
case 'country': case 'country':
case 'ema20': case 'ema20':
case 'ema50': case 'ema50':
@ -519,7 +525,7 @@ async function handleChangeValue(value) {
} else { } else {
checkedItems.add(value); 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 // Ensure valueMappings[ruleName] is initialized as an array
searchQuery = ''; searchQuery = '';
if (!Array.isArray(valueMappings[ruleName])) { if (!Array.isArray(valueMappings[ruleName])) {
@ -645,7 +651,7 @@ function handleInput(event) {
if (searchQuery.length > 0) { 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 => { testList = rawList?.filter(item => {
const index = item?.toLowerCase(); const index = item?.toLowerCase();
// Check if country starts with searchQuery // Check if country starts with searchQuery
@ -709,7 +715,7 @@ function handleInput(event) {
Stock Screener Stock Screener
</h1> </h1>
<span class="inline-block text-xs sm:text-sm font-semibold text-white ml-2 mt-3"> <span class="inline-block text-xs sm:text-sm font-semibold text-white ml-2 mt-3">
{ruleOfList?.length !== 0 ? filteredData?.length : 0} Matches Found {filteredData?.length} Matches Found
</span> </span>
</div> </div>
<div class="flex w-[50%] md:block md:w-auto mt-5 sm:ml-auto"> <div class="flex w-[50%] md:block md:w-auto mt-5 sm:ml-auto">
@ -847,7 +853,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','sector','country']?.includes(row?.rule)} {#if !['sma20','sma50','sma100','sma200','ema20', 'ema50', 'ema100', 'ema200', 'analystRating','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">
@ -870,14 +876,14 @@ function handleInput(event) {
<input bind:value={searchQuery} <input bind:value={searchQuery}
on:input={handleInput} on:input={handleInput}
autocomplete="off" autocomplete="off"
class="{!['analystRating','sector','country']?.includes(row?.rule) ? 'hidden' : ''} absolute fixed sticky w-full border-0 bg-[#09090B] border-b border-gray-200 class="{!['analystRating','sector','industry','country']?.includes(row?.rule) ? 'hidden' : ''} absolute fixed sticky w-full border-0 bg-[#09090B] border-b border-gray-200
focus:border-gray-200 focus:ring-0 text-white placeholder:text-gray-300" focus:border-gray-200 focus:ring-0 text-white placeholder:text-gray-300"
type="search" type="search"
placeholder="Search..."> placeholder="Search...">
</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','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} {#each row?.step as newValue}
<DropdownMenu.Item class="sm:hover:bg-[#27272A]"> <DropdownMenu.Item class="sm:hover:bg-[#27272A]">
@ -891,18 +897,18 @@ function handleInput(event) {
<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()}>
<label on:click={() => {handleChangeValue(item)}} class="cursor-pointer text-white" for={item}> <label on:click={() => {handleChangeValue(item)}} class="cursor-pointer text-white" for={item}>
<input type="checkbox" checked={isChecked(item)}> <input type="checkbox" class="rounded" checked={isChecked(item)}>
<span class="ml-2">{item}</span> <span class="ml-2">{item}</span>
</label> </label>
</div> </div>
</DropdownMenu.Item> </DropdownMenu.Item>
{/each} {/each}
{:else} {: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}
<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()}>
<label on:click={() => {handleChangeValue(item)}} class="cursor-pointer text-white" for={item}> <label on:click={() => {handleChangeValue(item)}} class="cursor-pointer text-white" for={item}>
<input type="checkbox" checked={isChecked(item)}> <input type="checkbox" class="rounded" checked={isChecked(item)}>
<span class="ml-2">{item}</span> <span class="ml-2">{item}</span>
</label> </label>
</div> </div>

View File

@ -1,4 +1,4 @@
import { sectorList, listOfRelevantCountries } from "$lib/utils"; import { sectorList, industryList, listOfRelevantCountries } from "$lib/utils";
const movingAverageConditions = { const movingAverageConditions = {
// EMA conditions // EMA conditions
@ -55,6 +55,7 @@ function convertUnitToValue(
const nonNumericValues = new Set([ const nonNumericValues = new Set([
"any", "any",
...sectorList, ...sectorList,
...industryList,
...listOfRelevantCountries, ...listOfRelevantCountries,
"hold", "hold",
"sell", "sell",
@ -104,7 +105,9 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) {
} }
// Handle categorical data like analyst ratings, sector, country // 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 (rule.value === "any") return true;
if (Array.isArray(ruleValue) && !ruleValue.includes(itemValue)) if (Array.isArray(ruleValue) && !ruleValue.includes(itemValue))