repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | /** |
| #2 | * HERMES x402 TUI — Market Data Panel |
| #3 | * |
| #4 | * Shows SOL price, trending tokens, and last trade signal. |
| #5 | */ |
| #6 | |
| #7 | import chalk from 'chalk'; |
| #8 | import type { DashboardState } from '../state.js'; |
| #9 | |
| #10 | function pct(n: number): string { |
| #11 | const s = (n > 0 ? '+' : '') + n.toFixed(1) + '%'; |
| #12 | return n > 0 ? chalk.green(s) : n < 0 ? chalk.red(s) : chalk.gray(s); |
| #13 | } |
| #14 | |
| #15 | function bar(n: number, max = 25): string { |
| #16 | const width = Math.round(Math.abs(n) / max * 8); |
| #17 | const filled = '█'.repeat(Math.min(width, 8)); |
| #18 | return n >= 0 ? chalk.green(filled.padEnd(8)) : chalk.red(filled.padEnd(8)); |
| #19 | } |
| #20 | |
| #21 | export function renderMarket(state: DashboardState, height: number): string[] { |
| #22 | const lines: string[] = []; |
| #23 | const { solPrice, solChange24h, trending, paperPnl, winRate, totalTrades, lastSignal } = state; |
| #24 | |
| #25 | // SOL price |
| #26 | lines.push(chalk.cyan('┌─ MARKET DATA ──────────────────┐')); |
| #27 | const solStr = solPrice > 0 ? `$${solPrice.toFixed(2)}` : '---'; |
| #28 | lines.push(`│ ${chalk.bold.white('SOL')} ${chalk.bold.yellow(solStr.padEnd(10))} ${pct(solChange24h).padEnd(9)} │`); |
| #29 | lines.push(chalk.gray('│ ──────────────────────────── │')); |
| #30 | |
| #31 | // Trending tokens |
| #32 | lines.push(`│ ${chalk.cyan('TRENDING TOKENS')} │`); |
| #33 | const toShow = trending.slice(0, 6); |
| #34 | for (const t of toShow) { |
| #35 | const sym = t.symbol.slice(0, 8).padEnd(8); |
| #36 | const b = bar(t.change); |
| #37 | const change = pct(t.change); |
| #38 | lines.push(`│ ${chalk.white(sym)} ${b} ${change.padEnd(8)} │`); |
| #39 | } |
| #40 | |
| #41 | // Pad if fewer than 6 tokens |
| #42 | for (let i = toShow.length; i < 6; i++) { |
| #43 | lines.push('│ │'); |
| #44 | } |
| #45 | |
| #46 | lines.push(chalk.gray('│ ──────────────────────────── │')); |
| #47 | |
| #48 | // P&L |
| #49 | lines.push(`│ ${chalk.cyan('P&L (PAPER)')} │`); |
| #50 | const pnlStr = (paperPnl >= 0 ? '+$' : '-$') + Math.abs(paperPnl).toFixed(2); |
| #51 | const pnlColored = paperPnl >= 0 ? chalk.green.bold(pnlStr) : chalk.red.bold(pnlStr); |
| #52 | lines.push(`│ Total : ${pnlColored.padEnd(22)}│`); |
| #53 | lines.push(`│ Win : ${chalk.yellow((winRate * 100).toFixed(1) + '%').padEnd(22)}│`); |
| #54 | lines.push(`│ Trades : ${chalk.white(String(totalTrades)).padEnd(22)}│`); |
| #55 | |
| #56 | // Last signal |
| #57 | lines.push(chalk.gray('│ ──────────────────────────── │')); |
| #58 | lines.push(`│ ${chalk.cyan('LAST SIGNAL')} │`); |
| #59 | if (lastSignal) { |
| #60 | const side = lastSignal.side === 'buy' |
| #61 | ? chalk.green('BUY ') |
| #62 | : lastSignal.side === 'sell' |
| #63 | ? chalk.red('SELL') |
| #64 | : chalk.gray('PASS'); |
| #65 | lines.push(`│ ${chalk.white(lastSignal.symbol.padEnd(10))} ${side} ${chalk.yellow(lastSignal.score + '/100')} │`); |
| #66 | lines.push(`│ Size: ${chalk.magenta(lastSignal.size.padEnd(24))}│`); |
| #67 | } else { |
| #68 | lines.push('│ No active signal │'); |
| #69 | lines.push('│ │'); |
| #70 | } |
| #71 | |
| #72 | lines.push(chalk.cyan('└────────────────────────────────┘')); |
| #73 | |
| #74 | while (lines.length < height) lines.push(''); |
| #75 | return lines; |
| #76 | } |
| #77 |