跳转至


课程  因子投资  机器学习  Python  Poetry  ppw  tools  programming  Numpy  Pandas  pandas  算法  hdbscan  聚类  选股  Algo  minimum  numpy  回测  数据标准化  algo  FFT  模式识别  配对交易  GBDT  LightGBM  XGBoost  statistics  CDF  KS-Test  monte-carlo  VaR  过拟合  algorithms  machine learning  strategy  python  sklearn  pdf  概率  数学  面试题  量化交易  策略分类  风险管理  Info  interview  career  强化学习  监督学习  AI量化  复权  数据  tushare  akshare  xgboost  PCA  wavelet  时序事件归因  SHAP  深度学习  归一化  BN  LN  WN  machine-learning  quant-trading  dropout  kaggle  boosting  决策树  泰勒展开  openclaw  resources  quant  deep-learning  tcn  time-series  causal-convolution  交易实战  避坑指南  Figures  Behavioral Economics  graduate  arma  garch  人物  职场  Quantopian  figure  Banz  金融行业  买方  卖方  story  量化传奇  rsi  zigzag  穹顶压力  因子  ESG  因子策略  投资  策略  pe  ORB  Xgboost  Alligator  Indicator  factor  alpha101  alpha  技术指标  wave  algorithm  pearson  spearman  套利  LOF  白银  因子分析  Alphalens  涨停板  herd-behaviour  momentum  因子评估  review  SMC  聪明钱  trade  history  indicators  zscore  波动率  lightgbm  顶背离  另类数据  freshman  others  AI  DeepSeek  network  量子计算  金融交易  IBM  weekly  进化论  logic-factor  Agent Skills  Skills Marketplace  VS Code  Tushare  XtQuant  BaoStock  A股  量化  neutralization  basics  LLT  backtest  backtrader  研报  papers  UBL  金融阅读  免费资源  华尔街日报  WSJ  量化学习  quantlib  jupyter-notebook  scikit-learn  pypinyin  qmt  xtquant  blog  static-site  duckdb  工具  colors  free resources  barra  world quant  Alpha  openbb  risk-management  llm  prompt  CANSLIM  Augment  arsenal  copilot  vscode  code  量化数据存储  hdf5  h5py  cursor  augment  trae  Jupyter  jupysql  pyarrow  parquet  数据源  quantstats  几何收益  实盘  clickhouse  polars  滑动窗口  notebook  sqlite  sqlite-utils  fastlite  大数据  PyArrow  UV  Pydantic  Engineering  redis  remote-agent  AI-tools  Moonshot  回测,研报,tushare  dividend 

一个散户自学量化的 20 个月

最后更新: 2026-04-11


一个散户自学量化的 20 个月

这两年,圈内传出来的量化薪资门槛大概是这样的:在上海,应届 Junior Quant 的 Base 加奖金一般在 60万-80万人民币;在香港,这个数字大概是 120万-150万港币;如果能进纽约的头部对冲基金,起薪基本是 30万-40万美元。

看到这些数字,很多人的第一反应是:“我也要去学 Python,搞个机器学习模型来炒股。”

我当初也是这么想的。作为一个在A股里交了不少学费的散户,我以为只要学了量化,学会了用代码看盘,就能精准预测明天的涨跌,从此财富自由。

直到我自己跌跌撞撞地摸索了 20 个月,把账户里的钱亏了又赚、赚了又亏之后,我才慢慢明白:量化的核心根本不是写代码,更不是预测未来。它更像是一个重新训练自己怎么理解市场的过程。

回头看,这 20 个月里真正有用的东西,大概就这几块。如果你也想从零开始自学量化,也许可以少走一点弯路。

目录: - 从猜涨跌,到开始算概率 - 写策略之前,先学会怀疑自己 - 股票不是一只一只看的 - 算出来的最优解,实盘不一定能做 - 到了期权这一步,才知道波动本身也会吃钱 - 最后真正卡住我的,是估算误差


从猜涨跌,到开始算概率

做散户的时候,我最喜欢干的事就是看图形、猜涨跌。“这根K线收了长下影,明天肯定涨!”

这是典型的绝对思维。后来我学了量化,第一件事就是被概率论狠狠敲醒:在市场里,“肯定”这两个字是最贵的。

1. 散户看单点,量化看“条件”

我以前总觉得某只股票是个好公司,所以该涨。后来我懂了,孤立的事件是没有交易价值的,有价值的是条件概率

\[ P(A \mid B)=\frac{P(A \cap B)}{P(B)} \]

我现在不问“它明天涨不涨”,我只问程序:“在过去 10 年里,当大盘跌破 30 日均线,但该股净流入超过 1 亿(条件B)时,它次日上涨(事件A)的概率是多少?” 加上了严苛的约束条件,我才发现以前自以为的“规律”全都是错觉。

2. 被套牢的本质,是不懂贝叶斯

散户最惨的死法是什么?死扛。买入后暴跌,到处找利好消息安慰自己。 贝叶斯公式治好了我的“头铁”:

\[ P(H \mid D)=\frac{P(D \mid H)P(H)}{P(D)} \]

不管我买入前多看好它(先验),只要它今天跌破了我的量化防线(新数据),我的看好程度就必须往下调(后验),该止损就止损。交易里最忌讳的就是头铁,新数据出来后,原来的判断就得跟着改。

3. 为什么看对了大趋势,账户还是亏光了?

$$ \mathbb{E}[X]=\sum_i x_iP(X=x_i) \quad \text{与} \quad \mathrm{Var}(X)=\mathbb{E}\left[(X-\mathbb{E}[X])^2\right] $$ 我曾经写过一个回测收益很高的策略(期望值为正),满仓干进去,结果碰上一次极端行情,账户回撤了 40%,我吓得割肉了。刚割完,策略就开始赚钱。我终于明白,期望值决定你能不能赚钱,而方差决定你能不能活到赚钱的那一天。

我的脱产自学清单(耗时约 1 个月): - 核心读物: Sheldon Ross 的 A First Course in Probability(直接刷完前 7 章,把课后题当做面试题来做)。 - 实战任务 1: 用 Python 写一个蒙特卡洛模拟器,测算如果一个策略胜率是 55%,赔率是 1:1,连续亏损 10 次的破产概率。 - 实战任务 2: 写一个贝叶斯追踪脚本,模拟一个连亏 5 天的趋势策略,观察它的“后验有效性”是如何跌破 20% 警戒线的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import numpy as np

# 测算:胜率55%,赔率1:1,初始资金10万,每次下注1万,连亏导致破产的概率
def simulate_ruin(win_rate=0.55, initial_capital=10, bet_size=1, n_simulations=10000, n_trades=100):
    ruin_count = 0
    for _ in range(n_simulations):
        capital = initial_capital
        for _ in range(n_trades):
            # 赢了+1万,输了-1万
            capital += bet_size if np.random.rand() < win_rate else -bet_size
            if capital <= 0:
                ruin_count += 1
                break
    return ruin_count / n_simulations

ruin_prob = simulate_ruin()
print(f"正期望策略的破产概率(方差的惩罚):{ruin_prob*100:.2f}%")
# 哪怕胜率偏向你,只要仓位管理不对,你依然有极高的概率死在半路上。

写策略之前,先学会怀疑自己

学了点代码后,我开始疯狂写策略。有一天,我调出了一个年化 50% 的完美参数,兴奋得一晚上没睡。上线实盘,半个月亏了 15%。

那一刻我意识到,人脑太容易骗自己了。我必须学统计学来给自己泼冷水。

1. 先假设自己是个骗子

现在我跑出好回测,第一反应不是高兴,而是做假设检验:假设这 50% 的收益全是我运气好蒙出来的(零假设 \(H_0\))。纯靠运气蒙出这个结果的概率(p值)有多大?如果概率很大,说明这个策略就是个垃圾。

