Skip to content
financial-data logo

Financial Data (金融数据处理)

financial-data

金融数据处理技能:交易数据导入、持仓数据管理、风险指标计算。 Use when: 需要处理交易记录、导入持仓数据、计算风险指标、数据清洗验证。 Triggers: "交易", "持仓", "导入", "数据", "IBKR", "风险", "净值", "回撤"

SKILL.md

Full skill instructions

Financial Data (金融数据处理)

💰 核心理念: 金融数据是投资决策的基础,必须确保数据准确性、完整性和一致性。垃圾进,垃圾出。

🔴 第一原则:数据验证优先

❌ 错误做法: 直接导入数据,假设数据正确
✅ 正确做法: 导入 → 验证 → 清洗 → 再验证 → 存储

❌ 错误做法: "这是券商数据,应该没问题"
✅ 正确做法: 任何外部数据都要经过完整验证流程

When to Use This Skill

使用此技能当你需要:

  • 从 IBKR、Gmail、Google Drive 导入交易数据
  • 处理持仓快照数据
  • 计算风险指标(VaR、回撤、夏普比率等)
  • 数据清洗和格式转换
  • 验证数据完整性和一致性
  • 处理多币种数据转换

Not For / Boundaries

此技能不适用于:

  • 实时行情数据获取(参考 api-integration skill)
  • AI 分析和建议生成(参考 agent 相关代码)
  • 数据库 schema 变更(参考 database-migration skill)

Quick Reference

🎯 数据处理工作流

数据源 → 获取原始数据 → 格式验证 → 数据清洗 → 业务验证 → 存储 → 确认
   ↓                                                    ↓
 IBKR/​Gmail/​Drive                                    失败 → 记录错误 → 人工处理

📋 数据导入前必问清单

问题目的
1. 数据源是什么?确定解析格式(XML/​CSV/​JSON)
2. 数据时间范围?避免重复导入或遗漏
3. 币种是什么?确定汇率转换需求
4. 有没有已存在的数据?决定是覆盖还是增量更新
5. 数据量有多大?评估是否需要分批处理

✅ 数据质量检查清单

检查项说明严重程度
必填字段完整ticker, date, quantity 等🔴 阻断
数值范围合理价格 > 0, 数量 ≠ 0🔴 阻断
日期格式正确YYYY-MM-DD🔴 阻断
币种有效USD/​HKD/​CNY🟡 警告
无重复记录同一交易不重复🟡 警告
数据连续性无缺失日期🟢 提示

数据源集成指南

1. IBKR Flex Query 导入

IBKR 是主要数据源,通过 Flex Query API 获取数据。

配置要求:

// 环境变量
VITE_CORS_PROXY_URL=https://your-proxy.workers.dev

// Flex Query 配置
const IB_TOKEN = "your_token";
const IB_QUERY_ID = "your_query_id";

数据获取流程:

1. 请求生成报表 (SendRequest)
2. 等待报表生成 (轮询 GetStatement)
3. 解析 XML 响应
4. 提取各类数据:
   - EquitySummaryByReportDateInBase → 账户摘要
   - OpenPosition → 持仓数据
   - Trade → 交易记录
   - ChangeInNAV → 净值变化
   - CashReportCurrency → 多币种现金

关键代码位置:

  • client/​src/​services/​ibkrFlexQuery.ts - IBKR 数据获取
  • client/​src/​services/​ibkrData.ts - IBKR 数据处理

2. Gmail 导入(交易确认邮件)

从券商确认邮件中提取交易数据。

支持的邮件格式:

  • IBKR 交易确认
  • 富途牛牛交易确认
  • 老虎证券交易确认

解析流程:

1. 通过 Gmail API 获取邮件
2. 解析邮件正文(HTML/纯文本)
3. 使用正则表达式提取交易信息
4. 验证并格式化数据

3. Google Drive 导入(CSV/​Excel)

从 Google Drive 导入历史数据文件。

支持的文件格式:

  • CSV(推荐)
  • Excel (.xlsx)

CSV 格式要求:

date,ticker,action,quantity,price,fee,currency,notes
2025-01-15,AAPL,BUY,100,185.50,1.00,USD,加仓
2025-01-16,AAPL,SELL,50,188.00,1.00,USD,止盈

数据验证规则

交易记录验证

// 必填字段验证
const requiredFields = ['date', 'ticker', 'action', 'quantity', 'price'];

// 数值范围验证
const validations = {
  price: (v: number) => v > 0,
  quantity: (v: number) => v !== 0,
  fee: (v: number) => v >= 0,
};

// 枚举值验证
const validActions = ['BUY', 'SELL', 'SHORT', 'COVER', 'DEPOSIT', 'WITHDRAW'];
const validCurrencies = ['USD', 'HKD', 'CNY'];
const validMarkets = ['US', 'HK', 'CN'];

