# 个人投资持仓管理系统 > 现代化、全面化的个人投资组合管理平台,支持多市场(美股、A股、港股、加密货币)统一管理。 ![License](https://img.shields.io/badge/license-MIT-blue.svg) ![Next.js](https://img.shields.io/badge/Next.js-16-black.svg) ![TypeScript](https://img.shields.io/badge/TypeScript-5-blue.svg) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-16-blue.svg) --- ## 功能特性 ### 核心功能 | 功能 | 描述 | |------|------| | **多市场支持** | 美股 (US)、A股 (CN)、港股 (HK)、加密货币 (CRYPTO) | | **资金流水管理** | 入金、出金记录 | | **交易流水管理** | 买入、卖出、分红、利息、费用 | | **持仓统计** | 实时市值、平均成本、浮动盈亏 | | **多币种转换** | 自动将各币种资产折算为 USD | | **资产配置图** | 饼图展示各市场占比 | | **数据导入导出** | CSV 格式导入导出 | ### 交易类型 | 类型 | 说明 | |------|------| | `BUY` | 买入 | | `SELL` | 卖出 | | `DEPOSIT` | 入金 | | `WITHDRAW` | 出金 | | `DIVIDEND` | 分红 | | `INTEREST` | 利息 | | `FEE` | 费用/手续费 | --- ## 技术架构 ### 技术栈 ``` 前端: ├── Next.js 16 (App Router) ├── React 19 ├── TypeScript 5 ├── Tailwind CSS 4 ├── shadcn/ui (组件库) ├── Recharts (图表) └── Sonner (Toast 通知) 后端: ├── Next.js API Routes ├── Prisma ORM └── PostgreSQL 16 实时数据: └── Alpha Vantage API ``` ### 数据库模型 ``` ┌─────────────┐ ┌─────────────┐ │ User │───1:N─│ Account │ └─────────────┘ └─────────────┘ │ │ 1:N ┌─────────────┼─────────────┐ │ │ │ ▼ ▼ ▼ ┌───────────┐ ┌───────────┐ ┌───────────┐ │Position │ │Transaction│ │ExchangeRate│ └───────────┘ └───────────┘ └───────────┘ │ ▼ ┌───────────┐ │ Security │ └───────────┘ ``` ### 表结构说明 | 表名 | 说明 | |------|------| | `User` | 用户表(预留多用户扩展) | | `Account` | 账户表(按市场类型分组) | | `Security` | 证券参考表(代码、名称、精度) | | `Transaction` | 交易流水表 | | `Position` | 持仓表(查询优化) | | `ExchangeRate` | 汇率参考表 | ### 字段精度设计 | 字段类型 | 精度 | 说明 | |----------|------|------| | 价格/金额 | `Decimal(20,4)` | 避免浮点精度丢失 | | 数量 | `Decimal(20,8)` | 加密货币支持8位小数 | | 汇率 | `Decimal(20,8)` | 高精度汇率转换 | --- ## API 接口 ### 账户管理 | 接口 | 方法 | 描述 | |------|------|------| | `/api/accounts` | GET | 获取账户列表 | | `/api/accounts` | POST | 创建账户 | ### 交易管理 | 接口 | 方法 | 描述 | |------|------|------| | `/api/transactions` | GET | 获取交易流水(支持分页) | | `/api/transactions` | POST | 记录交易(自动更新持仓/余额) | ### 持仓管理 | 接口 | 方法 | 描述 | |------|------|------| | `/api/positions` | GET | 获取持仓列表 | ### 仪表盘 | 接口 | 方法 | 描述 | |------|------|------| | `/api/dashboard/stats` | GET | 资产统计概览 | | `/api/dashboard/analytics` | GET | 持仓分析(含实时价格) | ### 数据导入 | 接口 | 方法 | 描述 | |------|------|------| | `/api/import/transactions` | POST | 批量导入交易记录 | ### 证券管理 | 接口 | 方法 | 描述 | |------|------|------| | `/api/securities` | GET | 搜索证券 | | `/api/securities` | POST | 添加证券 | ### 汇率管理 | 接口 | 方法 | 描述 | |------|------|------| | `/api/exchange-rates` | GET | 获取汇率列表 | | `/api/exchange-rates` | POST | 更新汇率 | --- ## 快速开始 ### 环境要求 - Node.js 20+ - PostgreSQL 16+ - npm 或 yarn ### 安装步骤 ```bash # 1. 克隆项目 git clone cd stock-portfolio # 2. 安装依赖 npm install # 3. 配置环境变量 cp .env.example .env # 编辑 .env 填入数据库连接信息 # 4. 生成 Prisma 客户端 npx prisma generate # 5. 初始化数据库 npx prisma migrate dev --name init npx prisma db seed # 6. 启动开发服务器 npm run dev # 7. 重置数据库 npx prisma migrate reset --force ``` ### 环境变量 ```env # 数据库连接 DATABASE_URL="postgresql://postgres:password@localhost:5432/stock_portfolio" # Alpha Vantage API Key(用于获取实时股价) ALPHA_VANTAGE_API_KEY="your-api-key" # HTTP 代理(可选,用于解决 API 访问问题) HTTP_PROXY="http://192.168.48.171:7893" HTTPS_PROXY="http://192.168.48.171:7893" # 极速数据 API Key(用于获取实时汇率,必须配置) JISU_API_KEY="your-jisuapi-key" ``` > **注意**:运行本项目前,必须在根目录配置 `.env` 文件,并添加 `JISU_API_KEY=您的极速数据Key`。汇率服务通过后端代理调用 JisuAPI,避免前端跨域问题。 --- ## 使用指南 ### 添加交易记录 1. 点击右上角「**记录交易**」按钮 2. 选择账户和交易类型 3. 输入证券代码(支持搜索) 4. 填写数量、价格(成交总额自动计算) 5. 点击「**确认记录**」 6. 在确认对话框中核实信息,点击「**确认**」 ### 导入批量交易 1. 点击右上角「**导入**」按钮 2. 点击「**下载模板**」获取 CSV 模板 3. 按照模板格式填写交易数据 4. 选择填写好的 CSV 文件 5. 预览导入数据(有效/错误标记) 6. 点击「**导入**」执行批量导入 ### 导出数据 1. 点击右上角「**导出**」按钮 2. 自动下载持仓 CSV 文件 3. 在「交易流水」标签页也可导出交易记录 ### 字段说明 #### 交易模板 CSV 格式 ```csv 时间,类型,证券代码,数量,价格,金额,手续费,币种,备注 2024-01-15 10:30:00,BUY,AAPL,10,185.50,1855.00,1.00,USD,买入苹果 ``` | 字段 | 必填 | 说明 | |------|------|------| | 时间 | 是 | 格式:`YYYY-MM-DD HH:mm:ss` | | 类型 | 是 | `BUY`/`SELL`/`DEPOSIT`/`WITHDRAW`/`DIVIDEND` | | 证券代码 | 否 | 买入/卖出/分红时填写 | | 数量 | 否 | 股票数量 | | 价格 | 否 | 单价 | | 金额 | 是 | 总金额 | | 手续费 | 否 | 交易手续费 | | 币种 | 是 | `USD`/`CNY`/`HKD`/`USDT` | | 备注 | 否 | 任意备注信息 | --- ## 成本计算 ### 平均成本法 (Average Cost) 系统采用**平均成本法**计算持仓成本: ``` 新平均成本 = (现有成本 × 现有数量 + 新买入成本) / (现有数量 + 新买入数量) ``` ### 示例 ``` 初始:买入 10 股 AAPL,价格 $150 → 平均成本 = $150 再次:买入 10 股 AAPL,价格 $160 → 新平均成本 = ($150×10 + $160×10) / 20 = $155 ``` --- ## 多币种处理 ### 汇率转换 系统以 **USD** 为基准货币,将所有资产折算为 USD 进行汇总: | 币种 | 汇率 (示例) | |------|-------------| | USD | 1.0 | | CNY | 0.137 | | HKD | 0.129 | | USDT | 1.0 | ### 更新汇率 通过 `/api/exchange-rates` 接口或数据库直接更新汇率参考表。 --- ## 界面预览 ### 资产概览 ``` ┌─────────────────────────────────────────────────────────┐ │ [Logo] 投资持仓管理 [账户▼] [导入] [导出] [记录交易] │ ├─────────────────────────────────────────────────────────┤ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 总资产 │ │ 浮动盈亏 │ │ 持仓市值 │ │ 账户数量 │ │ │ │ $125,430 │ │ +$3,250 │ │ $98,200 │ │ 4 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────────┘ ``` ### 持仓明细 | 证券 | 市场 | 数量 | 成本价 | 当前价 | 市值 | 盈亏 | |------|------|------|--------|--------|------|------| | AAPL | 美股 | 50 | $150.00 | $178.50 | $8,925 | +$1,425 (+19.0%) | | MSFT | 美股 | 20 | $380.00 | $415.20 | $8,304 | +$704 (+9.3%) | | BTC | 加密 | 0.5 | $60,000 | $67,500 | $33,750 | +$3,750 (+12.5%) | --- ## 项目结构 ``` stock-portfolio/ ├── prisma/ │ ├── schema.prisma # 数据库模型 │ ├── seed.ts # 初始化数据 │ └── migrations/ # 数据库迁移 ├── src/ │ ├── app/ │ │ ├── api/ # API 路由 │ │ │ ├── accounts/ │ │ │ ├── transactions/ │ │ │ ├── positions/ │ │ │ ├── securities/ │ │ │ ├── exchange-rates/ │ │ │ ├── dashboard/ │ │ │ └── import/ │ │ ├── page.tsx # 主页面 │ │ ├── layout.tsx # 布局 │ │ └── globals.css # 全局样式 │ ├── components/ │ │ └── ui/ # shadcn/ui 组件 │ ├── lib/ │ │ ├── api.ts # API 调用封装 │ │ ├── prisma.ts # Prisma 客户端 │ │ ├── import-export.ts # 导入导出工具 │ │ └── price-service.ts # 价格服务 │ └── types/ │ └── index.ts # 类型定义 ├── .env # 环境变量 ├── .env.example # 环境变量示例 ├── package.json ├── tsconfig.json ├── next.config.ts └── README.md ``` --- ## 常见问题 ### Q: 实时价格如何获取? A: 系统使用 Alpha Vantage API 获取美股实时价格。需要配置 `ALPHA_VANTAGE_API_KEY` 环境变量。 ### Q: 支持哪些市场? A: 目前支持美股 (US)、A股 (CN)、港股 (HK)、加密货币 (CRYPTO) 四个市场。 ### Q: 成本计算使用什么算法? A: 系统使用**平均成本法 (Average Cost)** 计算持仓成本。 ### Q: 基准货币是什么? A: 系统以 **USD** 为基准货币,所有资产会折算为 USD 进行汇总展示。 --- ## 许可证 MIT License - 详见 [LICENSE](LICENSE) 文件 --- ## 更新日志 ### v1.0.6 (2026-04-13) - 🔧 汇率服务安全重构:JisuAPI Key 从前端移至后端环境变量 `JISU_API_KEY`,彻底根除硬编码 - 🔧 JisuAPI 解析修复:修正 `data.status !== 0`(原错误使用 `data.code`)和 `data.result?.rate`(原错误使用 `data.result?.result`) - 🛡️ 缓存防毒:移除 `next: { revalidate }`,改用自研内存缓存,防止错误响应被 Next.js 缓存1小时 - 🔧 交易编辑原子性:PATCH `/api/transactions` 完整重写,增删改操作使用 `prisma.$transaction` 原子事务 - 📊 持仓重算服务:新增 `recalculatePosition()` 函数,PATCH 编辑时遍历历史 BUY/SELL 交易重算 avgCost - 🔧 BUG-301 修复:编辑交易时正确逆向原始交易并重算持仓,彻底解决"编辑后持仓不变"的 Blockering Bug - 🔧 币种自动识别:新增 `getCurrencyFromSymbol()` 函数,根据证券代码推断 CNY/HKD/USD - 🔧 BUG-401/402 修复:新建交易时证券切换自动更新 currency,resetTxForm 默认 USD 而非账户货币 - 💱 汇率 Fallback 强化:`getExchangeRate` 包裹完整 try-catch,确保 JisuAPI 失败时正确降级至 DEFAULT_RATES - 📝 注释修正:`transactions/route.ts` 注释 BUTH → BUY/SELL - 🔧 BUG-601 修复:`recalculatePosition()` 的 `upsert` 硬编码 `currency: 'USD'` → 动态提取 history 最后一笔交易的 currency;`update` 分支新增 `currency` 字段实现脏数据自愈(600690/601919 等 A股持仓被错误标记为 USD 的问题彻底修复) ### v1.0.5 (2026-04-13) - 📛 证券名称增强:修复 INTC 等证券名称显示为空的问题 (BUG-101) - 🔒 SELL超量校验:修复卖出数量超过持仓导致持仓变负的Bug (BUG-002) - 🔄 撤销BUY成本还原:修复撤销买入时平均成本计算公式错误 (BUG-003) - 💹 Decimal精度计算:持仓分析改用Prisma.Decimal进行金融计算,防止浮点精度丢失 (BUG-004) - 📛 证券名称显示:在持仓分析卡片、资产分布、盈亏排行等位置同时显示股票代码和名称 - 📋 证券数据库扩展:新增 Intel Corp. (INTC) 证券记录 - 🔍 回退逻辑增强:确保证券名称为空时显示代码而非空白 - 📈 腾讯行情解析升级:精准解析股票名称(索引1),支持港/A/美股及 ETF 名称自动获取 - 🔀 多市场涨跌解析修复:重构腾讯行情多市场适配层,美股(索引4/5)与港A股(索引31/32)使用差异化索引解析涨跌数据 - 🇨🇳 GBK中文解码修复:改用 `arrayBuffer() + TextDecoder('gbk')` 替代 `text()`,彻底解决A股/港股中文股票名称乱码问题 - 💱 JisuAPI实时汇率:接入 JisuAPI 获取实时汇率,缓存1小时,支持 CNY/HKD/USD 转换 - 📊 资产配置动态图:环形图改由后端实时聚合持仓数据驱动,支持 Tooltip 和百分比显示 - 🎨 资产配置图表优化:精美毛玻璃 Tooltip、颜色图标、去除生硬描边、useMemo 性能优化 - 💱 全局货币联动:资产配置图表数值随 CNY/USD/HKD 切换实时转换 - 📝 交易流水增强:新增证券名称列,显示"名称+代码"双行格式 - 💹 全局汇率展示:在导航栏实时显示 USD/CNY/HKD 汇率信息 - 🔧 BUG-202 修复:修正 `convertCurrency` 汇率换算逻辑(原逻辑除法/乘法颠倒,导致 USD→CNY 换算失效) - 🔧 BUG-201 修复:腾讯行情 API 获取失败时,`priceAvailable` 标记配合前端显示 "N/A" 替代虚假 0% - 🔧 BUG-203 增强:持仓分析 `name` 字段确保回退到 `pos.symbol`,名称永不空 - 💹 Decimal 精度保障:所有盈亏/汇率计算均使用 Prisma.Decimal,防止浮点精度丢失 ### v1.0.4 (2026-04-12) - 🐛 总资产计算修复:修复了多市场持仓汇总时货币转换错误的问题 - 🐛 浮动盈亏修复:修复了成本基数和市值货币单位不一致导致的错误 - 💹 持仓分析修复:确保所有持仓数据统一转换为 USD 后再汇总 - 📈 港股价格获取:改用腾讯行情接口(r_hk前缀)获取港股实时价格(小鹏汽车等) - 📈 A股价格获取:改用腾讯行情接口(sz/sh前缀)获取A股实时价格(海尔智家、中证现金流ETF等) - 📈 美股价格获取:改用腾讯行情接口(s_us前缀)获取美股实时价格 - 🔍 证券名称显示:搜索和选择证券时同时显示代码和中文名称 - 📋 证券数据库扩展:新增小鹏汽车(09868)、海尔智家(600690)、中证现金流ETF(159235)、Alphabet(GOOGL) - ✏️ 交易流水编辑:支持编辑已创建的交易记录 - 💰 持仓货币随市场:持仓明细和分析中各市场使用对应货币显示(港股用HKD、A股用CNY、美股用USD) ### v1.0.3 (2026-04-12) - 🗑️ 删除交易记录功能:支持删除误添加的交易记录,自动回滚账户余额和持仓变化 - 💰 显示货币选择器:支持 CNY/USD/HKD 三种货币显示,默认 CNY - 🔄 实时货币转换:根据汇率自动转换总资产显示 - 💱 账户货币联动:选择账户时自动设置对应结算货币(美股→USD、A股→CNY、加密→USDT、港股→HKD) - 🔧 加密货币格式化:USDT 映射为 USD 进行显示 ### v1.0.2 (2026-04-12) - 🔧 账户名称优化:改为港股账户、美股账户、A股账户、加密货币账户 - ✨ 成交总额自动计算:根据数量 × 价格自动计算 - 🗑️ 删除持仓功能:支持通过卖出全部来删除持仓 - 🎨 Select 组件显示优化:修复了下拉框显示问题 - 📝 代码注释中文化 ### v1.0.1 (2026-04-12) - 🔧 账户名称优化:改为港股账户、美股账户、A股账户、加密货币账户 - ✨ 成交总额自动计算:根据数量 × 价格自动计算 - 🗑️ 删除持仓功能:支持通过卖出全部来删除持仓 - 🎨 Select 组件显示优化:修复了下拉框显示问题 - 📝 代码注释中文化 ### v1.0.0 (2026-04-12) - ✨ 初始版本发布 - 支持多市场账户管理 - 支持交易记录(买入/卖出/入金/出金/分红) - 支持持仓统计和盈亏计算 - 支持数据导入导出(CSV) - 支持 Alpha Vantage 实时价格 - 响应式深色模式界面