Skip to content

Repository files navigation

terminal

The web trading terminal for Synthetic Bull. A dark, real-time trading interface built with Next.js 16, React 19, and TypeScript. Connects to the exchange engine over REST and WebSocket.


Running locally

cd terminal
npm install
npm run dev

Opens at http://localhost:3000. The exchange engine must be running at http://localhost:8080 or the URL set in the environment.

For production build:

npm run build
npm run start

Docker:

docker build -t synthetic-bull-terminal .
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8080 \
-e NEXT_PUBLIC_WS_URL=ws://localhost:8080 \
synthetic-bull-terminal

Environment variables

Create a .env.local file in this directory for local dev:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_WS_URL=ws://localhost:8080

Both variables are required. The NEXT_PUBLIC_ prefix means they are inlined at build time — the values baked into a Docker image point to whatever URLs were set during docker build.


Pages

RouteDescription
/Landing page — register or login
/tradeMain trading terminal
/dashboard30-day performance dashboard and trading journal
/public-marketAccessible to anyone not signed user
/chartsFor doing a proper 4x$ or 2x2 analysis of stocks

Tech stack

LibraryVersionPurpose
Next.js16.2.1Framework, app router, standalone build
React19.2.4UI
TypeScript5Types throughout
KlineCharts Pro0.1.1Candlestick chart with built-in indicators
KlineCharts9.8.12Core charting (used by Pro)
Recharts3.8.1P&L equity curve and daily P&L bar chart
Zustand5.0.12Global state (auth, symbols, portfolio, orders)
Axios1.14.0REST API client
TailwindCSSStyling

Component layout

src/
app/
page.tsx — landing / auth page
layout.tsx — root layout, font setup
trade/page.tsx — main trading terminal
dashboard/page.tsx — performance dashboard
components/
AppBoot.tsx — auth gate, bootstraps WS connection
AuthModal.tsx — register / login modal
Header.tsx — navbar, symbol ticker bar, WS latency indicator
ChartArea.tsx — chart container with resize handle
KlineProChart.tsx — KlineCharts Pro wrapper (SSR-safe dynamic import)
KlineProInner.tsx — chart logic: OHLCV feed, EMA/BOLL/MACD/VOL, fill markers
OrderBook.tsx — live bid/ask table with quantity bars
FillFlash.tsx — price flash animation on order book update
OrderEntry.tsx — LIMIT/MARKET/STOP_LIMIT order form
OpenOrders.tsx — open orders table with cancel button
PortfolioSummary.tsx — positions, cash, P&L, close position button
PnLChart.tsx — equity curve (Recharts AreaChart)
MyTrades.tsx — trade history blotter
LeaderboardPanel.tsx — ranked user table
DepthChart.tsx — bid/ask depth area chart
ToastStack.tsx — order fill / error toast notifications
ResizeHandle.tsx — draggable panel resize
dashboard/
DashStats.tsx — 5 stat cards with sparklines and arc gauges
DashNotesPanel.tsx — trades tab + notes tab with full CRUD
DashCalendar.tsx — monthly calendar, daily P&L, trade/note counts
DashOpenPositions.tsx — open positions table
DashCumPnL.tsx — 30-day cumulative P&L area chart
DashDailyPnL.tsx — daily P&L bar chart
ws/
manager.ts — WebSocket client, reconnect logic, latency tracking
store/
auth.ts — JWT, user info
symbols.ts — symbol list, active symbol
orderbook.ts — bid/ask state
trades.ts — recent trades ring buffer
portfolio.ts — cash, positions, P&L
orders.ts — open orders
ohlcv.ts — candle buffer
lib/
api.ts — axios instance with JWT interceptor
dashboard.ts — daily data grouping, stats computation
notes.ts — notes CRUD helpers
hooks/
useAnimatedNumber.ts — cubic ease-out number animation via rAF
useWebSocket.ts — subscribe to WS events by type
types/
index.ts — shared TypeScript interfaces

WebSocket connection

The WebSocketManager in src/ws/manager.ts manages a single connection per active symbol. On connect it records the open timestamp and calculates round-trip latency, which is displayed in the navbar.

Auto-reconnect fires after 3 seconds on unexpected close. Symbol changes are sent as {"type":"change_symbol","symbol":"ETH-USD"} rather than reconnecting.

Events consumed by the frontend:

  • orderbook — full LOB snapshot, replaces state
  • trade — single trade, prepended to tape
  • ohlcv — candle update (is_closed:false) or new closed candle (is_closed:true)
  • ticker — 24h stats update
  • portfolio — cash and positions after any fill
  • order_ack — confirmation a submitted order entered the LOB
  • order_cancel — confirmation of cancel

Chart indicators

All indicators are computed client-side from the OHLCV candle buffer. No backend calls are made for indicator data.

KlineCharts Pro handles: EMA(9), EMA(21), EMA(50), Bollinger Bands(20, 2σ), MACD(12,26,9), Volume.

The chart loads the full OHLCV history via GET /api/history/ohlcv/:symbol on connect, then appends live candles from the WebSocket. On each order_fill event, a fill marker is drawn on the chart at the execution price.


Dashboard data

The dashboard fetches four endpoints on load and refreshes every 30 seconds:

  • GET /api/portfolio — current positions
  • GET /api/history/pnl — all portfolio snapshots (equity curve source)
  • GET /api/history/my-trades — full trade history
  • GET /api/notes — journal notes

buildDailyData() in src/lib/dashboard.ts groups snapshots by calendar day. computeStats() derives win rate, profit factor, and average win/loss from the trade and snapshot records. All chart data is computed in the browser.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - opensoft-2026/terminal · GitHub
Skip to content

Repository files navigation

terminal

The web trading terminal for Synthetic Bull. A dark, real-time trading interface built with Next.js 16, React 19, and TypeScript. Connects to the exchange engine over REST and WebSocket.


Running locally

cd terminal
npm install
npm run dev

Opens at http://localhost:3000. The exchange engine must be running at http://localhost:8080 or the URL set in the environment.

For production build:

npm run build
npm run start

Docker:

docker build -t synthetic-bull-terminal .
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8080 \
-e NEXT_PUBLIC_WS_URL=ws://localhost:8080 \
synthetic-bull-terminal

Environment variables

Create a .env.local file in this directory for local dev:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_WS_URL=ws://localhost:8080

Both variables are required. The NEXT_PUBLIC_ prefix means they are inlined at build time — the values baked into a Docker image point to whatever URLs were set during docker build.


Pages

RouteDescription
/Landing page — register or login
/tradeMain trading terminal
/dashboard30-day performance dashboard and trading journal
/public-marketAccessible to anyone not signed user
/chartsFor doing a proper 4x$ or 2x2 analysis of stocks

Tech stack

LibraryVersionPurpose
Next.js16.2.1Framework, app router, standalone build
React19.2.4UI
TypeScript5Types throughout
KlineCharts Pro0.1.1Candlestick chart with built-in indicators
KlineCharts9.8.12Core charting (used by Pro)
Recharts3.8.1P&L equity curve and daily P&L bar chart
Zustand5.0.12Global state (auth, symbols, portfolio, orders)
Axios1.14.0REST API client
TailwindCSSStyling

Component layout

src/
app/
page.tsx — landing / auth page
layout.tsx — root layout, font setup
trade/page.tsx — main trading terminal
dashboard/page.tsx — performance dashboard
components/
AppBoot.tsx — auth gate, bootstraps WS connection
AuthModal.tsx — register / login modal
Header.tsx — navbar, symbol ticker bar, WS latency indicator
ChartArea.tsx — chart container with resize handle
KlineProChart.tsx — KlineCharts Pro wrapper (SSR-safe dynamic import)
KlineProInner.tsx — chart logic: OHLCV feed, EMA/BOLL/MACD/VOL, fill markers
OrderBook.tsx — live bid/ask table with quantity bars
FillFlash.tsx — price flash animation on order book update
OrderEntry.tsx — LIMIT/MARKET/STOP_LIMIT order form
OpenOrders.tsx — open orders table with cancel button
PortfolioSummary.tsx — positions, cash, P&L, close position button
PnLChart.tsx — equity curve (Recharts AreaChart)
MyTrades.tsx — trade history blotter
LeaderboardPanel.tsx — ranked user table
DepthChart.tsx — bid/ask depth area chart
ToastStack.tsx — order fill / error toast notifications
ResizeHandle.tsx — draggable panel resize
dashboard/
DashStats.tsx — 5 stat cards with sparklines and arc gauges
DashNotesPanel.tsx — trades tab + notes tab with full CRUD
DashCalendar.tsx — monthly calendar, daily P&L, trade/note counts
DashOpenPositions.tsx — open positions table
DashCumPnL.tsx — 30-day cumulative P&L area chart
DashDailyPnL.tsx — daily P&L bar chart
ws/
manager.ts — WebSocket client, reconnect logic, latency tracking
store/
auth.ts — JWT, user info
symbols.ts — symbol list, active symbol
orderbook.ts — bid/ask state
trades.ts — recent trades ring buffer
portfolio.ts — cash, positions, P&L
orders.ts — open orders
ohlcv.ts — candle buffer
lib/
api.ts — axios instance with JWT interceptor
dashboard.ts — daily data grouping, stats computation
notes.ts — notes CRUD helpers
hooks/
useAnimatedNumber.ts — cubic ease-out number animation via rAF
useWebSocket.ts — subscribe to WS events by type
types/
index.ts — shared TypeScript interfaces

WebSocket connection

The WebSocketManager in src/ws/manager.ts manages a single connection per active symbol. On connect it records the open timestamp and calculates round-trip latency, which is displayed in the navbar.

Auto-reconnect fires after 3 seconds on unexpected close. Symbol changes are sent as {"type":"change_symbol","symbol":"ETH-USD"} rather than reconnecting.

Events consumed by the frontend:

  • orderbook — full LOB snapshot, replaces state
  • trade — single trade, prepended to tape
  • ohlcv — candle update (is_closed:false) or new closed candle (is_closed:true)
  • ticker — 24h stats update
  • portfolio — cash and positions after any fill
  • order_ack — confirmation a submitted order entered the LOB
  • order_cancel — confirmation of cancel

Chart indicators

All indicators are computed client-side from the OHLCV candle buffer. No backend calls are made for indicator data.

KlineCharts Pro handles: EMA(9), EMA(21), EMA(50), Bollinger Bands(20, 2σ), MACD(12,26,9), Volume.

The chart loads the full OHLCV history via GET /api/history/ohlcv/:symbol on connect, then appends live candles from the WebSocket. On each order_fill event, a fill marker is drawn on the chart at the execution price.


Dashboard data

The dashboard fetches four endpoints on load and refreshes every 30 seconds:

  • GET /api/portfolio — current positions
  • GET /api/history/pnl — all portfolio snapshots (equity curve source)
  • GET /api/history/my-trades — full trade history
  • GET /api/notes — journal notes

buildDailyData() in src/lib/dashboard.ts groups snapshots by calendar day. computeStats() derives win rate, profit factor, and average win/loss from the trade and snapshot records. All chart data is computed in the browser.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - opensoft-2026/terminal · GitHub
Skip to content

Repository files navigation

terminal

The web trading terminal for Synthetic Bull. A dark, real-time trading interface built with Next.js 16, React 19, and TypeScript. Connects to the exchange engine over REST and WebSocket.


Running locally

cd terminal
npm install
npm run dev

Opens at http://localhost:3000. The exchange engine must be running at http://localhost:8080 or the URL set in the environment.

For production build:

npm run build
npm run start

Docker:

docker build -t synthetic-bull-terminal .
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8080 \
-e NEXT_PUBLIC_WS_URL=ws://localhost:8080 \
synthetic-bull-terminal

Environment variables

Create a .env.local file in this directory for local dev:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_WS_URL=ws://localhost:8080

Both variables are required. The NEXT_PUBLIC_ prefix means they are inlined at build time — the values baked into a Docker image point to whatever URLs were set during docker build.


Pages

RouteDescription
/Landing page — register or login
/tradeMain trading terminal
/dashboard30-day performance dashboard and trading journal
/public-marketAccessible to anyone not signed user
/chartsFor doing a proper 4x$ or 2x2 analysis of stocks

Tech stack

LibraryVersionPurpose
Next.js16.2.1Framework, app router, standalone build
React19.2.4UI
TypeScript5Types throughout
KlineCharts Pro0.1.1Candlestick chart with built-in indicators
KlineCharts9.8.12Core charting (used by Pro)
Recharts3.8.1P&L equity curve and daily P&L bar chart
Zustand5.0.12Global state (auth, symbols, portfolio, orders)
Axios1.14.0REST API client
TailwindCSSStyling

Component layout

src/
app/
page.tsx — landing / auth page
layout.tsx — root layout, font setup
trade/page.tsx — main trading terminal
dashboard/page.tsx — performance dashboard
components/
AppBoot.tsx — auth gate, bootstraps WS connection
AuthModal.tsx — register / login modal
Header.tsx — navbar, symbol ticker bar, WS latency indicator
ChartArea.tsx — chart container with resize handle
KlineProChart.tsx — KlineCharts Pro wrapper (SSR-safe dynamic import)
KlineProInner.tsx — chart logic: OHLCV feed, EMA/BOLL/MACD/VOL, fill markers
OrderBook.tsx — live bid/ask table with quantity bars
FillFlash.tsx — price flash animation on order book update
OrderEntry.tsx — LIMIT/MARKET/STOP_LIMIT order form
OpenOrders.tsx — open orders table with cancel button
PortfolioSummary.tsx — positions, cash, P&L, close position button
PnLChart.tsx — equity curve (Recharts AreaChart)
MyTrades.tsx — trade history blotter
LeaderboardPanel.tsx — ranked user table
DepthChart.tsx — bid/ask depth area chart
ToastStack.tsx — order fill / error toast notifications
ResizeHandle.tsx — draggable panel resize
dashboard/
DashStats.tsx — 5 stat cards with sparklines and arc gauges
DashNotesPanel.tsx — trades tab + notes tab with full CRUD
DashCalendar.tsx — monthly calendar, daily P&L, trade/note counts
DashOpenPositions.tsx — open positions table
DashCumPnL.tsx — 30-day cumulative P&L area chart
DashDailyPnL.tsx — daily P&L bar chart
ws/
manager.ts — WebSocket client, reconnect logic, latency tracking
store/
auth.ts — JWT, user info
symbols.ts — symbol list, active symbol
orderbook.ts — bid/ask state
trades.ts — recent trades ring buffer
portfolio.ts — cash, positions, P&L
orders.ts — open orders
ohlcv.ts — candle buffer
lib/
api.ts — axios instance with JWT interceptor
dashboard.ts — daily data grouping, stats computation
notes.ts — notes CRUD helpers
hooks/
useAnimatedNumber.ts — cubic ease-out number animation via rAF
useWebSocket.ts — subscribe to WS events by type
types/
index.ts — shared TypeScript interfaces

WebSocket connection

The WebSocketManager in src/ws/manager.ts manages a single connection per active symbol. On connect it records the open timestamp and calculates round-trip latency, which is displayed in the navbar.

Auto-reconnect fires after 3 seconds on unexpected close. Symbol changes are sent as {"type":"change_symbol","symbol":"ETH-USD"} rather than reconnecting.

Events consumed by the frontend:

  • orderbook — full LOB snapshot, replaces state
  • trade — single trade, prepended to tape
  • ohlcv — candle update (is_closed:false) or new closed candle (is_closed:true)
  • ticker — 24h stats update
  • portfolio — cash and positions after any fill
  • order_ack — confirmation a submitted order entered the LOB
  • order_cancel — confirmation of cancel

Chart indicators

All indicators are computed client-side from the OHLCV candle buffer. No backend calls are made for indicator data.

KlineCharts Pro handles: EMA(9), EMA(21), EMA(50), Bollinger Bands(20, 2σ), MACD(12,26,9), Volume.

The chart loads the full OHLCV history via GET /api/history/ohlcv/:symbol on connect, then appends live candles from the WebSocket. On each order_fill event, a fill marker is drawn on the chart at the execution price.


Dashboard data

The dashboard fetches four endpoints on load and refreshes every 30 seconds:

  • GET /api/portfolio — current positions
  • GET /api/history/pnl — all portfolio snapshots (equity curve source)
  • GET /api/history/my-trades — full trade history
  • GET /api/notes — journal notes

buildDailyData() in src/lib/dashboard.ts groups snapshots by calendar day. computeStats() derives win rate, profit factor, and average win/loss from the trade and snapshot records. All chart data is computed in the browser.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - opensoft-2026/terminal · GitHub
Skip to content

Repository files navigation

terminal

The web trading terminal for Synthetic Bull. A dark, real-time trading interface built with Next.js 16, React 19, and TypeScript. Connects to the exchange engine over REST and WebSocket.


Running locally

cd terminal
npm install
npm run dev

Opens at http://localhost:3000. The exchange engine must be running at http://localhost:8080 or the URL set in the environment.

For production build:

npm run build
npm run start

Docker:

docker build -t synthetic-bull-terminal .
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8080 \
-e NEXT_PUBLIC_WS_URL=ws://localhost:8080 \
synthetic-bull-terminal

Environment variables

Create a .env.local file in this directory for local dev:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_WS_URL=ws://localhost:8080

Both variables are required. The NEXT_PUBLIC_ prefix means they are inlined at build time — the values baked into a Docker image point to whatever URLs were set during docker build.


Pages

RouteDescription
/Landing page — register or login
/tradeMain trading terminal
/dashboard30-day performance dashboard and trading journal
/public-marketAccessible to anyone not signed user
/chartsFor doing a proper 4x$ or 2x2 analysis of stocks

Tech stack

LibraryVersionPurpose
Next.js16.2.1Framework, app router, standalone build
React19.2.4UI
TypeScript5Types throughout
KlineCharts Pro0.1.1Candlestick chart with built-in indicators
KlineCharts9.8.12Core charting (used by Pro)
Recharts3.8.1P&L equity curve and daily P&L bar chart
Zustand5.0.12Global state (auth, symbols, portfolio, orders)
Axios1.14.0REST API client
TailwindCSSStyling

Component layout

src/
app/
page.tsx — landing / auth page
layout.tsx — root layout, font setup
trade/page.tsx — main trading terminal
dashboard/page.tsx — performance dashboard
components/
AppBoot.tsx — auth gate, bootstraps WS connection
AuthModal.tsx — register / login modal
Header.tsx — navbar, symbol ticker bar, WS latency indicator
ChartArea.tsx — chart container with resize handle
KlineProChart.tsx — KlineCharts Pro wrapper (SSR-safe dynamic import)
KlineProInner.tsx — chart logic: OHLCV feed, EMA/BOLL/MACD/VOL, fill markers
OrderBook.tsx — live bid/ask table with quantity bars
FillFlash.tsx — price flash animation on order book update
OrderEntry.tsx — LIMIT/MARKET/STOP_LIMIT order form
OpenOrders.tsx — open orders table with cancel button
PortfolioSummary.tsx — positions, cash, P&L, close position button
PnLChart.tsx — equity curve (Recharts AreaChart)
MyTrades.tsx — trade history blotter
LeaderboardPanel.tsx — ranked user table
DepthChart.tsx — bid/ask depth area chart
ToastStack.tsx — order fill / error toast notifications
ResizeHandle.tsx — draggable panel resize
dashboard/
DashStats.tsx — 5 stat cards with sparklines and arc gauges
DashNotesPanel.tsx — trades tab + notes tab with full CRUD
DashCalendar.tsx — monthly calendar, daily P&L, trade/note counts
DashOpenPositions.tsx — open positions table
DashCumPnL.tsx — 30-day cumulative P&L area chart
DashDailyPnL.tsx — daily P&L bar chart
ws/
manager.ts — WebSocket client, reconnect logic, latency tracking
store/
auth.ts — JWT, user info
symbols.ts — symbol list, active symbol
orderbook.ts — bid/ask state
trades.ts — recent trades ring buffer
portfolio.ts — cash, positions, P&L
orders.ts — open orders
ohlcv.ts — candle buffer
lib/
api.ts — axios instance with JWT interceptor
dashboard.ts — daily data grouping, stats computation
notes.ts — notes CRUD helpers
hooks/
useAnimatedNumber.ts — cubic ease-out number animation via rAF
useWebSocket.ts — subscribe to WS events by type
types/
index.ts — shared TypeScript interfaces

WebSocket connection

The WebSocketManager in src/ws/manager.ts manages a single connection per active symbol. On connect it records the open timestamp and calculates round-trip latency, which is displayed in the navbar.

Auto-reconnect fires after 3 seconds on unexpected close. Symbol changes are sent as {"type":"change_symbol","symbol":"ETH-USD"} rather than reconnecting.

Events consumed by the frontend:

  • orderbook — full LOB snapshot, replaces state
  • trade — single trade, prepended to tape
  • ohlcv — candle update (is_closed:false) or new closed candle (is_closed:true)
  • ticker — 24h stats update
  • portfolio — cash and positions after any fill
  • order_ack — confirmation a submitted order entered the LOB
  • order_cancel — confirmation of cancel

Chart indicators

All indicators are computed client-side from the OHLCV candle buffer. No backend calls are made for indicator data.

KlineCharts Pro handles: EMA(9), EMA(21), EMA(50), Bollinger Bands(20, 2σ), MACD(12,26,9), Volume.

The chart loads the full OHLCV history via GET /api/history/ohlcv/:symbol on connect, then appends live candles from the WebSocket. On each order_fill event, a fill marker is drawn on the chart at the execution price.


Dashboard data

The dashboard fetches four endpoints on load and refreshes every 30 seconds:

  • GET /api/portfolio — current positions
  • GET /api/history/pnl — all portfolio snapshots (equity curve source)
  • GET /api/history/my-trades — full trade history
  • GET /api/notes — journal notes

buildDailyData() in src/lib/dashboard.ts groups snapshots by calendar day. computeStats() derives win rate, profit factor, and average win/loss from the trade and snapshot records. All chart data is computed in the browser.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - opensoft-2026/terminal · GitHub
Skip to content

Repository files navigation

terminal

