spb/crypto-trade-bot
Public
Python 54.7%
TypeScript 42.5%
SQL 1.9%
1const isNum = (v: unknown): v is number => typeof v === "number" && Number.isFinite(v);2const toNum = (v: unknown): number | null => {3 if (isNum(v)) return v;4 if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v))) return Number(v);5 return null;6};78export const fmtNum = (v: unknown, digits = 2): string => {9 const n = toNum(v);10 return n === null ? "—" : n.toLocaleString("en-US", { minimumFractionDigits: digits, maximumFractionDigits: digits });11};12export const fmtPrice = (v: unknown): string => {13 const n = toNum(v);14 if (n === null) return "—";15 const d = n >= 1000 ? 1 : n >= 10 ? 2 : n >= 1 ? 3 : 5;16 return n.toLocaleString("en-US", { minimumFractionDigits: d, maximumFractionDigits: d });17};18export const fmtPct = (v: unknown, digits = 2, alreadyPct = false): string => {19 const n = toNum(v);20 if (n === null) return "—";21 const p = alreadyPct ? n : n * 100;22 return `${p >= 0 ? "+" : ""}${p.toFixed(digits)}%`;23};24export const fmtPctPlain = (v: unknown, digits = 1): string => {25 const n = toNum(v);26 return n === null ? "—" : `${(n * 100).toFixed(digits)}%`;27};28export const fmtBps = (v: unknown, digits = 1): string => {29 const n = toNum(v);30 return n === null ? "—" : `${n.toFixed(digits)} bps`;31};32export const fmtUsd = (v: unknown, digits = 2): string => {33 const n = toNum(v);34 return n === null ? "—" : n.toLocaleString("en-US", { style: "currency", currency: "USD", minimumFractionDigits: digits, maximumFractionDigits: digits });35};36export const fmtRatio = (v: unknown, digits = 2): string => {37 const n = toNum(v);38 if (n === null) return "—";39 if (!Number.isFinite(n)) return n > 0 ? "∞" : "—";40 return n.toFixed(digits);41};42export const fmtTs = (ts: unknown): string => {43 const n = toNum(ts);44 if (n === null) return "—";45 const ms = n > 1e12 ? n : n * 1000;46 return new Date(ms).toISOString().replace("T", " ").slice(0, 19) + "Z";47};48export const fmtDate = (ts: unknown): string => {49 const n = toNum(ts);50 if (n === null) return "—";51 return new Date((n > 1e12 ? n : n * 1000)).toISOString().slice(0, 10);52};53export const fmtIso = (s: unknown): string => (typeof s === "string" ? s.replace("T", " ").slice(0, 19) : "—");54export const fmtAge = (s: unknown): string => {55 const n = toNum(s);56 if (n === null) return "—";57 if (n < 60) return `${n.toFixed(0)}s`;58 if (n < 3600) return `${(n / 60).toFixed(0)}m`;59 return `${(n / 3600).toFixed(1)}h`;60};61export const signClass = (v: unknown): string => {62 const n = toNum(v);63 if (n === null || n === 0) return "text-fg-muted";64 return n > 0 ? "text-up" : "text-down";65};66export { toNum };67