Add TradingView charts, sentiment, funding rates to Tools
This commit is contained in:
@@ -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 />
|
||||||
|
|||||||
@@ -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 => (
|
||||||
|
|||||||
Reference in New Issue
Block a user