add project docs and research materials; update arch doc with WSL2 dev setup
- docs/: 6 development documents (PRD, tech selection, architecture, risks, roadmap, design workflow) - research/: FIRE background materials, personal plan, Excel calculator - 03-架构设计.md: add Section 8 documenting WSL2 → Windows browser dev environment (Vite host config, access URLs, mobile debugging tip) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""生成可调参数的 FIRE(Barista 半退休) 测算表。改黄色参数格,结果用 Excel 公式自动重算。"""
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "FIRE测算"
|
||||
|
||||
# ---- 样式 ----
|
||||
title_font = Font(name="微软雅黑", size=14, bold=True, color="FFFFFF")
|
||||
title_fill = PatternFill("solid", fgColor="2F5597")
|
||||
head_font = Font(name="微软雅黑", size=11, bold=True, color="FFFFFF")
|
||||
head_fill = PatternFill("solid", fgColor="4472C4")
|
||||
sect_font = Font(name="微软雅黑", size=11, bold=True, color="2F5597")
|
||||
input_fill = PatternFill("solid", fgColor="FFF2CC") # 黄色=可改
|
||||
input_font = Font(name="微软雅黑", size=11, bold=True, color="C00000")
|
||||
calc_fill = PatternFill("solid", fgColor="E2EFDA") # 绿色=自动算
|
||||
normal_font = Font(name="微软雅黑", size=11)
|
||||
ok_fill = PatternFill("solid", fgColor="C6E0B4")
|
||||
thin = Side(style="thin", color="BFBFBF")
|
||||
border = Border(left=thin, right=thin, top=thin, bottom=thin)
|
||||
center = Alignment(horizontal="center", vertical="center")
|
||||
left = Alignment(horizontal="left", vertical="center")
|
||||
|
||||
def put(cell, value, font=normal_font, fill=None, align=left, fmt=None, bd=True):
|
||||
c = ws[cell]
|
||||
c.value = value
|
||||
c.font = font
|
||||
if fill: c.fill = fill
|
||||
c.alignment = align
|
||||
if fmt: c.number_format = fmt
|
||||
if bd: c.border = border
|
||||
return c
|
||||
|
||||
# ---- 标题 ----
|
||||
ws.merge_cells("A1:F1")
|
||||
put("A1", "FIRE 半退休 (Barista) 可调参数测算表", title_font, title_fill, center, bd=False)
|
||||
ws.row_dimensions[1].height = 28
|
||||
ws.merge_cells("A2:F2")
|
||||
put("A2", "用法:只改【黄色格子】里的数字,右侧/下方结果会自动重算。", Font(name="微软雅黑", size=9, italic=True, color="808080"), align=left, bd=False)
|
||||
|
||||
# ---- 参数区 ----
|
||||
put("A3", "① 可修改参数(改这里)", sect_font, bd=False)
|
||||
params = [
|
||||
("起始本金(元)", 70000, "#,##0"),
|
||||
("每月定投(元)", 1500, "#,##0"),
|
||||
("年开支(元)", 65000, "#,##0"),
|
||||
("兼职年收入(元)", 40000, "#,##0"),
|
||||
("安全提取率", 0.035, "0.0%"),
|
||||
("收益率-保守", 0.04, "0.0%"),
|
||||
("收益率-中性", 0.06, "0.0%"),
|
||||
("收益率-乐观", 0.08, "0.0%"),
|
||||
]
|
||||
r = 4
|
||||
for name, val, fmt in params:
|
||||
put(f"A{r}", name, normal_font, input_fill, left)
|
||||
put(f"B{r}", val, input_font, input_fill, center, fmt)
|
||||
r += 1
|
||||
# 记下行号
|
||||
ROW = {"本金":4, "月投":5, "开支":6, "兼职":7, "提取率":8, "保守":9, "中性":10, "乐观":11}
|
||||
|
||||
# ---- 自动计算:目标本金 ----
|
||||
put("A13", "② 自动计算结果", sect_font, bd=False)
|
||||
put("A14", "年缺口(开支-兼职,元)", normal_font, calc_fill)
|
||||
put("B14", f"=B{ROW['开支']}-B{ROW['兼职']}", normal_font, calc_fill, center, "#,##0")
|
||||
put("A15", "目标本金(元)", Font(name="微软雅黑", bold=True), calc_fill)
|
||||
put("B15", f"=B14/B{ROW['提取率']}", Font(name="微软雅黑", bold=True, color="C00000"), calc_fill, center, "#,##0")
|
||||
put("A16", "目标本金(万元)", Font(name="微软雅黑", bold=True), calc_fill)
|
||||
put("B16", "=B15/10000", Font(name="微软雅黑", bold=True, color="C00000"), calc_fill, center, "0.0")
|
||||
|
||||
# ---- 逐年测算表 ----
|
||||
put("A18", "③ 逐年资产测算(含分红复投;第一个出现 ✅ 的年份≈达成 Barista FIRE)", sect_font, bd=False)
|
||||
headers = ["年数", "保守(元)", "中性(元)", "乐观(元)", "中性(万)", "是否达标(中性)"]
|
||||
hr = 19
|
||||
for i, h in enumerate(headers):
|
||||
put(f"{get_column_letter(i+1)}{hr}", h, head_font, head_fill, center)
|
||||
|
||||
start = hr + 1
|
||||
for y in range(1, 31):
|
||||
rr = start + (y - 1)
|
||||
put(f"A{rr}", y, normal_font, None, center, "0")
|
||||
# FV(年化/12, 年数*12, -月投, -起始本金) -> 正数
|
||||
put(f"B{rr}", f"=FV($B${ROW['保守']}/12, A{rr}*12, -$B${ROW['月投']}, -$B${ROW['本金']})", normal_font, None, center, "#,##0")
|
||||
put(f"C{rr}", f"=FV($B${ROW['中性']}/12, A{rr}*12, -$B${ROW['月投']}, -$B${ROW['本金']})", normal_font, None, center, "#,##0")
|
||||
put(f"D{rr}", f"=FV($B${ROW['乐观']}/12, A{rr}*12, -$B${ROW['月投']}, -$B${ROW['本金']})", normal_font, None, center, "#,##0")
|
||||
put(f"E{rr}", f"=C{rr}/10000", normal_font, None, center, "0.0")
|
||||
put(f"F{rr}", f'=IF(C{rr}>=$B$15,"✅达标","")', Font(name="微软雅黑", bold=True, color="548235"), None, center)
|
||||
|
||||
# ---- 列宽 ----
|
||||
widths = [22, 14, 14, 14, 12, 16]
|
||||
for i, w in enumerate(widths):
|
||||
ws.column_dimensions[get_column_letter(i+1)].width = w
|
||||
|
||||
# ---- 说明页 ----
|
||||
ws2 = wb.create_sheet("说明")
|
||||
notes = [
|
||||
"【这张表怎么用】",
|
||||
"1. 在『FIRE测算』页,只改黄色格子里的数字(本金、月投、开支、兼职收入、提取率、收益率)。",
|
||||
"2. 绿色格子和下方表格会自动重算,不用动公式。",
|
||||
"",
|
||||
"【目标本金怎么来的】",
|
||||
"目标本金 =(年开支 − 兼职年收入)÷ 安全提取率",
|
||||
"例:开支6.5万、兼职4万、提取率3.5% → (65000-40000)/3.5% = 约71万。",
|
||||
"兼职每多赚1万,目标本金大约少29万。",
|
||||
"",
|
||||
"【提取率为什么用 3.5%】",
|
||||
"美国常用4%,但中国低利率、市场波动大、社保有空窗,打折到3%~3.5%更稳健。",
|
||||
"想更保守可把提取率改成 0.03。",
|
||||
"",
|
||||
"【收益率怎么理解】",
|
||||
"已包含分红再投资(总回报口径)。参考组合:红利ETF/工行50-60% + 宽基指数30% + 货基/国债10-15%。",
|
||||
"保守4% / 中性6% / 乐观8% 为假设值,不是承诺。",
|
||||
"",
|
||||
"【达成年限怎么看】",
|
||||
"看『是否达标(中性)』列,第一个出现 ✅ 的年份,就是按中性收益大约达成的年数。",
|
||||
"想看保守/乐观,可对比 保守(元)、乐观(元) 两列与目标本金B15的大小。",
|
||||
"",
|
||||
"【加速的关键】",
|
||||
"把『每月定投』从1500改成3000试试,会看到达成年限大幅缩短——提高储蓄率比纠结收益率更有效。",
|
||||
"",
|
||||
"⚠️ 本表为个人理性测算与学习参考,不构成投资建议,收益率为假设值、不保证实现。",
|
||||
]
|
||||
for i, line in enumerate(notes, start=1):
|
||||
c = ws2[f"A{i}"]
|
||||
c.value = line
|
||||
if line.startswith("【") or line.startswith("⚠️"):
|
||||
c.font = Font(name="微软雅黑", bold=True, color="2F5597")
|
||||
else:
|
||||
c.font = Font(name="微软雅黑", size=10)
|
||||
ws2.column_dimensions["A"].width = 95
|
||||
|
||||
out = "/mnt/d/opc_project/fire_goal/FIRE可调测算表.xlsx"
|
||||
wb.save(out)
|
||||
print("saved:", out)
|
||||
Reference in New Issue
Block a user