PortfolioBuddy2-架构参考文档Skill architecture-reference

Portfolio Buddy 2是一个量化交易投资组合分析工具的项目架构参考文档。该文档详细说明了React前端应用的结构、组件层次、关键钩子(如useMetrics、usePortfolio)、数据流、状态管理、Chart.js图表集成以及TypeScript最佳实践。内容涵盖量化金融指标计算(夏普比率、索提诺比率、最大回撤)、CSV数据处理、相关性分析、合约乘数调整和性能优化模式,是开发量化交易分析系统、回测平台和投资组合管理软件的重要技术参考。关键词:量化交易、投资组合分析、React架构、TypeScript、Chart.js、夏普比率、回测系统、前端开发、金融科技。

回测系统 0 次安装 18 次浏览 更新于 2/28/2026

name: architecture-reference description: “Portfolio Buddy 2项目结构快速参考。使用场景:添加新功能、修改现有组件、理解数据流或熟悉代码库。包含组件层次结构、钩子模式和实用函数。”

Portfolio Buddy 2 - 架构参考

组件层次结构

App.tsx (351行)
├── Header
│   └── 应用标题和品牌标识
├── UploadSection
│   ├── 文件上传至Supabase
│   ├── CSV解析和验证
│   └── 错误处理
├── ErrorList
│   └── 显示解析/验证错误
├── UploadedFilesList
│   └── 成功上传的文件列表
├── AnalyticsControls
│   ├── 切换指标视图
│   ├── 切换投资组合视图
│   └── 切换相关性视图
├── PortfolioSection (591行 - 需要重构!)
│   ├── usePortfolio钩子(日期过滤)
│   ├── useContractMultipliers钩子
│   ├── Chart.js权益曲线
│   ├── 投资组合统计
│   ├── ContractInput组件
│   ├── MasterContractControl
│   └── MetricsTable集成
├── CorrelationSection
│   ├── CorrelationHeatmap (Chart.js)
│   ├── 斯皮尔曼相关性
│   └── 皮尔逊相关性
├── MetricsTable (242行)
│   ├── useMetrics钩子
│   ├── useSorting钩子(高级多列排序)
│   ├── SortableHeader组件
│   └── 选择状态管理
└── SessionComplete
    └── 完成UI/消息

关键钩子

useMetrics

位置: src/hooks/useMetrics.ts 目的: 从上传的投资组合数据计算交易指标 功能:

  • 计算夏普比率、索提诺比率、最大回撤、年复合增长率、胜率等
  • 记忆化计算以提高性能
  • 优雅处理空/无效数据

用法:

const { metrics, isCalculating } = useMetrics(portfolioData, riskFreeRate)

返回:

  • metrics: 每个策略的计算指标数组
  • isCalculating: 布尔加载状态

注意: 包含4处TypeScript any违规(技术债务)

usePortfolio

位置: src/hooks/usePortfolio.ts 目的: 管理带日期范围过滤的投资组合数据 功能:

  • 解析CSV交易数据
  • 按日期范围过滤(开始/结束日期)
  • 构建权益曲线
  • 聚合日收益

用法:

const {
  portfolioData,
  filteredData,
  dateRange,
  setDateRange
} = usePortfolio(uploadedFiles)

近期添加: 日期范围过滤(提交258ba3a)

注意: 包含11处TypeScript any违规(技术债务)

useContractMultipliers

位置: src/hooks/useContractMultipliers.ts 目的: 管理期货交易的合约乘数 功能:

  • 按策略跟踪合约规模
  • 将乘数应用于指标
  • 主控一次设置所有合约

用法:

const {
  multipliers,
  setMultiplier,
  setAllMultipliers,
  getAdjustedMetrics
} = useContractMultipliers(strategies)

useSorting

位置: src/hooks/useSorting.ts 目的: MetricsTable的高级多列排序 功能:

  • 按优先级多列排序
  • 切换升序/降序
  • 每种数据类型的自定义比较逻辑

用法:

const {
  sortedData,
  sortColumn,
  sortDirection,
  handleSort
} = useSorting(data, defaultColumn)

实用函数

dataUtils.ts

位置: src/utils/dataUtils.ts 包含核心函数:

CSV与数据处理:

  • parseCSV(file) - 使用PapaParse解析CSV文件
  • processCurrencyColumns(data) - 清理货币值($,逗号)
  • parseFilenameComponents(filename) - 从文件名提取符号/方向/策略
  • getDisplayName(symbol, direction, strategy) - 格式化显示名称
  • normalizeDate(date) - 将日期标准化为UTC午夜
  • getDateKey(date) - 将日期转换为YYYY-MM-DD字符串键

指标计算:

  • calculateMetrics(data, filename) - 计算策略的交易级指标
    • 净利润、毛利润/亏损
    • 盈利因子、胜率
    • 平均盈利/亏损、期望值
    • 最大回撤(来自权益曲线)
    • 年复合增长率等效值(annualGrowthRate)
    • 总交易数、盈利/亏损计数
    • 注意: 不计算夏普或索提诺比率(这些在PortfolioSection.tsx中)
  • getAdjustedMetrics(metrics, multiplier) - 将合约乘数应用于指标

风险调整指标 (PortfolioSection.tsx):

  • 夏普比率 (第533行): 内联计算为(annualGrowthRate / 100) / (maxDrawdown / startingCapital)
  • 索提诺比率 (第133-158行): 使用下行偏差内联计算,使用无风险利率状态

相关性分析:

  • buildCorrelationMatrix(strategies) - 构建斯皮尔曼相关性矩阵
  • calculatePearsonCorrelation(returns1, returns2) - 皮尔逊相关系数
  • calculateRanks(values) - 斯皮尔曼相关的排名计算

交易计算:

  • getMarginRate(symbol) - 按符号获取保证金要求
  • calculateEquityCurve(trades) - 构建累积权益曲线
  • calculateDailyReturns(equity) - 从权益曲线计算日收益

格式化:

  • formatNumber(value, decimals) - 带小数格式化数字
  • formatCurrency(value) - 格式化为货币($X,XXX.XX)
  • formatPercent(value) - 格式化为百分比(X.XX%)

注意: 包含1处TypeScript any违规(技术债务)

数据流

上传与处理流程

1. 用户通过UploadSection上传CSV
   ↓
2. parseCSV()提取交易数据
   ↓
3. processCurrencyColumns()清理数据
   ↓
4. 文件上传至Supabase存储
   ↓
5. usePortfolio钩子获取并聚合数据
   ↓
6. 应用日期范围过滤器(如果设置)
   ↓
7. useMetrics计算所有指标
   ↓
8. MetricsTable显示结果

合约乘数流程

1. 用户在ContractInput中输入合约规模
   ↓
2. useContractMultipliers存储值
   ↓
3. getAdjustedMetrics()应用乘数
   ↓
4. 调整后的指标显示在MetricsTable中
   ↓
5. 投资组合图表更新调整后的值

排序流程

1. 用户点击SortableHeader
   ↓
2. useSorting更新排序列/方向
   ↓
3. 应用自定义比较逻辑
   ↓
4. MetricsTable重新渲染排序后的数据

相关性流程

1. 用户在MetricsTable中选择资产
   ↓
2. 选择状态传递给CorrelationSection
   ↓
3. buildCorrelationMatrix()计算相关性
   ↓
4. CorrelationHeatmap渲染Chart.js热力图
   ↓
5. 同时显示斯皮尔曼和皮尔逊相关性

状态管理

纯React钩子(无Zustand/TanStack Query)

  • 本地组件状态useState
  • 派生状态useMemo
  • 稳定回调useCallback
  • 值的引用useRef

示例模式:

const [data, setData] = useState<Trade[]>([])
const metrics = useMemo(() => calculateMetrics(data), [data])
const handleUpload = useCallback((file: File) => {
  // 上传逻辑
}, [])

无全局状态库

  • 属性沿组件树向下传递
  • 自定义钩子封装共享逻辑
  • 无Redux、Zustand或Jotai

添加新功能

新指标计算

  1. 将计算逻辑添加到dataUtils.calculateMetrics()
  2. 更新calculateMetrics()中的返回类型
  3. 将列添加到MetricsTable.tsx
  4. 如果需要,更新useSorting.ts中的排序逻辑
  5. 使用样本数据测试

示例: 索提诺比率在提交258ba3a和9f25040中添加

新图表组件

  1. src/components/中创建组件
  2. 使用Chart.js(非Recharts - 未使用)
  3. 导入所需的图表类型和插件:
    import { Line } from 'react-chartjs-2'
    import { Chart, registerables } from 'chart.js'
    import zoomPlugin from 'chartjs-plugin-zoom'
    
  4. 连接到useMetricsusePortfolio获取数据
  5. 添加到App.tsx中的相应部分

新钩子

  1. src/hooks/use[Feature].ts中创建
  2. 遵循命名约定:use前缀,驼峰式
  3. 返回具有清晰属性名称的对象
  4. 对所有类型使用TypeScript(避免any
  5. 为复杂逻辑添加JSDoc注释

Chart.js架构

当前设置

  • : Chart.js 4.x(非Recharts)
  • React包装器: react-chartjs-2
  • 使用的插件:
    • chartjs-plugin-zoom(平移和缩放)
    • chartjs-plugin-annotation(趋势线、标记)
    • chartjs-adapter-date-fns(时间尺度)

图表使用位置

  1. PortfolioSection: 权益曲线折线图
  2. CorrelationHeatmap: 相关性矩阵热力图
  3. CustomTooltip: 图表的共享工具提示组件

Recharts注意

⚠️ Recharts已安装但从未导入 - 应移除(11.5KB浪费)

组件大小指南

目标: 最大200行

当前违规:

  • ❌ PortfolioSection.tsx: 591行(限制的295%) - 高优先级重构
  • ❌ App.tsx: 351行(限制的175%)
  • ❌ MetricsTable.tsx: 242行(限制的121%) - 从350行改进

重构策略

对于PortfolioSection(591行):

  1. 将权益图表提取到EquityChartSection.tsx
  2. 将统计信息提取到PortfolioStats.tsx
  3. 将合约控制提取到ContractControls.tsx
  4. 在主组件中仅保留编排逻辑

TypeScript模式

数据结构的接口

interface Trade {
  date: Date
  symbol: string
  pnl: number
  // ...
}

interface Metric {
  name: string
  sharpe: number
  sortino: number
  // ...
}

避免any类型

当前违规(共15处) - 详见portfolio-context技能

首选方法:

// 错误
const data: any = parseData()

// 正确
interface ParsedData {
  trades: Trade[]
  errors: string[]
}
const data: ParsedData = parseData()

性能模式

使用useMemo记忆化

// 昂贵的相关性计算
const correlationMatrix = useMemo(
  () => buildCorrelationMatrix(selectedStrategies),
  [selectedStrategies]
)

使用useCallback稳定回调

const handleSort = useCallback((column: string) => {
  setSortColumn(column)
  setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc')
}, [])

避免过早优化

  • 先构建功能
  • 如果出现性能问题再进行性能分析
  • 基于数据而非假设进行优化