initial commit
This commit is contained in:
144
src/components/Scanner.js
Normal file
144
src/components/Scanner.js
Normal 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;
|
||||
Reference in New Issue
Block a user