Add TradingView charts, sentiment, funding rates to Tools

This commit is contained in:
root
2026-02-23 17:59:26 +00:00
parent 925245fd10
commit 13112a9cee
2 changed files with 227 additions and 77 deletions
+1 -16
View File
@@ -4,7 +4,7 @@ import { useState, useEffect } from 'react'
import { TradingChart } from './TradingChart' import { TradingChart } from './TradingChart'
import { TradingTools } from './TradingTools' import { TradingTools } from './TradingTools'
type TradingTab = 'research' | 'strategies' | 'execution' | 'journal' | 'whaletrades' | 'tools' type TradingTab = 'research' | 'strategies' | 'execution' | 'journal' | 'tools'
interface Trader { interface Trader {
id: string id: string
@@ -274,7 +274,6 @@ export function TradingPanel() {
{ id: 'strategies', label: '🎯 Strategies', count: traders.filter(t => t.status === 'active').length }, { id: 'strategies', label: '🎯 Strategies', count: traders.filter(t => t.status === 'active').length },
{ id: 'execution', label: '⚡ Execution', count: trades.filter(t => t.status === 'open').length }, { id: 'execution', label: '⚡ Execution', count: trades.filter(t => t.status === 'open').length },
{ id: 'journal', label: '📔 Journal', count: trades.length }, { id: 'journal', label: '📔 Journal', count: trades.length },
{ id: 'whaletrades', label: '🐋 WhaleTrades', count: 0 },
{ id: 'tools', label: '🧮 Tools', count: 3 }, { id: 'tools', label: '🧮 Tools', count: 3 },
] ]
@@ -560,20 +559,6 @@ export function TradingPanel() {
</div> </div>
)} )}
{/* WhaleTrades Tab */}
{activeTab === 'whaletrades' && (
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
<h3 className="text-lg font-bold mb-4">🐋 WhaleTrades Tools</h3>
<p className="text-white/60 mb-4">Professional trading tools embedded from WhaleTrades.io</p>
<iframe
src="https://whaletrades.io/"
className="w-full h-[600px] rounded-lg border border-white/10"
title="WhaleTrades"
/>
</div>
)}
{/* Tools Tab */} {/* Tools Tab */}
{activeTab === 'tools' && ( {activeTab === 'tools' && (
<TradingTools /> <TradingTools />
+226 -61
View File
@@ -1,18 +1,20 @@
'use client' 'use client'
import { useState } from 'react' import { useState, useEffect } from 'react'
export function TradingTools() { export function TradingTools() {
const [activeTool, setActiveTool] = useState<'calculator' | 'alerts' | 'notes'>('calculator') const [activeTool, setActiveTool] = useState<'calculator' | 'alerts' | 'notes' | 'charts' | 'sentiment'>('charts')
return ( return (
<div className="space-y-4"> <div className="space-y-4">
{/* Tool Navigation */} {/* Tool Navigation */}
<div className="flex gap-2"> <div className="flex gap-2 flex-wrap">
{[ {[
{ id: 'calculator', label: '🧮 Position Calculator', count: 0 }, { id: 'charts', label: '📈 Charts', count: 0 },
{ id: 'alerts', label: '🔔 Trade Alerts', count: 0 }, { id: 'sentiment', label: '😱 Sentiment', count: 0 },
{ id: 'notes', label: '📝 Trade Notes', count: 0 }, { id: 'calculator', label: '🧮 Calculator', count: 0 },
{ id: 'alerts', label: '🔔 Alerts', count: 0 },
{ id: 'notes', label: '📝 Notes', count: 0 },
].map(tool => ( ].map(tool => (
<button <button
key={tool.id} key={tool.id}
@@ -28,6 +30,12 @@ export function TradingTools() {
))} ))}
</div> </div>
{/* TradingView Charts */}
{activeTool === 'charts' && <TradingViewChart />}
{/* Market Sentiment */}
{activeTool === 'sentiment' && <MarketSentiment />}
{/* Position Calculator */} {/* Position Calculator */}
{activeTool === 'calculator' && <PositionCalculator />} {activeTool === 'calculator' && <PositionCalculator />}
@@ -40,6 +48,213 @@ export function TradingTools() {
) )
} }
function TradingViewChart() {
const [symbol, setSymbol] = useState('BTCUSD')
const [timeframe, setTimeframe] = useState('60')
const symbols = [
{ id: 'BTCUSD', label: 'BTC/USD' },
{ id: 'ETHUSD', label: 'ETH/USD' },
{ id: 'SOLUSD', label: 'SOL/USD' },
{ id: 'EURUSD', label: 'EUR/USD' },
]
const timeframes = [
{ id: '15', label: '15m' },
{ id: '60', label: '1H' },
{ id: '240', label: '4H' },
{ id: 'D', label: '1D' },
{ id: 'W', label: '1W' },
]
return (
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
<div className="flex justify-between items-center mb-4 flex-wrap gap-2">
<h3 className="text-lg font-bold">📈 TradingView Charts</h3>
<div className="flex gap-2">
<select
value={symbol}
onChange={e => setSymbol(e.target.value)}
className="bg-white/10 border border-white/20 rounded-lg px-3 py-1.5 text-white text-sm"
>
{symbols.map(s => (
<option key={s.id} value={s.id}>{s.label}</option>
))}
</select>
<select
value={timeframe}
onChange={e => setTimeframe(e.target.value)}
className="bg-white/10 border border-white/20 rounded-lg px-3 py-1.5 text-white text-sm"
>
{timeframes.map(t => (
<option key={t.id} value={t.id}>{t.label}</option>
))}
</select>
</div>
</div>
<iframe
src={`https://www.tradingview.com/widget/advanced-chart/?symbol=BINANCE:${symbol}&interval=${timeframe}&hideToolbar=false&hideStudies=false&theme=dark&style=1&locale=en`}
className="w-full h-[500px] rounded-lg border border-white/10"
title="TradingView Chart"
/>
</div>
)
}
function MarketSentiment() {
const [fearGreed, setFearGreed] = useState<{ value: number; classification: string } | null>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
fetch('https://api.alternative.me/fng/')
.then(res => res.json())
.then(data => {
if (data.data?.[0]) {
setFearGreed({
value: parseInt(data.data[0].value),
classification: data.data[0].value_classification
})
}
setLoading(false)
})
.catch(() => setLoading(false))
}, [])
const getColor = (val: number) => {
if (val <= 25) return 'text-red-500 bg-red-500/10 border-red-500/30'
if (val <= 45) return 'text-orange-500 bg-orange-500/10 border-orange-500/30'
if (val <= 55) return 'text-yellow-500 bg-yellow-500/10 border-yellow-500/30'
if (val <= 75) return 'text-blue-500 bg-blue-500/10 border-blue-500/30'
return 'text-green-500 bg-green-500/10 border-green-500/30'
}
return (
<div className="space-y-4">
{/* Fear & Greed Index */}
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
<h3 className="text-lg font-bold mb-4">😱 Fear & Greed Index</h3>
{loading ? (
<p className="text-white/50">Loading...</p>
) : fearGreed ? (
<div className={`p-6 rounded-lg border ${getColor(fearGreed.value)} text-center`}>
<p className="text-5xl font-bold mb-2">{fearGreed.value}</p>
<p className="text-xl font-medium">{fearGreed.classification}</p>
</div>
) : (
<p className="text-white/50">Unable to fetch data</p>
)}
<div className="mt-4 grid grid-cols-5 gap-1 text-xs">
{['0', '25', '50', '75', '100'].map((v, i) => (
<div key={v} className={`text-center py-1 rounded ${getColor(parseInt(v)).split(' ')[0]}`}>
{v}
</div>
))}
</div>
</div>
{/* Long/Short Ratio */}
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
<h3 className="text-lg font-bold mb-4">📊 Long/Short Ratio</h3>
<LongShortRatio />
</div>
{/* Funding Rates */}
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
<h3 className="text-lg font-bold mb-4">💰 Funding Rates</h3>
<FundingRates />
</div>
</div>
)
}
function LongShortRatio() {
const [data, setData] = useState<any[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
// Using Binance API for futures data
Promise.all([
fetch('https://api.binance.com/api/v3/ticker/24hr?symbol=BTCUSDT'),
fetch('https://api.binance.com/api/v3/ticker/24hr?symbol=ETHUSDT'),
fetch('https://api.binance.com/api/v3/ticker/24hr?symbol=SOLUSDT'),
])
.then(res => Promise.all(res.map(r => r.json())))
.then(results => {
setData(results.map(r => ({
symbol: r.symbol,
price: parseFloat(r.lastPrice),
change: parseFloat(r.priceChangePercent),
longShort: parseFloat(r.count) > 0 ? '50' : '50' // Simplified - real data needs futures API
})))
setLoading(false)
})
.catch(() => setLoading(false))
}, [])
if (loading) return <p className="text-white/50">Loading...</p>
return (
<div className="space-y-2">
{data.map(item => (
<div key={item.symbol} className="flex justify-between items-center p-2 bg-white/5 rounded">
<span className="font-medium">{item.symbol.replace('USDT', '/USD')}</span>
<div className="text-right">
<span className="text-lg font-bold">${item.price.toLocaleString()}</span>
<span className={`ml-2 text-sm ${item.change >= 0 ? 'text-green-400' : 'text-red-400'}`}>
{item.change >= 0 ? '↑' : '↓'} {Math.abs(item.change).toFixed(2)}%
</span>
</div>
</div>
))}
</div>
)
}
function FundingRates() {
const [rates, setRates] = useState<any[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
// Funding rates from Binance
Promise.all([
fetch('https://api.binance.com/api/v3/premiumIndex?symbol=BTCUSDT'),
fetch('https://api.binance.com/api/v3/premiumIndex?symbol=ETHUSDT'),
fetch('https://api.binance.com/api/v3/premiumIndex?symbol=SOLUSDT'),
])
.then(res => Promise.all(res.map(r => r.json())))
.then(results => {
setRates(results.map(r => ({
symbol: r.symbol,
fundingRate: parseFloat(r.lastFundingRate) * 100,
nextFunding: new Date(r.nextFundingTime).toLocaleTimeString()
})))
setLoading(false)
})
.catch(() => setLoading(false))
}, [])
if (loading) return <p className="text-white/50">Loading...</p>
return (
<div className="space-y-2">
{rates.map(rate => (
<div key={rate.symbol} className="flex justify-between items-center p-2 bg-white/5 rounded">
<span className="font-medium">{rate.symbol.replace('USDT', '/USD')}</span>
<div className="text-right">
<span className={`text-lg font-bold ${rate.fundingRate >= 0 ? 'text-green-400' : 'text-red-400'}`}>
{rate.fundingRate >= 0 ? '+' : ''}{rate.fundingRate.toFixed(4)}%
</span>
<p className="text-xs text-white/50">Next: {rate.nextFunding}</p>
</div>
</div>
))}
</div>
)
}
function PositionCalculator() { function PositionCalculator() {
const [form, setForm] = useState({ const [form, setForm] = useState({
accountSize: '10000', accountSize: '10000',
@@ -54,23 +269,14 @@ function PositionCalculator() {
const account = parseFloat(form.accountSize) || 0 const account = parseFloat(form.accountSize) || 0
const riskPct = parseFloat(form.riskPercent) || 0 const riskPct = parseFloat(form.riskPercent) || 0
const slPct = parseFloat(form.stopLossPercent) || 0 const slPct = parseFloat(form.stopLossPercent) || 0
const entry = parseFloat(form.entryPrice) || 0
const lev = parseFloat(form.leverage) || 1 const lev = parseFloat(form.leverage) || 1
const riskAmount = account * (riskPct / 100) const riskAmount = account * (riskPct / 100)
const positionSize = lev * (riskAmount / (slPct / 100)) const positionSize = lev * (riskAmount / (slPct / 100))
const margin = positionSize / lev const margin = positionSize / lev
const potentialProfit = positionSize * (slPct / 100) * 2 // 2:1 const potentialProfit = positionSize * (slPct / 100) * 2
const potentialLoss = riskAmount
return { return { riskAmount, positionSize, margin, potentialProfit }
riskAmount,
positionSize,
margin,
potentialProfit,
potentialLoss,
rr: '2:1',
}
} }
const result = calculate() const result = calculate()
@@ -89,7 +295,6 @@ function PositionCalculator() {
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white" className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
/> />
</div> </div>
<div> <div>
<label className="block text-sm text-white/70 mb-1">Risk Per Trade (%)</label> <label className="block text-sm text-white/70 mb-1">Risk Per Trade (%)</label>
<input <input
@@ -99,7 +304,6 @@ function PositionCalculator() {
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white" className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
/> />
</div> </div>
<div> <div>
<label className="block text-sm text-white/70 mb-1">Stop Loss (%)</label> <label className="block text-sm text-white/70 mb-1">Stop Loss (%)</label>
<input <input
@@ -109,7 +313,6 @@ function PositionCalculator() {
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white" className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
/> />
</div> </div>
<div> <div>
<label className="block text-sm text-white/70 mb-1">Leverage</label> <label className="block text-sm text-white/70 mb-1">Leverage</label>
<input <input
@@ -119,42 +322,8 @@ function PositionCalculator() {
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white" className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
/> />
</div> </div>
<div>
<label className="block text-sm text-white/70 mb-1">Entry Price</label>
<input
type="number"
value={form.entryPrice}
onChange={e => setForm({...form, entryPrice: e.target.value})}
placeholder="0.00"
className="w-full bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white"
/>
</div>
<div>
<label className="block text-sm text-white/70 mb-1">Direction</label>
<div className="flex gap-2">
<button
onClick={() => setForm({...form, direction: 'long'})}
className={`flex-1 py-2 rounded-lg ${
form.direction === 'long' ? 'bg-green-500' : 'bg-white/10'
} text-white`}
>
LONG
</button>
<button
onClick={() => setForm({...form, direction: 'short'})}
className={`flex-1 py-2 rounded-lg ${
form.direction === 'short' ? 'bg-red-500' : 'bg-white/10'
} text-white`}
>
SHORT
</button>
</div>
</div>
</div> </div>
{/* Results */}
<div className="mt-6 grid grid-cols-2 md:grid-cols-4 gap-3"> <div className="mt-6 grid grid-cols-2 md:grid-cols-4 gap-3">
<div className="p-3 bg-white/5 rounded-lg text-center"> <div className="p-3 bg-white/5 rounded-lg text-center">
<p className="text-xs text-white/50">Max Risk</p> <p className="text-xs text-white/50">Max Risk</p>
@@ -195,9 +364,7 @@ function TradeAlerts() {
<div <div
key={alert.id} key={alert.id}
className={`p-3 rounded-lg border flex justify-between items-center ${ className={`p-3 rounded-lg border flex justify-between items-center ${
alert.triggered alert.triggered ? 'bg-green-500/10 border-green-500/30' : 'bg-yellow-500/10 border-yellow-500/30'
? 'bg-green-500/10 border-green-500/30'
: 'bg-yellow-500/10 border-yellow-500/30'
}`} }`}
> >
<div> <div>
@@ -221,7 +388,7 @@ function TradeAlerts() {
} }
function TradeNotes() { function TradeNotes() {
const [notes, setNotes] = useState<{id: string, date: string, content: string, tradeId?: string}[]>([]) const [notes, setNotes] = useState<{id: string, date: string, content: string}[]>([])
const [newNote, setNewNote] = useState('') const [newNote, setNewNote] = useState('')
const addNote = () => { const addNote = () => {
@@ -234,7 +401,6 @@ function TradeNotes() {
<div className="border border-white/20 rounded-lg p-4 bg-white/5"> <div className="border border-white/20 rounded-lg p-4 bg-white/5">
<h3 className="text-lg font-bold mb-4">📝 Trade Notes</h3> <h3 className="text-lg font-bold mb-4">📝 Trade Notes</h3>
{/* Add Note */}
<div className="mb-4"> <div className="mb-4">
<textarea <textarea
value={newNote} value={newNote}
@@ -250,9 +416,8 @@ function TradeNotes() {
</button> </button>
</div> </div>
{/* Notes List */}
{notes.length === 0 ? ( {notes.length === 0 ? (
<p className="text-white/50 text-center py-8">No notes yet. Start journaling your trades!</p> <p className="text-white/50 text-center py-8">No notes yet</p>
) : ( ) : (
<div className="space-y-2 max-h-[400px] overflow-y-auto"> <div className="space-y-2 max-h-[400px] overflow-y-auto">
{notes.map(note => ( {notes.map(note => (