import React, { useState, useMemo } from 'react'; import { TrendingUp, TrendingDown, CheckCircle, XCircle, Filter, RefreshCw, Plus, Trash2, Info } from 'lucide-react'; const INITIAL_DATA = [ { id: 1, symbol: 'NSE:RELIANCE', price: 2450, ema50: 2400, sma200: 2440, rsi: 42, volume: 5000000 }, { id: 2, symbol: 'NSE:TCS', price: 3500, ema50: 3450, sma200: 3200, rsi: 65, volume: 2000000 }, { id: 3, symbol: 'NSE:INFY', price: 1400, ema50: 1420, sma200: 1600, rsi: 30, volume: 4500000 }, { id: 4, symbol: 'NSE:HDFCBANK', price: 1605, ema50: 1580, sma200: 1600, rsi: 44, volume: 8000000 }, { id: 5, symbol: 'NSE:ITC', price: 410, ema50: 400, sma200: 405, rsi: 41, volume: 12000000 }, { id: 6, symbol: 'NSE:SBIN', price: 580, ema50: 570, sma200: 550, rsi: 78, volume: 15000000 }, { id: 7, symbol: 'NSE:LT', price: 2900, ema50: 2850, sma200: 2880, rsi: 45, volume: 1000000 }, { id: 8, symbol: 'NSE:TATAMOTORS', price: 620, ema50: 615, sma200: 625, rsi: 43, volume: 30000000 }, ]; export default function ScreenerApp() { const [stocks, setStocks] = useState(INITIAL_DATA); const [filterOnlyEligible, setFilterOnlyEligible] = useState(false); const [newStock, setNewStock] = useState({ symbol: 'NSE:', price: '', sma200: '', rsi: '' }); const [isAdding, setIsAdding] = useState(false); // LOGIC ENGINE: Calculate derived metrics based on the User's Rules const processedStocks = useMemo(() => { return stocks.map(stock => { // Rule 1: Distance from 200 SMA const distanceRaw = (stock.price - stock.sma200) / stock.sma200; const distancePct = distanceRaw * 100; // Logic: Between -2% and +2% const nearSupport = Math.abs(distancePct) <= 2; // Rule 2: Trend Status const above200 = stock.price > stock.sma200; const trendStatus = above200 ? "Uptrend" : "Downtrend"; // Rule 3: RSI 40-45 (Calm/Pullback zone) const rsiEligible = stock.rsi >= 40 && stock.rsi <= 45; // Rule 4: Volume (Simple check for liquidity, visual only) const liquid = stock.volume > 500000; // FINAL ELIGIBILITY // Must be above 200 SMA (or very close to it if testing support from below? // The prompt said "Price > 200SMA" strictly, but usually near support allows slightly below. // We will stick to the prompt: Price > 200 SMA AND Near Support (+/- 2%) AND RSI 40-45. const isEligible = above200 && nearSupport && rsiEligible; return { ...stock, distancePct, trendStatus, isEligible, reasons: { nearSupport, rsiEligible, above200 } }; }); }, [stocks]); const filteredStocks = filterOnlyEligible ? processedStocks.filter(s => s.isEligible) : processedStocks; const handleAddStock = () => { if(!newStock.symbol || !newStock.price || !newStock.sma200 || !newStock.rsi) return; const stockToAdd = { id: Date.now(), symbol: newStock.symbol.toUpperCase(), price: parseFloat(newStock.price), sma200: parseFloat(newStock.sma200), ema50: 0, // Not strictly used in final YES/NO logic, just visual rsi: parseFloat(newStock.rsi), volume: 1000000 // Default liquid }; setStocks([...stocks, stockToAdd]); setNewStock({ symbol: 'NSE:', price: '', sma200: '', rsi: '' }); setIsAdding(false); }; const deleteStock = (id) => { setStocks(stocks.filter(s => s.id !== id)); }; return (
Logic Simulator: Validates stocks based on Liquidity, 200 SMA Support, and RSI (40-45).
| Symbol | Price | 200 SMA | Dist % | RSI | Trend | Eligible? | |
|---|---|---|---|---|---|---|---|
| {stock.symbol} | {stock.price} | {stock.sma200} | {/* Distance Column */}{stock.distancePct > 0 ? '+' : ''}{stock.distancePct.toFixed(2)}% | {/* RSI Column */}{stock.rsi} | {/* Trend Column */}
{stock.trendStatus === 'Uptrend'
?
|
{/* Eligibility Column */}
{stock.isEligible ? (
|
No stocks match the strict criteria right now.
Why did HDFCBANK (in the example) pass?
Price (1605) is greater than 200SMA (1600).
Distance is +0.31% (within 2% limit).
RSI is 44 (within 40-45 limit).
This is your "Gold Standard" setup.