/** * Markdown builder for `strategy_periodic_report` (weekly / monthly rolling windows). */ /** One row for the performance ranking table. */ export interface StrategyRankRow { strategyId: string; strategyName: string; totalReturn: number | null; sharpe: number | null; maxDrawdown: number | null; } /** Inputs collected by the tool before formatting. */ export interface PeriodicReportPayload { period: "weekly" | "monthly"; windowStartIso: string; windowEndIso: string; scanCountsByType: Map; priceAlertCount: number; rankRows: StrategyRankRow[]; } /** * Format a periodic performance report as Markdown for the agent. * * @param payload - Aggregated stats and ranking rows for the reporting window. * @returns Markdown string (zh headings, decimal returns as percent like daily scan). */ export function formatPeriodicReportMarkdown(payload: PeriodicReportPayload): string { const periodLabel = payload.period === "weekly" ? "周报" : "月报"; const start = payload.windowStartIso.slice(0, 10); const end = payload.windowEndIso.slice(0, 10); const lines: string[] = []; lines.push(`## 策略绩效${periodLabel} — ${start} ~ ${end}`); lines.push(""); lines.push("### 绩效排名"); lines.push(""); lines.push("| 排名 | 策略 | 总收益 | 夏普 | 最大回撤 |"); lines.push("|------|------|--------|------|----------|"); const sorted = [...payload.rankRows].sort((a, b) => { const ar = a.totalReturn ?? Number.NEGATIVE_INFINITY; const br = b.totalReturn ?? Number.NEGATIVE_INFINITY; return br - ar; }); sorted.forEach((row, i) => { const ret = row.totalReturn == null ? "—" : `${(row.totalReturn * 100).toFixed(2)}%`; const sharpe = row.sharpe == null ? "—" : row.sharpe.toFixed(2); const dd = row.maxDrawdown == null ? "—" : `${(row.maxDrawdown * 100).toFixed(2)}%`; lines.push(`| ${i + 1} | ${row.strategyName} | ${ret} | ${sharpe} | ${dd} |`); }); lines.push(""); lines.push("### 活动统计"); const keys = [...payload.scanCountsByType.keys()].sort(); if (keys.length === 0) { lines.push("- (窗口内无扫描记录)"); } else { for (const k of keys) { lines.push(`- ${k}: ${payload.scanCountsByType.get(k)} 次`); } } lines.push(`- 价格告警: ${payload.priceAlertCount} 条`); lines.push(""); return lines.join("\n"); }