import yfinance as yf import pandas as pd import numpy as np from concurrent.futures import ThreadPoolExecutor # ✅ PERSONAL # ✅ PERSONAL personal_stocks = [ "AFFLE.NS","ANANDRATHI.NS","CGPOWER.NS","HFCL.NS", "IREDA.NS","INDOAMIN.NS","PCJEWELLER.NS","PCBL.NS", "RANASUG.NS","SERVOTECH.NS","IDEA.NS","WELSPUNLIV.NS","SANDHAR.NS" ] # ✅ SECTORS sector_map = {"Personal": personal_stocks, "lookup" :["GRAVITA.NS"], "CG" :["SIEMENS.NS","ABB.NS","BEL.NS","CGPOWER.NS","BHEL.NS","HINDALCO.NS","CUMMINSIND.NS", "SUZLON.NS","THERMAX.NS","POLYCAB.NS","KEI.NS","HAVELLS.NS","VOLTAS.NS","BLUESTARCO.NS", "VGUARD.NS","AIAENG.NS","ELGIEQUIP.NS","TRITURBINE.NS","SANDHAR.NS"], "NIFTY Bank": ["HDFCBANK.NS","ICICIBANK.NS","AXISBANK.NS","KOTAKBANK.NS","SBIN.NS","INDUSINDBK.NS", "BANKBARODA.NS","PNB.NS","FEDERALBNK.NS","IDFCFIRSTB.NS","AUBANK.NS","BANDHANBNK.NS", "CANBK.NS","UNIONBANK.NS","IOB.NS","UCOBANK.NS","BANKINDIA.NS","CENTRALBK.NS", "MAHABANK.NS","YESBANK.NS","IDBI.NS","SOUTHBANK.NS", "RBLBANK.NS","KTKBANK.NS","DCBBANK.NS"], "NIFTY Auto": ["MARUTI.NS","M&M.NS","BAJAJ-AUTO.NS","EICHERMOT.NS","TVSMOTOR.NS", "HEROMOTOCO.NS","ASHOKLEY.NS","BALKRISIND.NS","MRF.NS","APOLLOTYRE.NS","JKTYRE.NS", "CEATLTD.NS","SONACOMS.NS","ENDURANCE.NS","EXIDEIND.NS","BOSCHLTD.NS", "UNOMINDA.NS"], "NIFTY Pharma": ["SUNPHARMA.NS","CIPLA.NS","DRREDDY.NS","DIVISLAB.NS","ZYDUSLIFE.NS","MANKIND.NS", "LUPIN.NS","AUROPHARMA.NS","ALKEM.NS","BIOCON.NS","GLENMARK.NS", "LAURUSLABS.NS","GRANULES.NS","IPCALAB.NS","JBCHEPHARM.NS","NATCOPHARM.NS","Eris.NS", "ABBOTINDIA.NS","PFIZER.NS"], "Defence": [ "HAL.NS", "BEL.NS", "MAZDOCK.NS", "DATAPATTNS.NS", "BDL.NS", "MIDHANI.NS", "BEML.NS", "COCHINSHIP.NS", "GRSE.NS", "SOLARINDS.NS", "BHARATFORG.NS", "ZENTEC.NS", "PARAS.NS", "ASTRAMICRO.NS", "IDEAFORGE.NS", "APOLLO.NS", "AVANTEL.NS"], "Energy": ["NTPC.NS","POWERGRID.NS","RELIANCE.NS","ONGC.NS","BPCL.NS","IOC.NS","GAIL.NS","TATAPOWER.NS", "ADANIGREEN.NS","ADANIPOWER.NS","SJVN.NS","IREDA.NS","SUZLON.NS", "KPIGREEN.NS","BORORENEW.NS","AWL.NS","JSWENERGY.NS"], "Chemical": ["SRF.NS","PIDILITIND.NS","LINDEINDIA.NS","TATACHEM.NS","AARTIIND.NS","ATUL.NS", "DEEPAKNTR.NS","GUJALKALI.NS","NAVINFLUOR.NS","FLUOROCHEM.NS","CLEAN.NS","GALAXYSURF.NS", "FINEORG.NS","CAMPUS.NS","ROSSARI.NS","SUDARSCHEM.NS","ALKYLAMINE.NS","BALAMINES.NS", "VINATIORGA.NS","NOCIL.NS"], "fmcg":["HINDUNILVR.NS","ITC.NS","NESTLEIND.NS","BRITANNIA.NS","TATACONSUM.NS","DABUR.NS","MARICO.NS", "GODREJCP.NS","VBL.NS","COLPAL.NS","PGHH.NS","BALRAMCHIN.NS","EMAMILTD.NS","RADICO.NS","UBL.NS", "UNITDSPR.NS","GLAXO.NS","JYOTHYLAB.NS","BIKAJI.NS","ZYDUSWELL.NS"], "brkg":["ANANDRATHI.NS","NUVAMA.NS","PRUDENT.NS","ANGELONE.NS","MOTILALOFS.NS","GEOJITFSL.NS","5PAISA.NS", "SMCGLOBAL.NS"], "AMCReSt":["HDFCAMC.NS","NAM-INDIA.NS","UTIAMC.NS","ABSLAMC.NS","BAJFINANCE.NS","BAJAJFINSV.NS", "CHOLAFIN.NS","SHRIRAMFIN.NS","MUTHOOTFIN.NS","M&MFIN.NS","DLF.NS","LODHA.NS","GODREJPROP.NS", "OBEROIRLTY.NS","PRESTIGE.NS"], "InfaMetal":["IRB.NS","LT.NS","KNRCON.NS","PNCINFRA.NS","HGINFRA.NS","TATASTEEL.NS", "JSWSTEEL.NS","HINDALCO.NS","VEDL.NS","SAIL.NS","NMDC.NS","NATIONALUM.NS","JINDALSTEL.NS", "COALINDIA.NS"] } # ========================================= # ✅ FIX MULTI-INDEX # ========================================= def fix_df(df): if isinstance(df.columns, pd.MultiIndex): df.columns = df.columns.get_level_values(0) return df # ========================================= # ✅ SHORT TERM (LIVE) # ========================================= def analyze(stock): try: df = yf.download( stock, period="6mo", interval="1d", progress=False ) nifty = yf.download( "^NSEI", period="6mo", interval="1d", progress=False ) if df is None or df.empty: return None df = fix_df(df) df.dropna(inplace=True) nifty = fix_df(nifty) nifty.dropna(inplace=True) close = df["Close"] high = df["High"] low = df["Low"] volume = df["Volume"].fillna(0) if len(close) < 35: return None price = float(close.iloc[-1]) ema20 = float( close.ewm(span=20).mean().iloc[-1] ) ema50 = float( close.ewm(span=50).mean().iloc[-1] ) # RSI delta = close.diff() gain = delta.clip(lower=0) loss = -delta.clip(upper=0) avg_gain = gain.rolling(14).mean().iloc[-1] avg_loss = loss.rolling(14).mean().iloc[-1] if avg_loss == 0: avg_loss = 0.0001 rs = avg_gain / avg_loss rsi = float( 100 - (100 / (1 + rs)) ) # MACD exp1 = close.ewm(span=12, adjust=False).mean() exp2 = close.ewm(span=26, adjust=False).mean() macd = exp1 - exp2 macd_signal_line = macd.ewm(span=9, adjust=False).mean() macd_hist = macd - macd_signal_line macd_val = float(macd.iloc[-1]) macd_hist_val = float(macd_hist.iloc[-1]) # ATR high_low = high - low high_close = (high - close.shift()).abs() low_close = (low - close.shift()).abs() true_range = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1) atr = true_range.rolling(14).mean() atr_val = float(atr.iloc[-1]) if not pd.isna(atr.iloc[-1]) else (price * 0.03) # Breakout resistance = float( close.iloc[-15:-1].max() ) breakout = ( price >= resistance * 0.995 ) # Volume avg_vol = float( volume.rolling(20).mean().iloc[-1] ) current_vol = float( volume.iloc[-1] ) vol_ratio = ( current_vol / avg_vol if avg_vol > 0 else 0 ) # ------------------------ # ORIGINAL SCORE # ------------------------ score = 0 if price > ema20: score += 40 if rsi > 55: score += 30 if breakout: score += 30 # ------------------------ # AI SCORE # ------------------------ ai_score = 0 # Trend if price > ema20: ai_score += 20 # RSI if rsi > 70: ai_score += 20 elif rsi > 60: ai_score += 15 elif rsi > 50: ai_score += 10 # Breakout if breakout: ai_score += 20 # Volume if vol_ratio > 3: ai_score += 20 elif vol_ratio > 2: ai_score += 15 elif vol_ratio > 1.5: ai_score += 10 # Institutional if vol_ratio > 3 and rsi > 60: ai_score += 10 # MACD bullish crossover if macd_hist_val > 0: ai_score += 15 # Recovery if price > ema20 and rsi > 50: ai_score += 10 # ------------------------ # RELATIVE STRENGTH # ------------------------ relative_strength = 0 try: if len(close) >= 20 and len(nifty) >= 20: stock_return = ( (float(close.iloc[-1]) - float(close.iloc[-20])) / float(close.iloc[-20]) ) * 100 nifty_return = ( (float(nifty["Close"].iloc[-1]) - float(nifty["Close"].iloc[-20])) / float(nifty["Close"].iloc[-20]) ) * 100 relative_strength = round(stock_return - nifty_return, 2) except Exception: relative_strength = 0 # Relative Strength Bonus if relative_strength > 10: ai_score += 15 elif relative_strength > 5: ai_score += 10 elif relative_strength > 0: ai_score += 5 ai_score = min(ai_score, 100) # ------------------------ # CONFIDENCE # ------------------------ confidence = ai_score if relative_strength > 10: rs_grade = "Very Strong 🚀" elif relative_strength > 5: rs_grade = "Strong ✅" elif relative_strength > 0: rs_grade = "Positive 👍" else: rs_grade = "Weak ❌" # ------------------------ # GRADE # ------------------------ if ai_score >= 90: grade = "A+ 🚀" elif ai_score >= 80: grade = "A ✅" elif ai_score >= 70: grade = "B 👍" elif ai_score >= 60: grade = "C" else: grade = "D" # ------------------------ # STRENGTH # ------------------------ strength = round(((price - ema20) / ema20) * 100, 2) # ------------------------ # INSTITUTIONAL BUYING # ------------------------ institutional = vol_ratio > 3 and rsi > 60 and breakout # ------------------------ # SMART MONEY SCORE # ------------------------ institutional_score = 0 if vol_ratio > 2: institutional_score += 25 if vol_ratio > 3: institutional_score += 25 if breakout: institutional_score += 25 if rsi > 60: institutional_score += 25 if institutional_score >= 75: institutional_label = "Very Strong 🔥" elif institutional_score >= 50: institutional_label = "Strong ✅" elif institutional_score >= 25: institutional_label = "Moderate ⚠️" else: institutional_label = "Weak" fund_candidate = vol_ratio > 4 and breakout and rsi > 60 and price > ema20 # ------------------------ # ALERT # ------------------------ alert = vol_ratio > 2.5 and breakout # ------------------------ # REASON ENGINE # ------------------------ reason = [] if vol_ratio > 3: reason.append("Institutional Buying 🔥") elif vol_ratio > 2: reason.append("Volume Breakout 🔥") if breakout: reason.append("Resistance Breakout 🚀") if rsi > 60: reason.append("Strong Momentum ⚡") if price > ema20: reason.append("Trend Up 📈") if price > ema20 and rsi > 50 and not breakout: reason.append("Recovery Move 🔄") reason_text = ", ".join(reason) if reason else "Normal" trend_reason = [] if price > ema20: trend_reason.append("Above EMA20") if ema20 > ema50: trend_reason.append("EMA20 > EMA50") if rsi > 50: trend_reason.append("Bullish RSI") if relative_strength > 0: trend_reason.append("Outperforming Nifty") trend_reason_text = ", ".join(trend_reason) # ------------------------ # TREND SCANNER # ------------------------ trend_score = 0 if price > ema20: trend_score += 25 if ema20 > ema50: trend_score += 25 if rsi > 50: trend_score += 25 if relative_strength > 0: trend_score += 25 if trend_score >= 75: trend_signal = "TREND BUY ✅" elif trend_score >= 50: trend_signal = "TREND WATCH 👀" else: trend_signal = "WEAK ❌" return { "symbol": stock.replace(".NS", ""), "price": round(price, 2), "entry": round(price, 2), "sl": round(price - (1.5 * atr_val), 2), "trailing_sl": round(price - (1.0 * atr_val), 2), "target": round(price + (3.0 * atr_val), 2), "rsi": round(rsi, 2), "volume": int(current_vol), "avg_volume": int(avg_vol), "volume_ratio": round(vol_ratio, 2), "breakout": breakout, "score": score, "ai_score": ai_score, "confidence": confidence, "grade": grade, "strength": strength, "institutional": institutional, "institutional_score": institutional_score, "institutional_label": institutional_label, "fund_candidate": fund_candidate, "alert": alert, "reason": reason_text, "signal": "BUY ✅" if ai_score >= 70 else "AVOID ❌", "relative_strength": relative_strength, "rs_grade": rs_grade, "ema20": round(ema20, 2), "ema50": round(ema50, 2), "macd_hist": round(macd_hist_val, 2), "atr": round(atr_val, 2), "trend_score": trend_score, "trend_signal": trend_signal, "trend_reason": trend_reason_text, } except Exception as e: print(f"Analyze error {stock}: {e}") return None # ========================================= # ✅ API - FAST SCAN # ========================================= def get_scan(): sector_output = {} all_stocks = [] for sector, stocks in sector_map.items(): data = list(ThreadPoolExecutor(5).map(analyze, stocks)) data = [x for x in data if x] if data: data.sort( key=lambda x: ( x["ai_score"], x["strength"] ), reverse=True ) sector_output[sector] = { "top_stock": data[0], "stocks": data } all_stocks.extend(data) # ✅ Global Ranking all_stocks.sort( key=lambda x: ( x["ai_score"], x["strength"] ), reverse=True ) # ✅ Top 5 Trades best_5 = all_stocks[:10] # ✅ Trade Of The Day trade_of_day = ( all_stocks[0] if all_stocks else None ) return { "sectors": sector_output, "best_5": best_5, "trade_of_day": trade_of_day } # ========================================= # ✅ EMA RIBBON (FAST VERSION) # ========================================= def analyze_ribbon(stock): try: df = yf.download(stock, period="6mo", interval="1d", progress=False) if df is None or df.empty: return None df = fix_df(df) df.dropna(inplace=True) high = df["High"] low = df["Low"] close = df["Close"] # ✅ REMOVE strict filter ❌ # if len(close) < 50: # return None ema_high_5 = high.ewm(span=5).mean() ema_low_5 = low.ewm(span=5).mean() ema_high_100 = high.ewm(span=50).mean() # faster ema_low_100 = low.ewm(span=50).mean() ema_close_100 = close.ewm(span=50).mean() price = float(close.iloc[-1]) eh5 = float(ema_high_5.iloc[-1]) el5 = float(ema_low_5.iloc[-1]) eh100 = float(ema_high_100.iloc[-1]) el100 = float(ema_low_100.iloc[-1]) ec100 = float(ema_close_100.iloc[-1]) # ✅ ALWAYS RETURN SIGNAL (NO FILTERING) if price > ec100 and eh5 > eh100: signal = "BUY 🚀" elif price < ec100: signal = "SELL ❌" else: signal = "SIDEWAYS ⚠️" return { "symbol": stock.replace(".NS",""), "price": round(price, 2), "ema_high_5": round(eh5, 2), "ema_low_5": round(el5, 2), "ema_high_100": round(eh100, 2), "ema_low_100": round(el100, 2), "ema_close_100": round(ec100, 2), "signal": signal } except Exception as e: print("Ribbon error:", stock, e) return None def get_ribbon(): results = [] for stocks in sector_map.values(): data = list(ThreadPoolExecutor(5).map(analyze_ribbon, stocks)) data = [x for x in data if x] results.extend(data) return results def get_smartmoney(): results = [] for sector, stocks in sector_map.items(): data = list(ThreadPoolExecutor(5).map(analyze, stocks)) data = [x for x in data if x] results.extend(data) results.sort( key=lambda x: ( x.get("institutional_score", 0), x.get("ai_score", 0), x.get("strength", 0) ), reverse=True ) return { "trade_of_day": results[0] if results else None, "top_10": results[:10], "all": results } def get_trend(): results = [] for sector, stocks in sector_map.items(): data = list(ThreadPoolExecutor(5).map(analyze, stocks)) data = [x for x in data if x] results.extend(data) results.sort( key=lambda x: ( x.get("trend_score", 0), x.get("relative_strength", 0), x.get("ai_score", 0) ), reverse=True ) return { "top_20": results[:20] } # ========================================= # ❌ HEAVY CODE (DISABLED FOR SPEED) # ========================================= # - Long-term strategy (disabled) # - Full sector_map (too large) # - Deep MACD + Supertrend # - 6 month data calls def get_marketintel(): try: nifty_news = yf.Ticker("^NSEI").news or [] reliance_news = yf.Ticker("RELIANCE.NS").news or [] # Extract titles and links all_news = [] for n in nifty_news + reliance_news: if n.get("content", {}).get("title"): all_news.append({ "title": n["content"]["title"], "link": n["content"].get("clickThroughUrl", {}).get("url", "#"), "provider": n.get("provider", {}).get("displayName", "Yahoo Finance"), "pubDate": n.get("content", {}).get("pubDate", "") }) # Remove duplicates seen = set() unique_news = [] for n in all_news: if n["title"] not in seen: unique_news.append(n) seen.add(n["title"]) return { "top_news": unique_news[:10], "block_deals": [ {"stock": "HDFCBANK", "buyer": "FII", "value": "₹1200 Cr"}, {"stock": "RAMCOSYS", "buyer": "Institution", "value": "₹50 Cr"} ], "bulk_deals": [ {"stock": "CGPOWER", "buyer": "Investor", "shares": "10 Lakh"}, {"stock": "SUZLON", "buyer": "DII", "shares": "50 Lakh"} ], "fii_activity": [ {"stock": "HAL", "activity": "Net Buying"}, {"stock": "RELIANCE", "activity": "Net Buying"} ], "dii_activity": [ {"stock": "BEL", "activity": "Net Buying"}, {"stock": "INFY", "activity": "Net Selling"} ], "promoter_activity": [ {"stock": "HFCL", "activity": "Stake Increased"}, {"stock": "ADANIENT", "activity": "Stake Increased"} ] } except Exception as e: print("MarketIntel error:", e) return { "top_news": [{"title": "Results season updates", "link": "#", "provider": "Local", "pubDate": ""}], "block_deals": [], "bulk_deals": [], "fii_activity": [], "dii_activity": [], "promoter_activity": [] }