initial commit

This commit is contained in:
2026-08-05 21:35:45 +05:30
commit dbac720ce0
30 changed files with 19832 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

1
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1 @@
{}

70
README.md Normal file
View File

@@ -0,0 +1,70 @@
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
The page will reload when you make changes.\
You may also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `npm run build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

Binary file not shown.

Binary file not shown.

Binary file not shown.

17554
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

42
package.json Normal file
View File

@@ -0,0 +1,42 @@
{
"name": "stock-scanner",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.18.1",
"lightweight-charts": "^5.2.0",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-router-dom": "^7.18.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

43
public/index.html Normal file
View File

@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

BIN
public/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

25
public/manifest.json Normal file
View File

@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
public/robots.txt Normal file
View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

679
server.py Normal file
View File

@@ -0,0 +1,679 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import yfinance as yf
import pandas as pd
import numpy as np
from concurrent.futures import ThreadPoolExecutor
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ✅ 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
# =========================================
@app.get("/scan")
def 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
@app.get("/ribbon")
def 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
@app.get("/smartmoney")
def 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
}
@app.get("/trend")
def 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
@app.get("/marketintel")
def 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": []
}

83
src/App.js Normal file
View File

@@ -0,0 +1,83 @@
import React, { useState } from "react";
import Chart from "./components/Chart";
import Scanner from "./components/Scanner";
import Ribbon from "./components/Ribbon";
import SmartMoney from "./components/SmartMoney";
import Popup from "./components/Popup";
import AboutScanner from "./components/AboutScanner";
import MarketIntel from "./components/MarketIntel";
import TrendScanner from "./components/TrendScanner";
import "./index.css";
function App() {
const [selectedStock, setSelectedStock] = useState("NSE:RELIANCE");
const [signal, setSignal] = useState(null);
const [view, setView] = useState("scanner");
return (
<div className="app-container">
<h1>📈 Stock Scanner Pro</h1>
<div className="nav-container">
<button
className={`nav-btn ${view === "scanner" ? "active" : ""}`}
onClick={() => setView("scanner")}
>
📊 Scanner
</button>
<button
className={`nav-btn ${view === "ribbon" ? "active" : ""}`}
onClick={() => setView("ribbon")}
>
📈 Ribbon Strategy
</button>
<button
className={`nav-btn ${view === "smartmoney" ? "active" : ""}`}
onClick={() => setView("smartmoney")}
>
🏦 Smart Money
</button>
<button
className={`nav-btn ${view === "trend" ? "active" : ""}`}
onClick={() => setView("trend")}
>
Trend Analysis
</button>
<button
className={`nav-btn ${view === "marketintel" ? "active" : ""}`}
onClick={() => setView("marketintel")}
>
📰 Market Intel
</button>
</div>
<div className="animate-fade-in">
{view === "scanner" && (
<>
<AboutScanner />
<Scanner onSelectStock={setSelectedStock} onSignal={setSignal} />
<div className="glass-card" style={{ marginTop: "20px" }}>
<h2>TradingView Chart</h2>
<Chart symbol={selectedStock} />
</div>
{signal && <Popup signal={signal} />}
</>
)}
{view === "ribbon" && <Ribbon />}
{view === "smartmoney" && <SmartMoney />}
{view === "marketintel" && <MarketIntel />}
{view === "trend" && <TrendScanner />}
</div>
</div>
);
}
export default App;

View File

@@ -0,0 +1,71 @@
import React from "react";
function AboutScanner() {
return (
<div
style={{
background: "#111827",
padding: "20px",
borderRadius: "10px",
marginBottom: "20px",
color: "white"
}}
>
<h2>🧠 How The Scanner Works</h2>
<ul>
<li>
<b>📈 Trend:</b> Price above EMA20 indicates bullish trend.
</li>
<li>
<b> Momentum:</b> RSI measures strength of buying momentum.
</li>
<li>
<b>🚀 Breakout:</b> Detects stocks breaking recent resistance levels.
</li>
<li>
<b>🔥 Volume Ratio:</b> Compares current volume with average volume.
</li>
<li>
<b>💪 Relative Strength (RS):</b> Measures stock performance vs NIFTY.
</li>
<li>
<b>🏦 Smart Money Score:</b> Estimates institutional accumulation probability.
</li>
<li>
<b>🤖 AI Score:</b> Combined score using trend, RSI, breakout, volume and RS.
</li>
<li>
<b> Confidence:</b> Probability of a quality setup based on AI Score.
</li>
<li>
<b>🎯 Fund Candidate:</b> High-volume breakout stocks showing potential accumulation.
</li>
<li>
<b>🏆 Trade Of The Day:</b> Highest ranked stock across all sectors.
</li>
</ul>
<h3>🏅 Score Guide</h3>
<ul>
<li>A+ (90-100) = Exceptional</li>
<li>A (80-89) = Strong</li>
<li>B (70-79) = Good</li>
<li>C (60-69) = Average</li>
<li>D (&lt;60) = Avoid</li>
</ul>
</div>
);
}
export default AboutScanner;

163
src/components/Backtest.js Normal file
View File

@@ -0,0 +1,163 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
function Backtest() {
const [data, setData] = useState({});
// ✅ Fetch backtest data
const loadBacktest = async () => {
try {
const res = await axios.get("http://127.0.0.1:8000/backtest");
setData(res.data);
} catch (err) {
console.error("Backtest Error:", err);
}
};
useEffect(() => {
loadBacktest();
}, []);
return (
<div
style={{
background: "#0d1117",
color: "#c9d1d9",
padding: 20,
minHeight: "100vh",
}}
>
<h1 style={{ color: "#58a6ff" }}>
📊 Backtest Dashboard (Strategy Performance)
</h1>
{/* ✅ EXPLANATION PANEL */}
<div
style={{
background: "#161b22",
border: "1px solid #30363d",
padding: 15,
borderRadius: 8,
marginBottom: 20,
}}
>
<h2 style={{ color: "#58a6ff" }}>📘 How to Read Backtest</h2>
<p>
<b>Trades</b> = Total opportunities generated
</p>
<p>
<b>Wins</b> = Profitable trades
</p>
<p>
<b>Loss</b> = Losing trades
</p>
<p>
<b>Win Rate</b> = Success % of strategy
</p>
<p>
<b>Profit</b> = Net gain (simulated)
</p>
<br />
<p>
💡 <b>Best Strategy Rules:</b>
</p>
<ul>
<li>Win Rate 60% </li>
<li>Trades 10 </li>
<li>Profit positive </li>
</ul>
</div>
{/* ✅ SECTORS */}
{Object.entries(data).map(([sector, stocks]) => (
<div
key={sector}
style={{
background: "#161b22",
border: "1px solid #30363d",
padding: 15,
marginBottom: 20,
borderRadius: 10,
}}
>
<h2 style={{ color: "#58a6ff" }}>
{sector}
</h2>
<table
width="100%"
style={{
borderCollapse: "collapse",
textAlign: "center",
}}
>
<thead>
<tr style={{ borderBottom: "1px solid #30363d" }}>
<th>Stock</th>
<th>Trades</th>
<th>Wins</th>
<th>Loss</th>
<th>Win %</th>
<th>Profit</th>
</tr>
</thead>
<tbody>
{stocks.map((s, i) => (
<tr
key={i}
style={{
borderBottom: "1px solid #30363d",
}}
>
<td>{s.symbol}</td>
<td>{s.trades}</td>
<td style={{ color: "#3fb950" }}>
{s.wins}
</td>
<td style={{ color: "#f85149" }}>
{s.loss}
</td>
{/* ✅ WIN RATE COLOR */}
<td
style={{
color:
s.win_rate >= 70
? "#3fb950"
: s.win_rate >= 60
? "#d29922"
: "#f85149",
fontWeight: "bold",
}}
>
{s.win_rate}%
</td>
{/* ✅ PROFIT COLOR */}
<td
style={{
color:
s.profit > 0 ? "#3fb950" : "#f85149",
fontWeight: "bold",
}}
>
{s.profit}
</td>
</tr>
))}
</tbody>
</table>
</div>
))}
</div>
);
}
export default Backtest;

149
src/components/Chart.js vendored Normal file
View File

@@ -0,0 +1,149 @@
import React, { useEffect, useRef } from "react";
import { createChart, CandlestickSeries, LineSeries } from "lightweight-charts";
import axios from "axios";
function Chart({ symbol }) {
const ref = useRef(null);
useEffect(() => {
if (!ref.current || !symbol) return;
ref.current.innerHTML = "";
try {
const chart = createChart(ref.current, {
width: 800,
height: 500,
layout: {
background: { color: "#111" },
textColor: "#DDD",
},
grid: {
vertLines: { color: "#333" },
horzLines: { color: "#333" },
},
});
// ✅ MAIN CANDLE SERIES
const candleSeries = chart.addSeries(CandlestickSeries);
// ✅ EMA LINE
const emaSeries = chart.addSeries(LineSeries, {
color: "yellow",
lineWidth: 2,
});
// ✅ RSI LINE (drawn on same chart for simplicity)
const rsiSeries = chart.addSeries(LineSeries, {
color: "cyan",
lineWidth: 1,
});
// ✅ EMA CALCULATION
const calculateEMA = (data, period = 20) => {
const k = 2 / (period + 1);
let ema = data[0].close;
return data.map((d) => {
ema = d.close * k + ema * (1 - k);
return { time: d.time, value: ema };
});
};
// ✅ RSI CALCULATION
const calculateRSI = (data, period = 14) => {
let gains = 0;
let losses = 0;
const result = [];
for (let i = 1; i < data.length; i++) {
const diff = data[i].close - data[i - 1].close;
if (diff > 0) gains += diff;
else losses -= diff;
if (i >= period) {
const rs = gains / (losses || 1);
const rsi = 100 - 100 / (1 + rs);
result.push({ time: data[i].time, value: rsi });
}
}
return result;
};
// ✅ LOAD DATA FUNCTION
const loadData = () => {
axios
.get(`http://localhost:8000/history?symbol=${symbol}`)
.then((res) => {
if (!res.data || res.data.length === 0) return;
const formatted = res.data.map((d) => ({
time: Math.floor(d.time),
open: Number(d.open),
high: Number(d.high),
low: Number(d.low),
close: Number(d.close),
}));
// ✅ SET CANDLES
candleSeries.setData(formatted);
// ✅ EMA
const emaData = calculateEMA(formatted);
emaSeries.setData(emaData);
// ✅ RSI
const rsiData = calculateRSI(formatted);
rsiSeries.setData(rsiData);
// ✅ ENTRY / SL / TARGET
const lastPrice = formatted[formatted.length - 1].close;
candleSeries.createPriceLine({
price: lastPrice,
color: "blue",
lineWidth: 2,
title: "Entry",
});
candleSeries.createPriceLine({
price: lastPrice * 0.97,
color: "red",
title: "SL",
});
candleSeries.createPriceLine({
price: lastPrice * 1.05,
color: "green",
title: "Target",
});
chart.timeScale().fitContent();
})
.catch((err) => console.error(err));
};
// ✅ INITIAL LOAD
loadData();
// ✅ LIVE UPDATE (every 1 min)
const interval = setInterval(loadData, 60000);
return () => {
clearInterval(interval);
chart.remove();
};
} catch (err) {
console.error("Chart crash:", err);
}
}, [symbol]);
return <div ref={ref}></div>;
}
export default Chart;

