Skip to content

Commit 6ffc016

Browse files
committed
Trading System UI
1 parent 48a5d20 commit 6ffc016

23 files changed

+7481
-5
lines changed

agent-ui/src/app/page.tsx

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ import Sidebar from '@/components/playground/Sidebar/Sidebar'
33
import { ChatArea } from '@/components/playground/ChatArea'
44
import { Phase3Dashboard } from '@/components/phase3/Phase3Dashboard'
55
import { BrandAgentManager } from '@/components/brand-agent/BrandAgentManager'
6+
import { TradingDashboard } from '@/components/trading/TradingDashboard'
7+
import { MarketDataProvider } from '@/services/contexts/MarketDataContext'
8+
import { TradingProvider } from '@/services/contexts/TradingContext'
69
import { Suspense, useState, useEffect } from 'react'
710
import { Button } from '@/components/ui/button'
811
import { Badge } from '@/components/ui/badge'
9-
import { Brain, MessageSquare, Zap, Sparkles } from 'lucide-react'
12+
import { Brain, MessageSquare, Zap, Sparkles, TrendingUp } from 'lucide-react'
1013

1114
export default function Home() {
12-
const [activeMode, setActiveMode] = useState<'playground' | 'phase3' | 'brand-agents'>('playground')
15+
const [activeMode, setActiveMode] = useState<'playground' | 'phase3' | 'brand-agents' | 'trading'>('playground')
1316
const [isHydrated, setIsHydrated] = useState(false)
1417

1518
useEffect(() => {
@@ -124,6 +127,23 @@ export default function Home() {
124127
Beta
125128
</Badge>
126129
</Button>
130+
<Button
131+
variant={activeMode === 'trading' ? 'default' : 'outline'}
132+
size="lg"
133+
onClick={() => setActiveMode('trading')}
134+
className={`transition-all duration-200 ${
135+
activeMode === 'trading'
136+
? 'bg-gradient-to-r from-emerald-500 to-teal-600 hover:from-emerald-600 hover:to-teal-700 shadow-lg shadow-emerald-500/25'
137+
: 'hover:bg-emerald-50 dark:hover:bg-slate-800 border-2'
138+
}`}
139+
>
140+
<TrendingUp className="mr-2 h-5 w-5" />
141+
Trading System
142+
<Badge variant="secondary" className="ml-2 bg-gradient-to-r from-blue-500 to-cyan-500 text-white border-0">
143+
<Zap className="mr-1 h-3 w-3" />
144+
Pro
145+
</Badge>
146+
</Button>
127147
</div>
128148
</div>
129149
<div className="hidden md:flex items-center space-x-4">
@@ -133,15 +153,19 @@ export default function Home() {
133153
? 'Interactive Agent Chat'
134154
: activeMode === 'phase3'
135155
? 'Integrated Semantic Agents'
136-
: 'Brand Agent Platform'
156+
: activeMode === 'brand-agents'
157+
? 'Brand Agent Platform'
158+
: 'Institutional Trading System'
137159
}
138160
</p>
139161
<p className="text-xs text-muted-foreground">
140162
{activeMode === 'playground'
141163
? 'Real-time AI conversations'
142164
: activeMode === 'phase3'
143165
? 'Advanced agent management'
144-
: 'AI-powered customer engagement'
166+
: activeMode === 'brand-agents'
167+
? 'AI-powered customer engagement'
168+
: 'High-frequency trading & risk management'
145169
}
146170
</p>
147171
</div>
@@ -161,10 +185,18 @@ export default function Home() {
161185
<div className="h-full">
162186
<Phase3Dashboard />
163187
</div>
164-
) : (
188+
) : activeMode === 'brand-agents' ? (
165189
<div className="h-full">
166190
<BrandAgentManager />
167191
</div>
192+
) : (
193+
<div className="h-full">
194+
<MarketDataProvider>
195+
<TradingProvider>
196+
<TradingDashboard />
197+
</TradingProvider>
198+
</MarketDataProvider>
199+
</div>
168200
)}
169201
</div>
170202
</div>
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
'use client'
2+
3+
import React, { useState } from 'react'
4+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
5+
import { Badge } from '@/components/ui/badge'
6+
import { Button } from '@/components/ui/button'
7+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
8+
import {
9+
TrendingUp,
10+
TrendingDown,
11+
Activity,
12+
BarChart3,
13+
RefreshCw,
14+
Wifi,
15+
WifiOff
16+
} from 'lucide-react'
17+
import { useSymbol, useOrderBook, useMarketDataConnection } from '@/services/hooks/useMarketData'
18+
19+
interface MarketData {
20+
symbol: string
21+
price: number
22+
change: number
23+
changePercent: number
24+
volume: number
25+
high24h: number
26+
low24h: number
27+
bid: number
28+
ask: number
29+
spread: number
30+
lastUpdate: Date
31+
}
32+
33+
interface OrderBookLevel {
34+
price: number
35+
size: number
36+
total: number
37+
}
38+
39+
export const MarketDataPanel: React.FC = () => {
40+
const [selectedSymbol, setSelectedSymbol] = useState('BTC/USD')
41+
42+
// Use real-time hooks
43+
const symbolData = useSymbol(selectedSymbol)
44+
const { orderBook } = useOrderBook(selectedSymbol)
45+
const { isConnected, connectionState } = useMarketDataConnection()
46+
47+
// Fallback data for when real-time data is not available
48+
const marketData = {
49+
symbol: selectedSymbol,
50+
price: symbolData.price || 43250.75,
51+
change: symbolData.change || 1250.25,
52+
changePercent: symbolData.changePercent || 2.98,
53+
volume: symbolData.volume || 125000000,
54+
high24h: symbolData.marketData?.high24h || 44100.00,
55+
low24h: symbolData.marketData?.low24h || 41800.50,
56+
bid: symbolData.quote?.bid || 43248.50,
57+
ask: symbolData.quote?.ask || 43252.25,
58+
spread: symbolData.quote ? (symbolData.quote.ask - symbolData.quote.bid) : 3.75,
59+
lastUpdate: new Date()
60+
}
61+
62+
// Use real-time order book data or fallback
63+
const bids = orderBook?.bids?.map((level, index) => ({
64+
price: level.price,
65+
size: level.size,
66+
total: orderBook.bids.slice(0, index + 1).reduce((sum, l) => sum + l.size, 0)
67+
})) || [
68+
{ price: 43248.50, size: 2.5, total: 2.5 },
69+
{ price: 43247.25, size: 1.8, total: 4.3 },
70+
{ price: 43246.00, size: 3.2, total: 7.5 },
71+
{ price: 43244.75, size: 0.9, total: 8.4 },
72+
{ price: 43243.50, size: 2.1, total: 10.5 }
73+
]
74+
75+
const asks = orderBook?.asks?.map((level, index) => ({
76+
price: level.price,
77+
size: level.size,
78+
total: orderBook.asks.slice(0, index + 1).reduce((sum, l) => sum + l.size, 0)
79+
})) || [
80+
{ price: 43252.25, size: 1.9, total: 1.9 },
81+
{ price: 43253.50, size: 2.7, total: 4.6 },
82+
{ price: 43254.75, size: 1.5, total: 6.1 },
83+
{ price: 43256.00, size: 3.1, total: 9.2 },
84+
{ price: 43257.25, size: 0.8, total: 10.0 }
85+
]
86+
87+
const symbols = ['BTC/USD', 'ETH/USD', 'AAPL', 'TSLA', 'SPY', 'QQQ', 'EUR/USD', 'GBP/USD']
88+
89+
const handleSymbolChange = (symbol: string) => {
90+
setSelectedSymbol(symbol)
91+
// In a real app, this would trigger a new data subscription
92+
setMarketData(prev => ({
93+
...prev,
94+
symbol,
95+
price: 100 + Math.random() * 1000,
96+
change: (Math.random() - 0.5) * 50,
97+
changePercent: (Math.random() - 0.5) * 10
98+
}))
99+
}
100+
101+
const formatPrice = (price: number) => {
102+
return price.toFixed(2)
103+
}
104+
105+
const formatVolume = (volume: number) => {
106+
if (volume >= 1000000) {
107+
return `${(volume / 1000000).toFixed(1)}M`
108+
}
109+
if (volume >= 1000) {
110+
return `${(volume / 1000).toFixed(1)}K`
111+
}
112+
return volume.toString()
113+
}
114+
115+
return (
116+
<Card className="h-full bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm border-0 shadow-lg">
117+
<CardHeader className="pb-4">
118+
<div className="flex items-center justify-between">
119+
<div>
120+
<CardTitle className="text-xl font-bold">Market Data</CardTitle>
121+
<CardDescription>Real-time market information and order book</CardDescription>
122+
</div>
123+
<div className="flex items-center space-x-2">
124+
<div className="flex items-center space-x-1">
125+
{isConnected ? (
126+
<Wifi className="h-4 w-4 text-green-500" />
127+
) : (
128+
<WifiOff className="h-4 w-4 text-red-500" />
129+
)}
130+
<span className="text-xs text-muted-foreground">
131+
{isConnected ? 'Live' : 'Disconnected'}
132+
</span>
133+
</div>
134+
<Button variant="outline" size="sm">
135+
<RefreshCw className="h-4 w-4" />
136+
</Button>
137+
</div>
138+
</div>
139+
</CardHeader>
140+
141+
<CardContent className="space-y-6">
142+
{/* Symbol Selector */}
143+
<div className="flex items-center space-x-4">
144+
<Select value={selectedSymbol} onValueChange={handleSymbolChange}>
145+
<SelectTrigger className="w-40">
146+
<SelectValue />
147+
</SelectTrigger>
148+
<SelectContent>
149+
{symbols.map(symbol => (
150+
<SelectItem key={symbol} value={symbol}>
151+
{symbol}
152+
</SelectItem>
153+
))}
154+
</SelectContent>
155+
</Select>
156+
<Badge variant="outline" className="text-xs">
157+
Last: {marketData.lastUpdate.toLocaleTimeString()}
158+
</Badge>
159+
</div>
160+
161+
{/* Price Information */}
162+
<div className="grid grid-cols-2 gap-4">
163+
<div className="space-y-2">
164+
<div className="flex items-center space-x-2">
165+
<span className="text-2xl font-bold">${formatPrice(marketData.price)}</span>
166+
<div className={`flex items-center space-x-1 ${
167+
marketData.change >= 0 ? 'text-green-500' : 'text-red-500'
168+
}`}>
169+
{marketData.change >= 0 ? (
170+
<TrendingUp className="h-4 w-4" />
171+
) : (
172+
<TrendingDown className="h-4 w-4" />
173+
)}
174+
<span className="font-medium">
175+
{marketData.change >= 0 ? '+' : ''}${formatPrice(marketData.change)}
176+
</span>
177+
<span className="text-sm">
178+
({marketData.changePercent >= 0 ? '+' : ''}{marketData.changePercent.toFixed(2)}%)
179+
</span>
180+
</div>
181+
</div>
182+
183+
<div className="grid grid-cols-2 gap-2 text-sm">
184+
<div>
185+
<span className="text-muted-foreground">Bid:</span>
186+
<span className="ml-2 font-medium text-green-500">${formatPrice(marketData.bid)}</span>
187+
</div>
188+
<div>
189+
<span className="text-muted-foreground">Ask:</span>
190+
<span className="ml-2 font-medium text-red-500">${formatPrice(marketData.ask)}</span>
191+
</div>
192+
<div>
193+
<span className="text-muted-foreground">Spread:</span>
194+
<span className="ml-2 font-medium">${formatPrice(marketData.spread)}</span>
195+
</div>
196+
<div>
197+
<span className="text-muted-foreground">Volume:</span>
198+
<span className="ml-2 font-medium">{formatVolume(marketData.volume)}</span>
199+
</div>
200+
</div>
201+
</div>
202+
203+
<div className="space-y-2">
204+
<div className="text-sm">
205+
<div className="flex justify-between">
206+
<span className="text-muted-foreground">24h High:</span>
207+
<span className="font-medium">${formatPrice(marketData.high24h)}</span>
208+
</div>
209+
<div className="flex justify-between">
210+
<span className="text-muted-foreground">24h Low:</span>
211+
<span className="font-medium">${formatPrice(marketData.low24h)}</span>
212+
</div>
213+
</div>
214+
</div>
215+
</div>
216+
217+
{/* Order Book */}
218+
<div className="space-y-4">
219+
<h4 className="font-semibold flex items-center space-x-2">
220+
<BarChart3 className="h-4 w-4" />
221+
<span>Order Book</span>
222+
</h4>
223+
224+
<div className="grid grid-cols-2 gap-4">
225+
{/* Bids */}
226+
<div>
227+
<div className="text-xs text-muted-foreground mb-2 grid grid-cols-3 gap-2">
228+
<span>Price</span>
229+
<span className="text-right">Size</span>
230+
<span className="text-right">Total</span>
231+
</div>
232+
<div className="space-y-1">
233+
{bids.map((bid, index) => (
234+
<div key={index} className="text-xs grid grid-cols-3 gap-2 py-1 hover:bg-green-50 dark:hover:bg-green-900/20 rounded">
235+
<span className="text-green-500 font-medium">${formatPrice(bid.price)}</span>
236+
<span className="text-right">{bid.size.toFixed(3)}</span>
237+
<span className="text-right text-muted-foreground">{bid.total.toFixed(3)}</span>
238+
</div>
239+
))}
240+
</div>
241+
</div>
242+
243+
{/* Asks */}
244+
<div>
245+
<div className="text-xs text-muted-foreground mb-2 grid grid-cols-3 gap-2">
246+
<span>Price</span>
247+
<span className="text-right">Size</span>
248+
<span className="text-right">Total</span>
249+
</div>
250+
<div className="space-y-1">
251+
{asks.map((ask, index) => (
252+
<div key={index} className="text-xs grid grid-cols-3 gap-2 py-1 hover:bg-red-50 dark:hover:bg-red-900/20 rounded">
253+
<span className="text-red-500 font-medium">${formatPrice(ask.price)}</span>
254+
<span className="text-right">{ask.size.toFixed(3)}</span>
255+
<span className="text-right text-muted-foreground">{ask.total.toFixed(3)}</span>
256+
</div>
257+
))}
258+
</div>
259+
</div>
260+
</div>
261+
</div>
262+
</CardContent>
263+
</Card>
264+
)
265+
}

0 commit comments

Comments
 (0)