Skip to content

Repository files navigation

模拟基金交易系统

Python Frontend Data Status

一个面向中国公募基金市场的本地化模拟交易与轮动回测系统。项目提供 Web 前端界面,支持从 AKShare 抓取全市场基金净值数据,缓存到本地 SQLite,并在浏览器中完成基金轮动策略模拟、交易记录展示、资产曲线绘制和模拟结果保存。

重要说明:本项目用于研究、教学和策略原型验证,不构成任何投资建议。基金历史收益不代表未来表现,真实交易还需要考虑申购费、赎回费、流动性、限购、暂停申赎、滑点、税费、平台规则和数据延迟等因素。

目录

核心能力

  • 支持自定义模拟开始月份和结束月份,当前前端可选择到 2026-12
  • 支持自定义初始资金,默认值为 3000 元。
  • 支持从 AKShare 获取中国市场公募基金目录与单位净值走势。
  • 支持设置本次最多抓取基金数量,当前系统上限为 2000 只。
  • 使用 SQLite 持久化基金元数据、历史净值、更新状态和失败记录。
  • 支持本地内置样本数据兜底,便于离线演示和接口不可用时继续运行。
  • 支持月度轮动回测:按月卖出到期持仓,再按排名和入场过滤决定是否重新买入。
  • 支持限制最多持有基金数量,以及同一板块最多持有数量。
  • 优先选择 C 类短期基金。
  • 支持多种买入分配方式:
    • 均等买入
    • 排名加权
    • 排名加权 + 风险惩罚
  • 支持单只基金仓位上限,避免资金过度集中。
  • 支持入场过滤:当榜首收益、前 N 平均收益或全市场正收益占比不足时,卖出后保持现金空仓等待。
  • 支持买入决策解释:展示当月排名、实际买入、同板块排除、风险惩罚和仓位计算。
  • 支持一键导出 HTML 回测报告。
  • 显示完整交易记录,包括买入额度、卖出额度、卖出时账户余额和交易说明。
  • 显示账户资产曲线、年度收益、累计收益、年化收益、最大回撤、月度胜率等指标。
  • 点击基金名称可查看该基金历史净值曲线。
  • 支持保存本次模拟结果到本地 JSON 文件。
  • 浏览器 localStorage 会保存最近一次模拟结果,刷新页面后可以恢复。

界面与交互

系统启动后会打开一个本地 Web 页面,主要区域包括:

  • 顶部参数区:开始月份、结束月份、最多抓取数量、初始资金、买入分配方式。
  • 策略参数区:收益排名前 N、最多持有数量、同板块限制、持有周期、单只仓位上限、入场过滤。
  • 数据质量区:展示当前 SQLite 缓存中的基金数量、净值数量、更新时间和失败数量。
  • 操作日志区:显示模拟进度、数据来源、估计耗时和关键操作。
  • 资产曲线区:展示账户资产随时间变化。
  • 年度收益区:对比每年收益表现。
  • 择时决策区:展示每个月是否买入或空仓等待,以及对应原因。
  • 交易记录区:展示所有买入和卖出记录。
  • 基金净值弹窗:点击基金名称后查看历史净值变化。

策略逻辑

当前默认策略是一个月度轮动策略:

  1. 系统读取指定回测区间内的基金月度净值。
  2. 每个月计算刚结束月份的基金收益率。
  3. 从当月收益率排名前 N 的基金中选择候选,默认 N = 10
  4. 优先选择 C 类基金。
  5. 买入时遵守以下约束:
    • 最多同时持有 3 只基金。
    • 同一板块最多持有 2 只基金。
    • 单只基金默认最高占账户资金 60%
  6. 买入后默认持有约 1 个月。
  7. 到下一个轮动月,先卖出到期持仓。
  8. 系统检查入场过滤条件:榜首收益、前 N 平均收益和全市场正收益占比。
  9. 如果条件满足,再基于新的月度排名重新买入;如果条件不满足,则保持现金空仓等待下一轮信号。
  10. 模拟结束时强制卖出剩余持仓,并计算最终账户资产。

买入分配方式说明:

  • 均等买入:选中的基金平分资金。
  • 排名加权:排名越靠前,分配权重越高。
  • 排名加权 + 风险惩罚:在排名权重基础上,对高波动或风险标签较高的基金降低分配比例。

数据来源

在线数据来自 AKShare:

  • 基金目录:fund_name_em
  • 历史净值:fund_open_fund_info_em
  • 指标:单位净值走势
  • 底层数据源:东方财富公开数据接口

数据更新流程:

  1. 前端点击“更新全市场净值”。
  2. 后端创建独立 worker 进程,避免 AKShare 依赖异常影响 Web 服务。
  3. worker 拉取全市场基金目录。
  4. 系统过滤货币、现金管理、理财、同业存单等不适合当前策略的基金。
  5. 按前端设置的最大数量逐只抓取历史净值。
  6. 每成功抓取一只基金,立即写入 SQLite。
  7. 更新完成后同步导出 data/funds.json,兼容前端旧格式。
  8. 页面后续优先读取 SQLite 缓存;没有数据库数据时回退到 data/funds.json,最后回退到 data/funds.js

首次全市场更新可能耗时较长。实际耗时取决于网络质量、AKShare 接口响应速度、基金数量上限和历史净值区间。

快速开始

1. 克隆项目

git clone <your-repo-url>
cd fund-simulator

如果你已经在本地项目目录中,可以直接进入:

cd fund-simulator

2. 安装依赖

python -m pip install -r requirements.txt

当前主要 Python 依赖:

akshare>=1.18.64

3. 启动服务

python server.py

服务启动后访问:

http://127.0.0.1:8765

4. 更新基金数据

打开页面后点击:

更新全市场净值

建议首次测试时先把“最多抓取”设为较小值,例如 50100,确认流程正常后再提高到 10002000

5. 开始模拟

设置开始月份、结束月份、初始资金和策略参数后,点击:

开始模拟交易

模拟完成后可以点击:

保存这次模拟

结果会保存到 saved-simulations/ 目录。

项目结构

fund-simulator/
├── app.js                 # 前端主控:事件绑定、状态协调、页面渲染
├── config.py              # 路径、常量、依赖路径配置
├── data/
│   ├── funds.js           # 内置兜底基金样本
│   ├── funds.json         # AKShare 更新后导出的兼容数据
│   └── funds.db           # SQLite 本地缓存
├── favicon.svg            # 浏览器标签页图标
├── fund_data.py           # AKShare 抓取、清洗、对齐和导出逻辑
├── fund_data_worker.py    # 后台数据更新进程入口
├── index.html             # 页面结构
├── js/
│   ├── config.js          # 前端常量与默认策略参数
│   ├── format.js          # 金额、百分比、月份、HTML 转义等工具函数
│   ├── report.js          # HTML 回测报告生成与下载
│   └── strategy.js        # 策略回测、入场过滤、仓位分配、收益指标
├── jobs.py                # 数据更新任务状态与 worker 管理
├── README.md              # 项目说明
├── requirements.txt       # Python 依赖
├── saved-simulations/     # 保存的模拟结果
├── server.py              # 本地 HTTP 服务和 API 路由
├── storage.py             # SQLite 读写、缓存和质量统计
└── styles.css             # 页面样式

后端接口

GET /

返回前端页面。

GET /api/fund-data

返回当前可用基金净值数据。读取优先级:

  1. SQLite 本地缓存 data/funds.db
  2. JSON 导出文件 data/funds.json
  3. 前端内置样本 data/funds.js

GET /api/fund-data/quality

返回当前本地缓存的数据质量摘要,包括基金数量、净值数量、最近更新时间和失败记录数量。

POST /api/update-fund-data

创建 AKShare 数据更新任务。

请求示例:

{
  "startMonth": "2020-01",
  "endMonth": "2026-12",
  "maxFunds": 2000,
  "includeMoneyFunds": false
}

GET /api/update-fund-data/status?jobId=<jobId>

查询数据更新进度。

POST /api/save-simulation

保存一次模拟结果到 saved-simulations/

本地持久化

系统当前使用三类本地持久化:

类型 路径 用途
SQLite data/funds.db 保存基金元数据、历史净值、更新批次、失败记录
JSON data/funds.json 保存 AKShare 更新后的兼容格式数据
JSON saved-simulations/ 保存用户点击“保存这次模拟”后的回测结果
localStorage 浏览器本地存储 保存最近一次模拟结果,便于刷新恢复

.gitignore 默认忽略本地抓取数据和模拟结果,避免把大型数据文件提交到 GitHub。

架构说明

后端已经按职责拆分:

  • server.py:只做 HTTP 请求处理、参数校验和响应序列化。
  • jobs.py:负责创建更新任务、维护任务状态、启动 worker 子进程。
  • fund_data.py:负责 AKShare 数据抓取、字段识别、净值清洗和时间区间对齐。
  • storage.py:负责 SQLite 表结构、缓存读写、失败标记和数据质量统计。
  • config.py:集中管理路径、数据源说明和系统级参数。

前端也已按职责拆分:

  • app.js:负责 DOM 事件、页面状态、弹窗、图表重绘和 API 调用。
  • js/config.js:集中管理前端常量、默认策略参数和数据源兜底说明。
  • js/format.js:提供金额、百分比、日期、HTML 转义等通用工具。
  • js/strategy.js:负责策略回测、入场过滤、仓位分配、收益指标和基金净值统计。
  • js/report.js:负责生成并下载单文件 HTML 回测报告。

这样拆分后,后续可以更容易地加入:

  • 多策略回测
  • 策略参数组合扫描
  • 数据更新任务队列
  • 更完整的测试用例
  • 云端部署或多人访问能力

后续规划

优先级较高的改进方向:

  • 增加申购费、赎回费、短期持有惩罚和管理费估算。
  • 增加沪深300、中证全债、偏股基金指数等基准对比。
  • 增加多策略对比,例如动量轮动、低回撤优先、风险平价、定投策略。
  • 增加自动化测试,覆盖排名、买入、卖出、仓位限制和同板块限制。

常见问题

为什么最多只抓取 2000 只基金?

AKShare 全市场基金目录可能有上万条记录。逐只抓取历史净值会耗费较长时间,也可能触发接口限流。当前系统把最大抓取数量限制为 2000,是为了保证本地演示、开发和调试的可控性。

如果我把前端数量设置成 2000 会怎样?

系统会按 2000 作为本次抓取上限执行。超过 2000 的输入会被前后端共同限制到 2000,避免创建过大的抓取任务。

为什么我选择 2012 年开始,模拟却只能从更晚月份开始?

模拟只能使用当前本地缓存已经覆盖的净值区间。如果 SQLite 缓存最早只有 2024-01,而你选择 2012-01,系统会提示需要先按所选区间更新 AKShare 净值数据,不再静默从 2024-01 开始模拟。

当前策略是不是会使用未来数据?

当前轮动逻辑使用刚结束月份的收益排名做下一个持有周期的买入决策。也就是说,买入依据是买入前已经发生的月度净值变化,不应该直接使用买入之后的收益作为买入依据。

为什么模拟收益可能和真实交易不同?

真实基金交易存在确认日、净值公布延迟、申购赎回费、短期赎回惩罚、暂停交易、限购、平台规则和资金到账时间。当前系统是策略研究工具,不是实盘交易系统。

可以部署到服务器吗?

可以。当前项目是 Python 本地 HTTP 服务 + 静态前端页面。部署到云服务器时,需要让 Python 服务常驻运行,并通过 Nginx、宝塔面板、Docker 或 systemd 等方式暴露访问入口。

联系方式

如果你对这个项目感兴趣,或者希望交流基金回测、策略模拟、数据源接入、部署和二次开发,可以通过邮件联系:

chinas0310@gmail.com

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages