尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

通用指数定投机器人修改估值分位加仓档位,自定义5档加仓梯度

通用指数定投机器人修改估值分位加仓档位,自定义5档加仓梯度
📅 发布时间:2026/6/21 8:59:12

“通用指数定投机器人” 本身是一个定期定额(或定期不定额)投资指数的策略,现在要给它加上 估值分位加仓档位,并且是 自定义的 5 档梯度,也就是说根据当前指数 PE(或 PB)在历史中的分位数,来决定当期投入金额的倍率。

我会按照你给的顺序,用 Python 实现一个简化但结构清晰的版本,方便你后续扩展成实盘或回测系统。

一、实际应用场景描述

指数定投 是普通投资者参与股市最常见的方式之一,比如每周固定投 1000 元到沪深 300 ETF。

但“固定金额”有一个问题:没有考虑市场贵贱——贵的时候买和便宜的时候买一样多,长期收益不是最优。

估值分位加仓 的思路是:

- 当指数估值处于历史 低位(便宜) → 多买

- 当指数估值处于历史 高位(贵) → 少买或不买

这样能 摊薄成本、提升长期收益率,是智能投顾中常见的“增强型定投”策略。

二、引入痛点

传统固定金额定投有以下痛点:

1. 不管贵贱一个价沪深 300 PE 15 倍买 1000 元,PE 8 倍还是买 1000 元,没有利用“便宜多买”的机会。

2. 高位站岗风险如果在市场高位(如 2015 年牛市顶点)开始定投,需要很长时间回本。

3. 资金利用率低低位时没有加大投入,导致底部筹码收集不足。

4. 缺乏系统化规则很多人的“手动加仓”凭感觉,没有统一标准,容易情绪化操作。

三、核心逻辑讲解

3.1 核心思想

我们用 PE(市盈率)历史分位数 来衡量“贵贱”:

PE 分位数 = (当前 PE 在历史中排多少%)

例如:

- 当前 PE 分位 = 10% → 比历史上 90% 的时间都便宜 → 加大买入

- 当前 PE 分位 = 80% → 比历史上 80% 的时间都贵 → 减少买入或暂停

3.2 五档加仓梯度设计

我们定义 5 个档位,你可以自定义:

档位 PE 分位区间 买入倍率 含义

1 < 20% 2.0x 很度低估,重仓

2 20% ~ 40% 1.5x 低估,加码

3 40% ~ 60% 1.0x 正常,按基准投

4 60% ~ 80% 0.5x 高估,少投

5 ≥ 80% 0.0x 极度高估,暂停

倍率乘上“基准定投金额”,就是当期实际买入金额。

3.3 关键公式

当期买入金额 = 基准金额 × 档位倍率

如果档位倍率为 0,则当期不买入(相当于暂停定投)。

四、项目结构(简化版)

index_dca_robot/

├── README.md

├── requirements.txt

├── config.yaml

├── data/

│ └── index_pe_history.csv # 指数历史 PE 数据

├── src/

│ ├── data_loader.py # 数据加载

│ ├── valuation.py # ★ 估值分位计算

│ ├── dca_engine.py # ★ 定投引擎(含五档加仓)

│ └── backtester.py # 回测与统计

└── main.py

五、完整代码(模块化 + 清晰注释)

"requirements.txt"

pandas>=1.5

numpy>=1.21

pyyaml>=6.0

matplotlib>=3.5

"config.yaml"

# 指数定投机器人配置

# 定投参数

dca:

base_amount: 1000 # 基准定投金额(元)

frequency: "W" # 定投频率:W=周,M=月

# ★ 五档加仓梯度(可自定义)

valuation_brackets:

- { max_pct: 20, multiplier: 2.0 } # 极度低估

- { max_pct: 40, multiplier: 1.5 } # 低估

- { max_pct: 60, multiplier: 1.0 } # 正常

- { max_pct: 80, multiplier: 0.5 } # 高估

- { max_pct: 100, multiplier: 0.0 } # 极度高估

# 回测区间

backtest:

start_date: "2018-01-01"

end_date: "2024-12-31"

"src/data_loader.py"

"""

data_loader.py

加载指数历史 PE 数据

"""

import pandas as pd

def load_pe_history(filepath: str) -> pd.DataFrame:

"""

加载指数历史 PE 数据

预期格式:

date,pe

2018-01-02,12.5

2018-01-03,12.3

...

"""

df = pd.read_csv(filepath, parse_dates=['date'])

df = df.set_index('date').sort_index()

return df

"src/valuation.py"(★ 核心模块)

"""

valuation.py

★ 估值分位计算模块

"""

import pandas as pd

import numpy as np

class ValuationEngine:

"""

根据历史 PE 数据,计算当前 PE 的分位数,

并映射到对应的“买入倍率”。

"""

def __init__(self, brackets: list[dict]):

"""

参数:

brackets: list of dict,每个 dict 包含:

- max_pct: 分位上限(0~100)

- multiplier: 对应买入倍率

"""

# 按 max_pct 升序排列

self.brackets = sorted(brackets, key=lambda x: x['max_pct'])

def compute_percentile(self, pe_series: pd.Series, current_pe: float) -> float:

"""

计算当前 PE 在历史中的分位数(0~100)

逻辑:

(历史 PE <= 当前 PE 的天数) / (总天数) × 100

"""

if len(pe_series) == 0:

return 50.0 # 无数据时默认中位

count = (pe_series <= current_pe).sum()

pct = (count / len(pe_series)) * 100.0

return round(pct, 2)

def get_multiplier(self, pe_percentile: float) -> float:

"""

根据 PE 分位数返回对应的买入倍率

"""

for bracket in self.brackets:

if pe_percentile <= bracket['max_pct']:

return bracket['multiplier']

return self.brackets[-1]['multiplier']

"src/dca_engine.py"(★ 核心模块)

"""

dca_engine.py

★ 指数定投引擎:根据估值分位动态调整买入金额

"""

import pandas as pd

import numpy as np

from typing import Optional

class DCAEngine:

"""

通用指数定投机器人(支持估值分位加仓)

"""

def __init__(

self,

base_amount: float,

valuation_engine: "ValuationEngine",

frequency: str = "W"

):

"""

参数:

base_amount: 基准定投金额(元)

valuation_engine: 估值引擎实例

frequency: 定投频率,"W"=每周,"M"=每月

"""

self.base_amount = base_amount

self.ve = valuation_engine

self.frequency = frequency

# 状态记录

self.cash = 0.0 # 持有现金(元)

self.shares = 0.0 # 持有份额

self.total_invested = 0.0 # 累计投入

self.trade_log: list[dict] = [] # 交易日志

def _get_frequency_date(self, date: pd.Timestamp) -> bool:

"""

判断当前日期是否应该执行定投:

- W: 每周一

- M: 每月第一个交易日

"""

if self.frequency == "W":

return date.dayofweek == 0

elif self.frequency == "M":

return date.day == 1

return False

def run_daily(

self,

date: pd.Timestamp,

index_price: float,

pe_value: float,

pe_history: pd.Series

):

"""

每日调用,由回测引擎驱动

参数:

date: 当前日期

index_price: 当日指数点位(或 ETF 价格)

pe_value: 当日 PE

pe_history: 截至当日的历史 PE 序列

"""

# 只在定投日执行

if not self._get_frequency_date(date):

return

# ★ 核心:计算 PE 分位 + 获取买入倍率

pe_pct = self.ve.compute_percentile(pe_history, pe_value)

multiplier = self.ve.get_multiplier(pe_pct)

# 计算当期买入金额

invest_amount = self.base_amount * multiplier

if invest_amount <= 0:

# 暂停定投

self.trade_log.append({

'date': date,

'action': 'skip',

'reason': f'PE分位 {pe_pct:.1f}% → 倍率 {multiplier}x',

'amount': 0,

'price': index_price,

'shares': 0

})

return

# 执行买入

shares_bought = invest_amount / index_price

self.cash -= invest_amount

self.shares += shares_bought

self.total_invested += invest_amount

self.trade_log.append({

'date': date,

'action': 'buy',

'reason': f'PE分位 {pe_pct:.1f}% → 倍率 {multiplier}x',

'amount': invest_amount,

'price': index_price,

'shares': shares_bought

})

def get_snapshot(self, current_price: float) -> dict:

"""返回当前账户快照"""

market_value = self.shares * current_price

return {

'cash': self.cash,

'shares': self.shares,

'market_value': market_value,

'total_invested': self.total_invested,

'pnl': market_value - self.total_invested,

'pnl_pct': (

(market_value - self.total_invested) / self.total_invested * 100

if self.total_invested > 0 else 0

)

}

"src/backtester.py"

"""

backtester.py

回测引擎:驱动定投机器人

"""

import pandas as pd

from src.dca_engine import DCAEngine

def run_backtest(

engine: DCAEngine,

price_data: pd.DataFrame,

pe_data: pd.DataFrame,

start_date: str,

end_date: str

) -> dict:

"""

遍历历史数据,驱动定投引擎

"""

dates = price_data.index

if start_date:

dates = dates[dates >= pd.Timestamp(start_date)]

if end_date:

dates = dates[dates <= pd.Timestamp(end_date)]

for date in dates:

if date not in price_data.index:

continue

price = price_data.loc[date, 'close']

pe_val = pe_data.loc[date, 'pe'] if date in pe_data.index else None

if price <= 0 or pe_val is None:

continue

# 构建截至当前的历史 PE 序列

hist_pe = pe_data.loc[:date, 'pe']

engine.run_daily(date, price, pe_val, hist_pe)

return {

'trade_log': engine.trade_log,

'engine': engine

}

"main.py"

"""

main.py

主入口:运行估值分位加仓定投回测

"""

import yaml

import pandas as pd

from pathlib import Path

from src.data_loader import load_pe_history

from src.valuation import ValuationEngine

from src.dca_engine import DCAEngine

from src.backtester import run_backtest

def load_config(path='config.yaml'):

with open(path) as f:

return yaml.safe_load(f)

def generate_mock_data(n_days=1800):

"""生成模拟指数价格和 PE 数据"""

import numpy as np

dates = pd.date_range('2018-01-01', periods=n_days, freq='B')

np.random.seed(42)

# 模拟指数价格

price = pd.DataFrame({

'close': 3000 * pd.Series(

np.cumprod(1 + np.random.normal(0.0003, 0.015, n_days))

).values

}, index=dates)

# 模拟 PE:均值回归

pe_base = 12 + np.random.normal(0, 0.3, n_days)

pe_base = pd.Series(pe_base.cumsum() / range(1, n_days + 1) * 100, index=dates)

pe_df = pd.DataFrame({'pe': pe_base})

return price, pe_df

def main():

cfg = load_config()

# 加载/生成数据

try:

pe_data = load_pe_history('data/index_pe_history.csv')

price_data = pd.DataFrame({'close': pe_data['pe'] * 100})

except FileNotFoundError:

print("未找到数据文件,使用模拟数据")

price_data, pe_data = generate_mock_data()

# 初始化估值引擎

ve = ValuationEngine(cfg['valuation_brackets'])

# 初始化定投引擎

engine = DCAEngine(

base_amount=cfg['dca']['base_amount'],

valuation_engine=ve,

frequency=cfg['dca']['frequency']

)

# 运行回测

result = run_backtest(

engine, price_data, pe_data,

cfg['backtest']['start_date'],

cfg['backtest']['end_date']

)

# 打印结果

log = result['trade_log']

buys = [t for t in log if t['action'] == 'buy']

skips = [t for t in log if t['action'] == 'skip']

print(f"\n{'='*60}")

print(f" 指数定投回测结果")

print(f"{'='*60}")

print(f" 定投次数: {len(buys)} 次")

print(f" 暂停次数: {len(skips)} 次")

print(f" 累计投入: ¥{engine.total_invested:,.0f}")

snap = engine.get_snapshot(price_data['close'].iloc[-1])

print(f" 持有份额: {snap['shares']:.2f}")

print(f" 市值: ¥{snap['market_value']:,.2f}")

print(f" 累计收益: ¥{snap['pnl']:,.2f}")

print(f" 累计收益率: {snap['pnl_pct']:.2f}%")

print(f"{'='*60}\n")

# 打印前 10 条交易

print("前 10 条交易记录:")

for t in log[:10]:

print(f" {t['date'].strftime('%Y-%m-%d')} | "

f"{t['action']:>4} | "

f"金额 ¥{t['amount']:>8,.0f} | "

f"理由: {t['reason']}")

if __name__ == '__main__':

main()

六、README.md 与使用说明

# 通用指数定投机器人 — 估值分位加仓版

## 核心功能

根据指数 PE 历史分位数,自定义 5 档加仓梯度,自动调整每期定投金额。

## 安装

```bash

pip install -r requirements.txt

```

