From 05302bbf968843637e7c0ca48752bc5a0adcade2 Mon Sep 17 00:00:00 2001 From: MuslemRahimi Date: Sun, 23 Jun 2024 15:42:58 +0200 Subject: [PATCH] add trend && fundamental prediction to stock screeener --- src/lib/utils.js | 3 + .../stock-screener/[strategyId]/+page.svelte | 102 ++++++++++++++++-- 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/src/lib/utils.js b/src/lib/utils.js index f8ea4d40..637ac7e7 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -242,6 +242,9 @@ export const formatRuleValue = (rule) => { else if (['ratingRecommendation'].includes(rule.name)) { return rule.value === 2 ? 'Buy' : rule.value === 1 ? 'Hold' : 'Sell'; } + else if (['trendAnalysis','fundamentalAnalysis'].includes(rule.name)) { + return `${rule.condition} ${rule.value}% Accuracy`; + } else { return `${rule.condition} ${rule.value}${rule.name.includes('Growth') ? ' %' : ''}`; } diff --git a/src/routes/stock-screener/[strategyId]/+page.svelte b/src/routes/stock-screener/[strategyId]/+page.svelte index 1acdaafc..7e159183 100644 --- a/src/routes/stock-screener/[strategyId]/+page.svelte +++ b/src/routes/stock-screener/[strategyId]/+page.svelte @@ -29,7 +29,16 @@ const title = data?.getStrategy?.title; - const stockScreenerData = data?.getStockScreenerData?.filter(item => item?.ratingRecommendation !== null); + let stockScreenerData = data?.getStockScreenerData?.filter(item => { + const ratingRecommendationExists = item?.ratingRecommendation !== null; + const trendAnalysisAccuracyExists = item?.trendAnalysis?.accuracy !== null; + const fundamentalAnalysisAccuracyExists = item?.fundamentalAnalysis?.accuracy !== null; + + + // Return true only if both conditions are satisfied + return ratingRecommendationExists && trendAnalysisAccuracyExists && fundamentalAnalysisAccuracyExists; +}); + let filteredData = []; @@ -82,6 +91,8 @@ esgScore: (ruleOfList?.find(item => item.name === "esgScore") || { condition: 'above' }).condition, marketCap: (ruleOfList?.find(item => item.name === "marketCap") || { condition: 'above' }).condition, var: (ruleOfList?.find(item => item.name === "var") || { condition: 'above' }).condition, + trendAnalysis: (ruleOfList?.find(item => item.name === "trendAnalysis") || { condition: 'above' }).condition, + fundamentalAnalysis: (ruleOfList?.find(item => item.name === "fundamentalAnalysis") || { condition: 'above' }).condition, }; let ruleTrend = { @@ -137,6 +148,8 @@ { rule: 'growthEBITDA', label: 'EBITDA Growth [%]', category: 'fund'}, { rule: 'esgScore', label: 'ESG Score', category: 'fund' }, { rule: 'var', label: 'Value at Risk (VaR)', category: 'fund' }, + { rule: 'trendAnalysis', label: 'AI Trend Analysis (Bullish)', category: 'ai' }, + { rule: 'fundamentalAnalysis', label: 'AI Fundamental Analysis (Bullish)', category: 'ai' }, { rule: 'ratingRecommendation', label: 'Analyst Rating', category: 'fund'} ]; @@ -216,7 +229,8 @@ let valueChange3Y = (ruleOfList?.find(item => item.name === "change3Y") || { value: 0 }).value; let valueAvgVolume = (ruleOfList?.find(item => item.name === "avgVolume") || { value: 10 }).value; let valueVaR = (ruleOfList?.find(item => item.name === "var") || { value: -10 }).value; - + let valueTrendAnalysis = (ruleOfList?.find(item => item.name === "trendAnalysis") || { value: 50 }).value; + let valueFundamentalAnalysis = (ruleOfList?.find(item => item.name === "fundamentalAnalysis") || { value: 50 }).value; const ratingRecommendations = [ @@ -290,6 +304,8 @@ const valueMappings = { change3Y: valueChange3Y, avgVolume: valueAvgVolume, var: valueVaR, + trendAnalysis: valueTrendAnalysis, + fundamentalAnalysis: valueFundamentalAnalysis, }; const conditions = { @@ -339,6 +355,8 @@ const conditions = { change3Y: ruleCondition.change3Y, avgVolume: ruleCondition.avgVolume, var: ruleCondition.var, + trendAnalysis: ruleCondition.trendAnalysis, + fundamentalAnalysis: ruleCondition.fundamentalAnalysis, }; @@ -676,6 +694,12 @@ $: { case 'var': ruleToUpdate.value = valueVaR; break; + case 'trendAnalysis': + ruleToUpdate.value = valueTrendAnalysis; + break; + case 'fundamentalAnalysis': + ruleToUpdate.value = valueFundamentalAnalysis; + break; default: // Handle any case not explicitly mentioned break; @@ -721,6 +745,25 @@ function filterStockScreenerData() { return false; } } + + else if (rule.name === 'trendAnalysis') { + if (rule.condition === "above" && item[rule.name]?.accuracy <= rule.value ) { + return false; + } + else if (rule.condition === "below" && item[rule.name]?.accuracy > rule.value ) { + return false; + } + } + + else if (rule.name === 'fundamentalAnalysis') { + if (rule.condition === "above" && item[rule.name]?.accuracy <= rule.value ) { + return false; + } + else if (rule.condition === "below" && item[rule.name]?.accuracy > rule.value ) { + return false; + } + } + else { if (rule.condition === "above" && item[rule.name] !== null && item[rule.name] <= rule.value) { @@ -785,7 +828,6 @@ $: { - @@ -793,7 +835,6 @@ $: { - @@ -854,7 +895,54 @@ $: {
- + + + + {#if ruleName === 'trendAnalysis'} + +
+ AI Trend Analysis (Bullish) {ruleCondition[ruleName]} {valueTrendAnalysis}% + + + +
+ +
+ +
+ + {/if} + + + + {#if ruleName === 'fundamentalAnalysis'} + +
+ AI Fund. Analysis (Bullish) {ruleCondition[ruleName]} {valueFundamentalAnalysis}% + + + +
+ +
+ +
+ + {/if} + + {#if ruleName === 'revenue'} @@ -2065,11 +2153,11 @@ $: { {#each displayResults as item} - goto("/stocks/"+item?.symbol)} class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] bg-[#0F0F0F] border-b-[#0F0F0F] shake-ticker cursor-pointer"> + goto("/stocks/"+item?.symbol)} class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] bg-[#0F0F0F] border-b-[#0F0F0F] odd:bg-[#202020] cursor-pointer">
{item?.symbol} - {item?.name?.length > charNumber ? item?.name?.slice(0,charNumber) + "..." : item?.name} + {item?.name?.length > charNumber ? item?.name?.slice(0,charNumber) + "..." : item?.name}