Files
signal-platform/frontend/src/lib/format.ts
T
dennisthiessenandClaude Opus 5 14cfa44fc5
Deploy / lint (push) Successful in 9s
Deploy / test (push) Successful in 1m16s
Deploy / deploy (push) Successful in 38s
refactor(signals): drop the now-unused fmtMoney helper
It was lifted from BacktestPanel during the extraction, then lost its last
caller in the same branch when avg_trade_pnl became an EV / trade tile rendered
with fmtSignedMoney and disappeared from the monitor footnote. formatPrice
already covers a bare unsigned amount if one is ever needed again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 22:40:37 +02:00

130 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Format a number as a price string with 2 decimal places and thousands separators.
* e.g. 1234.5 → "1,234.50"
*/
export function formatPrice(n: number): string {
return n.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
/**
* Format a number as a percentage string with 2 decimal places.
* e.g. 12.345 → "12.35%"
*/
export function formatPercent(n: number): string {
return `${n.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}%`;
}
/**
* Format a large number with K/M/B suffix.
* Values >= 1_000_000_000 → "1.23B"
* Values >= 1_000_000 → "456.7M"
* Values >= 1_000 → "12.3K"
* Values < 1_000 → plain number, no suffix
*/
export function formatLargeNumber(n: number): string {
const abs = Math.abs(n);
const sign = n < 0 ? '-' : '';
if (abs >= 1_000_000_000) {
return `${sign}${(abs / 1_000_000_000).toFixed(2).replace(/\.?0+$/, '')}B`;
}
if (abs >= 1_000_000) {
return `${sign}${(abs / 1_000_000).toFixed(1).replace(/\.?0+$/, '')}M`;
}
if (abs >= 1_000) {
return `${sign}${(abs / 1_000).toFixed(1).replace(/\.?0+$/, '')}K`;
}
return n.toString();
}
/**
* Format an ISO date string as a short date.
* e.g. "2025-01-15T14:30:00Z" → "Jan 15, 2025"
*/
export function formatDate(d: string): string {
const date = new Date(d);
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
});
}
/**
* Format an ISO date string as a date with time.
* e.g. "2025-01-15T14:30:00Z" → "Jan 15, 2025 2:30 PM"
*/
export function formatDateTime(d: string): string {
const date = new Date(d);
return `${date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})} ${date.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true,
})}`;
}
// ── Metric display helpers ─────────────────────────────────────────────────
// Shared by the Signals backtest/paper-trade panels. Dashboard and
// OpenTradesPanel deliberately still carry their own copies — migrating them is
// a separate change, not drive-by scope.
/** R-multiple with an explicit sign. e.g. 1.2 → "+1.20R", null → "—" */
export function fmtR(v: number | null | undefined): string {
if (v === null || v === undefined) return '—';
return `${v > 0 ? '+' : ''}${v.toFixed(2)}R`;
}
/** e.g. 12.34 → "12.3%" */
export function fmtPct(v: number | null | undefined): string {
return v === null || v === undefined ? '—' : `${v.toFixed(1)}%`;
}
/** e.g. 12.34 → "+12.3%" */
export function fmtSignedPct(v: number | null | undefined): string {
if (v === null || v === undefined) return '—';
return `${v > 0 ? '+' : ''}${v.toFixed(1)}%`;
}
/** Always rendered negative, whatever sign the source uses. 17.3 → "-17.3%" */
export function fmtDrawdown(v: number | null | undefined): string {
return v === null || v === undefined ? '—' : `-${Math.abs(v).toFixed(1)}%`;
}
/** e.g. 15.3 → "15.3d" */
export function fmtDays(v: number | null | undefined): string {
return v === null || v === undefined ? '—' : `${v.toFixed(1)}d`;
}
/** Unitless ratios — Sharpe, Sortino, Calmar, Gain/Pain, profit factor. */
export function fmtRatio(v: number | null | undefined): string {
return v === null || v === undefined ? '—' : v.toFixed(2);
}
/**
* Signed currency, using U+2212 for negatives. e.g. -12.3 → "$12.30"
* Use wherever a value can go negative and the unit is money.
* (For a bare unsigned amount there is already `formatPrice` above.)
*/
export function fmtSignedMoney(v: number | null | undefined): string {
if (v === null || v === undefined) return '—';
return `${v >= 0 ? '+' : ''}$${Math.abs(v).toFixed(2)}`;
}
/** Green above zero, red below, neutral at zero or null. */
export function rColor(v: number | null | undefined): string {
if (v === null || v === undefined) return 'text-gray-400';
if (v > 0) return 'text-emerald-400';
if (v < 0) return 'text-red-400';
return 'text-gray-300';
}