持仓数据验证

// 持仓一致性检查
function validatePositions(positions: Position[], transactions: Transaction[]) {
  // 1. 计算交易累计数量
  const calculatedQty = calculateFromTransactions(transactions);
  
  // 2. 与持仓数量对比
  for (const pos of positions) {
    const expected = calculatedQty[pos.ticker] || 0;
    if (pos.quantity !== expected) {
      console.warn(`持仓不一致: ${pos.ticker} 实际=${pos.quantity} 计算=${expected}`);
    }
  }
}

净值数据验证

// 净值连续性检查
function validateNetWorthHistory(records: NetWorthRecord[]) {
  const sorted = records.sort((a, b) => a.date.localeCompare(b.date));
  
  for (let i = 1; i < sorted.length; i++) {
    const prev = sorted[i - 1];
    const curr = sorted[i];
    
    // 检查日期连续性(工作日)
    const daysDiff = getBusinessDaysDiff(prev.date, curr.date);
    if (daysDiff > 1) {
      console.warn(`净值数据缺失: ${prev.date} 到 ${curr.date}`);
    }
    
    // 检查异常波动(单日变化超过 10%)
    const changePercent = (curr.netWorth - prev.netWorth) / prev.netWorth * 100;
    if (Math.abs(changePercent) > 10) {
      console.warn(`异常波动: ${curr.date} 变化 ${changePercent.toFixed(2)}%`);
    }
  }
}

数据清洗最佳实践

1. 股票代码标准化

// 统一股票代码格式
function normalizeSymbol(symbol: string, market: Market): string {
  switch (market) {
    case 'HK':
      // 港股:补齐到 5 位数字
      return symbol.replace(/^0+/, '').padStart(5, '0');
    case 'CN':
      // A股:保持 6 位数字
      return symbol.padStart(6, '0');
    case 'US':
    default:
      // 美股:大写字母
      return symbol.toUpperCase().replace(/[^A-Z]/​g, '');
  }
}

2. 日期格式标准化

// 统一日期格式为 YYYY-MM-DD
function normalizeDate(dateStr: string): string {
  // 处理 IBKR 格式: 20250115
  if (/^\d{8}$/​.test(dateStr)) {
    return `${dateStr.slice(0, 4)}-${dateStr.slice(4, 6)}-${dateStr.slice(6, 8)}`;
  }
  
  // 处理 MM/​DD/​YYYY 格式
  if (/^\d{1,2}\/\d{1,2}\/\d{4}$/​.test(dateStr)) {
    const [m, d, y] = dateStr.split('/');
    return `${y}-${m.padStart(2, '0')}-${d.padStart(2, '0')}`;
  }
  
  // 已经是标准格式
  return dateStr;
}

3. 金额和汇率处理

// 汇率常量(应从实时数据获取)
const EXCHANGE_RATES = {
  USD_CNY: 7.04,
  HKD_CNY: 0.93,
};

// 转换为 CNY
function toCNY(amount: number, currency: Currency): number {
  switch (currency) {
    case 'USD':
      return amount * EXCHANGE_RATES.USD_CNY;
    case 'HKD':
      return amount * EXCHANGE_RATES.HKD_CNY;
    case 'CNY':
    default:
      return amount;
  }
}

4. 重复数据处理

// 交易记录去重
function deduplicateTransactions(transactions: Transaction[]): Transaction[] {
  const seen = new Set<string>();
  
  return transactions.filter(tx => {
    // 生成唯一键:日期 + 股票 + 动作 + 数量 + 价格
    const key = `${tx.date}_${tx.ticker}_${tx.action}_${tx.quantity}_${tx.price}`;
    
    if (seen.has(key)) {
      console.warn(`发现重复交易: ${key}`);
      return false;
    }
    
    seen.add(key);
    return true;
  });
}

风险指标计算

核心风险指标

指标公式说明
最大回撤(峰值 - 谷值) / 峰值历史最大亏损幅度
夏普比率(收益率 - 无风险利率) / 波动率风险调整后收益
VaR (95%)历史分位数法95% 置信度下的最大损失
胜率盈利交易数 / 总交易数交易成功率
盈亏比平均盈利 / 平均亏损风险回报比

计算示例

// 计算最大回撤
function calculateMaxDrawdown(netWorthHistory: number[]): {
  maxDrawdown: number;
  maxDrawdownPercent: number;
  peakDate: string;
  troughDate: string;
} {
  let peak = netWorthHistory[0];
  let maxDrawdown = 0;
  let maxDrawdownPercent = 0;
  
  for (const value of netWorthHistory) {
    if (value > peak) {
      peak = value;
    }
    
    const drawdown = peak - value;
    const drawdownPercent = drawdown / peak;
    
    if (drawdownPercent > maxDrawdownPercent) {
      maxDrawdown = drawdown;
      maxDrawdownPercent = drawdownPercent;
    }
  }
  
  return { maxDrawdown, maxDrawdownPercent, peakDate: '', troughDate: '' };
}

// 计算夏普比率
function calculateSharpeRatio(
  returns: number[],
  riskFreeRate: number = 0.02
): number {
  const avgReturn = returns.reduce((a, b) => a + b, 0) / returns.length;
  const variance = returns.reduce((sum, r) => sum + Math.pow(r - avgReturn, 2), 0) / returns.length;
  const stdDev = Math.sqrt(variance);
  
  // 年化
  const annualizedReturn = avgReturn * 252;
  const annualizedStdDev = stdDev * Math.sqrt(252);
  
  return (annualizedReturn - riskFreeRate) / annualizedStdDev;
}

数据库表结构

详细的数据库 schema 定义请参考:

  • references/​data-schemas.md - 完整的数据结构定义

核心表概览

表名用途主键
transactions交易记录uuid
stock_positions股票持仓快照bigserial
option_positions期权持仓快照bigserial
dashboard_snapshots每日驾驶舱快照bigserial
risk_metrics风险指标bigserial
watchlist观察列表uuid

Examples

Example 1: 从 IBKR 导入数据

Input: "需要从 IBKR 导入最新的交易和持仓数据"

Steps:

  1. 调用 fetchIBKRFlexQuery() 获取数据
  2. 验证返回的数据完整性
  3. 调用 syncIBKRToSupabase() 同步到数据库
  4. 验证同步结果

Expected Output:

import { syncIBKRToSupabase } from '@/​services/​ibkrFlexQuery';

const result = await syncIBKRToSupabase(true, (stage, progress) => {
  console.log(`[${progress}%] ${stage}`);
});

if (result.success) {
  console.log('同步成功:', result.data);
} else {
  console.error('同步失败:', result.message);
}

Example 2: 验证持仓数据一致性

Input: "检查持仓数据是否与交易记录一致"

Steps:

  1. 获取所有交易记录
  2. 计算每个股票的累计持仓
  3. 与当前持仓对比
  4. 输出差异报告

Expected Output:

// 获取数据
const transactions = await getTransactions();
const positions = await getPositions();

// 计算预期持仓
const expectedPositions = calculatePositionsFromTransactions(transactions);

// 对比
for (const pos of positions) {
  const expected = expectedPositions[pos.ticker] || 0;
  if (pos.quantity !== expected) {
    console.warn(`❌ ${pos.ticker}: 实际=${pos.quantity}, 预期=${expected}`);
  } else {
    console.log(`✅ ${pos.ticker}: ${pos.quantity}`);
  }
}

Example 3: 计算风险指标

Input: "计算最近 30 天的风险指标"

Steps:

  1. 获取净值历史数据
  2. 计算日收益率
  3. 计算各项风险指标
  4. 存储到 risk_metrics 表

Expected Output:

// 获取净值数据
const netWorthHistory = await getNetWorthHistory(30);

// 计算日收益率
const returns = calculateDailyReturns(netWorthHistory);

// 计算风险指标
const metrics = {
  maxDrawdown: calculateMaxDrawdown(netWorthHistory),
  sharpeRatio: calculateSharpeRatio(returns),
  var95: calculateVaR(returns, 0.95),
  volatility: calculateVolatility(returns),
};

// 存储
await saveRiskMetrics(metrics);

常见问题处理

Q1: IBKR 数据获取失败

可能原因:

  1. Token 过期
  2. CORS 代理不可用
  3. 网络问题

解决方案:

// 1. 检查 Token 有效性
// 登录 IBKR 账户管理 → 报表 → Flex Queries → 检查 Token

// 2. 尝试备用代理
const FALLBACK_PROXIES = [
  'https://corsproxy.io/?',
  'https://api.allorigins.win/​raw?url=',
];

// 3. 增加重试次数和超时时间

Q2: 数据重复导入

解决方案:

// 使用 upsert 而非 insert
const { error } = await supabase
  .from('transactions')
  .upsert(transactions, {
    onConflict: 'date,ticker,action,quantity,price',
    ignoreDuplicates: true
  });

Q3: 汇率数据不准确

解决方案:

// 1. 使用实时汇率 API
const rates = await fetchExchangeRates();

// 2. 或使用 IBKR 提供的汇率
const fxRate = trade.fxRateToBase;

References

  • references/​data-schemas.md: 完整的数据结构定义
  • references/​validation-rules.md: 数据验证规则详解
  • references/​import-templates.md: 数据导入模板

Maintenance

  • Sources: 项目实际代码, IBKR API 文档, 金融数据处理最佳实践
  • Last Updated: 2025-01-01
  • Known Limits:
    • IBKR Flex Query 有请求频率限制
    • 历史数据导入需要手动触发
    • 汇率数据可能有延迟

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View