Claude Code 实战:oh-my-claudecode ------ 从零构建个人量化程序
项目前:工具选型与环境准备
这个项目要做什么
个人量化程序(Quant Personal)v1.0
功能范围:
✅ 数据获取: 从 Tushare/AKShare 拉取 A 股日线数据
✅ 数据存储: SQLite 本地存储(轻量、单人使用)
✅ 策略引擎: 双均线交叉策略(经典入门策略)
✅ 回测系统: 基于历史数据的策略回测
✅ 报告输出: 回测结果 HTML 报告(收益曲线 + 指标统计)
✅ 定时任务: 每天收盘后自动拉取数据并更新
技术栈:
Python 3.12 + Click CLI + SQLAlchemy + Pandas + Plotly + Pydantic
不做什么(范围边界):
❌ 不接实时交易接口(只做分析和回测)
❌ 不做 Web 界面(CLI 工具即可)
❌ 不支持港股美股(v1 只做 A 股)
装了什么工具、每个用来干什么
工具 用途
──────────────────────────────────────────
Claude Code AI 编程的主力工具(日常开发)
oh-my-claudecode 增强 Claude Code(Hooks/Skills/项目模板)
ruff Python 代码检查和格式化
pytest 测试框架
pre-commit Git 提交前自动检查
第一步:安装 oh-my-claudecode
bash
# 1. 确认 Claude Code 已安装
claude --version
# 输出: Claude Code v2.x.x
# 2. 克隆 oh-my-claudecode(社区增强框架)
cd ~/
git clone https://github.com/barryness/oh-my-claudecode.git
# 注意: 如果官方仓库地址变更,请查看最新文档
# 3. 将 oh-my-claudecode 的配置合并到项目中
# oh-my-claudecode 本质是一套预配置的模板文件:
# ├── templates/ # CLAUDE.md 模板(适配不同项目类型)
# ├── hooks/ # 预定义的 Hooks 配置
# ├── commands/ # 自定义 Slash Commands
# └── skills/ # 通用 Skill 文件
第二步:创建项目骨架
bash
# 创建项目目录
mkdir -p ~/projects/quant-personal
cd ~/projects/quant-personal
# 初始化 Git
git init
git config user.name "Barry"
git config user.email "barry@example.com"
# 创建 Python 项目结构
mkdir -p src/quant_personal/{data,strategy,backtest,report,cli}
mkdir -p tests/{unit,integration}
mkdir -p specs
mkdir -p .claude
# 初始化 Python 环境
python3.12 -m venv venv
source venv/bin/activate
pip install --upgrade pip
# 安装基础依赖
pip install \
click \
sqlalchemy \
pandas \
pydantic \
plotly \
akshare \
tushare \
pytest \
pytest-cov \
pre-commit \
ruff
第一步:注入 oh-my-claudecode 的配置体系
1.1 复制 CLAUDE.md 模板
bash
# oh-my-claudecode 提供了针对 Python 数据项目的模板
cp ~/oh-my-claudecode/templates/python-data/CLAUDE.md ./
# 模板内容大概是这样(你需要按自己情况修改)
模板打开后,按项目实际情况修改。这是修改后的版本:
markdown
# Quant Personal
> Claude Code 项目指令。个人量化分析工具。
## 技术栈
- Python 3.12+,所有代码通过 `ruff check` 和 `ruff format`
- 数据获取: AKShare (A 股) / Tushare (备选)
- 数据存储: SQLAlchemy 2.0 + SQLite(本地单人使用)
- CLI: Click 8.x
- 数据处理: Pandas 2.x
- 可视化: Plotly(HTML 报告)
- 数据校验: Pydantic v2
## 目录结构
```
src/quant_personal/
├── data/ # 数据获取 (fetcher.py) + 数据模型 (models.py)
├── strategy/ # 策略基类 (base.py) + 具体策略
├── backtest/ # 回测引擎 (engine.py) + 指标计算 (metrics.py)
├── report/ # HTML 报告生成 (generator.py)
└── cli/ # Click 命令行接口 (main.py)
```
## 规则
- 所有函数标注完整类型(参数 + 返回值)
- 数据模型用 Pydantic 或 SQLAlchemy,不用裸 dict
- 异常不吞------捕获后必须日志记录或重新抛出
- 文件路径用 pathlib.Path,不硬编码字符串
- 所有 SQLAlchemy 查询使用 2.0 风格(select() 语法)
## 测试规范
- 单元测试放在 tests/unit/
- 集成测试放在 tests/integration/
- 数据获取模块的测试使用 mock 数据(不调真实 API)
- 回测模块的测试使用固定数据集(保证结果可复现)
- 覆盖率目标: >80%
- 提交前必须通过: ruff check + pytest
## 禁忌
- 不要硬编码 Tushare/AKShare 的 Token
- 不要写 print() 调试------用 logging 模块
- 不要在模块顶层创建 Session 实例
- 不要用 pandas 的 inplace=True(已弃用)
- 不要提交 .db 文件和 .env 文件
1.2 配置 Hooks(自动质量门禁)
oh-my-claudecode 提供了预配置的 Hooks。复制到项目中:
bash
cp ~/oh-my-claudecode/hooks/python-quality.json .claude/hooks.json
内容如下(这是核心,确保每次 AI 生成代码后自动检查质量):
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"filePattern": "*.py",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && python -m ruff check --fix \"$CLAUDE_TOOL_FILE_PATH\" && python -m ruff format --quiet \"$CLAUDE_TOOL_FILE_PATH\""
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_TOOL_COMMAND\" | grep -qE 'rm -rf|git push --force|git reset --hard HEAD~'; then echo '[HOOK] BLOCKED: Destructive command detected'; exit 1; fi"
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "if [ \"$CLAUDE_NOTIFICATION_TYPE\" = \"Edit\" ] || [ \"$CLAUDE_NOTIFICATION_TYPE\" = \"Write\" ]; then python -m pytest tests/unit/ -x -q 2>/dev/null || true; fi"
}
]
}
]
}
}
三层保护:
- PostToolUse:AI 每次写/改 Python 文件 → 自动 ruff 检查和格式化
- PreToolUse :拦截
rm -rf、git push --force等危险命令 - Notification:代码改动后自动跑单元测试(静默失败,不阻塞)
1.3 复制预置 Slash Commands
bash
cp ~/oh-my-claudecode/commands/* .claude/commands/
oh-my-claudecode 提供的常用命令:
.claude/commands/
├── review.md # 代码审查(安全检查 + 逻辑 + 性能 + 风格)
├── test.md # 运行当前改动相关的测试
├── clean.md # ruff format + ruff check --fix + 清理未使用 import
├── spec-prd.md # 生成 PRD 模板
├── spec-arch.md # 生成 Architecture 模板
└── git-commit.md # 自动生成规范的 commit message
挑两个重要的展示内容:
.claude/commands/review.md:
markdown
审查当前 staged 文件(git diff --cached)或指定文件。
## 审查维度
### 1. 安全(优先级最高)
- [ ] SQL 注入:是否使用参数化查询,有没有字符串拼接 SQL
- [ ] 敏感信息:是否硬编码 Token/密码/密钥
- [ ] 路径遍历:文件操作是否校验了路径范围
### 2. 逻辑正确性
- [ ] 边界条件:空列表、None、0、负数等是否处理
- [ ] 错误处理:异常是妥善处理还是被吞掉
- [ ] 并发安全:数据库操作是否考虑了并发场景(本项目单用户,此项可放宽)
### 3. 性能
- [ ] N+1 查询:ORM 关系加载是否合理
- [ ] 大数据量:DataFrame 操作是否高效
- [ ] 不必要的 I/O:是否有重复读取
### 4. 代码风格
- [ ] 类型标注:所有函数有完整类型标注
- [ ] 命名:符合 Python 命名惯例
- [ ] 函数长度:是否超过 30 行
## 输出格式
对每个问题:🔴 严重 / 🟡 注意 / 🟢 建议
最后给出总体评分(通过/需修改/拒绝)
.claude/commands/git-commit.md:
markdown
分析当前 staged 的改动,生成规范的 commit message。
格式: type(scope): 中文简短描述
Type: feat / fix / refactor / test / docs / chore
Scope: data / strategy / backtest / report / cli
只输出 commit 命令,不做其他操作。
第二步:Spec 三件套------先设计再动手
2.1 生成 PRD
在 Claude Code 中执行:
/spec-prd
oh-my-claudecode 的 /spec-prd 命令会引导 AI 输出 PRD 到 specs/01-prd.md。生成后你审阅修改,最终内容:
markdown
# PRD: Quant Personal v1.0
## 产品目标
构建一个 CLI 个人量化分析工具,支持 A 股数据获取、策略回测、结果可视化。
## 用户故事
1. 作为投资者,我希望能下载 A 股历史数据到本地数据库(数据获取)
2. 作为投资者,我希望能用双均线策略对单只股票做回测(策略回测)
3. 作为投资者,我希望看到回测结果的收益曲线和关键指标(可视化报告)
## 功能列表(按优先级)
| # | 功能 | 优先级 | 验收标准 |
|---|------|--------|----------|
| F1 | 数据获取 CLI | P0 | `quant fetch 600519` 下载茅台历史数据到 SQLite |
| F2 | 数据模型 | P0 | SQLAlchemy 模型,支持按代码+日期范围查询 |
| F3 | 双均线策略 | P1 | 短期均线上穿长期均线→买入信号,下穿→卖出信号 |
| F4 | 回测引擎 | P1 | 输入股票代码+策略+日期范围,输出交易记录和持仓变化 |
| F5 | 指标计算 | P1 | 年化收益率、最大回撤、夏普比率、胜率 |
| F6 | HTML 报告 | P2 | 收益曲线图 + 指标汇总表 + 交易明细表 |
| F7 | 定时任务 | P2 | 每天 15:30 自动拉取持仓股票数据 |
## 非功能需求
- 回测 10 年数据耗时 < 10 秒
- 数据获取失败有明确错误提示(不静默)
- 所有 CLI 命令 help 信息清晰
## 不做什么
- 不接实时交易
- 不做 Web 界面
- v1 不支持港股美股
2.2 生成架构设计
/spec-arch
AI 生成后你审阅修改:
markdown
# Architecture: Quant Personal v1.0
## 整体架构
```
┌────────────────────────────────────────────┐
│ CLI (Click) │
│ quant fetch | quant backtest | quant report │
└──────┬──────────┬──────────┬──────────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Data │ │ Backtest │ │ Report │
│ Module │ │ Engine │ │ Generator│
└────┬─────┘ └────┬─────┘ └──────────┘
│ │
▼ ▼
┌──────────────────────────────────┐
│ SQLite Database │
│ stocks | daily_prices | trades │
└──────────────────────────────────┘
```
## 数据模型
```python
class Stock(Base):
__tablename__ = "stocks"
id: int (PK)
symbol: str (唯一,如 "600519")
name: str (如 "贵州茅台")
class DailyPrice(Base):
__tablename__ = "daily_prices"
id: int (PK)
stock_id: int (FK → stocks.id)
trade_date: date
open: float
high: float
low: float
close: float
volume: int
# 联合唯一约束: (stock_id, trade_date)
```
## 策略接口
```python
class BaseStrategy(ABC):
@abstractmethod
def generate_signals(self, df: pd.DataFrame) -> pd.Series:
"""输入K线数据,输出信号序列 (1=买入, -1=卖出, 0=持有)"""
```
## 关键设计决策
1. SQLite 而非 PostgreSQL------单人本地使用,零运维
2. Pydantic 做 CLI 参数校验------Click 原生校验偏弱
3. Plotly 生成 HTML 报告------比 matplotlib 图片更交互
2.3 生成任务列表
在 Claude Code 中:
基于 @specs/01-prd.md 和 @specs/02-architecture.md,生成任务列表到 @specs/03-tasks.md。
每个 Task 是可独立完成和测试的最小单元,按依赖排序。
审阅后的最终版本:
markdown
# 任务列表: Quant Personal v1.0
## Phase 1: 项目基础
- [ ] Task 1.1: 初始化项目配置(pyproject.toml, conftest.py, .env.example)
- [ ] Task 1.2: 数据模型(models.py: Stock + DailyPrice)
- [ ] Task 1.3: 数据库初始化(engine.py: 建表 + Session 管理)
## Phase 2: 数据获取
- [ ] Task 2.1: AKShare 数据获取适配器(fetcher.py)
- [ ] Task 2.2: 数据获取 CLI 命令(`quant fetch <symbol>`)
- [ ] Task 2.3: 数据获取单元测试(mock API 响应)
## Phase 3: 策略
- [ ] Task 3.1: 策略基类(base.py: BaseStrategy ABC)
- [ ] Task 3.2: 双均线策略实现(ma_cross.py)
- [ ] Task 3.3: 策略单元测试
## Phase 4: 回测
- [ ] Task 4.1: 回测引擎(engine.py: 信号→交易记录→持仓变化)
- [ ] Task 4.2: 指标计算(metrics.py: 年化收益/最大回撤/夏普比率/胜率)
- [ ] Task 4.3: 回测 CLI 命令(`quant backtest <symbol> --strategy ma_cross`)
- [ ] Task 4.4: 回测集成测试(固定数据集,验证结果可复现)
## Phase 5: 报告
- [ ] Task 5.1: HTML 报告生成(generator.py: Plotly 图表 + 指标汇总)
- [ ] Task 5.2: 报告 CLI 命令(`quant report <backtest_id>`)
## Phase 6: 定时任务
- [ ] Task 6.1: 定时任务脚本(crontab 或 schedule 库)
第三步:逐 Task 实现------真实对话记录
下面是实际开发中的关键节点对话。每个 Task 展示你在 Claude Code 中输入什么、AI 输出什么、你怎么审阅和纠正。
Task 1.1: 项目配置
👤: 初始化项目配置。创建 pyproject.toml,项目名 quant-personal,Python 3.12+。
依赖: click, sqlalchemy>=2.0, pandas, pydantic>=2.0, plotly, akshare。
开发依赖: pytest, pytest-cov, ruff, pre-commit。
配置 ruff: 行宽 100,select = ["E", "F", "I", "N", "W", "UP"]。
创建 .env.example(包含 TUSHARE_TOKEN 和 AKSHARE_TOKEN 模板)。
创建 tests/conftest.py(Fixture: 临时 SQLite 数据库)。
AI 生成文件后,你检查:
👤: pyproject.toml 中加一条: [tool.ruff.lint] 下加 ignore = ["E501"]。
因为有些 SQL 语句超 100 字符是正常的。
👤: conftest.py 的 temp_db fixture 加 scope="function",每个测试函数独立数据库。
Task 1.2: 数据模型
👤: 实现数据模型。基于 @specs/02-architecture.md 的设计。
要求:
- Stock 表: id, symbol(唯一索引), name
- DailyPrice 表: id, stock_id(FK→stocks), trade_date, open, high, low, close, volume
- (stock_id, trade_date) 联合唯一约束
- 模型加 __repr__ 方法(方便调试)
- 所有 Column 显式指定类型,不用类型推断
文件: src/quant_personal/data/models.py
AI 生成:
python
"""量化数据模型"""
from datetime import date
from sqlalchemy import Integer, String, Float, Date, ForeignKey, UniqueConstraint
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class Stock(Base):
__tablename__ = "stocks"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
symbol: Mapped[str] = mapped_column(String(10), unique=True, index=True, nullable=False)
name: Mapped[str] = mapped_column(String(100), nullable=False)
prices: Mapped[list["DailyPrice"]] = relationship(back_populates="stock", cascade="all, delete-orphan")
def __repr__(self) -> str:
return f"<Stock(id={self.id}, symbol='{self.symbol}', name='{self.name}')>"
class DailyPrice(Base):
__tablename__ = "daily_prices"
__table_args__ = (UniqueConstraint("stock_id", "trade_date", name="uq_stock_date"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
stock_id: Mapped[int] = mapped_column(ForeignKey("stocks.id"), nullable=False)
trade_date: Mapped[date] = mapped_column(Date, nullable=False)
open: Mapped[float] = mapped_column(Float, nullable=False)
high: Mapped[float] = mapped_column(Float, nullable=False)
low: Mapped[float] = mapped_column(Float, nullable=False)
close: Mapped[float] = mapped_column(Float, nullable=False)
volume: Mapped[int] = mapped_column(Integer, nullable=False)
stock: Mapped["Stock"] = relationship(back_populates="prices")
def __repr__(self) -> str:
return f"<DailyPrice(stock_id={self.stock_id}, date={self.trade_date}, close={self.close})>"
你的审阅:
👤: 检查几点:
1. Stock.symbol 长度 String(10) 够吗?A 股代码是 6 位,够了。
2. volume 用 BigInteger 还是 Integer?Integer 最大 2^31≈21 亿,A 股日成交额不会超过,用 Integer 够了。
3. cascade="all, delete-orphan" 确认------删除 Stock 时自动删除关联的 DailyPrice。符合预期。
4. ✅ 通过
然后 hooks 自动触发 ruff 格式化(不需要你手动执行)。
Task 1.3: 数据库引擎
👤: 实现数据库初始化和 Session 管理。
要求:
- 用 SQLAlchemy 2.0 风格
- 数据库文件路径从环境变量 QUANT_DB_PATH 读取,默认 ./data/quant.db
- 提供 get_session() 生成器函数(context manager)
- 提供 init_db() 函数(创建所有表)
- 不要用全局 Session 实例
文件: src/quant_personal/data/engine.py
AI 生成,你审阅:
👤: init_db() 里 echo=True 去掉,生产环境不需要打印 SQL。
加一行: data_dir.mkdir(parents=True, exist_ok=True)(确保目录存在)。
Task 2.1: 数据获取适配器
这是第一个需要跟外部 API 打交道的模块。你用 AKShare(免费,不需要 Token)。
👤: 实现 AKShare 数据获取适配器。
要求:
- 输入: 股票代码(如 "600519"),开始日期,结束日期(可选,默认今天)
- 输出: list[dict],每个 dict 包含 trade_date/open/high/low/close/volume
- 异常处理: 网络错误 → 重试 2 次(间隔 3 秒),仍失败 → raise
- 数据校验: 用 Pydantic 校验每个字段类型和范围(价格 > 0,成交量 >= 0)
- 用 logging 记录日志,不用 print
AKShare API: ak.stock_zh_a_hist(symbol="600519", period="daily",
start_date="20200101", end_date="20250605")
返回 DataFrame,列名: 日期/开盘/收盘/最高/最低/成交量
文件: src/quant_personal/data/fetcher.py
同时创建: src/quant_personal/data/schemas.py (Pydantic 校验模型)
AI 生成后,关键审阅点:
👤: 几个问题:
1. 重试逻辑用 tenacity 库(pip install tenacity),不要自己写 while 循环
2. Pydantic model 中的 trade_date 用 date 类型,不要用 str
3. 日志加上 trace_id(用 uuid4),方便排查
4. volume 字段 AKShare 返回的可能为 None(停牌日),处理为 0
Task 2.2: CLI 命令
👤: 实现数据获取 CLI。用 Click 框架。
命令: quant fetch <symbol>
选项:
--start YYYYMMDD (必填)
--end YYYYMMDD (可选,默认今天)
--output json|table (可选,默认 table)
流程:
1. 校验参数(用 Pydantic)
2. 调用 fetcher 获取数据
3. 存入数据库(去重------已存在的 trade_date 跳过)
4. 输出结果摘要(下载了多少条、跳过了多少条)
文件: src/quant_personal/cli/main.py
用 @cli.group() 组织命令,未来可以加 backtest/report 子命令。
Task 3.2: 双均线策略
👤: 实现双均线交叉策略。基于 @src/quant_personal/strategy/base.py。
规则:
- 短期均线(默认 5 日)上穿长期均线(默认 20 日)→ 信号 = 1(买入)
- 短期均线下穿长期均线 → 信号 = -1(卖出)
- 其余 → 信号 = 0(持有)
输入: DataFrame(列: trade_date, open, high, low, close, volume)
输出: DataFrame(新增列: ma_short, ma_long, signal)
⚠️ 注意: 前 N-1 天(不足长期均线长度)的信号应设为 0,不是 NaN
文件: src/quant_personal/strategy/ma_cross.py
AI 生成后,审阅:
👤: 检查:
1. 信号逻辑: 上穿 = 今天 short > long AND 昨天 short <= long ✅
2. 前 19 天(不足 20 日均线)signal = 0 ✅
3. 参数可配置(short_window, long_window)✅
4. ✅ 通过
Task 4.1: 回测引擎
这是最核心的模块。你用详细的 Prompt 确保 AI 一次写对:
👤: 实现回测引擎。这是核心模块,请仔细阅读要求。
输入:
- prices: DataFrame(from database,含 trade_date/open/high/low/close/volume)
- strategy: BaseStrategy 实例
- initial_capital: float(初始资金,默认 100000)
- commission_rate: float(手续费率,默认 0.0003,即万三)
回测逻辑:
1. 逐日遍历 prices
2. 当信号 = 1 且当前持仓 = 0:
→ 全仓买入(买入股数 = 可用资金 / 当日收盘价,向下取整到 100 的倍数)
→ 记录交易: 日期/类型(BUY)/价格/数量/手续费/金额
3. 当信号 = -1 且当前持仓 > 0:
→ 全仓卖出
→ 记录交易: 日期/类型(SELL)/价格/数量/手续费/金额
4. 计算每日持仓市值 = 持仓数量 × 当日收盘价 + 现金
5. 输出: BacktestResult 对象
BacktestResult 包含:
- trades: list[Trade](每笔交易记录)
- daily_values: list[DailyValue](每日持仓市值)
- 初始资金/最终资金/总收益率
⚠️ 关键约束:
- 买入时必须考虑手续费(买入金额 × 0.0003,最低 5 元)
- 卖出时也收手续费 + 印花税(卖出金额 × 0.001,仅卖出时)
- 股数必须是 100 的整数倍(A 股规则)
- 不能卖空(持仓 = 0 时不能卖出)
文件: src/quant_personal/backtest/engine.py
同时创建: src/quant_personal/backtest/schemas.py (Trade, DailyValue, BacktestResult)
由于这个 Prompt 非常详细,AI 基本一次就能输出正确的代码。你审阅时重点看:
👤: 检查:
1. ✅ 买入手续费 = max(买入金额 × 0.0003, 5)
2. ✅ 卖出费用 = max(卖出金额 × 0.0003, 5) + 卖出金额 × 0.001
3. ✅ shares = int(cash / price / 100) * 100(向下取整到 100 的倍数)
4. ✅ 不能卖空
5. ✅ 回测结果数据类型正确
Task 4.2: 指标计算
👤: 实现回测指标计算,基于 @src/quant_personal/backtest/engine.py 的 BacktestResult。
计算以下指标:
1. 年化收益率: (最终资金/初始资金)^(252/交易日数) - 1
2. 最大回撤: 从任意峰值到最低谷的最大跌幅百分比
3. 夏普比率: (年化收益率 - 无风险利率) / 年化波动率
无风险利率默认 0.025(2.5%)
4. 胜率: 盈利交易笔数 / 总交易笔数
5. 总交易笔数
输入: BacktestResult
输出: MetricsResult (Pydantic model)
文件: src/quant_personal/backtest/metrics.py
Task 4.3: 回测 CLI
👤: 实现回测 CLI 命令。
命令: quant backtest <symbol> [OPTIONS]
选项:
--strategy ma_cross (当前仅此一种)
--start YYYYMMDD (必填)
--end YYYYMMDD (可选,默认今天)
--capital FLOAT (可选,默认 100000)
--short-window INT (可选,默认 5)
--long-window INT (可选,默认 20)
--output json|table (可选,默认 table)
流程:
1. 从数据库查询指定股票和日期范围的日线数据
2. 初始化策略实例(传入参数)
3. 运行回测引擎
4. 计算指标
5. 输出结果
文件: src/quant_personal/cli/main.py(添加 backtest 子命令)
Task 5.1: HTML 报告
👤: 实现 HTML 报告生成。
输入: BacktestResult + MetricsResult
输出: 单个 HTML 文件,包含:
1. 收益曲线(Plotly 折线图,X轴=日期,Y轴=市值,标注买卖点)
2. 指标汇总表(年化收益率/最大回撤/夏普比率/胜率/交易次数)
3. 交易明细表(日期/类型/价格/数量/手续费/金额)
样式要求:
- 深色背景,白字
- 表格用 Bootstrap 风格
- 自包含(所有 CSS/JS 内嵌在 HTML 中)
文件: src/quant_personal/report/generator.py
Task 6.1: 定时任务
👤: 实现每日定时数据更新。
用 Python 的 schedule 库 + 一个常驻脚本:
脚本: scripts/daily_sync.py
功能:
- 每天 15:30 执行(A 股收盘后)
- 读取 config/watchlist.txt(每行一个股票代码)
- 逐个下载最近 30 天的日线数据
- 存入数据库(自动去重)
- 完成记录日志
文件: scripts/daily_sync.py
同时创建: config/watchlist.txt(示例)
第四步:Hooks 在开发过程中的实际作用
整个开发过程中,oh-my-claudecode 的 Hooks 在后台静默工作。回顾一下它们节省了多少时间:
场景一: AI 写了一个 import 顺序错误的文件
没有 Hook: 你发现 → 纠正 AI → AI 修改 → 重新格式化
有 Hook: AI 写完 → Hook 自动 ruff format → import 已排序 ✅
节省: 每次 1-2 分钟 × 约 40 个文件 = 40-80 分钟
场景二: AI 尝试执行 rm -rf 清理临时文件
没有 Hook: AI 执行 → 可能误删 → 你恢复 → 骂人
有 Hook: AI 执行 → Hook 拦截 → AI 告诉你"被阻止了" ✅
节省: 灾难性损失
场景三: AI 修改了一个核心函数,没跑测试
没有 Hook: 你手动跑测试 → 发现 3 个失败 → 排查 → 修复
有 Hook: AI 写完 → Hook 自动跑测试 → 失败 → AI 立刻看到 → 自己修复 ✅
节省: 每次 5-10 分钟 × 约 15 次 = 75-150 分钟
第五步:生产级收尾
5.1 生成测试套件
bash
# 在 Claude Code 中
👤: 检查测试覆盖率,补全缺失的单测。目标 > 80%。
🤖: [分析 coverage report]
当前覆盖率 72%。
未覆盖: fetcher.py 的错误处理分支、metrics.py 的边界条件。
[生成补充测试]
覆盖率 → 84% ✅
5.2 配置 pre-commit
yaml
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: local
hooks:
- id: pytest
name: pytest
entry: python -m pytest tests/unit/ -x -q
language: system
types: [python]
pass_filenames: false
bash
pre-commit install
5.3 验证整个流水线
bash
# 完整功能验证
source venv/bin/activate
# 1. 下载茅台 5 年数据
quant fetch 600519 --start 20200101
# 输出: 下载 1325 条,新增 1325 条,跳过 0 条
# 2. 运行回测
quant backtest 600519 --start 20200101 --strategy ma_cross --short-window 5 --long-window 20
# 输出:
# ====================================
# 回测结果: 600519 贵州茅台
# 策略: 双均线交叉 (5, 20)
# 回测区间: 2020-01-01 ~ 2025-06-05
# ====================================
# 初始资金: ¥100,000.00
# 最终资金: ¥218,350.00
# 总收益率: 118.35%
# 年化收益率: 15.62%
# 最大回撤: -22.31%
# 夏普比率: 0.84
# 胜率: 42.3% (22/52)
# 交易次数: 52
# 3. 生成报告
quant report --symbol 600519 --start 20200101 --strategy ma_cross
# 输出: 报告已生成 → reports/600519_ma_cross_20200101_20250605.html
# 4. 运行所有测试
pytest tests/ -v
# 输出: 28 passed in 2.35s
# 5. 代码质量
ruff check src/
# 输出: All checks passed!
完整项目结构回顾
quant-personal/
├── CLAUDE.md # Claude Code 项目指令
├── pyproject.toml # 项目配置 + ruff 规则
├── .pre-commit-config.yaml # pre-commit hooks
├── .gitignore
├── .env.example # Token 模板
│
├── .claude/
│ ├── hooks.json # 自动质量检查
│ └── commands/ # 自定义命令
│ ├── review.md
│ ├── test.md
│ ├── clean.md
│ ├── spec-prd.md
│ ├── spec-arch.md
│ └── git-commit.md
│
├── specs/
│ ├── 01-prd.md # 需求文档
│ ├── 02-architecture.md # 架构设计
│ └── 03-tasks.md # 任务列表(27 个 Task,全部 ✅)
│
├── src/quant_personal/
│ ├── data/
│ │ ├── models.py # Stock + DailyPrice ORM 模型
│ │ ├── engine.py # 数据库引擎 + Session 管理
│ │ ├── fetcher.py # AKShare 数据获取适配器
│ │ └── schemas.py # Pydantic 校验模型
│ ├── strategy/
│ │ ├── base.py # 策略抽象基类
│ │ └── ma_cross.py # 双均线交叉策略
│ ├── backtest/
│ │ ├── engine.py # 回测引擎
│ │ ├── metrics.py # 指标计算
│ │ └── schemas.py # BacktestResult/MetricsResult
│ ├── report/
│ │ └── generator.py # HTML 报告生成
│ └── cli/
│ └── main.py # Click CLI 入口
│
├── scripts/
│ └── daily_sync.py # 定时数据同步脚本
│
├── config/
│ └── watchlist.txt # 关注股票列表
│
└── tests/
├── conftest.py # 公共 Fixtures
├── unit/
│ ├── test_models.py
│ ├── test_fetcher.py
│ ├── test_ma_cross.py
│ ├── test_engine.py
│ └── test_metrics.py
└── integration/
└── test_backtest_e2e.py # 端到端测试
这篇文章的核心交付
1. oh-my-claudecode 三个核心能力:
→ Hooks(自动格式化 + 危险命令拦截 + 自动跑测试)
→ 预置 Slash Commands(review/test/clean/spec-prd/spec-arch/git-commit)
→ CLAUDE.md 模板(按项目类型提供最佳实践规则)
2. Spec Driven 实操:
→ PRD(需求范围 + 验收标准)→ Architecture(数据模型 + 策略接口)→ Tasks(27 个)
→ 每个 Spec 经过你审阅修改后才进入执行阶段
3. 逐 Task 实现的关键对话:
→ 每个 Task 展示完整的 Prompt + AI 输出 + 你的审阅纠正
→ 越核心的模块(回测引擎)Prompt 越详细
4. 国产模型适配:
→ 详细 Prompt 比简洁 Prompt 效果好(因为模型不需要"猜")
→ 每次一个 Task,上下文干净
→ 用 @ 引用前面确认过的文件,不靠记忆
5. 生产级收尾:
→ 测试覆盖率 > 80%
→ pre-commit 自动检查
→ 完整功能验证通过的输出