/** * 图表统一主题(TradingView Lightweight Charts)。 * * 单一来源:所有图表组件只从这里取色,避免各页面各自硬编码导致深浅不一的观感。 * 与 globals.css 的 CSS 变量保持同一套语义色(pos=涨/盈利口径按 A 股习惯为红涨绿跌, * 但收益曲线的“正/负”沿用页面既有的绿正红负,故分 `up/down` 与 `pos/neg` 两组)。 */ export const CHART = { /** 透明底:跟随卡片背景,避免图表出现色块拼接 */ background: "transparent", text: "#a8b3c9", textStrong: "#e9eef7", faint: "#8b98b2", grid: "rgba(150,165,195,0.10)", border: "rgba(150,165,195,0.22)", crosshair: "rgba(150,165,195,0.45)", tooltipBg: "rgba(20,29,48,0.96)", tooltipBorder: "rgba(150,165,195,0.28)", /** 收益语义(绿=正、红=负,与页面 Pill/Metric 一致) */ pos: "#3ddc97", neg: "#ff7a7a", accent: "#3fb6ff", violet: "#b98bff", amber: "#d4a72c", /** A 股涨跌语义(红涨绿跌) */ up: "#e5484d", down: "#2fb36b", /** 多序列叠加配色(实验对比用,最多 8 条) */ series: [ "#3fb6ff", "#3ddc97", "#d4a72c", "#b98bff", "#ff7a7a", "#4dd0e1", "#f06292", "#9ccc65", ], } as const; /** 买卖点标记语义色:与图例文字一致,买入=绿、卖出=红/紫 */ export const MARKER_COLORS = { BUY: "#3ddc97", SELL: "#ff5a5a", SIG_BUY: "#b98bff", SIG_SELL: "#8b7bd8", } as const; export function seriesColor(index: number): string { return CHART.series[index % CHART.series.length]; } /** 去掉 "YYYY-MM-DD" 的年份,用于横轴/表格紧凑显示 */ export function shortDate(d: string): string { return d.length >= 10 ? d.slice(5) : d; } /** 千分位 + 指定小数位(净值/金额) */ export function fmtNum(v: number, digits = 0): string { return v.toLocaleString("zh-CN", { minimumFractionDigits: digits, maximumFractionDigits: digits, }); } /** 百分比(入参已是百分数,如 24.86 → "+24.86%") */ export function fmtPct(v: number, digits = 2): string { return `${v > 0 ? "+" : ""}${v.toFixed(digits)}%`; } /** 紧凑金额:12.5 万 / 1.23 亿 */ export function fmtMoney(v: number): string { const abs = Math.abs(v); if (abs >= 1e8) return `${(v / 1e8).toFixed(2)} 亿`; if (abs >= 1e4) return `${(v / 1e4).toFixed(2)} 万`; return fmtNum(v, 0); }