664 lines
20 KiB
Python
664 lines
20 KiB
Python
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(user_sector_map):
|
|
|
|
sector_output = {}
|
|
all_stocks = []
|
|
|
|
for sector, stocks in user_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(user_sector_map):
|
|
|
|
results = []
|
|
|
|
for sector, stocks in user_sector_map.items():
|
|
data = list(ThreadPoolExecutor(5).map(analyze_ribbon, stocks))
|
|
data = [x for x in data if x]
|
|
for x in data:
|
|
x["sector"] = sector
|
|
results.extend(data)
|
|
|
|
return results
|
|
|
|
def get_smartmoney(user_sector_map):
|
|
|
|
results = []
|
|
|
|
for sector, stocks in user_sector_map.items():
|
|
data = list(ThreadPoolExecutor(5).map(analyze, stocks))
|
|
data = [x for x in data if x]
|
|
for x in data:
|
|
x["sector"] = sector
|
|
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(user_sector_map):
|
|
|
|
results = []
|
|
|
|
for sector, stocks in user_sector_map.items():
|
|
data = list(ThreadPoolExecutor(5).map(analyze, stocks))
|
|
data = [x for x in data if x]
|
|
for x in data:
|
|
x["sector"] = sector
|
|
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": []
|
|
} |