# 基金定投收益计算工具
使用 `akshare` 获取基金净值数据,`exchange_calendars` 判断交易日,自动计算定投收益。
## 安装依赖
```bash
pip install -r requirements.txt
```
## 功能特性
- ✅ 自动计算定投日期(月/周定投)
- ✅ 支持手动投资日期配置
- ✅ 支持定投失败日期配置
- ✅ 自动获取基金净值数据
- ✅ 交易日智能判断(非交易日顺延)
- ✅ 计算总体收益、年化收益率、IRR
- ✅ 计算每笔投资的收益明细
- ✅ 支持历史任意时点收益计算
## 快速开始
### 示例1:每月定投
```python
from datetime import date
from fund import Fund
# 创建基金对象
fund = Fund(
fund_code="005827", # 基金代码
buy_fee_rate=0.0015, # 申购费率 0.15%
regular_rule={
"start_date": date(2024, 1, 15),
"interval": "monthly", # 每月定投
"day": 15, # 每月15日
"amount": 1000 # 每次1000元
},
skip_dates=[date(2024, 3, 15)], # 跳过的日期
manual_investments=[ # 手动投资
{"date": date(2024, 2, 10), "amount": 5000}
]
)
# 获取所有投资日期
dates = fund.get_all_investment_dates()
# 获取投资记录明细
records = fund.get_investment_records()
# 计算总体收益
result = fund.calculate_return()
print(f"收益率: {result['return_rate']:.2f}%")
print(f"IRR: {result['irr']:.2f}%")
# 计算每笔投资收益
each_result = fund.calculate_each_investment_return()
```
### 示例2:每周定投
```python
fund = Fund(
fund_code="110022",
regular_rule={
"start_date": date(2024, 9, 1),
"interval": "weekly",
"weekday": 4, # 每周五(0=周一)
"amount": 500
}
)
```
### 示例3:计算历史收益
```python
# 计算9月30日的收益
result = fund.calculate_return(as_of_date=date(2024, 9, 30))
# 不传日期则使用最新净值
result = fund.calculate_return()
```
## API 说明
### Fund 类
#### 构造函数
```python
Fund(
fund_code: str, # 基金代码(6位)
fund_name: str = None, # 基金名称(可选,自动获取)
buy_fee_rate: float = 0.0015, # 申购费率
regular_rule: dict = None, # 定投规则
skip_dates: list[date] = None, # 跳过的日期
manual_investments: list[dict] = None # 手动投资
)
```
**定投规则格式:**
每月定投:
```python
{
"start_date": date(2024, 1, 15),
"interval": "monthly",
"day": 15, # 每月的日期
"amount": 1000
}
```
每周定投:
```python
{
"start_date": date(2024, 1, 1),
"interval": "weekly",
"weekday": 4, # 0=周一, 4=周五
"amount": 500
}
```
双周定投:
```python
{
"start_date": date(2024, 1, 1),
"interval": "biweekly",
"weekday": 4,
"amount": 500
}
```
#### 方法
##### `get_all_investment_dates() -> list[date]`
返回所有投资日期(定投+手动),按时间排序。
##### `get_investment_records() -> list[dict]`
返回每笔投资的详细记录:
```python
[{
"date": date, # 投资日期
"amount": float, # 投入本金
"fee": float, # 手续费
"net_amount": float, # 扣费后金额
"nav": float, # 买入净值
"shares": float # 买入份额
}, ...]
```
##### `calculate_return(as_of_date: date = None) -> dict`
计算总体收益:
```python
{
"as_of_date": date, # 计算日期
"total_cost": float, # 总投入(含手续费)
"total_net_cost": float, # 总投入(扣除手续费)
"total_shares": float, # 总份额
"current_nav": float, # 当前净值
"current_value": float, # 当前价值
"profit": float, # 收益金额
"return_rate": float, # 收益率(%)
"annualized_return": float, # 年化收益率(%)
"irr": float # 内部收益率(%)
}
```
##### `calculate_each_investment_return(as_of_date: date = None) -> list[dict]`
计算每笔投资的收益:
```python
[{
"date": date,
"amount": float, # 投入金额
"buy_nav": float, # 买入净值
"shares": float, # 买入份额
"current_nav": float, # 当前净值
"current_value": float, # 当前价值
"profit": float, # 该笔收益
"return_rate": float # 该笔收益率(%)
}, ...]
```
## 运行示例
```bash
python example.py
```
## 注意事项
1. **净值更新时间**:基金净值在交易日收盘后(晚上18:00-22:00)公布
2. **交易日处理**:非交易日会自动顺延到下一个交易日
3. **费率**:仅考虑申购费,不考虑赎回费
4. **数据来源**:使用 akshare 从东方财富获取数据,免费无需token
## 收益率说明
### 简单收益率
```
收益率 = (当前价值 - 总投入) / 总投入 × 100%
```
### 年化收益率
```
年化收益率 = 收益率 / 持有天数 × 365
```
### IRR(内部收益率)
考虑资金的时间价值,求解使净现值为0的收益率,更准确反映投资回报。
## 常见问题
**Q: 为什么定投日期不是我设定的日期?**
A: 如果设定日期是非交易日(周末/节假日),会自动顺延到下一个交易日。
**Q: 如何查看历史某一天的收益?**
A: 使用 `calculate_return(as_of_date=date(2024, 9, 30))`
**Q: 手动投资和定投日期重叠怎么办?**
A: 系统会分别记录,两笔投资都会生效。
Raw data
{
"_id": null,
"home_page": null,
"name": "fund-investment-calculator",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "fund, investment, financial, calculator, \u5b9a\u6295",
"author": null,
"author_email": "liwenyi <lwy.lwy@163.com>",
"download_url": "https://files.pythonhosted.org/packages/30/f5/03c5c357fc4838a6f842bf2f7ac432cae3d35d1003afb0a3bd313c64a40b/fund_investment_calculator-0.1.0.tar.gz",
"platform": null,
"description": "# \u57fa\u91d1\u5b9a\u6295\u6536\u76ca\u8ba1\u7b97\u5de5\u5177\n\n\u4f7f\u7528 `akshare` \u83b7\u53d6\u57fa\u91d1\u51c0\u503c\u6570\u636e\uff0c`exchange_calendars` \u5224\u65ad\u4ea4\u6613\u65e5\uff0c\u81ea\u52a8\u8ba1\u7b97\u5b9a\u6295\u6536\u76ca\u3002\n\n## \u5b89\u88c5\u4f9d\u8d56\n\n```bash\npip install -r requirements.txt\n```\n\n## \u529f\u80fd\u7279\u6027\n\n- \u2705 \u81ea\u52a8\u8ba1\u7b97\u5b9a\u6295\u65e5\u671f\uff08\u6708/\u5468\u5b9a\u6295\uff09\n- \u2705 \u652f\u6301\u624b\u52a8\u6295\u8d44\u65e5\u671f\u914d\u7f6e\n- \u2705 \u652f\u6301\u5b9a\u6295\u5931\u8d25\u65e5\u671f\u914d\u7f6e\n- \u2705 \u81ea\u52a8\u83b7\u53d6\u57fa\u91d1\u51c0\u503c\u6570\u636e\n- \u2705 \u4ea4\u6613\u65e5\u667a\u80fd\u5224\u65ad\uff08\u975e\u4ea4\u6613\u65e5\u987a\u5ef6\uff09\n- \u2705 \u8ba1\u7b97\u603b\u4f53\u6536\u76ca\u3001\u5e74\u5316\u6536\u76ca\u7387\u3001IRR\n- \u2705 \u8ba1\u7b97\u6bcf\u7b14\u6295\u8d44\u7684\u6536\u76ca\u660e\u7ec6\n- \u2705 \u652f\u6301\u5386\u53f2\u4efb\u610f\u65f6\u70b9\u6536\u76ca\u8ba1\u7b97\n\n## \u5feb\u901f\u5f00\u59cb\n\n### \u793a\u4f8b1\uff1a\u6bcf\u6708\u5b9a\u6295\n\n```python\nfrom datetime import date\nfrom fund import Fund\n\n# \u521b\u5efa\u57fa\u91d1\u5bf9\u8c61\nfund = Fund(\n fund_code=\"005827\", # \u57fa\u91d1\u4ee3\u7801\n buy_fee_rate=0.0015, # \u7533\u8d2d\u8d39\u7387 0.15%\n regular_rule={\n \"start_date\": date(2024, 1, 15),\n \"interval\": \"monthly\", # \u6bcf\u6708\u5b9a\u6295\n \"day\": 15, # \u6bcf\u670815\u65e5\n \"amount\": 1000 # \u6bcf\u6b211000\u5143\n },\n skip_dates=[date(2024, 3, 15)], # \u8df3\u8fc7\u7684\u65e5\u671f\n manual_investments=[ # \u624b\u52a8\u6295\u8d44\n {\"date\": date(2024, 2, 10), \"amount\": 5000}\n ]\n)\n\n# \u83b7\u53d6\u6240\u6709\u6295\u8d44\u65e5\u671f\ndates = fund.get_all_investment_dates()\n\n# \u83b7\u53d6\u6295\u8d44\u8bb0\u5f55\u660e\u7ec6\nrecords = fund.get_investment_records()\n\n# \u8ba1\u7b97\u603b\u4f53\u6536\u76ca\nresult = fund.calculate_return()\nprint(f\"\u6536\u76ca\u7387: {result['return_rate']:.2f}%\")\nprint(f\"IRR: {result['irr']:.2f}%\")\n\n# \u8ba1\u7b97\u6bcf\u7b14\u6295\u8d44\u6536\u76ca\neach_result = fund.calculate_each_investment_return()\n```\n\n### \u793a\u4f8b2\uff1a\u6bcf\u5468\u5b9a\u6295\n\n```python\nfund = Fund(\n fund_code=\"110022\",\n regular_rule={\n \"start_date\": date(2024, 9, 1),\n \"interval\": \"weekly\",\n \"weekday\": 4, # \u6bcf\u5468\u4e94\uff080=\u5468\u4e00\uff09\n \"amount\": 500\n }\n)\n```\n\n### \u793a\u4f8b3\uff1a\u8ba1\u7b97\u5386\u53f2\u6536\u76ca\n\n```python\n# \u8ba1\u7b979\u670830\u65e5\u7684\u6536\u76ca\nresult = fund.calculate_return(as_of_date=date(2024, 9, 30))\n\n# \u4e0d\u4f20\u65e5\u671f\u5219\u4f7f\u7528\u6700\u65b0\u51c0\u503c\nresult = fund.calculate_return()\n```\n\n## API \u8bf4\u660e\n\n### Fund \u7c7b\n\n#### \u6784\u9020\u51fd\u6570\n\n```python\nFund(\n fund_code: str, # \u57fa\u91d1\u4ee3\u7801\uff086\u4f4d\uff09\n fund_name: str = None, # \u57fa\u91d1\u540d\u79f0\uff08\u53ef\u9009\uff0c\u81ea\u52a8\u83b7\u53d6\uff09\n buy_fee_rate: float = 0.0015, # \u7533\u8d2d\u8d39\u7387\n regular_rule: dict = None, # \u5b9a\u6295\u89c4\u5219\n skip_dates: list[date] = None, # \u8df3\u8fc7\u7684\u65e5\u671f\n manual_investments: list[dict] = None # \u624b\u52a8\u6295\u8d44\n)\n```\n\n**\u5b9a\u6295\u89c4\u5219\u683c\u5f0f\uff1a**\n\n\u6bcf\u6708\u5b9a\u6295\uff1a\n```python\n{\n \"start_date\": date(2024, 1, 15),\n \"interval\": \"monthly\",\n \"day\": 15, # \u6bcf\u6708\u7684\u65e5\u671f\n \"amount\": 1000\n}\n```\n\n\u6bcf\u5468\u5b9a\u6295\uff1a\n```python\n{\n \"start_date\": date(2024, 1, 1),\n \"interval\": \"weekly\",\n \"weekday\": 4, # 0=\u5468\u4e00, 4=\u5468\u4e94\n \"amount\": 500\n}\n```\n\n\u53cc\u5468\u5b9a\u6295\uff1a\n```python\n{\n \"start_date\": date(2024, 1, 1),\n \"interval\": \"biweekly\",\n \"weekday\": 4,\n \"amount\": 500\n}\n```\n\n#### \u65b9\u6cd5\n\n##### `get_all_investment_dates() -> list[date]`\n\n\u8fd4\u56de\u6240\u6709\u6295\u8d44\u65e5\u671f\uff08\u5b9a\u6295+\u624b\u52a8\uff09\uff0c\u6309\u65f6\u95f4\u6392\u5e8f\u3002\n\n##### `get_investment_records() -> list[dict]`\n\n\u8fd4\u56de\u6bcf\u7b14\u6295\u8d44\u7684\u8be6\u7ec6\u8bb0\u5f55\uff1a\n\n```python\n[{\n \"date\": date, # \u6295\u8d44\u65e5\u671f\n \"amount\": float, # \u6295\u5165\u672c\u91d1\n \"fee\": float, # \u624b\u7eed\u8d39\n \"net_amount\": float, # \u6263\u8d39\u540e\u91d1\u989d\n \"nav\": float, # \u4e70\u5165\u51c0\u503c\n \"shares\": float # \u4e70\u5165\u4efd\u989d\n}, ...]\n```\n\n##### `calculate_return(as_of_date: date = None) -> dict`\n\n\u8ba1\u7b97\u603b\u4f53\u6536\u76ca\uff1a\n\n```python\n{\n \"as_of_date\": date, # \u8ba1\u7b97\u65e5\u671f\n \"total_cost\": float, # \u603b\u6295\u5165\uff08\u542b\u624b\u7eed\u8d39\uff09\n \"total_net_cost\": float, # \u603b\u6295\u5165\uff08\u6263\u9664\u624b\u7eed\u8d39\uff09\n \"total_shares\": float, # \u603b\u4efd\u989d\n \"current_nav\": float, # \u5f53\u524d\u51c0\u503c\n \"current_value\": float, # \u5f53\u524d\u4ef7\u503c\n \"profit\": float, # \u6536\u76ca\u91d1\u989d\n \"return_rate\": float, # \u6536\u76ca\u7387\uff08%\uff09\n \"annualized_return\": float, # \u5e74\u5316\u6536\u76ca\u7387\uff08%\uff09\n \"irr\": float # \u5185\u90e8\u6536\u76ca\u7387\uff08%\uff09\n}\n```\n\n##### `calculate_each_investment_return(as_of_date: date = None) -> list[dict]`\n\n\u8ba1\u7b97\u6bcf\u7b14\u6295\u8d44\u7684\u6536\u76ca\uff1a\n\n```python\n[{\n \"date\": date,\n \"amount\": float, # \u6295\u5165\u91d1\u989d\n \"buy_nav\": float, # \u4e70\u5165\u51c0\u503c\n \"shares\": float, # \u4e70\u5165\u4efd\u989d\n \"current_nav\": float, # \u5f53\u524d\u51c0\u503c\n \"current_value\": float, # \u5f53\u524d\u4ef7\u503c\n \"profit\": float, # \u8be5\u7b14\u6536\u76ca\n \"return_rate\": float # \u8be5\u7b14\u6536\u76ca\u7387\uff08%\uff09\n}, ...]\n```\n\n## \u8fd0\u884c\u793a\u4f8b\n\n```bash\npython example.py\n```\n\n## \u6ce8\u610f\u4e8b\u9879\n\n1. **\u51c0\u503c\u66f4\u65b0\u65f6\u95f4**\uff1a\u57fa\u91d1\u51c0\u503c\u5728\u4ea4\u6613\u65e5\u6536\u76d8\u540e\uff08\u665a\u4e0a18:00-22:00\uff09\u516c\u5e03\n2. **\u4ea4\u6613\u65e5\u5904\u7406**\uff1a\u975e\u4ea4\u6613\u65e5\u4f1a\u81ea\u52a8\u987a\u5ef6\u5230\u4e0b\u4e00\u4e2a\u4ea4\u6613\u65e5\n3. **\u8d39\u7387**\uff1a\u4ec5\u8003\u8651\u7533\u8d2d\u8d39\uff0c\u4e0d\u8003\u8651\u8d4e\u56de\u8d39\n4. **\u6570\u636e\u6765\u6e90**\uff1a\u4f7f\u7528 akshare \u4ece\u4e1c\u65b9\u8d22\u5bcc\u83b7\u53d6\u6570\u636e\uff0c\u514d\u8d39\u65e0\u9700token\n\n## \u6536\u76ca\u7387\u8bf4\u660e\n\n### \u7b80\u5355\u6536\u76ca\u7387\n```\n\u6536\u76ca\u7387 = (\u5f53\u524d\u4ef7\u503c - \u603b\u6295\u5165) / \u603b\u6295\u5165 \u00d7 100%\n```\n\n### \u5e74\u5316\u6536\u76ca\u7387\n```\n\u5e74\u5316\u6536\u76ca\u7387 = \u6536\u76ca\u7387 / \u6301\u6709\u5929\u6570 \u00d7 365\n```\n\n### IRR\uff08\u5185\u90e8\u6536\u76ca\u7387\uff09\n\u8003\u8651\u8d44\u91d1\u7684\u65f6\u95f4\u4ef7\u503c\uff0c\u6c42\u89e3\u4f7f\u51c0\u73b0\u503c\u4e3a0\u7684\u6536\u76ca\u7387\uff0c\u66f4\u51c6\u786e\u53cd\u6620\u6295\u8d44\u56de\u62a5\u3002\n\n## \u5e38\u89c1\u95ee\u9898\n\n**Q: \u4e3a\u4ec0\u4e48\u5b9a\u6295\u65e5\u671f\u4e0d\u662f\u6211\u8bbe\u5b9a\u7684\u65e5\u671f\uff1f**\nA: \u5982\u679c\u8bbe\u5b9a\u65e5\u671f\u662f\u975e\u4ea4\u6613\u65e5\uff08\u5468\u672b/\u8282\u5047\u65e5\uff09\uff0c\u4f1a\u81ea\u52a8\u987a\u5ef6\u5230\u4e0b\u4e00\u4e2a\u4ea4\u6613\u65e5\u3002\n\n**Q: \u5982\u4f55\u67e5\u770b\u5386\u53f2\u67d0\u4e00\u5929\u7684\u6536\u76ca\uff1f**\nA: \u4f7f\u7528 `calculate_return(as_of_date=date(2024, 9, 30))`\n\n**Q: \u624b\u52a8\u6295\u8d44\u548c\u5b9a\u6295\u65e5\u671f\u91cd\u53e0\u600e\u4e48\u529e\uff1f**\nA: \u7cfb\u7edf\u4f1a\u5206\u522b\u8bb0\u5f55\uff0c\u4e24\u7b14\u6295\u8d44\u90fd\u4f1a\u751f\u6548\u3002\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "\u57fa\u91d1\u5b9a\u6295\u6536\u76ca\u8ba1\u7b97\u5de5\u5177\uff0c\u652f\u6301\u81ea\u52a8\u83b7\u53d6\u51c0\u503c\u6570\u636e\u548c\u4ea4\u6613\u65e5\u5224\u65ad",
"version": "0.1.0",
"project_urls": {
"Bug Tracker": "https://github.com/wenyili/fund-investment-calculator/issues",
"Homepage": "https://github.com/wenyili/fund-investment-calculator",
"Repository": "https://github.com/wenyili/fund-investment-calculator"
},
"split_keywords": [
"fund",
" investment",
" financial",
" calculator",
" \u5b9a\u6295"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "0749808484342ecfe0f569d464de4edeee39485ab8a4b977619bf4fd0ac0afc1",
"md5": "ae4ae9e88c9207418a88cb0060d5792f",
"sha256": "c1e8ebb29f56133cee8ad84e758c17077acf5ed3ebd37c72b6b8d0b6990f4a9a"
},
"downloads": -1,
"filename": "fund_investment_calculator-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "ae4ae9e88c9207418a88cb0060d5792f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 11449,
"upload_time": "2025-10-07T10:36:59",
"upload_time_iso_8601": "2025-10-07T10:36:59.648465Z",
"url": "https://files.pythonhosted.org/packages/07/49/808484342ecfe0f569d464de4edeee39485ab8a4b977619bf4fd0ac0afc1/fund_investment_calculator-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "30f503c5c357fc4838a6f842bf2f7ac432cae3d35d1003afb0a3bd313c64a40b",
"md5": "edc99b1e925bc3e34e1d68dd72addae8",
"sha256": "56a00f39d9a516900655a3b2f43c2b87e477d061cef7bbe1e3c5d619f7ec7e4f"
},
"downloads": -1,
"filename": "fund_investment_calculator-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "edc99b1e925bc3e34e1d68dd72addae8",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 15242,
"upload_time": "2025-10-07T10:37:00",
"upload_time_iso_8601": "2025-10-07T10:37:00.936684Z",
"url": "https://files.pythonhosted.org/packages/30/f5/03c5c357fc4838a6f842bf2f7ac432cae3d35d1003afb0a3bd313c64a40b/fund_investment_calculator-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-07 10:37:00",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "wenyili",
"github_project": "fund-investment-calculator",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "akshare",
"specs": [
[
">=",
"1.14.0"
]
]
},
{
"name": "exchange-calendars",
"specs": [
[
">=",
"4.5.0"
]
]
},
{
"name": "pandas",
"specs": [
[
">=",
"2.0.0"
]
]
},
{
"name": "scipy",
"specs": [
[
">=",
"1.11.0"
]
]
}
],
"lcname": "fund-investment-calculator"
}