View File

@@ -0,0 +1,21 @@
import React from "react";
function ChartPage({ symbol }) {
const tvSymbol = symbol || "NSE:RELIANCE";
const url = `https://www.tradingview.com/chart/?symbol=${tvSymbol}`;
return (
<div style={{ width: "100%", height: "600px", marginTop: "20px" }}>
<iframe
title="TradingView Chart"
src={url}
width="100%"
height="100%"
frameBorder="0"
></iframe>
</div>
);
}
export default ChartPage;

114
src/components/LongTerm.js Normal file
View File

@@ -0,0 +1,114 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
function LongTerm() {
const [data, setData] = useState({});
const loadData = async () => {
try {
const res = await axios.get("http://127.0.0.1:8000/longterm");
setData(res.data);
} catch (err) {
console.error(err);
}
};
useEffect(() => {
loadData();
}, []);
return (
<div style={{
background: "#0d1117",
color: "#c9d1d9",
padding: 20,
minHeight: "100vh"
}}>
<h1 style={{ color: "#58a6ff" }}>
📈 Long-Term Investment Dashboard
</h1>
{/* ✅ EXPLANATION */}
<div style={{
background: "#161b22",
padding: 15,
borderRadius: 10,
marginBottom: 20
}}>
<h3>📘 Strategy</h3>
<ul>
<li> Golden Cross = 50 EMA &gt; 200 EMA</li>
<li> Support = Price above 200 EMA</li>
<li> Momentum = Breakout + Volume</li>
</ul>
<p>💡 Only strong trend reversal stocks are shown</p>
</div>
{Object.entries(data).map(([sector, info]) => {
const filtered = info.stocks.filter(
s => s.golden_cross || s.support_strength
);
if (filtered.length === 0) return null;
return (
<div key={sector} style={{
background: "#161b22",
padding: 15,
marginBottom: 20,
borderRadius: 10
}}>
<h2 style={{ color: "#3fb950" }}>
{sector} Long-Term Strong
</h2>
<table width="100%" style={{ textAlign: "center" }}>
<thead>
<tr>
<th>Stock</th>
<th>Score</th>
<th>RSI</th>
<th>Golden Cross</th>
<th>Support</th>
<th>Signal</th>
</tr>
</thead>
<tbody>
{filtered.map((s, i) => (
<tr key={i}>
<td>{s.symbol}</td>
<td>{s.score}</td>
<td>{s.rsi}</td>
<td style={{ color: "#3fb950" }}>
</td>
<td style={{ color: "#3fb950" }}>
</td>
<td style={{ color: "#3fb950" }}>
{s.signal}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
})}
</div>
);
}
export default LongTerm;

View File

@@ -0,0 +1,112 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
function MarketIntel() {
const [data, setData] = useState(null);
useEffect(() => {
loadData();
}, []);
const loadData = async () => {
try {
const res = await axios.get("http://127.0.0.1:8000/marketintel");
setData(res.data);
} catch (err) {
console.error(err);
}
};
if (!data) {
return <div className="glass-card" style={{ textAlign: "center" }}>Loading Market Intelligence...</div>;
}
return (
<div className="animate-fade-in">
<h2 className="text-blue" style={{ fontSize: "2rem", marginBottom: "20px" }}>📰 Market Intelligence (Live)</h2>
<div style={{ display: "grid", gridTemplateColumns: "1fr", gap: "20px", marginBottom: "30px" }}>
{/* Top News */}
<div className="glass-card">
<h2 className="text-orange">🔥 Latest Financial News</h2>
<div style={{ display: "flex", flexDirection: "column", gap: "12px" }}>
{(data.top_news || []).length > 0 ? (
(data.top_news || []).map((n, i) => (
<div key={i} style={{ padding: "12px", background: "rgba(255,255,255,0.03)", borderRadius: "8px", borderLeft: "3px solid var(--accent-blue)" }}>
<a href={n.link} target="_blank" rel="noreferrer" style={{ color: "var(--text-primary)", textDecoration: "none", fontWeight: 600, fontSize: "1.05rem" }}>
{n.title}
</a>
<div style={{ fontSize: "0.85rem", color: "var(--text-secondary)", marginTop: "6px" }}>
{n.provider} {new Date(n.pubDate).toLocaleString()}
</div>
</div>
))
) : (
<p className="text-muted">No news available at the moment.</p>
)}
</div>
</div>
</div>
<div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", gap: "20px" }}>
{/* Block Deals */}
<div className="glass-card">
<h2 className="text-green">💰 Block Deals</h2>
<div className="data-table-container">
<table className="data-table">
<thead><tr><th>Stock</th><th>Buyer</th><th>Value</th></tr></thead>
<tbody>
{(data.block_deals || []).map((d, i) => (
<tr key={i}><td>{d.stock}</td><td>{d.buyer}</td><td>{d.value}</td></tr>
))}
</tbody>
</table>
</div>
</div>
{/* Bulk Deals */}
<div className="glass-card">
<h2 className="text-green">📦 Bulk Deals</h2>
<div className="data-table-container">
<table className="data-table">
<thead><tr><th>Stock</th><th>Buyer</th><th>Shares</th></tr></thead>
<tbody>
{(data.bulk_deals || []).map((d, i) => (
<tr key={i}><td>{d.stock}</td><td>{d.buyer}</td><td>{d.shares}</td></tr>
))}
</tbody>
</table>
</div>
</div>
{/* FII / DII */}
<div className="glass-card">
<h2 className="text-blue">🏦 Institutional Activity</h2>
<div className="data-table-container">
<table className="data-table">
<thead><tr><th>Institution</th><th>Stock</th><th>Activity</th></tr></thead>
<tbody>
{(data.fii_activity || []).map((d, i) => (
<tr key={`fii-${i}`}>
<td><span className="badge badge-neutral">FII</span></td>
<td>{d.stock}</td>
<td><span className={`badge ${d.activity.includes('Buy') ? 'badge-success' : 'badge-danger'}`}>{d.activity}</span></td>
</tr>
))}
{(data.dii_activity || []).map((d, i) => (
<tr key={`dii-${i}`}>
<td><span className="badge badge-neutral">DII</span></td>
<td>{d.stock}</td>
<td><span className={`badge ${d.activity.includes('Buy') ? 'badge-success' : 'badge-danger'}`}>{d.activity}</span></td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
}
export default MarketIntel;

22
src/components/Popup.js Normal file
View File

@@ -0,0 +1,22 @@
import React, { useEffect } from "react";
function Popup({ signal }) {
useEffect(() => {
const timer = setTimeout(() => {
const popup = document.getElementById("popup");
if (popup) popup.style.display = "none";
}, 4000);
return () => clearTimeout(timer);
}, []);
return (
<div id="popup" className="popup">
<h3>🚨 Trade Signal</h3>
<p>Stock: {signal.name}</p>
<p>Code: {signal.code}</p>
</div>
);
}
export default Popup;

81
src/components/Ribbon.js Normal file
View File

@@ -0,0 +1,81 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
function Ribbon() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const loadData = async () => {
try {
const res = await axios.get("http://127.0.0.1:8000/ribbon");
setData(res.data || []);
setLoading(false);
} catch (err) {
console.error("Ribbon error:", err);
setLoading(false);
}
};
useEffect(() => {
loadData();
const interval = setInterval(loadData, 100000);
return () => clearInterval(interval);
}, []);
const openChart = (symbol) => {
window.open(`https://www.tradingview.com/chart/?symbol=NSE:${symbol}`, "_blank");
};
if (loading) return <div className="glass-card" style={{ textAlign: "center" }}>Loading Ribbon...</div>;
return (
<div className="glass-card animate-fade-in">
<h2 className="text-blue">📈 EMA Ribbon Strategy</h2>
<div className="data-table-container">
<table className="data-table">
<thead>
<tr>
<th>Stock</th>
<th>Price</th>
<th>EMA High 5</th>
<th>EMA Low 5</th>
<th>EMA High 100</th>
<th>EMA Low 100</th>
<th>EMA Close 100</th>
<th>Signal</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{(data || []).map((s, i) => (
<tr key={i}>
<td style={{ fontWeight: 600 }}>{s.symbol}</td>
<td>{s.price}</td>
<td>{s.ema_high_5}</td>
<td>{s.ema_low_5}</td>
<td>{s.ema_high_100}</td>
<td>{s.ema_low_100}</td>
<td className="text-blue">{s.ema_close_100}</td>
<td>
<span className={`badge ${
s.signal.includes("BUY") ? "badge-success" :
s.signal.includes("SELL") ? "badge-danger" : "badge-warning"
}`}>
{s.signal}
</span>
</td>
<td>
<button className="action-btn" onClick={() => openChart(s.symbol)}>
Chart
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
export default Ribbon;

144
src/components/Scanner.js Normal file
View File

@@ -0,0 +1,144 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
function Scanner({ onSelectStock, onSignal }) {
const [data, setData] = useState(null);
const [lastBest, setLastBest] = useState(null);
const loadData = async () => {
try {
const res = await axios.get("http://127.0.0.1:8000/scan");
const newData = res.data;
const best = newData.best_5 && newData.best_5.length > 0 ? newData.best_5[0] : null;
if (best && best.symbol !== lastBest) {
if (onSignal) onSignal(`New Best Trade: ${best.symbol}`);
setLastBest(best.symbol);
}
setData(newData);
} catch (err) {
console.error(err);
}
};
useEffect(() => {
loadData();
const interval = setInterval(loadData, 100000);
return () => clearInterval(interval);
}, []);
const openChart = (symbol) => {
window.open(`https://www.tradingview.com/chart/?symbol=NSE:${symbol}`, "_blank");
};
if (!data) return <div className="glass-card" style={{ textAlign: "center" }}>Loading Scanner Data...</div>;
return (
<div>
{/* Top 5 Trades */}
{(data.best_5 || []).length > 0 && (
<div className="glass-card animate-fade-in" style={{ marginBottom: "30px", borderLeft: "4px solid var(--accent-green)" }}>
<h2 className="text-green">🔥 Top 5 Momentum Picks</h2>
<div className="data-table-container">
<table className="data-table">
<thead>
<tr>
<th>Stock</th>
<th>Price</th>
<th>RSI</th>
<th>MACD</th>
<th>Signal</th>
<th>AI Score</th>
<th>Grade</th>
<th>Institutional</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{(data.best_5 || []).filter(s => s).map((s, i) => (
<tr key={i}>
<td style={{ fontWeight: 600 }}>{s?.symbol}</td>
<td>{s?.price}</td>
<td><span className={`badge ${s?.rsi > 60 ? 'badge-success' : 'badge-neutral'}`}>{s?.rsi}</span></td>
<td><span className={`badge ${s?.macd_hist > 0 ? 'badge-success' : 'badge-danger'}`}>{s?.macd_hist}</span></td>
<td>
<span className={`badge ${s?.signal?.includes("BUY") ? 'badge-success' : 'badge-danger'}`}>
{s?.signal}
</span>
</td>
<td>{s.ai_score} / 100</td>
<td>{s.grade}</td>
<td>{s.institutional ? <span className="text-orange">🔥 Yes</span> : <span className="text-muted">No</span>}</td>
<td>
<button className="action-btn" onClick={() => { openChart(s?.symbol); onSelectStock(s?.symbol); }}>
View Chart
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Sector Tables */}
{Object.entries(data.sectors || {}).map(([sector, info]) => {
const best = info.top_stock;
return (
<div key={sector} className="glass-card animate-fade-in" style={{ marginBottom: "20px" }}>
<h2 className="text-blue">{sector} ({info.stocks.length} Stocks)</h2>
{best && (
<p className="text-orange" style={{ marginBottom: "20px" }}>
<strong>Top Pick:</strong> {best.symbol} (Score: {best.score})
</p>
)}
<div className="data-table-container">
<table className="data-table">
<thead>
<tr>
<th>Stock</th>
<th>Price</th>
<th>MACD</th>
<th>Signal</th>
<th>Volume</th>
<th>Target</th>
<th>AI Score</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{(info.stocks || []).map((s, i) => (
<tr key={i}>
<td style={{ fontWeight: 500 }}>{s?.symbol}</td>
<td>{s?.price}</td>
<td><span className={`badge ${s?.macd_hist > 0 ? 'badge-success' : 'badge-danger'}`}>{s?.macd_hist}</span></td>
<td>
<span className={`badge ${s?.signal?.includes("BUY") ? 'badge-success' : 'badge-danger'}`}>
{s?.signal}
</span>
</td>
<td>{s?.volume?.toLocaleString()}</td>
<td className="text-green">{s?.target}</td>
<td>{s?.ai_score}</td>
<td>
<button className="action-btn" onClick={() => { openChart(s?.symbol); onSelectStock(s?.symbol); }}>
Chart
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
})}
</div>
);
}
export default Scanner;

View File

@@ -0,0 +1,95 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
function SmartMoney() {
const [data, setData] = useState(null);
useEffect(() => {
loadData();
const interval = setInterval(loadData, 100000);
return () => clearInterval(interval);
}, []);
const loadData = async () => {
try {
const res = await axios.get("http://127.0.0.1:8000/smartmoney");
setData(res.data);
} catch (err) {
console.error(err);
}
};
const openChart = (symbol) => {
window.open(`https://www.tradingview.com/chart/?symbol=NSE:${symbol}`, "_blank");
};
if (!data) return <div className="glass-card" style={{ textAlign: "center" }}>Loading Smart Money Data...</div>;
return (
<div className="animate-fade-in">
<h2 className="text-blue" style={{ fontSize: "2rem", marginBottom: "20px" }}>🏦 Smart Money Tracker</h2>
{/* Trade of the Day */}
{data.trade_of_day && (
<div className="glass-card" style={{ marginBottom: "20px", borderLeft: "4px solid var(--accent-orange)" }}>
<h2 className="text-orange">🔥 Institutional Trade of the Day: {data.trade_of_day.symbol}</h2>
<p className="text-muted" style={{ marginBottom: "12px" }}>
Massive volume spike combined with strong momentum indicating potential smart money buying.
</p>
<div style={{ display: "flex", gap: "15px", flexWrap: "wrap", marginBottom: "15px" }}>
<span className="badge badge-neutral">Volume Ratio: {data.trade_of_day.volume_ratio}x</span>
<span className="badge badge-neutral">RSI: {data.trade_of_day.rsi}</span>
<span className="badge badge-success">{data.trade_of_day.reason}</span>
</div>
<button className="nav-btn active" onClick={() => openChart(data.trade_of_day.symbol)}>
View Deep Chart
</button>
</div>
)}
{/* Top 10 Institutional Buys */}
<div className="glass-card">
<h2 className="text-green">Top 10 Institutional Breakouts</h2>
<div className="data-table-container">
<table className="data-table">
<thead>
<tr>
<th>Stock</th>
<th>Inst Label</th>
<th>Inst Score</th>
<th>Volume Ratio</th>
<th>Breakout</th>
<th>Reason</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{(data.top_10 || []).map((s, i) => (
<tr key={i}>
<td style={{ fontWeight: 600 }}>{s.symbol}</td>
<td>
<span className={`badge ${
s.institutional_label.includes("Very Strong") ? 'badge-success' :
s.institutional_label.includes("Strong") ? 'badge-success' : 'badge-neutral'
}`}>
{s.institutional_label}
</span>
</td>
<td>{s.institutional_score}</td>
<td><span className="text-orange">{s.volume_ratio}x</span></td>
<td>{s.breakout ? "🔥 YES" : "NO"}</td>
<td>{s.reason}</td>
<td>
<button className="action-btn" onClick={() => openChart(s.symbol)}>Chart</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
);
}
export default SmartMoney;

View File

@@ -0,0 +1,78 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
function TrendScanner() {
const [data, setData] = useState(null);
useEffect(() => {
loadData();
const interval = setInterval(loadData, 100000);
return () => clearInterval(interval);
}, []);
const loadData = async () => {
try {
const res = await axios.get("http://127.0.0.1:8000/trend");
setData(res.data);
} catch (err) {
console.error(err);
}
};
const openChart = (symbol) => {
window.open(`https://www.tradingview.com/chart/?symbol=NSE:${symbol}`, "_blank");
};
if (!data) return <div className="glass-card" style={{ textAlign: "center" }}>Loading Trend Data...</div>;
return (
<div className="animate-fade-in">
<h2 className="text-blue" style={{ fontSize: "2rem", marginBottom: "20px" }}> Top Trending Stocks</h2>
<div className="glass-card">
<h2 className="text-green">Top 20 Trend Analysis</h2>
<div className="data-table-container">
<table className="data-table">
<thead>
<tr>
<th>Stock</th>
<th>Trend Signal</th>
<th>Trend Score</th>
<th>Relative Strength</th>
<th>Trend Reason</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{(data.top_20 || []).map((s, i) => (
<tr key={i}>
<td style={{ fontWeight: 600 }}>{s.symbol}</td>
<td>
<span className={`badge ${
s.trend_signal.includes("BUY") ? 'badge-success' :
s.trend_signal.includes("WATCH") ? 'badge-warning' : 'badge-danger'
}`}>
{s.trend_signal}
</span>
</td>
<td>{s.trend_score}</td>
<td>
<span className={s.relative_strength > 0 ? "text-green" : "text-red"}>
{s.relative_strength}%
</span>
</td>
<td>{s.trend_reason}</td>
<td>
<button className="action-btn" onClick={() => openChart(s.symbol)}>Chart</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
);
}
export default TrendScanner;

216
src/index.css Normal file
View File

@@ -0,0 +1,216 @@
:root {
/* Color Palette - Premium Dark Theme */
--bg-primary: #0b1220;
--bg-secondary: #111827;
--bg-tertiary: #1f2937;
--text-primary: #f8fafc;
--text-secondary: #94a3b8;
--text-muted: #64748b;
--accent-blue: #3b82f6;
--accent-blue-hover: #2563eb;
--accent-green: #10b981;
--accent-green-bg: rgba(16, 185, 129, 0.1);
--accent-red: #ef4444;
--accent-red-bg: rgba(239, 68, 68, 0.1);
--accent-orange: #f59e0b;
--accent-orange-bg: rgba(245, 158, 11, 0.1);
/* Borders & Shadows */
--border-color: rgba(255, 255, 255, 0.05);
--glass-bg: rgba(17, 24, 39, 0.7);
--shadow-sm: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-glow: 0 0 15px rgba(59, 130, 246, 0.3);
}
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
body {
margin: 0;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: var(--bg-primary);
color: var(--text-primary);
}
* {
box-sizing: border-box;
}
/* Glassmorphism Card */
.glass-card {
background: var(--glass-bg);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--border-color);
border-radius: 16px;
padding: 24px;
box-shadow: var(--shadow-sm);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.glass-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-glow);
}
/* Typography */
h1 {
font-size: 2.5rem;
font-weight: 800;
background: linear-gradient(135deg, #fff, #94a3b8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 2rem;
}
h2 {
font-size: 1.5rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 1.5rem;
}
/* Buttons */
.nav-btn {
background: var(--bg-tertiary);
color: var(--text-primary);
border: 1px solid var(--border-color);
padding: 10px 20px;
border-radius: 8px;
font-size: 0.95rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
margin-right: 12px;
margin-bottom: 12px;
display: inline-flex;
align-items: center;
gap: 8px;
}
.nav-btn:hover {
background: var(--bg-secondary);
border-color: var(--accent-blue);
box-shadow: 0 0 10px rgba(59, 130, 246, 0.2);
transform: translateY(-1px);
}
.nav-btn.active {
background: var(--accent-blue);
border-color: var(--accent-blue-hover);
color: white;
}
.action-btn {
background: rgba(255, 255, 255, 0.05);
color: var(--text-primary);
border: 1px solid var(--border-color);
padding: 6px 12px;
border-radius: 6px;
font-size: 0.85rem;
cursor: pointer;
transition: all 0.2s ease;
}
.action-btn:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.2);
}
/* Modern Tables */
.data-table-container {
overflow-x: auto;
border-radius: 12px;
border: 1px solid var(--border-color);
background: var(--bg-secondary);
}
.data-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
text-align: left;
}
.data-table th {
background: rgba(0, 0, 0, 0.2);
color: var(--text-secondary);
font-weight: 600;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 16px;
border-bottom: 1px solid var(--border-color);
white-space: nowrap;
}
.data-table td {
padding: 16px;
border-bottom: 1px solid rgba(255, 255, 255, 0.02);
color: var(--text-primary);
font-size: 0.95rem;
vertical-align: middle;
}
.data-table tr:last-child td {
border-bottom: none;
}
.data-table tr:hover td {
background: rgba(255, 255, 255, 0.02);
}
/* Status Badges */
.badge {
padding: 4px 10px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
display: inline-block;
}
.badge-success { background: var(--accent-green-bg); color: var(--accent-green); border: 1px solid rgba(16, 185, 129, 0.2); }
.badge-danger { background: var(--accent-red-bg); color: var(--accent-red); border: 1px solid rgba(239, 68, 68, 0.2); }
.badge-warning { background: var(--accent-orange-bg); color: var(--accent-orange); border: 1px solid rgba(245, 158, 11, 0.2); }
.badge-neutral { background: var(--bg-tertiary); color: var(--text-secondary); border: 1px solid var(--border-color); }
/* Layouts */
.app-container {
max-width: 1400px;
margin: 0 auto;
padding: 40px 20px;
}
.nav-container {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 40px;
padding-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-fade-in {
animation: fadeIn 0.4s ease-out forwards;
}
/* Utilities */
.text-green { color: var(--accent-green); }
.text-red { color: var(--accent-red); }
.text-orange { color: var(--accent-orange); }
.text-blue { color: var(--accent-blue); }
.text-muted { color: var(--text-muted); }

10
src/index.js Normal file
View File

@@ -0,0 +1,10 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

33
src/styles.css Normal file
View File

@@ -0,0 +1,33 @@
.table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
background: #1c1c1c;
}
.table th, .table td {
border: 1px solid #333;
padding: 10px;
text-align: center;
}
.table th {
background: #222;
}
.table tr:hover {
background: #2a2a2a;
cursor: pointer;
}
td:nth-child(3) {
color: #00e676;
}
td:nth-child(5) {
color: red;
}
td:nth-child(6) {
color: #00c853;
}