The web trading terminal for Synthetic Bull. A dark, real-time trading interface built with Next.js 16, React 19, and TypeScript. Connects to the exchange engine over REST and WebSocket.


Running locally

cd terminal
npm install
npm run dev

Opens at http://localhost:3000. The exchange engine must be running at http://localhost:8080 or the URL set in the environment.

For production build:

npm run build
npm run start

Docker:

docker build -t synthetic-bull-terminal .
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8080 \
-e NEXT_PUBLIC_WS_URL=ws://localhost:8080 \
synthetic-bull-terminal

Environment variables

Create a .env.local file in this directory for local dev:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_WS_URL=ws://localhost:8080

Both variables are required. The NEXT_PUBLIC_ prefix means they are inlined at build time — the values baked into a Docker image point to whatever URLs were set during docker build.


Pages

RouteDescription
/Landing page — register or login
/tradeMain trading terminal
/dashboard30-day performance dashboard and trading journal
/public-marketAccessible to anyone not signed user
/chartsFor doing a proper 4x$ or 2x2 analysis of stocks

Tech stack

LibraryVersionPurpose
Next.js16.2.1Framework, app router, standalone build
React19.2.4UI
TypeScript5Types throughout
KlineCharts Pro0.1.1Candlestick chart with built-in indicators
KlineCharts9.8.12Core charting (used by Pro)
Recharts3.8.1P&L equity curve and daily P&L bar chart
Zustand5.0.12Global state (auth, symbols, portfolio, orders)
Axios1.14.0REST API client
TailwindCSSStyling

Component layout

src/
app/
page.tsx — landing / auth page
layout.tsx — root layout, font setup
trade/page.tsx — main trading terminal
dashboard/page.tsx — performance dashboard
components/
AppBoot.tsx — auth gate, bootstraps WS connection
AuthModal.tsx — register / login modal
Header.tsx — navbar, symbol ticker bar, WS latency indicator
ChartArea.tsx — chart container with resize handle
KlineProChart.tsx — KlineCharts Pro wrapper (SSR-safe dynamic import)
KlineProInner.tsx — chart logic: OHLCV feed, EMA/BOLL/MACD/VOL, fill markers
OrderBook.tsx — live bid/ask table with quantity bars
FillFlash.tsx — price flash animation on order book update
OrderEntry.tsx — LIMIT/MARKET/STOP_LIMIT order form
OpenOrders.tsx — open orders table with cancel button
PortfolioSummary.tsx — positions, cash, P&L, close position button
PnLChart.tsx — equity curve (Recharts AreaChart)
MyTrades.tsx — trade history blotter
LeaderboardPanel.tsx — ranked user table
DepthChart.tsx — bid/ask depth area chart
ToastStack.tsx — order fill / error toast notifications
ResizeHandle.tsx — draggable panel resize
dashboard/
DashStats.tsx — 5 stat cards with sparklines and arc gauges
DashNotesPanel.tsx — trades tab + notes tab with full CRUD
DashCalendar.tsx — monthly calendar, daily P&L, trade/note counts
DashOpenPositions.tsx — open positions table
DashCumPnL.tsx — 30-day cumulative P&L area chart
DashDailyPnL.tsx — daily P&L bar chart
ws/
manager.ts — WebSocket client, reconnect logic, latency tracking
store/
auth.ts — JWT, user info
symbols.ts — symbol list, active symbol
orderbook.ts — bid/ask state
trades.ts — recent trades ring buffer
portfolio.ts — cash, positions, P&L
orders.ts — open orders
ohlcv.ts — candle buffer
lib/
api.ts — axios instance with JWT interceptor
dashboard.ts — daily data grouping, stats computation
notes.ts — notes CRUD helpers
hooks/
useAnimatedNumber.ts — cubic ease-out number animation via rAF
useWebSocket.ts — subscribe to WS events by type
types/
index.ts — shared TypeScript interfaces

WebSocket connection

The WebSocketManager in src/ws/manager.ts manages a single connection per active symbol. On connect it records the open timestamp and calculates round-trip latency, which is displayed in the navbar.

Auto-reconnect fires after 3 seconds on unexpected close. Symbol changes are sent as {"type":"change_symbol","symbol":"ETH-USD"} rather than reconnecting.

Events consumed by the frontend:

  • orderbook — full LOB snapshot, replaces state
  • trade — single trade, prepended to tape
  • ohlcv — candle update (is_closed:false) or new closed candle (is_closed:true)
  • ticker — 24h stats update
  • portfolio — cash and positions after any fill
  • order_ack — confirmation a submitted order entered the LOB
  • order_cancel — confirmation of cancel

Chart indicators

All indicators are computed client-side from the OHLCV candle buffer. No backend calls are made for indicator data.

KlineCharts Pro handles: EMA(9), EMA(21), EMA(50), Bollinger Bands(20, 2σ), MACD(12,26,9), Volume.

The chart loads the full OHLCV history via GET /api/history/ohlcv/:symbol on connect, then appends live candles from the WebSocket. On each order_fill event, a fill marker is drawn on the chart at the execution price.


Dashboard data

The dashboard fetches four endpoints on load and refreshes every 30 seconds:

  • GET /api/portfolio — current positions
  • GET /api/history/pnl — all portfolio snapshots (equity curve source)
  • GET /api/history/my-trades — full trade history
  • GET /api/notes — journal notes

buildDailyData() in src/lib/dashboard.ts groups snapshots by calendar day. computeStats() derives win rate, profit factor, and average win/loss from the trade and snapshot records. All chart data is computed in the browser.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - opensoft-2026/terminal · GitHub
Skip to content

Repository files navigation

terminal