2. 调参就是自我欺骗

我以前喜欢试各种参数:均线 5 日不行换 10 日,总能试出一个赚钱的。 后来我知道这叫多重比较问题。试了 1000 次总会撞上一次好运,如果不做 Bonferroni 调整(\(\alpha_{\text{adj}}=\frac{\alpha}{n}\)),我选出来的所谓“最强策略”,不过是完美拟合了历史的一段噪音而已。

3. 接受自己算不准

$$ \hat{\theta}{MLE} = \arg\max\theta \sum_{i=1}^n \log f(x_i\mid\theta) $$ 市场到底是怎么运转的?没人知道。极大似然估计(MLE)教会我务实:拿现有的这批数据,反推一组“最有可能生成这些数据”的参数凑合用。别追求完美预测,在当前样本下管用就行了。

我的脱产自学清单(耗时约 1.5 个月): - 核心读物: Casella & Berger 的 Statistical Inference(非常硬核,专治各种对统计指标的想当然)。 - 实战任务 1: 拉取标普 500 过去 10 年的数据,写一个滚动窗口(Rolling Window),用 MLE 估算收益率的尖峰厚尾特征。 - 实战任务 2: 自己手写一个 Bootstrap 置换检验器:把你的交易信号打乱重排 5,000 次,看你的原始夏普率在这 5,000 个纯随机结果里排在什么位置。排不进前 5%,就直接废弃。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np

# 用置换检验打碎你的“回测幻觉”
def bootstrap_sharpe_test(strategy_returns, n_permutations=5000):
    actual_sharpe = np.mean(strategy_returns) / np.std(strategy_returns) * np.sqrt(252)

    random_sharpes = []
    for _ in range(n_permutations):
        # 打乱收益率序列(破坏原有的时序逻辑)
        shuffled = np.random.permutation(strategy_returns)
        sharpe = np.mean(shuffled) / np.std(shuffled) * np.sqrt(252)
        random_sharpes.append(sharpe)

    # 计算 p 值:有多少次纯随机打乱的结果,比你辛苦写出来的策略夏普还要高?
    p_value = np.sum(np.array(random_sharpes) >= actual_sharpe) / n_permutations
    return actual_sharpe, p_value

# 假设这是一段勉强跑赢的真实策略收益
fake_returns = np.random.normal(0.0005, 0.015, 1000)
sharpe, p_val = bootstrap_sharpe_test(fake_returns)
print(f"原策略夏普: {sharpe:.2f}")
print(f"纯随机超越你的概率 (p-value): {p_val:.4f}")
# 如果 p 值大于 0.05,直接把代码删了,那是纯噪音。

股票不是一只一只看的

散户看盘,是一只股票一只股票地看。但量化不能这么玩,当你管理几十只股票时,你必须学会线性代数,看清它们背后的网。

1. 股票是互相牵扯的

我以前满仓干了 5 只股票,以为自己分散投资了,结果大盘一跌全崩了。因为它们的相关性太高。 后来我学会了用协方差矩阵 \(\Sigma\)。整个投资组合的风险,其实是一个矩阵运算:

\[ \sigma_p^2=\mathbf{w}'\Sigma\mathbf{w} \]

我买的不是孤立的股票,我买的是它们之间的关系。

2. 剥离掉没用的新闻

$$ \Sigma=Q\Lambda Q^{-1} $$ 每天看新闻炒股太累了。PCA(主成分分析)帮我降了维。它把几百只股票的杂乱涨跌过滤掉,直接抽出驱动大盘的那两三个核心主轴。看透了主轴,我就再也不去盯个股的噪音了。

我的脱产自学清单(耗时约 1.5 个月): - 核心读物: David C. Lay 的 Linear Algebra and Its Applications(这本书里有很多关于动力系统的精彩论述)。 - 必做推导: 在纸上用特征分解,一步步把多资产组合的方差公式 \(\sigma_p^2=\mathbf{w}'\Sigma\mathbf{w}\) 拆解到最底层的正交向量上。 - 实战任务: 下载纳斯达克 100 指数的成分股日频数据,自己写一个基于 PCA 的统计套利(Statistical Arbitrage)回测。抽出前两个主成分作为“市场噪音”,交易剩余的残差(Residuals)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import numpy as np

# 模拟 50 只股票的收益率矩阵(带有一定的系统性相关)
np.random.seed(42)
n_stocks = 50
n_days = 1000
market_factor = np.random.normal(0, 0.01, n_days)
# 股票收益 = 市场因子暴露 + 个股特异性噪音
returns = np.outer(market_factor, np.random.uniform(0.5, 1.5, n_stocks)) + np.random.normal(0, 0.02, (n_days, n_stocks))

# PCA:协方差矩阵特征分解
cov_matrix = np.cov(returns, rowvar=False)
eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)

# 对特征值降序排列
idx = np.argsort(eigenvalues)[::-1]
eigenvalues = eigenvalues[idx]

variance_explained = eigenvalues / np.sum(eigenvalues)
print(f"第一主成分(市场因子)解释了总方差的: {variance_explained[0]*100:.2f}%")
print("散户盯着那 50 个特异性噪音看,而量化直接提取并交易这个第一主成分。")

算出来的最优解,实盘不一定能做

算出了完美的持仓比例,但实盘买不进去怎么办?我开始学微积分与优化理论,学习怎么向现实妥协。

1. 别看太远,顾好眼下

$$ f(x)=f(a)+f'(a)(x-a)+\frac{f''(a)}{2}(x-a)^2+\cdots $$ 预测未来太难了。Taylor 展开教我的道理是:只要把眼下的这一小步风险(一阶导和二阶导)给对冲平了就行。不猜大趋势,只管当下的生存。

2. 戴着镣铐跳舞

$$ \min_{\mathbf{w}}\mathbf{w}'\Sigma\mathbf{w} \quad \text{s.t.} \quad \mu'\mathbf{w}\ge\bar{\mu},\; \mathbf{1}'\mathbf{w}=1 $$ 现实交易有手续费、有滑点、有仓位限制。凸优化求解器就是干这个的:在这些死规矩的“镣铐”下,硬算出一个你能实际操作的、最不坏的方案。

我的脱产自学清单(耗时约 1 个月): - 核心读物: Nocedal & Vandenberghe 的 Convex Optimization(把 KKT 条件彻底吃透,这是优化问题里跟现实妥协的核心密码)。 - 推导任务: 证明拉格朗日乘子(Lagrange Multipliers)在投资组合资金限制约束下的经济学含义(即“影子价格”)。 - 实战任务: 使用 scipy.optimize 构建一个多空组合模型,硬性加上“最大杠杆率 = 1.5”以及“单日最大换手率 < 10%”的罚函数(Penalty Function),然后强行求解。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import numpy as np
from scipy.optimize import minimize

# 一个带有惩罚项的“脏活”优化器
def constrained_portfolio_optimization(expected_returns, cov_matrix, target_return=0.1):
    n = len(expected_returns)

    def objective(weights):
        # 目标:最小化方差
        return np.dot(weights.T, np.dot(cov_matrix, weights))

    # 限制1:权重和为1(不能无限借钱)
    # 限制2:预期收益必须达到目标
    constraints = [
        {'type': 'eq', 'fun': lambda w: np.sum(w) - 1},
        {'type': 'ineq', 'fun': lambda w: np.dot(w, expected_returns) - target_return}
    ]

    # 现实的枷锁:单只股票仓位不能超过30%,可以做空但不能低于-10%
    bounds = tuple((-0.1, 0.3) for _ in range(n))

    initial_weights = np.array([1/n] * n)
    result = minimize(objective, initial_weights, method='SLSQP', bounds=bounds, constraints=constraints)
    return result.x

# 市场并不完美,求解器给你的往往也是一个满是“妥协”的解。

到了期权这一步,才知道波动本身也会吃钱

最后,我触碰到了量化的深水区:随机微积分

1. 颠簸本身就会吃钱

\((dW_t)^2=dt\)

\[ dY= \left( \frac{\partial f}{\partial t} + \mu\frac{\partial f}{\partial X} + \frac{1}{2}\sigma^2\frac{\partial^2 f}{\partial X^2} \right)dt + \sigma\frac{\partial f}{\partial X}dW_t \]

这个多出来的二阶项告诉我:哪怕股票最后涨回了原价,中间剧烈的上下震荡,也会实打实地磨掉我的本金。

2. 放弃个人看法

$$ \frac{\partial V}{\partial t} + \frac{1}{2}\sigma2S2\frac{\partial^2 V}{\partial S^2} + rS\frac{\partial V}{\partial S} -rV=0 $$ 在 Black-Scholes 方程里,代表预期收益率的 \(\mu\) 消失了。期权定价只跟波动率有关。只要对冲做得好,我个人觉得明天会涨还是会跌,其实没那么重要。真正起作用的,是你怎么处理波动、怎么处理风险。

我的脱产自学清单(耗时约 2 个月): - 终极圣经: Björk 的 Arbitrage Theory in Continuous Time(非常严密地讲解了鞅鞅理论和测度变换)。 - 实战任务 1: 自己在纸上用二叉树(Binomial Tree)模型推导出期权定价,并证明当步长 \(\Delta t \to 0\) 时,它收敛于 Black-Scholes 解析解。 - 实战任务 2: 写一个期权动态 Delta 对冲的模拟器(Delta Hedging Simulator)。给定一条带有跳跃(Jump)的股价路径,计算你每天对冲需要花费多少摩擦成本,看最后对冲下来的净利润是否能完全抹平期权的理论费率。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import numpy as np

# 这是一个极其简化的 Delta 对冲模拟器:看看由于“不连续”带来的摩擦成本有多可怕
def simulate_delta_hedging(S0=100, K=100, T=1.0, r=0.05, sigma=0.2, steps=252):
    from scipy.stats import norm
    dt = T / steps

    # 模拟一条真实的带有跳跃的股价路径
    prices = [S0]
    for _ in range(steps):
        jump = np.random.normal(0, sigma * np.sqrt(dt))
        # 偶尔来个暴跌(模拟黑天鹅)
        if np.random.rand() < 0.01: jump -= 0.05
        prices.append(prices[-1] * np.exp((r - 0.5*sigma**2)*dt + jump))

    def get_delta(S, t):
        if t == T: return 1.0 if S > K else 0.0
        d1 = (np.log(S/K) + (r + sigma**2/2)*(T-t)) / (sigma*np.sqrt(T-t))
        return norm.cdf(d1)

    # 每天调整仓位,计算摩擦成本
    hedging_cost = 0
    current_delta = get_delta(S0, 0)
    for i in range(1, steps):
        new_delta = get_delta(prices[i], i*dt)
        # 假设每次调仓有万分之五的手续费
        trade_cost = abs(new_delta - current_delta) * prices[i] * 0.0005
        hedging_cost += trade_cost
        current_delta = new_delta

    return hedging_cost

cost = simulate_delta_hedging()
print(f"期权对冲的隐藏炸弹:1年下来,单靠摩擦成本就吃掉了 ${cost:.2f}")

最后真正卡住我的,是估算误差

20 个月后,我不再看K线图了,也不再去股吧里跟人争论明天的大盘走势了。

我终于明白,很多散户转型做量化,最后还是死路一条,是因为他们只学会了写代码,却没有学会敬畏估算误差(Estimation Error)。他们拿着充满噪音的历史数据,算出一个看似完美的参数,然后满仓冲进去,本质上还是在“赌博”。

现在的我,承认历史数据是脏的,承认模型是脆弱的。我不追求算准明天,我只做大概率的事,严格对冲风险,分散持仓,然后把剩下的交给时间。

这大概就是我这 20 个月里真正学到的东西。