## 快速开始

### 1. 准备数据

创建 `data/index_pe_history.csv`:

```csv

date,pe

2018-01-02,12.5

2018-01-03,12.3

...

```

### 2. 配置五档梯度

编辑 `config.yaml`:

```yaml

dca:

base_amount: 1000 # 基准定投 1000 元/期

frequency: "W" # 每周一定投

valuation_brackets:

- { max_pct: 20, multiplier: 2.0 } # 很度低估 → 2000 元

- { max_pct: 40, multiplier: 1.5 } # 低估 → 1500 元

- { max_pct: 60, multiplier: 1.0 } # 正常 → 1000 元

- { max_pct: 80, multiplier: 0.5 } # 高估 → 500 元

- { max_pct: 100, multiplier: 0.0 } # 极度高估 → 暂停

```

### 3. 运行

```bash

python main.py

```

输出:定投次数、暂停次数、累计收益、交易明细

## 自定义档位

你可以自由修改 `valuation_brackets`,例如:

| 风格 | 档位设置 |

|------|----------|

| 激进型 | 低估 3x、正常 1.5x、高估 0.5x |

| 保守型 | 低估 1.5x、正常 1x、高估 0x |

| 自定义 | 任意分位 + 任意倍率 |

七、核心知识点卡片

┌──────────────────────────────────────────────────────────────┐

│ 指数定投 + 估值分位加仓 — 核心知识 │

├────────────────┬─────────────────────────────────────────────┤

│ 估值分位 │ 当前 PE 在历史上的百分位(0~100%) │

│ 分位越低 │ 越便宜,越应加大买入 │

│ 五档梯度 │ 自定义分位区间 + 对应买入倍率 │

│ 基准金额 │ 固定锚点,所有倍率基于它计算 │

│ 暂停定投 │ 高位(如 ≥80% 分位)时倍率 0x │

│ 核心优势 │ 便宜多买、贵时少买,摊薄长期成本 │

│ 适用标的 │ 宽基指数(沪深 300/中证 500/创业板指) │

│ 频率选择 │ 周定投平滑波动,月定投减少手续费冲击 │

└────────────────┴─────────────────────────────────────────────┘

八、免责声明与风险提示

⚠️ 免责声明:本代码仅供学习、研究与量化教学用途,不构成任何投资建议或投资决策依据。模拟数据为随机数生成,不代表任何真实指数或标的历史表现。

⚠️ 风险提示:

- 历史 PE 分位不能完全预测未来,市场估值中枢可能长期抬升或下移

- 极端行情下 PE 可能失真(如盈利大幅波动时)

- 定投频率与费率结构会显著影响实际收益

- 回测结果不代表实盘表现,未考虑滑点、申赎费率差异等

九、总结

给通用指数定投机器人加上 估值分位五档加仓梯度,核心价值在于:

1. 便宜多买、贵时少买 —— 用历史估值做锚,系统化提升定投性价比

2. 五档梯度完全自定义 —— 激进/保守/个性化策略都能灵活配置

3. 逻辑清晰、可回测验证 —— 每一笔买入都有明确的估值依据

4. 适合宽基指数长期投资 —— 沪深 300、中证 500 等流动性好、估值稳定的标的

核心原则:定投的本质是"分批入场、摊薄成本",加上估值分位判断后,它变成了"聪明地分批入场"——这正是指数投资的长期致胜之道。

本文代码仅供学习和技术交流,不构成任何投资建议,股市有风险,入市需谨慎!

利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!

相关新闻

  • 嵌入式GUI开发实战:emWin图形库配置与集成全解析
  • 泸州市黄金回收店铺权威实力排行榜及电话地址推荐 2026年实测五家诚信优选实体门店 - 亦辰小黄鸭
  • 剑盾100个TR技能

最新新闻

  • 承德市奢侈品手表包包回收经历分享:跑了5家店,说说真实感受 - 谊识预商务
  • AMD Ryzen终极调试指南:SMUDebugTool完整教程,释放处理器隐藏性能
  • 番茄小说下载器终极指南:免费开源工具助您轻松保存全网小说资源
  • 阿克苏地区黄金回收去哪儿好?整理了5家靠谱实体店地址电话 - 千叶啊
  • GPT-4 Turbo响应优化实战:低延迟LLM应用开发指南
  • UVa 559 Squares (II)

日新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号