The web trading terminal for Synthetic Bull. A dark, real-time trading interface built with Next.js 16, React 19, and TypeScript. Connects to the exchange engine over REST and WebSocket.


Running locally

cd terminal
npm install
npm run dev

Opens at http://localhost:3000. The exchange engine must be running at http://localhost:8080 or the URL set in the environment.

For production build:

npm run build
npm run start

Docker:

docker build -t synthetic-bull-terminal .
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8080 \
-e NEXT_PUBLIC_WS_URL=ws://localhost:8080 \
synthetic-bull-terminal

Environment variables

Create a .env.local file in this directory for local dev:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_WS_URL=ws://localhost:8080

Both variables are required. The NEXT_PUBLIC_ prefix means they are inlined at build time — the values baked into a Docker image point to whatever URLs were set during docker build.


Pages

RouteDescription
/Landing page — register or login
/tradeMain trading terminal
/dashboard30-day performance dashboard and trading journal
/public-marketAccessible to anyone not signed user
/chartsFor doing a proper 4x$ or 2x2 analysis of stocks

Tech stack

LibraryVersionPurpose
Next.js16.2.1Framework, app router, standalone build
React19.2.4UI
TypeScript5Types throughout
KlineCharts Pro0.1.1Candlestick chart with built-in indicators
KlineCharts9.8.12Core charting (used by Pro)
Recharts3.8.1P&L equity curve and daily P&L bar chart
Zustand5.0.12Global state (auth, symbols, portfolio, orders)
Axios1.14.0REST API client
TailwindCSSStyling

Component layout

src/
app/
page.tsx — landing / auth page
layout.tsx — root layout, font setup
trade/page.tsx — main trading terminal
dashboard/page.tsx — performance dashboard
components/
AppBoot.tsx — auth gate, bootstraps WS connection
AuthModal.tsx — register / login modal
Header.tsx — navbar, symbol ticker bar, WS latency indicator
ChartArea.tsx — chart container with resize handle
KlineProChart.tsx — KlineCharts Pro wrapper (SSR-safe dynamic import)
KlineProInner.tsx — chart logic: OHLCV feed, EMA/BOLL/MACD/VOL, fill markers
OrderBook.tsx — live bid/ask table with quantity bars
FillFlash.tsx — price flash animation on order book update
OrderEntry.tsx — LIMIT/MARKET/STOP_LIMIT order form
OpenOrders.tsx — open orders table with cancel button
PortfolioSummary.tsx — positions, cash, P&L, close position button
PnLChart.tsx — equity curve (Recharts AreaChart)
MyTrades.tsx — trade history blotter
LeaderboardPanel.tsx — ranked user table
DepthChart.tsx — bid/ask depth area chart
ToastStack.tsx — order fill / error toast notifications
ResizeHandle.tsx — draggable panel resize
dashboard/
DashStats.tsx — 5 stat cards with sparklines and arc gauges
DashNotesPanel.tsx — trades tab + notes tab with full CRUD
DashCalendar.tsx — monthly calendar, daily P&L, trade/note counts
DashOpenPositions.tsx — open positions table
DashCumPnL.tsx — 30-day cumulative P&L area chart
DashDailyPnL.tsx — daily P&L bar chart
ws/
manager.ts — WebSocket client, reconnect logic, latency tracking
store/
auth.ts — JWT, user info
symbols.ts — symbol list, active symbol
orderbook.ts — bid/ask state
trades.ts — recent trades ring buffer
portfolio.ts — cash, positions, P&L
orders.ts — open orders
ohlcv.ts — candle buffer
lib/
api.ts — axios instance with JWT interceptor
dashboard.ts — daily data grouping, stats computation
notes.ts — notes CRUD helpers
hooks/
useAnimatedNumber.ts — cubic ease-out number animation via rAF
useWebSocket.ts — subscribe to WS events by type
types/
index.ts — shared TypeScript interfaces

WebSocket connection

The WebSocketManager in src/ws/manager.ts manages a single connection per active symbol. On connect it records the open timestamp and calculates round-trip latency, which is displayed in the navbar.

Auto-reconnect fires after 3 seconds on unexpected close. Symbol changes are sent as {"type":"change_symbol","symbol":"ETH-USD"} rather than reconnecting.

Events consumed by the frontend:

  • orderbook — full LOB snapshot, replaces state
  • trade — single trade, prepended to tape
  • ohlcv — candle update (is_closed:false) or new closed candle (is_closed:true)
  • ticker — 24h stats update
  • portfolio — cash and positions after any fill
  • order_ack — confirmation a submitted order entered the LOB
  • order_cancel — confirmation of cancel

Chart indicators

All indicators are computed client-side from the OHLCV candle buffer. No backend calls are made for indicator data.

KlineCharts Pro handles: EMA(9), EMA(21), EMA(50), Bollinger Bands(20, 2σ), MACD(12,26,9), Volume.

The chart loads the full OHLCV history via GET /api/history/ohlcv/:symbol on connect, then appends live candles from the WebSocket. On each order_fill event, a fill marker is drawn on the chart at the execution price.


Dashboard data

The dashboard fetches four endpoints on load and refreshes every 30 seconds:

  • GET /api/portfolio — current positions
  • GET /api/history/pnl — all portfolio snapshots (equity curve source)
  • GET /api/history/my-trades — full trade history
  • GET /api/notes — journal notes

buildDailyData() in src/lib/dashboard.ts groups snapshots by calendar day. computeStats() derives win rate, profit factor, and average win/loss from the trade and snapshot records. All chart data is computed in the browser.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - opensoft-2026/terminal · GitHub
Skip to content

Repository files navigation

terminal

The web trading terminal for Synthetic Bull. A dark, real-time trading interface built with Next.js 16, React 19, and TypeScript. Connects to the exchange engine over REST and WebSocket.


Running locally

cd terminal
npm install
npm run dev

Opens at http://localhost:3000. The exchange engine must be running at http://localhost:8080 or the URL set in the environment.

For production build:

npm run build
npm run start

Docker:

docker build -t synthetic-bull-terminal .
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8080 \
-e NEXT_PUBLIC_WS_URL=ws://localhost:8080 \
synthetic-bull-terminal

Environment variables

Create a .env.local file in this directory for local dev:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_WS_URL=ws://localhost:8080

Both variables are required. The NEXT_PUBLIC_ prefix means they are inlined at build time — the values baked into a Docker image point to whatever URLs were set during docker build.


Pages

RouteDescription
/Landing page — register or login
/tradeMain trading terminal
/dashboard30-day performance dashboard and trading journal
/public-marketAccessible to anyone not signed user
/chartsFor doing a proper 4x$ or 2x2 analysis of stocks

Tech stack

LibraryVersionPurpose
Next.js16.2.1Framework, app router, standalone build
React19.2.4UI
TypeScript5Types throughout
KlineCharts Pro0.1.1Candlestick chart with built-in indicators
KlineCharts9.8.12Core charting (used by Pro)
Recharts3.8.1P&L equity curve and daily P&L bar chart
Zustand5.0.12Global state (auth, symbols, portfolio, orders)
Axios1.14.0REST API client
TailwindCSSStyling

Component layout

src/
app/
page.tsx — landing / auth page
layout.tsx — root layout, font setup
trade/page.tsx — main trading terminal
dashboard/page.tsx — performance dashboard
components/
AppBoot.tsx — auth gate, bootstraps WS connection
AuthModal.tsx — register / login modal
Header.tsx — navbar, symbol ticker bar, WS latency indicator
ChartArea.tsx — chart container with resize handle
KlineProChart.tsx — KlineCharts Pro wrapper (SSR-safe dynamic import)
KlineProInner.tsx — chart logic: OHLCV feed, EMA/BOLL/MACD/VOL, fill markers
OrderBook.tsx — live bid/ask table with quantity bars
FillFlash.tsx — price flash animation on order book update
OrderEntry.tsx — LIMIT/MARKET/STOP_LIMIT order form
OpenOrders.tsx — open orders table with cancel button
PortfolioSummary.tsx — positions, cash, P&L, close position button
PnLChart.tsx — equity curve (Recharts AreaChart)
MyTrades.tsx — trade history blotter
LeaderboardPanel.tsx — ranked user table
DepthChart.tsx — bid/ask depth area chart
ToastStack.tsx — order fill / error toast notifications
ResizeHandle.tsx — draggable panel resize
dashboard/
DashStats.tsx — 5 stat cards with sparklines and arc gauges
DashNotesPanel.tsx — trades tab + notes tab with full CRUD
DashCalendar.tsx — monthly calendar, daily P&L, trade/note counts
DashOpenPositions.tsx — open positions table
DashCumPnL.tsx — 30-day cumulative P&L area chart
DashDailyPnL.tsx — daily P&L bar chart
ws/
manager.ts — WebSocket client, reconnect logic, latency tracking
store/
auth.ts — JWT, user info
symbols.ts — symbol list, active symbol
orderbook.ts — bid/ask state
trades.ts — recent trades ring buffer
portfolio.ts — cash, positions, P&L
orders.ts — open orders
ohlcv.ts — candle buffer
lib/
api.ts — axios instance with JWT interceptor
dashboard.ts — daily data grouping, stats computation
notes.ts — notes CRUD helpers
hooks/
useAnimatedNumber.ts — cubic ease-out number animation via rAF
useWebSocket.ts — subscribe to WS events by type
types/
index.ts — shared TypeScript interfaces

WebSocket connection

The WebSocketManager in src/ws/manager.ts manages a single connection per active symbol. On connect it records the open timestamp and calculates round-trip latency, which is displayed in the navbar.

Auto-reconnect fires after 3 seconds on unexpected close. Symbol changes are sent as {"type":"change_symbol","symbol":"ETH-USD"} rather than reconnecting.

Events consumed by the frontend:

  • orderbook — full LOB snapshot, replaces state
  • trade — single trade, prepended to tape
  • ohlcv — candle update (is_closed:false) or new closed candle (is_closed:true)
  • ticker — 24h stats update
  • portfolio — cash and positions after any fill
  • order_ack — confirmation a submitted order entered the LOB
  • order_cancel — confirmation of cancel

Chart indicators

All indicators are computed client-side from the OHLCV candle buffer. No backend calls are made for indicator data.

KlineCharts Pro handles: EMA(9), EMA(21), EMA(50), Bollinger Bands(20, 2σ), MACD(12,26,9), Volume.

The chart loads the full OHLCV history via GET /api/history/ohlcv/:symbol on connect, then appends live candles from the WebSocket. On each order_fill event, a fill marker is drawn on the chart at the execution price.


Dashboard data

The dashboard fetches four endpoints on load and refreshes every 30 seconds:

  • GET /api/portfolio — current positions
  • GET /api/history/pnl — all portfolio snapshots (equity curve source)
  • GET /api/history/my-trades — full trade history
  • GET /api/notes — journal notes

buildDailyData() in src/lib/dashboard.ts groups snapshots by calendar day. computeStats() derives win rate, profit factor, and average win/loss from the trade and snapshot records. All chart data is computed in the browser.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - opensoft-2026/terminal · GitHub
Skip to content

Repository files navigation

terminal

The web trading terminal for Synthetic Bull. A dark, real-time trading interface built with Next.js 16, React 19, and TypeScript. Connects to the exchange engine over REST and WebSocket.


Running locally

cd terminal
npm install
npm run dev

Opens at http://localhost:3000. The exchange engine must be running at http://localhost:8080 or the URL set in the environment.

For production build:

npm run build
npm run start

Docker:

docker build -t synthetic-bull-terminal .
docker run -p 3000:3000 \
-e NEXT_PUBLIC_API_URL=http://localhost:8080 \
-e NEXT_PUBLIC_WS_URL=ws://localhost:8080 \
synthetic-bull-terminal

Environment variables

Create a .env.local file in this directory for local dev:

NEXT_PUBLIC_API_URL=http://localhost:8080
NEXT_PUBLIC_WS_URL=ws://localhost:8080

Both variables are required. The NEXT_PUBLIC_ prefix means they are inlined at build time — the values baked into a Docker image point to whatever URLs were set during docker build.


Pages

RouteDescription
/Landing page — register or login
/tradeMain trading terminal
/dashboard30-day performance dashboard and trading journal
/public-marketAccessible to anyone not signed user
/chartsFor doing a proper 4x$ or 2x2 analysis of stocks

Tech stack

LibraryVersionPurpose
Next.js16.2.1Framework, app router, standalone build
React19.2.4UI
TypeScript5Types throughout
KlineCharts Pro0.1.1Candlestick chart with built-in indicators
KlineCharts9.8.12Core charting (used by Pro)
Recharts3.8.1P&L equity curve and daily P&L bar chart
Zustand5.0.12Global state (auth, symbols, portfolio, orders)
Axios1.14.0REST API client
TailwindCSSStyling

Component layout

src/
app/
page.tsx — landing / auth page
layout.tsx — root layout, font setup
trade/page.tsx — main trading terminal
dashboard/page.tsx — performance dashboard
components/
AppBoot.tsx — auth gate, bootstraps WS connection
AuthModal.tsx — register / login modal
Header.tsx — navbar, symbol ticker bar, WS latency indicator
ChartArea.tsx — chart container with resize handle
KlineProChart.tsx — KlineCharts Pro wrapper (SSR-safe dynamic import)
KlineProInner.tsx — chart logic: OHLCV feed, EMA/BOLL/MACD/VOL, fill markers
OrderBook.tsx — live bid/ask table with quantity bars
FillFlash.tsx — price flash animation on order book update
OrderEntry.tsx — LIMIT/MARKET/STOP_LIMIT order form
OpenOrders.tsx — open orders table with cancel button
PortfolioSummary.tsx — positions, cash, P&L, close position button
PnLChart.tsx — equity curve (Recharts AreaChart)
MyTrades.tsx — trade history blotter
LeaderboardPanel.tsx — ranked user table
DepthChart.tsx — bid/ask depth area chart
ToastStack.tsx — order fill / error toast notifications
ResizeHandle.tsx — draggable panel resize
dashboard/
DashStats.tsx — 5 stat cards with sparklines and arc gauges
DashNotesPanel.tsx — trades tab + notes tab with full CRUD
DashCalendar.tsx — monthly calendar, daily P&L, trade/note counts
DashOpenPositions.tsx — open positions table
DashCumPnL.tsx — 30-day cumulative P&L area chart
DashDailyPnL.tsx — daily P&L bar chart
ws/
manager.ts — WebSocket client, reconnect logic, latency tracking
store/
auth.ts — JWT, user info
symbols.ts — symbol list, active symbol
orderbook.ts — bid/ask state
trades.ts — recent trades ring buffer
portfolio.ts — cash, positions, P&L
orders.ts — open orders
ohlcv.ts — candle buffer
lib/
api.ts — axios instance with JWT interceptor
dashboard.ts — daily data grouping, stats computation
notes.ts — notes CRUD helpers
hooks/
useAnimatedNumber.ts — cubic ease-out number animation via rAF
useWebSocket.ts — subscribe to WS events by type
types/
index.ts — shared TypeScript interfaces

WebSocket connection

The WebSocketManager in src/ws/manager.ts manages a single connection per active symbol. On connect it records the open timestamp and calculates round-trip latency, which is displayed in the navbar.

Auto-reconnect fires after 3 seconds on unexpected close. Symbol changes are sent as {"type":"change_symbol","symbol":"ETH-USD"} rather than reconnecting.

Events consumed by the frontend:

  • orderbook — full LOB snapshot, replaces state
  • trade — single trade, prepended to tape
  • ohlcv — candle update (is_closed:false) or new closed candle (is_closed:true)
  • ticker — 24h stats update
  • portfolio — cash and positions after any fill
  • order_ack — confirmation a submitted order entered the LOB
  • order_cancel — confirmation of cancel

Chart indicators

All indicators are computed client-side from the OHLCV candle buffer. No backend calls are made for indicator data.

KlineCharts Pro handles: EMA(9), EMA(21), EMA(50), Bollinger Bands(20, 2σ), MACD(12,26,9), Volume.

The chart loads the full OHLCV history via GET /api/history/ohlcv/:symbol on connect, then appends live candles from the WebSocket. On each order_fill event, a fill marker is drawn on the chart at the execution price.


Dashboard data

The dashboard fetches four endpoints on load and refreshes every 30 seconds:

  • GET /api/portfolio — current positions
  • GET /api/history/pnl — all portfolio snapshots (equity curve source)
  • GET /api/history/my-trades — full trade history
  • GET /api/notes — journal notes

buildDailyData() in src/lib/dashboard.ts groups snapshots by calendar day. computeStats() derives win rate, profit factor, and average win/loss from the trade and snapshot records. All chart data is computed in the browser.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages