Compare commits
2 Commits
e6dbd11ba1
...
2418f11142
| Author | SHA1 | Date |
|---|---|---|
|
|
2418f11142 | |
|
|
edb4b29ea8 |
|
|
@ -0,0 +1,3 @@
|
||||||
|
github: hemangjoshi37a
|
||||||
|
custom:
|
||||||
|
- "https://hjlabs.in"
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 381 KiB After Width: | Height: | Size: 381 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 284 KiB After Width: | Height: | Size: 288 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 81 KiB |
|
|
@ -0,0 +1,26 @@
|
||||||
|
cff-version: 1.2.0
|
||||||
|
title: "TradingAgents: Multi-Agents LLM Financial Trading Framework"
|
||||||
|
message: "If you use this software, please cite our paper."
|
||||||
|
type: software
|
||||||
|
license: Apache-2.0
|
||||||
|
url: "https://github.com/hemangjoshi37a/TradingAgents"
|
||||||
|
repository-code: "https://github.com/hemangjoshi37a/TradingAgents"
|
||||||
|
preferred-citation:
|
||||||
|
type: article
|
||||||
|
title: "TradingAgents: Multi-Agents LLM Financial Trading Framework"
|
||||||
|
authors:
|
||||||
|
- family-names: Xiao
|
||||||
|
given-names: Yijia
|
||||||
|
- family-names: Joshi
|
||||||
|
given-names: Hemang
|
||||||
|
year: 2024
|
||||||
|
journal: "arXiv preprint"
|
||||||
|
doi: "10.48550/arXiv.2412.20138"
|
||||||
|
url: "https://arxiv.org/abs/2412.20138"
|
||||||
|
keywords:
|
||||||
|
- multi-agent systems
|
||||||
|
- financial trading
|
||||||
|
- large language models
|
||||||
|
- stock analysis
|
||||||
|
- algorithmic trading
|
||||||
|
- quantitative finance
|
||||||
21
README.md
21
README.md
|
|
@ -1,25 +1,31 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
<img src="assets/schema.png" width="120" alt="TradingAgents Logo" />
|
<img src="assets/schema.png" width="120" alt="TradingAgents - Multi-Agent LLM Financial Trading Framework Logo" />
|
||||||
|
|
||||||
# TradingAgents
|
# TradingAgents
|
||||||
|
|
||||||
### Multi-Agent LLM Financial Trading Framework
|
### Multi-Agent LLM Financial Trading Framework
|
||||||
|
|
||||||
[](https://arxiv.org/abs/2412.20138)
|
[](https://arxiv.org/abs/2412.20138)
|
||||||
[](https://www.python.org/)
|
[](https://www.python.org/)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](https://react.dev/)
|
[](https://react.dev/)
|
||||||
[](https://fastapi.tiangolo.com/)
|
[](https://fastapi.tiangolo.com/)
|
||||||
[](https://tailwindcss.com/)
|
[](https://tailwindcss.com/)
|
||||||
|
|
||||||
|
[](https://hjlabs.in)
|
||||||
|
[](https://github.com/hemangjoshi37a/TradingAgents/stargazers)
|
||||||
|
[](https://github.com/hemangjoshi37a/TradingAgents/network/members)
|
||||||
|
[](https://github.com/hemangjoshi37a/TradingAgents/issues)
|
||||||
|
[](https://github.com/hemangjoshi37a/TradingAgents/commits/main)
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
An open-source framework that deploys **specialized AI agents** — analysts, researchers, traders, and risk managers — to collaboratively analyze markets and generate investment recommendations through structured debate.
|
An open-source framework that deploys **specialized AI agents** — analysts, researchers, traders, and risk managers — to collaboratively analyze markets and generate investment recommendations through structured debate.
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
[Getting Started](#getting-started) • [Web Dashboard](#nifty50-ai-web-dashboard) • [Python API](#python-api) • [Architecture](#architecture) • [Contributing](#contributing)
|
[Getting Started](#getting-started) • [Web Dashboard](#nifty50-ai-web-dashboard) • [Python API](#python-api) • [Architecture](#architecture) • [Contributing](#contributing) • [hjlabs.in](https://hjlabs.in)
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|
@ -375,8 +381,15 @@ If you find TradingAgents useful in your research, please cite:
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
Built and maintained by **[hjlabs.in](https://hjlabs.in)**
|
### Built and maintained by **[hjlabs.in](https://hjlabs.in)**
|
||||||
|
|
||||||
|
[](https://hjlabs.in)
|
||||||
|
[](https://github.com/hemangjoshi37a)
|
||||||
|
[](https://www.linkedin.com/in/hemang-joshi/)
|
||||||
|
[](https://www.youtube.com/@hjlabs)
|
||||||
|
|
||||||
<sub>Made with AI agents that actually debate before deciding.</sub>
|
<sub>Made with AI agents that actually debate before deciding.</sub>
|
||||||
|
|
||||||
|
If you find this project useful, please consider giving it a star on GitHub!
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1497,12 +1497,12 @@ def update_daily_recommendation_summary(date: str):
|
||||||
for s in buy_stocks[:5]
|
for s in buy_stocks[:5]
|
||||||
]
|
]
|
||||||
|
|
||||||
# Stocks to avoid: bottom-ranked SELL stocks (last 5)
|
# Stocks to avoid: all SELL stocks
|
||||||
stocks_to_avoid = [
|
stocks_to_avoid = [
|
||||||
{'symbol': s['symbol'], 'company_name': s['company_name'],
|
{'symbol': s['symbol'], 'company_name': s['company_name'],
|
||||||
'confidence': s['confidence'], 'reason': s['reason'],
|
'confidence': s['confidence'], 'reason': s['reason'],
|
||||||
'rank': s['rank']}
|
'rank': s['rank']}
|
||||||
for s in sell_stocks[-5:]
|
for s in sell_stocks
|
||||||
]
|
]
|
||||||
|
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,8 +1,17 @@
|
||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "nifty50-ai-dashboard",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"description": "Nifty50 AI Web Dashboard - Real-time AI stock recommendations with backtesting",
|
||||||
|
"homepage": "https://hjlabs.in",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/hemangjoshi37a/TradingAgents.git",
|
||||||
|
"directory": "frontend"
|
||||||
|
},
|
||||||
|
"author": "hjlabs.in",
|
||||||
|
"license": "Apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ export default function AIAnalysisPanel({
|
||||||
<Brain className="w-5 h-5" />
|
<Brain className="w-5 h-5" />
|
||||||
<span className="font-semibold text-sm">AI Analysis</span>
|
<span className="font-semibold text-sm">AI Analysis</span>
|
||||||
<span className="text-xs bg-white/20 px-2 py-0.5 rounded-full">
|
<span className="text-xs bg-white/20 px-2 py-0.5 rounded-full">
|
||||||
{sections.length} sections
|
{sections.length} {sections.length === 1 ? 'section' : 'sections'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,16 @@ export default function Footer() {
|
||||||
<Link to="/history" className="hover:text-gray-900 dark:hover:text-gray-200 transition-colors">History</Link>
|
<Link to="/history" className="hover:text-gray-900 dark:hover:text-gray-200 transition-colors">History</Link>
|
||||||
<Link to="/about" className="hover:text-gray-900 dark:hover:text-gray-200 transition-colors">How It Works</Link>
|
<Link to="/about" className="hover:text-gray-900 dark:hover:text-gray-200 transition-colors">How It Works</Link>
|
||||||
<span className="text-gray-200 dark:text-gray-700">|</span>
|
<span className="text-gray-200 dark:text-gray-700">|</span>
|
||||||
<a href="#" className="hover:text-gray-900 dark:hover:text-gray-200 transition-colors">Disclaimer</a>
|
<a href="#disclaimer" title="AI-generated recommendations for educational purposes only. Not financial advice." className="hover:text-gray-900 dark:hover:text-gray-200 transition-colors">Disclaimer</a>
|
||||||
<a href="#" className="hover:text-gray-900 dark:hover:text-gray-200 transition-colors">Privacy</a>
|
<a href="#privacy" title="We don't collect any personal data. All analysis runs locally." className="hover:text-gray-900 dark:hover:text-gray-200 transition-colors">Privacy</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Social & Copyright */}
|
{/* Social & Copyright */}
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<a href="#" className="text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
<a href="https://github.com/hemangjoshi37a/TradingAgents" target="_blank" rel="noopener noreferrer" className="text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
||||||
<Github className="w-4 h-4" />
|
<Github className="w-4 h-4" />
|
||||||
</a>
|
</a>
|
||||||
<a href="#" className="text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
<a href="https://x.com/heaborla" target="_blank" rel="noopener noreferrer" className="text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 transition-colors">
|
||||||
<Twitter className="w-4 h-4" />
|
<Twitter className="w-4 h-4" />
|
||||||
</a>
|
</a>
|
||||||
<span className="text-xs text-gray-400 dark:text-gray-500">© {new Date().getFullYear()}</span>
|
<span className="text-xs text-gray-400 dark:text-gray-500">© {new Date().getFullYear()}</span>
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,8 @@ function calculateSmartTrades(
|
||||||
|
|
||||||
delete openPositions[symbol];
|
delete openPositions[symbol];
|
||||||
}
|
}
|
||||||
stocksTracked++;
|
// SELL exits position to cash — don't count in stocksTracked
|
||||||
|
// since no capital is deployed and return is 0
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ export default function TopPicks({ picks }: TopPicksProps) {
|
||||||
BUY
|
BUY
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[11px] text-gray-600 dark:text-gray-400 line-clamp-2 mb-2 leading-relaxed">{pick.reason}</p>
|
<p className="text-[11px] text-gray-600 dark:text-gray-400 line-clamp-2 mb-2 leading-relaxed">{pick.reason?.replace(/\*\*/g, '').replace(/\*/g, '')}</p>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className={`text-[11px] px-2 py-0.5 rounded-md font-medium border ${
|
<span className={`text-[11px] px-2 py-0.5 rounded-md font-medium border ${
|
||||||
pick.risk_level === 'LOW' ? 'bg-emerald-50 dark:bg-emerald-900/20 text-emerald-700 dark:text-emerald-400 border-emerald-200/50 dark:border-emerald-800/30' :
|
pick.risk_level === 'LOW' ? 'bg-emerald-50 dark:bg-emerald-900/20 text-emerald-700 dark:text-emerald-400 border-emerald-200/50 dark:border-emerald-800/30' :
|
||||||
|
|
@ -98,7 +98,7 @@ export function StocksToAvoid({ stocks }: StocksToAvoidProps) {
|
||||||
SELL
|
SELL
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[11px] text-gray-600 dark:text-gray-400 line-clamp-2 mb-2 leading-relaxed">{stock.reason}</p>
|
<p className="text-[11px] text-gray-600 dark:text-gray-400 line-clamp-2 mb-2 leading-relaxed">{stock.reason?.replace(/\*\*/g, '').replace(/\*/g, '')}</p>
|
||||||
<ChevronRight className="w-3.5 h-3.5 text-gray-400 dark:text-gray-500 group-hover:text-red-600 dark:group-hover:text-red-400 transition-colors" />
|
<ChevronRight className="w-3.5 h-3.5 text-gray-400 dark:text-gray-500 group-hover:text-red-600 dark:group-hover:text-red-400 transition-colors" />
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -540,7 +540,9 @@ export default function Dashboard() {
|
||||||
|
|
||||||
{/* Top Picks and Avoid Section - Side by Side Compact */}
|
{/* Top Picks and Avoid Section - Side by Side Compact */}
|
||||||
<div className="grid lg:grid-cols-2 gap-4">
|
<div className="grid lg:grid-cols-2 gap-4">
|
||||||
<TopPicks picks={recommendation.top_picks} />
|
{recommendation.top_picks.length > 0 && (
|
||||||
|
<TopPicks picks={recommendation.top_picks} />
|
||||||
|
)}
|
||||||
<StocksToAvoid stocks={recommendation.stocks_to_avoid} />
|
<StocksToAvoid stocks={recommendation.stocks_to_avoid} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,13 @@ function getValueColorClass(value: number): string {
|
||||||
: 'text-red-500 dark:text-red-400';
|
: 'text-red-500 dark:text-red-400';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format percentage without negative zero (e.g. "-0.0" becomes "0.0")
|
||||||
|
function fmtPct(val: number, decimals = 1): string {
|
||||||
|
const s = val.toFixed(decimals);
|
||||||
|
if (s === '-0.0' || s === '-0.00') return s.replace('-', '');
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
// Investment Mode Toggle Component
|
// Investment Mode Toggle Component
|
||||||
function InvestmentModeToggle({
|
function InvestmentModeToggle({
|
||||||
mode,
|
mode,
|
||||||
|
|
@ -287,6 +294,8 @@ export default function History() {
|
||||||
topPicksReturnDistribution: undefined as ReturnBucket[] | undefined,
|
topPicksReturnDistribution: undefined as ReturnBucket[] | undefined,
|
||||||
dateReturns: {} as Record<string, number>,
|
dateReturns: {} as Record<string, number>,
|
||||||
allBacktestData: {} as Record<string, Record<string, number>>,
|
allBacktestData: {} as Record<string, Record<string, number>>,
|
||||||
|
dailyReturnsArray: [] as number[],
|
||||||
|
topPicksDailyReturns: [] as number[],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,21 +322,19 @@ export default function History() {
|
||||||
|
|
||||||
// Cumulative returns
|
// Cumulative returns
|
||||||
const cumulativeData: CumulativeReturnPoint[] = [];
|
const cumulativeData: CumulativeReturnPoint[] = [];
|
||||||
let aiMultiplier = 1, indexMultiplier = 1;
|
let aiMultiplier = 1;
|
||||||
|
|
||||||
// Nifty daily returns
|
// Nifty50 price ratio approach: direct comparison to start price
|
||||||
|
// This avoids losing Nifty returns on days without backtest data
|
||||||
const sortedNiftyDates = Object.keys(nifty50Prices).sort();
|
const sortedNiftyDates = Object.keys(nifty50Prices).sort();
|
||||||
const niftyDailyReturns: Record<string, number> = {};
|
const hasNiftyData = sortedNiftyDates.length > 0;
|
||||||
for (let i = 1; i < sortedNiftyDates.length; i++) {
|
const niftyStartPrice = hasNiftyData ? nifty50Prices[sortedNiftyDates[0]] : null;
|
||||||
const prevPrice = nifty50Prices[sortedNiftyDates[i - 1]];
|
|
||||||
const currPrice = nifty50Prices[sortedNiftyDates[i]];
|
|
||||||
niftyDailyReturns[sortedNiftyDates[i]] = ((currPrice - prevPrice) / prevPrice) * 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getNiftyReturn = (date: string): number => {
|
const getNiftyReturnForDate = (date: string): number => {
|
||||||
if (niftyDailyReturns[date] !== undefined) return niftyDailyReturns[date];
|
if (!hasNiftyData || !niftyStartPrice) return 0;
|
||||||
const closestDate = sortedNiftyDates.find(d => d >= date) || sortedNiftyDates[sortedNiftyDates.length - 1];
|
const closestDate = sortedNiftyDates.find(d => d >= date) || sortedNiftyDates[sortedNiftyDates.length - 1];
|
||||||
return (closestDate && niftyDailyReturns[closestDate] !== undefined) ? niftyDailyReturns[closestDate] : 0;
|
if (!closestDate || !nifty50Prices[closestDate]) return 0;
|
||||||
|
return ((nifty50Prices[closestDate] / niftyStartPrice) - 1) * 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
const dateReturnsMap: Record<string, number> = {};
|
const dateReturnsMap: Record<string, number> = {};
|
||||||
|
|
@ -381,14 +388,13 @@ export default function History() {
|
||||||
else if (weightedReturn < 0) { losses++; totalLossReturn += Math.abs(weightedReturn); }
|
else if (weightedReturn < 0) { losses++; totalLossReturn += Math.abs(weightedReturn); }
|
||||||
|
|
||||||
aiMultiplier *= (1 + weightedReturn / 100);
|
aiMultiplier *= (1 + weightedReturn / 100);
|
||||||
const indexDailyReturn = getNiftyReturn(date);
|
const niftyCumulativeReturn = getNiftyReturnForDate(date);
|
||||||
indexMultiplier *= (1 + indexDailyReturn / 100);
|
|
||||||
|
|
||||||
cumulativeData.push({
|
cumulativeData.push({
|
||||||
date,
|
date,
|
||||||
value: Math.round(aiMultiplier * 10000) / 100,
|
value: Math.round(aiMultiplier * 10000) / 100,
|
||||||
aiReturn: Math.round((aiMultiplier - 1) * 1000) / 10,
|
aiReturn: Math.round((aiMultiplier - 1) * 1000) / 10,
|
||||||
indexReturn: Math.round((indexMultiplier - 1) * 1000) / 10,
|
indexReturn: Math.round(niftyCumulativeReturn * 10) / 10,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -431,7 +437,7 @@ export default function History() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const avgWin = wins > 0 ? totalWinReturn / wins : 0;
|
const avgWin = wins > 0 ? totalWinReturn / wins : 0;
|
||||||
const avgLoss = losses > 0 ? totalLossReturn / losses : 1;
|
const avgLoss = losses > 0 ? totalLossReturn / losses : 0;
|
||||||
|
|
||||||
riskMetrics = {
|
riskMetrics = {
|
||||||
sharpeRatio: Math.round(sharpeRatio * 100) / 100,
|
sharpeRatio: Math.round(sharpeRatio * 100) / 100,
|
||||||
|
|
@ -492,8 +498,9 @@ export default function History() {
|
||||||
{ range: '2% to 3%', min: 2, max: 3, count: 0, stocks: [] },
|
{ range: '2% to 3%', min: 2, max: 3, count: 0, stocks: [] },
|
||||||
{ range: '> 3%', min: 3, max: Infinity, count: 0, stocks: [] },
|
{ range: '> 3%', min: 3, max: Infinity, count: 0, stocks: [] },
|
||||||
];
|
];
|
||||||
let topPicksMultiplier = 1, topPicksIndexMultiplier = 1;
|
let topPicksMultiplier = 1;
|
||||||
let latestTopPicksDateWithData: string | null = null;
|
let latestTopPicksDateWithData: string | null = null;
|
||||||
|
const topPicksDailyReturnsArr: number[] = [];
|
||||||
|
|
||||||
for (const date of sortedDates) {
|
for (const date of sortedDates) {
|
||||||
const rec = recommendations.find(r => r.date === date);
|
const rec = recommendations.find(r => r.date === date);
|
||||||
|
|
@ -511,14 +518,14 @@ export default function History() {
|
||||||
|
|
||||||
if (dateCount > 0) {
|
if (dateCount > 0) {
|
||||||
const avgReturn = dateReturn / dateCount;
|
const avgReturn = dateReturn / dateCount;
|
||||||
|
topPicksDailyReturnsArr.push(avgReturn);
|
||||||
topPicksMultiplier *= (1 + avgReturn / 100);
|
topPicksMultiplier *= (1 + avgReturn / 100);
|
||||||
const indexDailyReturn = getNiftyReturn(date);
|
const topPicksNiftyReturn = getNiftyReturnForDate(date);
|
||||||
topPicksIndexMultiplier *= (1 + indexDailyReturn / 100);
|
|
||||||
topPicksCumulative.push({
|
topPicksCumulative.push({
|
||||||
date,
|
date,
|
||||||
value: Math.round(topPicksMultiplier * 10000) / 100,
|
value: Math.round(topPicksMultiplier * 10000) / 100,
|
||||||
aiReturn: Math.round((topPicksMultiplier - 1) * 1000) / 10,
|
aiReturn: Math.round((topPicksMultiplier - 1) * 1000) / 10,
|
||||||
indexReturn: Math.round((topPicksIndexMultiplier - 1) * 1000) / 10,
|
indexReturn: Math.round(topPicksNiftyReturn * 10) / 10,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -548,17 +555,19 @@ export default function History() {
|
||||||
topPicksReturnDistribution: topPicksDistribution,
|
topPicksReturnDistribution: topPicksDistribution,
|
||||||
dateReturns: dateReturnsMap,
|
dateReturns: dateReturnsMap,
|
||||||
allBacktestData: allBacktest,
|
allBacktestData: allBacktest,
|
||||||
|
dailyReturnsArray: dailyReturns,
|
||||||
|
topPicksDailyReturns: topPicksDailyReturnsArr,
|
||||||
};
|
};
|
||||||
}, [batchBacktestByDate, hasBacktestData, recommendations, nifty50Prices]);
|
}, [batchBacktestByDate, hasBacktestData, recommendations, nifty50Prices]);
|
||||||
|
|
||||||
// Overall stats
|
// Overall stats
|
||||||
const overallStats = useMemo(() => {
|
const overallStats = useMemo(() => {
|
||||||
if (recommendations.length > 0 && chartData.cumulativeReturns && chartData.cumulativeReturns.length > 0) {
|
if (recommendations.length > 0 && chartData.dailyReturnsArray && chartData.dailyReturnsArray.length > 0) {
|
||||||
const lastPoint = chartData.cumulativeReturns[chartData.cumulativeReturns.length - 1];
|
const mean = chartData.dailyReturnsArray.reduce((a, b) => a + b, 0) / chartData.dailyReturnsArray.length;
|
||||||
return {
|
return {
|
||||||
totalDays: recommendations.length,
|
totalDays: recommendations.length,
|
||||||
totalPredictions: accuracyMetrics.total_predictions,
|
totalPredictions: accuracyMetrics.total_predictions,
|
||||||
avgDailyReturn: Math.round((lastPoint.aiReturn / chartData.cumulativeReturns.length) * 10) / 10,
|
avgDailyReturn: Math.round(mean * 10) / 10,
|
||||||
avgMonthlyReturn: 0,
|
avgMonthlyReturn: 0,
|
||||||
overallAccuracy: Math.round(accuracyMetrics.success_rate * 100),
|
overallAccuracy: Math.round(accuracyMetrics.success_rate * 100),
|
||||||
bestDay: null,
|
bestDay: null,
|
||||||
|
|
@ -566,7 +575,7 @@ export default function History() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return { totalDays: recommendations.length, totalPredictions: 0, avgDailyReturn: 0, avgMonthlyReturn: 0, overallAccuracy: 0, bestDay: null, worstDay: null };
|
return { totalDays: recommendations.length, totalPredictions: 0, avgDailyReturn: 0, avgMonthlyReturn: 0, overallAccuracy: 0, bestDay: null, worstDay: null };
|
||||||
}, [recommendations, chartData.cumulativeReturns, accuracyMetrics]);
|
}, [recommendations, chartData.dailyReturnsArray, accuracyMetrics]);
|
||||||
|
|
||||||
// Filtered stats for Performance Summary
|
// Filtered stats for Performance Summary
|
||||||
const filteredStats = useMemo(() => {
|
const filteredStats = useMemo(() => {
|
||||||
|
|
@ -578,14 +587,17 @@ export default function History() {
|
||||||
return { totalDays: dates.length, avgDailyReturn: overallStats.avgDailyReturn, buySignals: signalTotals.buy, sellSignals: signalTotals.sell, holdSignals: signalTotals.hold };
|
return { totalDays: dates.length, avgDailyReturn: overallStats.avgDailyReturn, buySignals: signalTotals.buy, sellSignals: signalTotals.sell, holdSignals: signalTotals.hold };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const topPicksMean = chartData.topPicksDailyReturns.length > 0
|
||||||
|
? chartData.topPicksDailyReturns.reduce((a, b) => a + b, 0) / chartData.topPicksDailyReturns.length
|
||||||
|
: 0;
|
||||||
return {
|
return {
|
||||||
totalDays: dates.length,
|
totalDays: dates.length,
|
||||||
avgDailyReturn: 0,
|
avgDailyReturn: Math.round(topPicksMean * 10) / 10,
|
||||||
buySignals: recommendations.reduce((acc, r) => acc + r.top_picks.length, 0),
|
buySignals: recommendations.reduce((acc, r) => acc + r.top_picks.length, 0),
|
||||||
sellSignals: 0,
|
sellSignals: 0,
|
||||||
holdSignals: 0,
|
holdSignals: 0,
|
||||||
};
|
};
|
||||||
}, [summaryMode, dates.length, overallStats.avgDailyReturn, recommendations]);
|
}, [summaryMode, dates.length, overallStats.avgDailyReturn, recommendations, chartData.topPicksDailyReturns]);
|
||||||
|
|
||||||
// Date stats
|
// Date stats
|
||||||
const dateStatsMap = useMemo(() => {
|
const dateStatsMap = useMemo(() => {
|
||||||
|
|
@ -1069,7 +1081,7 @@ export default function History() {
|
||||||
<div className={`text-sm font-bold mt-0.5 ${
|
<div className={`text-sm font-bold mt-0.5 ${
|
||||||
selectedDate === date ? 'text-white' : getValueColorClass(avgReturn)
|
selectedDate === date ? 'text-white' : getValueColorClass(avgReturn)
|
||||||
}`}>
|
}`}>
|
||||||
{isPositive ? '+' : ''}{avgReturn.toFixed(1)}%
|
{isPositive ? '+' : ''}{fmtPct(avgReturn)}%
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={`text-[10px] mt-0.5 ${selectedDate === date ? 'text-white/80' : 'opacity-60'}`}>
|
<div className={`text-[10px] mt-0.5 ${selectedDate === date ? 'text-white/80' : 'opacity-60'}`}>
|
||||||
|
|
@ -1098,7 +1110,7 @@ export default function History() {
|
||||||
Overall
|
Overall
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm font-bold mt-0.5">
|
<div className="text-sm font-bold mt-0.5">
|
||||||
{overallStats.avgDailyReturn >= 0 ? '+' : ''}{overallStats.avgDailyReturn.toFixed(1)}%
|
{overallStats.avgDailyReturn >= 0 ? '+' : ''}{fmtPct(overallStats.avgDailyReturn)}%
|
||||||
</div>
|
</div>
|
||||||
<div className="text-[10px] mt-0.5 text-white/80">
|
<div className="text-[10px] mt-0.5 text-white/80">
|
||||||
{overallStats.overallAccuracy}% accurate
|
{overallStats.overallAccuracy}% accurate
|
||||||
|
|
@ -1391,7 +1403,7 @@ export default function History() {
|
||||||
? 'bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400'
|
? 'bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400'
|
||||||
: getValueColorClass(nextDayReturn)
|
: getValueColorClass(nextDayReturn)
|
||||||
}`} title={bt?.hold_days ? `${bt.hold_days}d return` : '1d return'}>
|
}`} title={bt?.hold_days ? `${bt.hold_days}d return` : '1d return'}>
|
||||||
{nextDayReturn >= 0 ? '+' : ''}{nextDayReturn.toFixed(1)}%
|
{nextDayReturn >= 0 ? '+' : ''}{fmtPct(nextDayReturn)}%
|
||||||
{bt?.hold_days && <span className="text-[9px] opacity-60">/{bt.hold_days}d</span>}
|
{bt?.hold_days && <span className="text-[9px] opacity-60">/{bt.hold_days}d</span>}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1415,7 +1427,7 @@ export default function History() {
|
||||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
||||||
{[
|
{[
|
||||||
{ label: 'Days Tracked', value: filteredStats.totalDays.toString(), icon: <Clock className="w-4 h-4" />, color: 'nifty', modal: 'daysTracked' as SummaryModalType },
|
{ label: 'Days Tracked', value: filteredStats.totalDays.toString(), icon: <Clock className="w-4 h-4" />, color: 'nifty', modal: 'daysTracked' as SummaryModalType },
|
||||||
{ label: 'Avg Return', value: `${filteredStats.avgDailyReturn >= 0 ? '+' : ''}${filteredStats.avgDailyReturn.toFixed(1)}%`, icon: <TrendingUp className="w-4 h-4" />, color: filteredStats.avgDailyReturn >= 0 ? 'emerald' : 'red', modal: 'avgReturn' as SummaryModalType },
|
{ label: 'Avg Return', value: `${filteredStats.avgDailyReturn >= 0 ? '+' : ''}${fmtPct(filteredStats.avgDailyReturn)}%`, icon: <TrendingUp className="w-4 h-4" />, color: filteredStats.avgDailyReturn >= 0 ? 'emerald' : 'red', modal: 'avgReturn' as SummaryModalType },
|
||||||
{ label: summaryMode === 'topPicks' ? 'Top Picks' : 'Buy Signals', value: filteredStats.buySignals.toString(), icon: <ArrowUpRight className="w-4 h-4" />, color: 'emerald', modal: 'buySignals' as SummaryModalType },
|
{ label: summaryMode === 'topPicks' ? 'Top Picks' : 'Buy Signals', value: filteredStats.buySignals.toString(), icon: <ArrowUpRight className="w-4 h-4" />, color: 'emerald', modal: 'buySignals' as SummaryModalType },
|
||||||
{ label: 'Sell Signals', value: filteredStats.sellSignals.toString(), icon: <ArrowDownRight className="w-4 h-4" />, color: 'red', modal: 'sellSignals' as SummaryModalType },
|
{ label: 'Sell Signals', value: filteredStats.sellSignals.toString(), icon: <ArrowDownRight className="w-4 h-4" />, color: 'red', modal: 'sellSignals' as SummaryModalType },
|
||||||
].map(({ label, value, icon, color, modal }) => (
|
].map(({ label, value, icon, color, modal }) => (
|
||||||
|
|
|
||||||
|
|
@ -1080,7 +1080,7 @@ export default function StockDetail() {
|
||||||
<div>
|
<div>
|
||||||
<span className="font-semibold text-green-800 dark:text-green-300 text-sm">Top Pick: </span>
|
<span className="font-semibold text-green-800 dark:text-green-300 text-sm">Top Pick: </span>
|
||||||
<span className="text-sm text-green-700 dark:text-green-400">
|
<span className="text-sm text-green-700 dark:text-green-400">
|
||||||
{latestRecommendation.top_picks.find(p => p.symbol === symbol)?.reason}
|
{latestRecommendation.top_picks.find(p => p.symbol === symbol)?.reason?.replace(/\*\*/g, '').replace(/\*/g, '')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1094,7 +1094,7 @@ export default function StockDetail() {
|
||||||
<div>
|
<div>
|
||||||
<span className="font-semibold text-red-800 dark:text-red-300 text-sm">Avoid: </span>
|
<span className="font-semibold text-red-800 dark:text-red-300 text-sm">Avoid: </span>
|
||||||
<span className="text-sm text-red-700 dark:text-red-400">
|
<span className="text-sm text-red-700 dark:text-red-400">
|
||||||
{latestRecommendation.stocks_to_avoid.find(s => s.symbol === symbol)?.reason}
|
{latestRecommendation.stocks_to_avoid.find(s => s.symbol === symbol)?.reason?.replace(/\*\*/g, '').replace(/\*/g, '')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/hemangjoshi37a/TradingAgents/issues"
|
"url": "https://github.com/hemangjoshi37a/TradingAgents/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/hemangjoshi37a/TradingAgents#readme",
|
"homepage": "https://hjlabs.in",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright": "^1.58.1"
|
"playwright": "^1.58.1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,27 @@ version = "0.1.0"
|
||||||
description = "Multi-Agent LLM Financial Trading Framework with AI-powered stock analysis, structured debates, and backtesting"
|
description = "Multi-Agent LLM Financial Trading Framework with AI-powered stock analysis, structured debates, and backtesting"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
license = {text = "Apache-2.0"}
|
||||||
|
authors = [
|
||||||
|
{name = "Hemang Joshi", email = "hemangjoshi37a@gmail.com"},
|
||||||
|
]
|
||||||
|
keywords = [
|
||||||
|
"trading", "ai", "multi-agent", "llm", "stock-analysis",
|
||||||
|
"nifty50", "backtesting", "langchain", "langgraph",
|
||||||
|
"algorithmic-trading", "quantitative-finance", "stock-market",
|
||||||
|
]
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 4 - Beta",
|
||||||
|
"Intended Audience :: Financial and Insurance Industry",
|
||||||
|
"License :: OSI Approved :: Apache Software License",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Topic :: Office/Business :: Financial :: Investment",
|
||||||
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
||||||
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"akshare>=1.16.98",
|
"akshare>=1.16.98",
|
||||||
"backtrader>=1.9.78.123",
|
"backtrader>=1.9.78.123",
|
||||||
|
|
@ -33,3 +54,10 @@ dependencies = [
|
||||||
"typing-extensions>=4.14.0",
|
"typing-extensions>=4.14.0",
|
||||||
"yfinance>=0.2.63",
|
"yfinance>=0.2.63",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://hjlabs.in"
|
||||||
|
Repository = "https://github.com/hemangjoshi37a/TradingAgents"
|
||||||
|
Documentation = "https://github.com/hemangjoshi37a/TradingAgents#readme"
|
||||||
|
Issues = "https://github.com/hemangjoshi37a/TradingAgents/issues"
|
||||||
|
"Research Paper" = "https://arxiv.org/abs/2412.20138"
|
||||||
|
|
|
||||||
28
setup.py
28
setup.py
|
|
@ -7,10 +7,17 @@ from setuptools import setup, find_packages
|
||||||
setup(
|
setup(
|
||||||
name="tradingagents",
|
name="tradingagents",
|
||||||
version="0.1.0",
|
version="0.1.0",
|
||||||
description="Multi-Agents LLM Financial Trading Framework",
|
description="Multi-Agent LLM Financial Trading Framework with AI-powered stock analysis, structured debates, and backtesting",
|
||||||
author="TradingAgents Team",
|
long_description=open("README.md", encoding="utf-8").read(),
|
||||||
author_email="yijia.xiao@cs.ucla.edu",
|
long_description_content_type="text/markdown",
|
||||||
url="https://github.com/hemangjoshi37a/TradingAgents",
|
author="Hemang Joshi",
|
||||||
|
author_email="hemangjoshi37a@gmail.com",
|
||||||
|
url="https://hjlabs.in",
|
||||||
|
project_urls={
|
||||||
|
"Source": "https://github.com/hemangjoshi37a/TradingAgents",
|
||||||
|
"Issues": "https://github.com/hemangjoshi37a/TradingAgents/issues",
|
||||||
|
"Research Paper": "https://arxiv.org/abs/2412.20138",
|
||||||
|
},
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"langchain>=0.1.0",
|
"langchain>=0.1.0",
|
||||||
|
|
@ -33,11 +40,20 @@ setup(
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 4 - Beta",
|
||||||
"Intended Audience :: Financial and Trading Industry",
|
"Intended Audience :: Financial and Insurance Industry",
|
||||||
"License :: OSI Approved :: Apache Software License",
|
"License :: OSI Approved :: Apache Software License",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
"Topic :: Office/Business :: Financial :: Investment",
|
"Topic :: Office/Business :: Financial :: Investment",
|
||||||
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
||||||
|
],
|
||||||
|
keywords=[
|
||||||
|
"trading", "ai", "multi-agent", "llm", "stock-analysis",
|
||||||
|
"nifty50", "backtesting", "langchain", "langgraph",
|
||||||
|
"algorithmic-trading", "quantitative-finance",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue