传统观念:散户资金小不用仓位管理,编程模拟小资金满仓/分仓两套方案多年回测,量化仓位管理对小散影响。
⚠️ 全文含免责声明与风险提示,不荐股、不承诺收益、不引导开户、无任何引流
一、实际应用场景描述
在智能证券投资课程中,仓位管理(Position Sizing)是区分"赌徒"与"交易员"的分水岭,也是散户最容易忽视的课题。
本程序适用于:
- 高校量化投资、证券实务课程实验
- 个人投资者交易纪律与风控训练
- 行为金融学"散户心理"教学演示
- 小资金是否需要仓位管理的量化论证
核心目标:
- 模拟小资金满仓 vs 分仓(如 3 只 × 33%)两套方案
- 回测多年累计收益与最大回撤
- 量化仓位管理对小散的实际影响
- 用数据回答:"散户资金小,还需要仓位管理吗?"
✅ 不做未来预测
✅ 不构成投资建议
✅ 仅作为历史回测教学示例
二、痛点引入(真实可感知)
痛点 表现
"钱少无所谓" 散户认为仓位管理是大资金的事
满仓梭哈 全仓一只,赌对了吹半年,赌错了躺平
风险集中 一只暴雷,账户腰斩
缺乏对比 不知道分仓到底能好多少
工具门槛高 专业回测平台复杂,散户望而却步
👉 需要一个轻量、本地、可解释、可复现的仓位管理回测工具
三、核心逻辑讲解(工程视角)
1️⃣ 数据模型设计
PortfolioSession
├── strategy_name 策略名称(满仓 / 分仓)
├── initial_capital 初始资金
├── holdings 持仓明细
└── nav_history 净值历史
2️⃣ 两套方案设计(教学用)
方案 配置 逻辑
满仓方案 100% 资金买入 1 只 高风险高回报
分仓方案 33% × 3 只(等权) 分散风险
⚠️ 教学中强调:分仓不是"分散到 100 只",而是在可管理范围内降低单点风险。
3️⃣ 回测流程
初始化两个组合(满仓 / 分仓)
逐日更新每只持仓的市值
满仓:100% 跟随一只
分仓:33% 各跟随一只
记录每日总净值
计算累计收益与最大回撤
输出对比报告
4️⃣ 关键公式
累计收益率:
累计收益率 = (期末净值 − 初始资金) / 初始资金 × 100%
最大回撤:
最大回撤 = max[(历史最高净值 − 当前净值) / 历史最高净值] × 100%
5️⃣ 设计原则
- 规则透明,参数可配置
- 不美化任何一方,让数据说话
- 小资金场景,贴近散户真实体量(如 1 万–10 万)
四、Python 模块化代码(可直接运行)
📁 项目结构
position_sizing_backtest/
│
├── main.py
├── models.py
├── backtester.py
├── comparator.py
├── reporter.py
├── storage.py
├── README.md
└── DISCLAIMER.md
✅ models.py(数据建模)
"""
models.py
仓位管理回测数据模型
"""
class Holding:
"""单只持仓"""
def __init__(self, symbol, weight, return_series):
"""
symbol: 股票代码
weight: 仓位权重(如 1.0 = 100%, 0.33 = 33%)
return_series: 该股票的日收益率序列(%)
"""
self.symbol = symbol
self.weight = weight
self.return_series = return_series
class PortfolioSession:
"""投资组合回测场景"""
def __init__(self, strategy_name, initial_capital, holdings):
self.strategy_name = strategy_name
self.initial_capital = initial_capital
self.holdings = holdings
self.nav_history = []
✅ backtester.py(核心回测引擎)
"""
backtester.py
满仓 vs 分仓回测引擎
"""
class PortfolioBacktester:
"""组合回测引擎"""
def __init__(self, session):
self.session = session
def run(self):
"""
核心回测逻辑:
逐日计算组合净值
"""
# 找到最短的收益率序列长度
min_len = min(len(h.return_series) for h in self.session.holdings)
nav_history = []
for day in range(min_len):
daily_return = 0
for h in self.session.holdings:
daily_return += h.weight * h.return_series[day]
if day == 0:
nav = self.session.initial_capital * (1 + daily_return / 100)
else:
nav = nav_history[-1] * (1 + daily_return / 100)
nav_history.append(round(nav, 2))
self.session.nav_history = nav_history
return nav_history
def summarize(self):
"""汇总统计"""
navs = self.session.nav_history
if not navs:
return None
initial = self.session.initial_capital
final = navs[-1]
# 累计收益
total_return = (final - initial) / initial * 100
# 最大回撤
peak = navs[0]
max_dd = 0
for nav in navs:
if nav > peak:
peak = nav
dd = (peak - nav) / peak * 100
if dd > max_dd:
max_dd = dd
# 年化收益(简化)
years = len(navs) / 252 # 假设 252 个交易日/年
if years > 0:
annual_return = ((final / initial) ** (1 / years) - 1) * 100
else:
annual_return = 0
return {
"strategy": self.session.strategy_name,
"initial_capital": initial,
"final_nav": final,
"total_return_pct": round(total_return, 2),
"annual_return_pct": round(annual_return, 2),
"max_drawdown_pct": round(max_dd, 2),
"trading_days": len(navs)
}
✅ comparator.py(双方案对比)
"""
comparator.py
满仓 vs 分仓收益对比
"""
from backtester import PortfolioBacktester
def compare_strategies(full_portfolio, split_portfolio):
"""
对比满仓与分仓方案
"""
engine_full = PortfolioBacktester(full_portfolio)
engine_split = PortfolioBacktester(split_portfolio)
navs_full = engine_full.run()
navs_split = engine_split.run()
summary_full = engine_full.summarize()
summary_split = engine_split.summarize()
# 对比指标
return_diff = summary_split["total_return_pct"] - summary_full["total_return_pct"]
dd_diff = summary_split["max_drawdown_pct"] - summary_full["max_drawdown_pct"]
return {
"full": summary_full,
"split": summary_split,
"return_diff_pct": round(return_diff, 2),
"drawdown_diff_pct": round(dd_diff, 2),
"winner": "分仓" if return_diff > 0 else "满仓"
}
✅ reporter.py(对比报告输出)
"""
reporter.py
仓位管理对比报告
"""
def report(comparison):
f = comparison["full"]
s = comparison["split"]
print("\n" + "=" * 60)
print("【小资金仓位管理回测对比报告】")
print("=" * 60)
print(f"\n📌 方案 A:{f['strategy']}")
print(f" 初始资金:{f['initial_capital']} 元")
print(f" 期末净值:{f['final_nav']} 元")
print(f" 累计收益:{f['total_return_pct']}%")
print(f" 年化收益:{f['annual_return_pct']}%")
print(f" 最大回撤:{f['max_drawdown_pct']}%")
print(f"\n📌 方案 B:{s['strategy']}")
print(f" 初始资金:{s['initial_capital']} 元")
print(f" 期末净值:{s['final_nav']} 元")
print(f" 累计收益:{s['total_return_pct']}%")
print(f" 年化收益:{s['annual_return_pct']}%")
print(f" 最大回撤:{s['max_drawdown_pct']}%")
print(f"\n📊 核心对比:")
print(f" 收益差值:{comparison['return_diff_pct']} 个百分点")
print(f" 回撤差值:{comparison['drawdown_diff_pct']} 个百分点")
print(f" 收益胜出:{comparison['winner']}方案")
print(f"\n💡 教学启示:")
print("-" * 60)
if comparison["return_diff_pct"] > 0:
print(f" ✅ 分仓方案多赚 {comparison['return_diff_pct']} 个百分点")
elif comparison["return_diff_pct"] < 0:
print(f" ⚠️ 满仓方案多赚 {abs(comparison['return_diff_pct'])} 个百分点")
print(f" 但需承受 {f['max_drawdown_pct']}% 的最大回撤风险")
else:
print(f" ➡️ 两种方案收益持平")
if s["max_drawdown_pct"] < f["max_drawdown_pct"]:
print(f" ✅ 分仓方案最大回撤减少 {abs(comparison['drawdown_diff_pct'])} 个百分点")
print(f" 风险控制效果显著")
print(f"\n 核心结论:")
print(f" 小资金同样需要仓位管理——")
print(f" 不是为了追求最高收益,而是为了活得更久。")
print("=" * 60)
✅ storage.py(本地存储)
"""
storage.py
JSON 本地存储
"""
import json
FILE_PATH = "position_sizing_result.json"
def save_result(data):
with open(FILE_PATH, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
✅ main.py(交互入口)
"""
main.py
小资金满仓 vs 分仓回测工具
"""
from models import Holding, PortfolioSession
from comparator import compare_strategies
from reporter import report
from storage import save_result
def main():
print("=== 小资金仓位管理回测工具(教学版)===")
print("量化「散户资金小,不用仓位管理」是否成立\n")
capital = float(input("初始资金(默认 10000):") or "10000")
# ===== 方案 A:满仓 =====
print("\n📌 方案 A:满仓(100% 一只)")
symbol_a = input("股票代码:")
print(f"请输入 {symbol_a} 的日收益率序列(空格分隔,%):")
returns_a = list(map(float, input().split()))
full_portfolio = PortfolioSession(
"满仓方案(100%)",
capital,
[Holding(symbol_a, 1.0, returns_a)]
)
# ===== 方案 B:分仓 =====
print("\n📌 方案 B:分仓(3 只 × 33%)")
holdings = []
for i in range(3):
sym = input(f"第 {i+1} 只股票代码:")
print(f"请输入 {sym} 的日收益率序列(空格分隔,%):")
rets = list(map(float, input().split()))
holdings.append(Holding(sym, 0.33, rets))
split_portfolio = PortfolioSession(
"分仓方案(3×33%)",
capital,
holdings
)
# 执行对比
comparison = compare_strategies(full_portfolio, split_portfolio)
# 输出报告
report(comparison)
# 保存结果
save_result(comparison)
print("✅ 回测结果已保存")
if __name__ == "__main__":
main()
五、README 与使用说明
# 小资金仓位管理回测工具(教学版)
## 项目说明
模拟小资金满仓 vs 分仓两套方案多年回测,量化仓位管理对散户的实际影响。
## 使用方式
```bash
python main.py
```
## 输入示例
```
初始资金:10000
方案 A:满仓
股票代码:600519
日收益率:1.2 -0.8 2.1 -1.5 0.3 ...
方案 B:分仓
第 1 只:600519
日收益率:1.2 -0.8 2.1 -1.5 0.3 ...
第 2 只:000858
日收益率:0.5 1.8 -0.3 1.2 -0.9 ...
第 3 只:601318
日收益率:-0.3 1.1 0.8 -0.5 1.5 ...
```
## 对比维度
| 指标 | 说明 |
|---|---|
| 累计收益率 | 整个回测期的收益 |
| 年化收益率 | 扣除时间因素后的可比指标 |
| 最大回撤 | 从最高点到最低点的最大跌幅 |
## 适用范围
- 量化投资课程
- 仓位管理教学
- 行为金融:散户心理训练
## 注意事项
- 仅基于历史数据
- 不构成任何投资建议
- 使用前请阅读 DISCLAIMER.md
六、DISCLAIMER.md(免责声明与风险提示)
# 免责声明与风险提示
## 免责声明
本程序仅供**教学与科研用途**,用于演示仓位管理对投资收益与风险的影响。
作者不提供任何证券交易建议,不推荐任何股票,不承诺任何收益。
## 风险提示
1. 历史回测不代表未来表现,过去收益不保证未来结果
2. 分仓方案假设各持仓相关性低,现实中可能同涨同跌
3. 回测未考虑手续费、滑点、流动性等现实约束
4. "分仓一定更好"本身也是一种认知偏差
5. 小资金交易成本占比更高,分仓可能加剧成本问题
6. 实盘前请充分测试与验证,并结合个人风险承受能力
使用本工具产生的任何后果,作者概不负责。
七、核心知识点卡片(教学向)
分类 内容
Python 类、列表遍历、函数封装、字典操作
量化金融 仓位管理、组合回测、最大回撤
投资理念 散户也需要风控,分散≠无效
行为金融 过度自信偏差、赌徒谬误
数据分析 收益率计算、风险指标对比
工程思想 模块化、策略与数据解耦、可复现
可扩展性 可接入真实行情 API、支持动态再平衡
八、总结(工程师视角)
这是一个完全中立、去营销化、可教学的原型系统:
✅ 不鼓吹满仓
✅ 不神化分仓
✅ 不伪装成选股或择时系统
它真正展示的是:
如何用 Python 把"散户要不要仓位管理"从口头争论,变成可量化、可对比、可反思的教学实验
核心教学价值:
传统观念 数据可能揭示的真相
"钱少,一把梭" 一把梭的回撤可能是分仓的 2–3 倍
"分仓赚得少" 长期看分仓的夏普比率可能更优
"仓位管理是大户的事" 小资金破产风险同样真实存在
"我运气好" 运气无法回测,风险可以量化
本文代码仅供学习与技术交流,不构成任何投资建议,股市有风险,入市需谨慎!
利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛
