// frontend/src/components/ResearchReportPanel.tsx import React, { useState, useEffect } from 'react'; import { API_BASE } from '../config'; import type { StrategyParams } from './StrategySettings'; interface ComponentData { type: 'paragraph' | 'heading3' | 'table' | 'code' | 'alert' | 'list'; content?: string; lang?: string; alert_type?: string; headers?: string[]; rows?: Record[]; items?: string[]; } interface SectionData { title: string; id: string; components: ComponentData[]; } interface ReportResponse { success: boolean; title: string; sections: SectionData[]; error?: string; } interface ResearchReportPanelProps { onApplyParams: (config: Partial, tab: 'dashboard') => void; activeTicker: string; } // Checkbox item schema for dynamic storage interface ChecklistItem { id: string; label: string; category: string; checked: boolean; } const DEFAULT_CHECKLIST: ChecklistItem[] = [ { id: '1', label: '离线研究:验证在不同交易周期下参数的最优稳定区,拒绝“孤立最优点”', category: '回测治理', checked: true }, { id: '2', label: '数据治理:引入复权与原始价分离机制,复权价生成信号,原始价仿真成交', category: '回测治理', checked: true }, { id: '3', label: '防过拟合:使用 Walk-forward 滚动向前优化及 PBO (概率过拟合) 检测', category: '回测治理', checked: false }, { id: '4', label: '对账系统:在收盘后对本地仓位账本与券商实际持仓执行自动化对账校验', category: '生产治理', checked: false }, { id: '5', label: '报警熔断:实现微信/钉钉 API 异常、数据源延迟或账户硬回撤熔断通知', category: '生产治理', checked: false }, { id: '6', label: '程序化报告:A 股交易前向证券监督管理部门或交易所进行程序化备案登记', category: '合规治理', checked: false }, { id: '7', label: 'Shadow Live:小资金或空跑两周,检验真实滑点佣金摩擦成本与回测偏差', category: '实盘迁移', checked: false }, ]; const formatContent = (text: string): string => { return (text || '') .replace(/\uE200cite[^\uE201]*\uE201/g, '') // Hide unicode citation blocks .replace(/\[cite\|[^\]]*\]/g, '') // Hide markdown citation brackets .replace(/[\uE200-\uE202]/g, '') // Clear stray unicode markers .replace(/\*\*(.*?)\*\*/g, '$1') .replace(/`(.*?)`/g, '$1'); }; export const ResearchReportPanel: React.FC = ({ onApplyParams }) => { const [report, setReport] = useState(null); const [loading, setLoading] = useState(true); const [activeSectionId, setActiveSectionId] = useState('executive_summary'); // Interactive Calculator State const [capital, setCapital] = useState(100000); const [dailyTarget, setDailyTarget] = useState(500); // Sizing Calculator State const [accountEquity, setAccountEquity] = useState(100000); const [riskPercent, setRiskPercent] = useState(0.5); // 0.5% const [atrStopDistance, setAtrStopDistance] = useState(3.5); // $3.5 stop distance // A-Share vs US Stock active sub-tab const [comparisonMarket, setComparisonMarket] = useState<'A' | 'US'>('US'); // Candlestick shapes search const [candlestickSearch, setCandlestickSearch] = useState(''); // Checklist state (persisted locally) const [checklist, setChecklist] = useState(() => { const saved = localStorage.getItem('quant_research_checklist'); return saved ? JSON.parse(saved) : DEFAULT_CHECKLIST; }); useEffect(() => { localStorage.setItem('quant_research_checklist', JSON.stringify(checklist)); }, [checklist]); const toggleChecklistItem = (id: string) => { setChecklist(prev => prev.map(item => item.id === id ? { ...item, checked: !item.checked } : item)); }; useEffect(() => { const fetchReport = async () => { setLoading(true); try { const res = await fetch(`${API_BASE}/api/research_report`); const json = await res.json(); if (json.success) { setReport(json); if (json.sections && json.sections.length > 0) { setActiveSectionId(json.sections[0].id); } } else { console.error("Report fetch failed:", json.error); } } catch (e) { console.error("Connection to research API failed:", e); } finally { setLoading(false); } }; fetchReport(); }, []); if (loading) { return (
📖 Loading dynamic research report and compilation assets...
); } if (!report || !report.sections) { return (
⚠️ Failed to load Deep Research Report. Please ensure the backend server is running and deep-research-report.md is present in the project folder.
); } // Calculate annual return needed based on inputs // Required Annual Return = (Daily Target * 252 trading days / Capital) * 100 const annualReturnRequired = (dailyTarget * 252 / capital) * 100; let feasibilityLabel = ""; let feasibilityClass = ""; let feasibilityDesc = ""; if (annualReturnRequired > 100) { feasibilityLabel = "🔴 极高风险 / 几乎不可能"; feasibilityClass = "danger"; feasibilityDesc = "对于日线级别股票交易,超过 100% 的年化净收益率在统计上是极其罕见且不可持续的。这需要你使用极高杠杆或承担毁灭性的回撤风险,极易导致爆仓。建议增加初始本金或降低每日收益目标。"; } else if (annualReturnRequired >= 50) { feasibilityLabel = "🟠 高度激进 / 极具挑战"; feasibilityClass = "warning"; feasibilityDesc = "50% - 100% 的年化净收益率属于专业量化基金的顶尖水平或高杠杆趋势行情下的特殊表现。需要极高胜率、极佳的滑点控制和高度一致的系统执行,伴随的系统性回撤风险也相当高。"; } else if (annualReturnRequired >= 20) { feasibilityLabel = "💛 中度合理 / 可以争取"; feasibilityClass = "moderate"; feasibilityDesc = "20% - 50% 年化复合收益率。在多策略并行、严格资金管理、以及牛市或高动量市场环境下,是一个可以通过精细化系统交易去争取的理性目标。"; } else { feasibilityLabel = "💚 稳健安全 / 可行性高"; feasibilityClass = "success"; feasibilityDesc = "低于 20% 年化回报。最符合低频日线执行、资产均衡配置与稳健风控的现实路径。系统对单次执行偏差与交易摩擦的敏感度较低,抗风险能力最强。"; } // Sizing Calculator Formula: Qty = (Equity * RiskPercent / 100) / StopDistance const riskAmountDollar = accountEquity * (riskPercent / 100); const sharesToBuy = Math.floor(riskAmountDollar / (atrStopDistance || 0.01)); const totalPositionValue = sharesToBuy * 150; // Assume stock price is $150 for illustration // SVGs for K-Lines const renderKLineSVG = (patternName: string) => { const name = patternName.toLowerCase(); // SVG standard settings const width = 60; const height = 90; if (name.includes('hammer') || name.includes('锤子')) { return ( ); } if (name.includes('star') || name.includes('流星') || name.includes('黄昏')) { return ( ); } if (name.includes('doji') || name.includes('十字星')) { return ( ); } if (name.includes('engulfing') || name.includes('吞没')) { const isBull = name.includes('bullish') || name.includes('看涨'); return ( {/* Left candle (small) */} {/* Right candle (big engulfing) */} ); } if (name.includes('marubozu') || name.includes('光头')) { const isBull = name.includes('bull') || name.includes('长阳') || name.includes('红'); return ( ); } // Default Spinning Top style return ( ); }; // Specific Candlestick configurations that we can map parameters to const candlestickData: Array<{ name: string; type: string; formula: string; desc: string; strategy: Partial; }> = [ { name: "长阳线 / 大阳线 (Big Bullish)", type: "bullish", formula: "bull and body_ratio >= 0.6 and upper_ratio <= 0.3 and lower_ratio <= 0.3", desc: "买方全天绝对主导,代表多头攻击动能充沛,后市看涨概率大。", strategy: { strategy_mode: "patterns", trailing_stop_atr_mult: 2.0 } }, { name: "长阴线 / 大阴线 (Big Bearish)", type: "bearish", formula: "bear and body_ratio >= 0.6 and upper_ratio <= 0.3 and lower_ratio <= 0.3", desc: "空方全天绝对掌控,恐慌情绪蔓延,通常需要离场防御。", strategy: { strategy_mode: "dynamic" } }, { name: "十字星 (Doji)", type: "neutral", formula: "body_ratio <= 0.1", desc: "多空平衡,波动率收缩。处于长期趋势末端常代表变盘,处于趋势中途代表调整中继。", strategy: { strategy_mode: "consensus" } }, { name: "锤头线 (Hammer)", type: "bullish", formula: "lower_ratio >= 2.0 and upper_ratio <= 0.5 and body_ratio <= 0.35 and trend_down_ctx", desc: "底部强力吸筹,价格探底回升。在均线支撑位或超卖区具有极高可靠性。", strategy: { strategy_mode: "patterns", trailing_stop_atr_mult: 1.5 } }, { name: "射击之星 (Shooting Star)", type: "bearish", formula: "upper_ratio >= 2.0 and lower_ratio <= 0.5 and body_ratio <= 0.35 and trend_up_ctx", desc: "上方抛压沉重,多头冲高回落,是经典的高位见顶抛售信号。", strategy: { strategy_mode: "patterns", profit_target_pct: 0.02 } }, { name: "看涨吞没 (Bullish Engulfing)", type: "bullish", formula: "prev.close < prev.open and curr.close > curr.open and curr.open <= prev.close and curr.close >= prev.open", desc: "后一根阳线实体完全覆盖前一根阴线实体,是多头强力反攻的底部信号。", strategy: { strategy_mode: "patterns", trailing_stop_atr_mult: 2.5 } }, { name: "看跌吞没 (Bearish Engulfing)", type: "bearish", formula: "prev.close > prev.open and curr.close < curr.open and curr.open >= prev.close and curr.close <= prev.open", desc: "后一根阴线实体覆盖前一阳线,说明多头撤退,空头全盘接管。", strategy: { strategy_mode: "patterns" } } ]; return (
{/* 侧边导航栏 & 头部标题 */}
{/* 左侧文档树目录 */} {/* 右侧交互式文档主体 */}
{report.sections.map((sec) => (

{sec.title}

{/* 1. 执行摘要:挂载“资金-收益可行性计算器” */} {sec.id === 'executive_summary' && (

📊 交易目标与本金可行性评估工具

你的目标是长期平均每天净赚 500 美元。根据市场统计学,年化净收益率(按 252 个交易日计)与所需本金存在以下动态关系。移动滑块查看您的方案可行性。

setCapital(Number(e.target.value))} />
$10k $250k $500k $1M
setDailyTarget(Number(e.target.value))} />
$50 $500 $1000 $2000
目标年增长率 (Required Return)
50 ? 'var(--color-red)' : 'var(--color-green)', fontSize: '2rem', fontWeight: 800 }}> {annualReturnRequired.toFixed(1)}%
系统评级 (Feasibility Rating)
{feasibilityLabel}

{feasibilityDesc}

)} {/* 2. 关键目标与约束:A股与美股规则的对比切换卡片 */} {sec.id === 'key_goals___constraints' && (

🇺🇸 / 🇨🇳 市场环境与规则适配器

代码必须通过策略底层适配器屏蔽市场交易差异。切换标签对比主要规则:

{comparisonMarket === 'US' ? (
交易时间:9:30 - 16:00 ET (盘前 4:00-9:30, 盘后 16:00-20:00)
交收规则:支持 T+0 日内回转交易(不再受旧 PDT 限制,采用 FINRA Rule 4210 日内保证金制)。
做空规则:允许直接借券做空,可融券票池庞大。
杠杆机制:Reg T 初始 50% 保证金率,且盘中日内保证金实时核算。
监管要求:零售账户低门槛,交易系统需遵守券商 API 调用速率限制。
) : (
交易时间:9:30-11:30, 13:00-15:00 CST (有精确开收盘集合竞价段)。
交收规则:实行普通股票 T+1 机制,买入当日不可卖出,需等次日交收。
做空规则:普通散户难以融券,做空通常需要股指期货对冲或融券白名单。
杠杆机制:主要依赖券商融资融券,杠杆率受严控。
程序化报告:深沪交易所针对个人及机构程序化交易要求事先备案报告(包括软件标识、最高申报速度等)。
)}
)} {/* 3. K线与技术指标:挂载“常见K线形态库”与 SVG 可视化 */} {sec.id === 'kline_patterns___indicators' && (

🕯️ 常见日线 K 线形态智能识别库

setCandlestickSearch(e.target.value)} style={{ background: '#111', border: '1px solid var(--color-border)', borderRadius: '6px', padding: '6px 12px', color: '#fff', fontSize: '0.8rem', minWidth: '200px' }} />
{candlestickData .filter(item => item.name.toLowerCase().includes(candlestickSearch.toLowerCase()) || item.desc.includes(candlestickSearch)) .map((item, idx) => (
{renderKLineSVG(item.name)}
{item.name}
{item.desc}
{item.formula}
{item.type === 'bullish' ? '看涨' : item.type === 'bearish' ? '看跌' : '中性'}
))}
)} {/* 4. 量化策略清单:挂载“Regime Router 架构流图” */} {sec.id === 'quantitative_strategy_checklist' && (

🚦 Regime Router 市场状态路由引擎架构

本系统并不是盲目执行单一策略,而是先通过 Regime Classifier 进行环境识别,再将决策权路由给子模块:

{/* Inputs */} 行情 OHLCV 输入 {/* Arrow 1 */} {/* Classifier */} Regime Classifier - ADX 趋势强度 - 均线多空斜率 - ATR 波动分位数 {/* Split Arrows */} {/* Branch 1 */} Trend Up (趋势做多) Donchian 突破 / EMA 金叉 {/* Branch 2 */} Range Bound (均值回归) RSI 超卖 / 布林下轨支撑 {/* Branch 3 */} Trend Down / High Vol 强制风控平仓 / 保持空仓 {/* Merge Arrows */} {/* Risk Gate */} 下单风控层 次日订单计划 {/* Marker Definitions */}
)} {/* 5. 风控与资金管理:挂载“单笔仓位风险控制计算器” */} {sec.id === 'risk_control___capital_management' && (

🛡️ 单笔交易头寸风险计算器 (ATR-Based Sizing)

不要主观觉得该买多少股,应当让系统根据最大风险预算止损距离来反推头寸规模:

setAccountEquity(Number(e.target.value))} />
setRiskPercent(Number(e.target.value))} />
setAtrStopDistance(Number(e.target.value))} />
单笔最大可承受亏损
${riskAmountDollar.toLocaleString(undefined, { minimumFractionDigits: 2 })}
建议买入数量 (Position Size)
{sharesToBuy.toLocaleString()} 股
(以每股 $150 估算,占用保证金约 ${totalPositionValue.toLocaleString()},敞口占比 {(totalPositionValue / accountEquity * 100).toFixed(1)}%)
)} {/* 6. 回测与参数优化:Walk-Forward 优化流向图 */} {sec.id === 'backtesting___parameter_optimization' && (

🔄 Walk-Forward 滚动向前优化流程线

为了防止参数过拟合于历史噪音,我们必须进行样本内外的滑动窗滚动测试:

{/* Time bar */} 历史起点 未来/实盘 {/* Window 1 */} 训练集 (Train) 1 测试集 (Test) 1 {/* Window 2 (shifted) */} 训练集 (Train) 2 测试集 (Test) 2 {/* Window 3 (shifted) */} 训练集 (Train) 3 测试集 (Test) 3
)} {/* 7. 实盘部署与代码清单:挂载源码链接 */} {sec.id === 'production_deployment___code_checklist' && ( )} {/* 8. 参考来源与合规风险提示:挂载 checklist 跟踪 */} {sec.id === 'references___compliance_risk_alert' && (

📋 量化系统“回测至实盘”迁移合规与风控自查表

在系统准备进入模拟盘或实盘运行前,您需要手动验证以下各维度的完备性。勾选可保存自查进度:

{checklist.map(item => ( ))}
)} {/* 渲染 Markdown 的普通组件 */} {sec.components.map((comp, cidx) => { if (comp.type === 'paragraph') { return (

); } if (comp.type === 'heading3') { return

{comp.content}

; } if (comp.type === 'table' && comp.headers && comp.rows) { // If it's a table, let's render it as a premium HTML table return (
{comp.headers.map((h, hidx) => ( ))} {comp.rows.map((row, ridx) => ( {comp.headers!.map((h, colidx) => ( ))}
{h}
))}
); } if (comp.type === 'code') { return (
{comp.lang}
                        {comp.content}
                      
); } if (comp.type === 'alert') { let alertTitle = "提示"; if (comp.alert_type === 'warning') alertTitle = "警告"; if (comp.alert_type === 'caution') alertTitle = "注意"; if (comp.alert_type === 'important') alertTitle = "重要"; if (comp.alert_type === 'tip') alertTitle = "提示"; return (
{alertTitle}
); } if (comp.type === 'list' && comp.items) { return (
    {comp.items.map((item, lidx) => (
  • ))}
); } return null; })}
))}
); };