modify filter system for ema rules
This commit is contained in:
parent
a6b5d56a66
commit
613b78216e
@ -47,10 +47,10 @@ const allRules = {
|
|||||||
sma50: { label: 'SMA50', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
sma50: { label: 'SMA50', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
||||||
sma100: { label: 'SMA100', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
sma100: { label: 'SMA100', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
||||||
sma200: { label: 'SMA200', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
sma200: { label: 'SMA200', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
||||||
ema20: { label: 'EMA20', step: ['Stock Price > EMA20', 'EMA20 > EMA50'], category: 'ta', defaultValue: 'any' },
|
ema20: { label: 'EMA20', step: ['Stock Price > EMA20', 'EMA20 > EMA50', 'EMA20 > EMA100', 'EMA20 > EMA200'], category: 'ta', defaultValue: 'any' },
|
||||||
ema50: { label: 'EMA50', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
ema50: { label: 'EMA50', step: ['Stock Price > EMA50', 'EMA50 > EMA20', 'EMA50 > EMA100', 'EMA50 > EMA200'], category: 'ta', defaultCondition: 'over', defaultValue: 'any' },
|
||||||
ema100: { label: 'EMA100', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
ema100: { label: 'EMA100', step: ['Stock Price > EMA100', 'EMA100 > EMA20', 'EMA100 > EMA50', 'EMA100 > EMA200'], category: 'ta', defaultCondition: 'over', defaultValue: 'any' },
|
||||||
ema200: { label: 'EMA200', step: ['Stock Price'], category: 'ta', defaultCondition: 'over', defaultValue: 'Stock Price' },
|
ema200: { label: 'EMA200', step: ['Stock Price > EMA200', 'EMA200 > EMA20', 'EMA200 > EMA50', 'EMA200 > EMA100'], category: 'ta', defaultCondition: 'over', defaultValue: 'any' },
|
||||||
price: { label: 'Stock Price', step: [1000,500,400,300,200,150,100,80,60,50,20,10,1], category: 'fund', defaultCondition: 'over', defaultValue: 10 },
|
price: { label: 'Stock Price', step: [1000,500,400,300,200,150,100,80,60,50,20,10,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%' },
|
||||||
@ -158,16 +158,31 @@ const allRules = {
|
|||||||
|
|
||||||
|
|
||||||
const getStockScreenerData = async (rules) => {
|
const getStockScreenerData = async (rules) => {
|
||||||
|
|
||||||
console.log('Fetching new data from API');
|
console.log('Fetching new data from API');
|
||||||
|
|
||||||
// Extract the rule names
|
// Extract the rule names
|
||||||
let getRuleOfList = rules?.map(rule => rule.name) || [];
|
let getRuleOfList = rules?.map(rule => rule.name) || [];
|
||||||
|
|
||||||
// If 'ema20' is included, ensure 'ema50' is also added
|
// Define the EMA parameters to check
|
||||||
if (getRuleOfList?.includes("ema20") && !getRuleOfList?.includes("ema50")) {
|
const emaParameters = ['ema20', 'ema50', 'ema100', 'ema200'];
|
||||||
getRuleOfList.push("ema50");
|
|
||||||
}
|
// Function to check and add missing EMA parameters
|
||||||
console.log(getRuleOfList)
|
const ensureAllEmaParameters = (params) => {
|
||||||
|
const includedEmaParameters = params.filter(param => emaParameters.includes(param));
|
||||||
|
if (includedEmaParameters.length > 0) {
|
||||||
|
emaParameters.forEach(param => {
|
||||||
|
if (!params.includes(param)) {
|
||||||
|
params.push(param);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ensure all required EMA parameters are included
|
||||||
|
ensureAllEmaParameters(getRuleOfList);
|
||||||
|
|
||||||
|
console.log(getRuleOfList);
|
||||||
|
|
||||||
const postData = { ruleOfList: getRuleOfList };
|
const postData = { ruleOfList: getRuleOfList };
|
||||||
const response = await fetch(data?.apiURL + '/stock-screener-data', {
|
const response = await fetch(data?.apiURL + '/stock-screener-data', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -177,11 +192,13 @@ const getStockScreenerData = async (rules) => {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify(postData)
|
body: JSON.stringify(postData)
|
||||||
});
|
});
|
||||||
|
|
||||||
const output = await response.json();
|
const output = await response.json();
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let filteredData = [];
|
let filteredData = [];
|
||||||
let displayResults = [];
|
let displayResults = [];
|
||||||
let isSaved = false;
|
let isSaved = false;
|
||||||
@ -272,6 +289,9 @@ function handleAddRule() {
|
|||||||
case 'sector':
|
case 'sector':
|
||||||
case 'country':
|
case 'country':
|
||||||
case 'ema20':
|
case 'ema20':
|
||||||
|
case 'ema50':
|
||||||
|
case 'ema100':
|
||||||
|
case 'ema200':
|
||||||
newRule = { name: ruleName, value: Array.isArray(valueMappings[ruleName]) ? valueMappings[ruleName] : [valueMappings[ruleName]] }; // Ensure value is an array
|
newRule = { name: ruleName, value: Array.isArray(valueMappings[ruleName]) ? valueMappings[ruleName] : [valueMappings[ruleName]] }; // Ensure value is an array
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -529,7 +549,7 @@ function changeRuleCondition(name: string, state: string) {
|
|||||||
|
|
||||||
async function handleChangeValue(value) {
|
async function handleChangeValue(value) {
|
||||||
// Check if the current rule is "country"
|
// Check if the current rule is "country"
|
||||||
if (['ema20', 'analystRating','sector','country']?.includes(ruleName)) {
|
if (['ema20', 'ema50', 'ema100', 'ema200','analystRating','sector','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])) {
|
||||||
@ -855,7 +875,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 !['ema20', 'analystRating','sector','country']?.includes(row?.rule)}
|
{#if !['ema20', 'ema50', 'ema100', 'ema200', 'analystRating','sector','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">
|
||||||
@ -885,7 +905,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 !['ema20','analystRating','sector','country']?.includes(row?.rule)}
|
{#if !['ema20', 'ema50', 'ema100', 'ema200', 'analystRating','sector','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]">
|
||||||
|
|
||||||
@ -894,7 +914,7 @@ function handleInput(event) {
|
|||||||
</button>
|
</button>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
{/each}
|
{/each}
|
||||||
{:else if ['ema20']?.includes(row?.rule)}
|
{:else if ['ema20', 'ema50', 'ema100', 'ema200']?.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()}>
|
||||||
@ -1162,14 +1182,8 @@ function handleInput(event) {
|
|||||||
{#each displayRules as row (row?.rule)}
|
{#each displayRules as row (row?.rule)}
|
||||||
{#if row?.rule !== 'marketCap'}
|
{#if row?.rule !== 'marketCap'}
|
||||||
<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]">
|
||||||
{#if row?.rule === 'analystRating'}
|
{#if ['ema20', 'ema50', 'ema100', 'ema200', 'analystRating','sector','country','analystRating']?.includes(row?.rule)}
|
||||||
{item?.analystRating}
|
{item[row?.rule]}
|
||||||
{:else if row?.rule === 'sector'}
|
|
||||||
{item?.sector}
|
|
||||||
{:else if row?.rule === 'country'}
|
|
||||||
{item?.country}
|
|
||||||
{:else if row?.rule === 'ema20'}
|
|
||||||
{item?.ema20}
|
|
||||||
{:else if ['fundamentalAnalysis','trendAnalysis']?.includes(row?.rule)}
|
{:else if ['fundamentalAnalysis','trendAnalysis']?.includes(row?.rule)}
|
||||||
{item[row?.rule]?.accuracy}%
|
{item[row?.rule]?.accuracy}%
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
@ -1,62 +1,76 @@
|
|||||||
import { getCache, setCache } from '$lib/store';
|
import { getCache, setCache } from "$lib/store";
|
||||||
|
|
||||||
|
// Define the EMA parameters to check
|
||||||
|
const emaParameters = ["ema20", "ema50", "ema100", "ema200"];
|
||||||
|
// Function to check and add missing EMA parameters
|
||||||
|
const ensureAllEmaParameters = (params) => {
|
||||||
|
const includedEmaParameters = params.filter((param) =>
|
||||||
|
emaParameters.includes(param)
|
||||||
|
);
|
||||||
|
if (includedEmaParameters.length > 0) {
|
||||||
|
emaParameters.forEach((param) => {
|
||||||
|
if (!params.includes(param)) {
|
||||||
|
params.push(param);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const load = async ({ parent, params }) => {
|
||||||
|
const { apiURL, apiKey, fastifyURL } = await parent();
|
||||||
|
|
||||||
|
const getStrategyId = async () => {
|
||||||
|
return params.strategyId;
|
||||||
|
};
|
||||||
|
|
||||||
export const load = async ({parent, params}) => {
|
const getStrategy = async () => {
|
||||||
|
let output;
|
||||||
|
|
||||||
|
// make the POST request to the endpoint
|
||||||
|
const postData = { strategyId: params.strategyId };
|
||||||
|
const response = await fetch(fastifyURL + "/get-strategy", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData),
|
||||||
|
});
|
||||||
|
|
||||||
const { apiURL, apiKey, fastifyURL} = await parent();
|
output = (await response.json())?.items;
|
||||||
|
|
||||||
const getStrategyId = async () => {
|
|
||||||
return params.strategyId;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStrategy = async () => {
|
|
||||||
let output;
|
|
||||||
|
|
||||||
// make the POST request to the endpoint
|
|
||||||
const postData = {'strategyId': params.strategyId}
|
|
||||||
const response = await fetch(fastifyURL+'/get-strategy', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify(postData)
|
|
||||||
});
|
|
||||||
|
|
||||||
output = (await response.json())?.items;
|
|
||||||
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
const getStockScreenerData = async () => {
|
const getStockScreenerData = async () => {
|
||||||
let output;
|
let output;
|
||||||
const strategy = await getStrategy();
|
const strategy = await getStrategy();
|
||||||
const ruleOfList = strategy?.rules?.map(item => item?.name) || [];
|
let getRuleOfList = strategy?.rules?.map((item) => item?.name) || [];
|
||||||
const ruleNames = ruleOfList.sort().join(',');
|
|
||||||
|
// Ensure all required EMA parameters are included
|
||||||
|
ensureAllEmaParameters(getRuleOfList);
|
||||||
|
|
||||||
|
const ruleNames = getRuleOfList.sort().join(",");
|
||||||
|
|
||||||
// Get cached data for the specific tickerID
|
// Get cached data for the specific tickerID
|
||||||
const cachedData = getCache(ruleNames, 'getStockScreenerData');
|
const cachedData = getCache(ruleNames, "getStockScreenerData");
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
output = cachedData;
|
output = cachedData;
|
||||||
} else {
|
} else {
|
||||||
|
const postData = { ruleOfList: getRuleOfList };
|
||||||
const postData = {'ruleOfList': ruleOfList}
|
|
||||||
// make the POST request to the endpoint
|
// make the POST request to the endpoint
|
||||||
const response = await fetch(apiURL + '/stock-screener-data', {
|
const response = await fetch(apiURL + "/stock-screener-data", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json", "X-API-KEY": apiKey
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": apiKey,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(postData)
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
|
|
||||||
output = await response.json();
|
output = await response.json();
|
||||||
|
|
||||||
// Cache the data for this specific tickerID with a specific name 'getStockScreenerData'
|
// Cache the data for this specific tickerID with a specific name 'getStockScreenerData'
|
||||||
setCache(ruleNames, output, 'getStockScreenerData');
|
setCache(ruleNames, output, "getStockScreenerData");
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@ -1,5 +1,25 @@
|
|||||||
import { sectorList, listOfRelevantCountries } from "$lib/utils";
|
import { sectorList, listOfRelevantCountries } from "$lib/utils";
|
||||||
|
|
||||||
|
const movingAverageConditions = {
|
||||||
|
"Stock Price > EMA20": (item) => item.price > item.ema20,
|
||||||
|
"Stock Price > EMA50": (item) => item.price > item.ema50,
|
||||||
|
"Stock Price > EMA100": (item) => item.price > item.ema100,
|
||||||
|
"Stock Price > EMA200": (item) => item.price > item.ema200,
|
||||||
|
"EMA20 > EMA50": (item) => item.ema20 > item.ema50,
|
||||||
|
"EMA20 > EMA100": (item) => item.ema20 > item.ema100,
|
||||||
|
"EMA20 > EMA200": (item) => item.ema20 > item.ema200,
|
||||||
|
"EMA50 > EMA20": (item) => item.ema50 > item.ema20,
|
||||||
|
"EMA50 > EMA100": (item) => item.ema50 > item.ema100,
|
||||||
|
"EMA50 > EMA200": (item) => item.ema50 > item.ema200,
|
||||||
|
"EMA100 > EMA20": (item) => item.ema100 > item.ema20,
|
||||||
|
"EMA100 > EMA50": (item) => item.ema100 > item.ema50,
|
||||||
|
"EMA100 > EMA200": (item) => item.ema100 > item.ema200,
|
||||||
|
"EMA200 > EMA20": (item) => item.ema200 > item.ema20,
|
||||||
|
"EMA200 > EMA50": (item) => item.ema200 > item.ema50,
|
||||||
|
"EMA200 > EMA100": (item) => item.ema200 > item.ema100,
|
||||||
|
// Add additional conditions here
|
||||||
|
};
|
||||||
|
|
||||||
// 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
|
||||||
function convertUnitToValue(
|
function convertUnitToValue(
|
||||||
input: string | number | string[]
|
input: string | number | string[]
|
||||||
@ -58,15 +78,14 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) {
|
|||||||
const ruleName = rule.name.toLowerCase();
|
const ruleName = rule.name.toLowerCase();
|
||||||
|
|
||||||
// Handle trend and fundamental analysis
|
// Handle trend and fundamental analysis
|
||||||
if (["trendanalysis", "fundamentalanalysis"].includes(ruleName)) {
|
if (["trendAnalysis", "fundamentalAnalysis"].includes(rule.name)) {
|
||||||
const accuracy = item[ruleName]?.accuracy;
|
const accuracy = item[rule.name]?.accuracy;
|
||||||
if (rule.condition === "over" && accuracy <= ruleValue) return false;
|
if (rule.condition === "over" && accuracy <= ruleValue) return false;
|
||||||
if (rule.condition === "under" && accuracy > ruleValue) return false;
|
if (rule.condition === "under" && accuracy > ruleValue) return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle categorical data like analyst ratings, sector, country
|
// Handle categorical data like analyst ratings, sector, country
|
||||||
if (["analystrating", "sector", "country"].includes(ruleName)) {
|
else if (["analystrating", "sector", "country"].includes(ruleName)) {
|
||||||
if (ruleValue === "any") return true;
|
if (ruleValue === "any") return true;
|
||||||
return Array.isArray(ruleValue)
|
return Array.isArray(ruleValue)
|
||||||
? ruleValue.includes(itemValue)
|
? ruleValue.includes(itemValue)
|
||||||
@ -74,7 +93,7 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle moving averages
|
// Handle moving averages
|
||||||
if (
|
else if (
|
||||||
[
|
[
|
||||||
"ema20",
|
"ema20",
|
||||||
"ema50",
|
"ema50",
|
||||||
@ -89,19 +108,11 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) {
|
|||||||
if (ruleValue === "any") return true;
|
if (ruleValue === "any") return true;
|
||||||
|
|
||||||
for (const condition of ruleValue) {
|
for (const condition of ruleValue) {
|
||||||
if (condition === "Stock Price > EMA20") {
|
if (movingAverageConditions[condition]) {
|
||||||
const stockPrice = item["price"];
|
if (!movingAverageConditions[condition](item)) return false;
|
||||||
const maValue = item["ema20"];
|
} else {
|
||||||
if (!stockPrice || !maValue) return false;
|
console.warn(`Unknown condition: ${condition}`);
|
||||||
if (!(stockPrice > maValue)) return false;
|
|
||||||
}
|
}
|
||||||
if (condition === "EMA20 > EMA50") {
|
|
||||||
const ema20 = item["ema20"];
|
|
||||||
const ema50 = item["ema50"];
|
|
||||||
if (!ema20 || !ema50) return false;
|
|
||||||
if (ema20 < ema50) return false;
|
|
||||||
}
|
|
||||||
// Add additional conditions here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // If all conditions are met
|
return true; // If all conditions are met
|
||||||
@ -117,6 +128,7 @@ async function filterStockScreenerData(stockScreenerData, ruleOfList) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onmessage = async (event: MessageEvent) => {
|
onmessage = async (event: MessageEvent) => {
|
||||||
const { stockScreenerData, ruleOfList } = event.data || {};
|
const { stockScreenerData, ruleOfList } = event.data || {};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user