主题切换
20.3 金融与策略题
量化面试中的金融与策略考察的是"将金融知识转化为量化模型"的能力。面试官希望看到你不仅理解金融理论,而且能用数学语言精确表达、用代码快速实现、并对边界条件和实际限制有清醒认识。
期权定价
Black-Scholes 公式核心推导思路
Black-Scholes 期权定价模型的推导基于以下核心思想:
- 构建一个delta对冲组合:持有 1 份期权多头,同时卖空
份标的资产。 - 该组合在瞬间是无风险的,因此其收益应等于无风险利率。
- 由此得到 BS 偏微分方程:
$$\frac{\partial C}{\partial t} + \frac{1}{2}\sigma^2 S^2 \frac{\partial^2 C}{\partial S^2} + rS\frac{\partial C}{\partial S} - rC = 0$$
- 解此 PDE(通过热方程变换),得到欧式看涨期权定价公式:
$$C = S_0 \cdot N(d_1) - K \cdot e^{-rT} \cdot N(d_2)$$ $$d_1 = \frac{\ln(S_0/K) + (r + \sigma^2/2)T}{\sigma\sqrt{T}}, \quad d_2 = d_1 - \sigma\sqrt{T}$$
其中
Put-Call Parity(买卖权平价关系)
Put-Call Parity 是无套利关系中最重要的一对:
$$C - P = S_0 - K \cdot e^{-rT}$$
理解:做多看涨期权 + 做空看跌期权 = 远期多头。如果这个等式不成立,存在套利机会。
面试常见追问:
- 如果
,如何套利?(卖 call、买 put、买股票、借入 K 的现值) - Put-Call Parity 的假设是什么?(欧式期权、无股息、无交易成本、可以卖空、同一执行价格和到期日)
Greeks 的含义与应用
| Greeks | 公式 | 含义 | 面试要点 |
|---|---|---|---|
| Delta ( | 期权价格对标的价格的敏感度 | ATM 期权 Delta ≈ 0.5 | |
| Gamma ( | Delta 对标的价格的敏感度 | 衡量对冲频率需求 | |
| Theta ( | 时间衰减 | 买方的"痛苦"指标 | |
| Vega ( | 对波动率的敏感度 | 不是希腊字母但很重要 | |
| Rho ( | 对无风险利率的敏感度 | 通常影响较小 |
此处有展示代码展开 ▼
python
import numpy as np
from scipy.stats import norm
class BlackScholes:
"""Black-Scholes 期权定价与 Greeks 计算"""
@staticmethod
def price(S: float, K: float, T: float, r: float,
sigma: float, option_type: str = 'call') -> float:
"""
欧式期权定价
Parameters
----------
S : float
标的资产现价
K : float
行权价格
T : float
剩余期限(年)
r : float
无风险利率(连续复利)
sigma : float
年化波动率
option_type : str
'call' 或 'put'
"""
if T <= 0:
return max(0, S - K) if option_type == 'call' else max(0, K - S)
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if option_type == 'call':
return S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
else:
return K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
@staticmethod
def delta(S: float, K: float, T: float, r: float,
sigma: float, option_type: str = 'call') -> float:
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
if option_type == 'call':
return norm.cdf(d1)
else:
return norm.cdf(d1) - 1
@staticmethod
def gamma(S: float, K: float, T: float, r: float, sigma: float) -> float:
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
return norm.pdf(d1) / (S * sigma * np.sqrt(T))
@staticmethod
def vega(S: float, K: float, T: float, r: float, sigma: float) -> float:
"""Vega: 波动率每变化1%(0.01),期权价格的变化量"""
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
return S * np.sqrt(T) * norm.pdf(d1) / 100 # 除以100转换为1%
@staticmethod
def theta(S: float, K: float, T: float, r: float,
sigma: float, option_type: str = 'call') -> float:
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
theta_val = -(S * norm.pdf(d1) * sigma) / (2 * np.sqrt(T))
if option_type == 'call':
theta_val -= r * K * np.exp(-r * T) * norm.cdf(d2)
else:
theta_val += r * K * np.exp(-r * T) * norm.cdf(-d2)
return theta_val / 365 # 转换为每日 theta
@staticmethod
def implied_volatility(market_price: float, S: float, K: float,
T: float, r: float, option_type: str = 'call',
tol: float = 1e-6, max_iter: int = 100) -> float:
"""使用 Newton-Raphson 方法计算隐含波动率"""
sigma = 0.3 # 初始猜测
for _ in range(max_iter):
price = BlackScholes.price(S, K, T, r, sigma, option_type)
vega = BlackScholes.vega(S, K, T, r, sigma) * 100 # vega 需要反归一化
diff = price - market_price
if abs(diff) < tol:
return sigma
if abs(vega) < 1e-10:
break
sigma = sigma - diff / vega
# 确保 sigma 在合理范围内
if sigma <= 0.001:
sigma = 0.001
elif sigma > 5.0:
sigma = 5.0
return sigma # 近似的隐含波动率
# 验证 Put-Call Parity
S, K, T, r, sigma = 100, 100, 1.0, 0.05, 0.20
call_price = BlackScholes.price(S, K, T, r, sigma, 'call')
put_price = BlackScholes.price(S, K, T, r, sigma, 'put')
parity_lhs = call_price - put_price
parity_rhs = S - K * np.exp(-r * T)
print(f"Put-Call Parity 验证:")
print(f" C - P = {parity_lhs:.6f}")
print(f" S - Ke^(-rT) = {parity_rhs:.6f}")
print(f" 差异: {abs(parity_lhs - parity_rhs):.2e}")点击展开可浏览运行结果
Put-Call Parity 验证: C - P = 4.877058 S - Ke^(-rT) = 4.877058 差异: 0.00e+00
做市博弈题
做市商(Market Maker)面试中经常出现以下类型的问题:
买卖价差设定
问题:你是某只股票的做市商。你观察到成交频率为每 10 秒一次,每次成交后价格变动的标准差为 0.02 元。假设你的目标是在对冲掉库存风险后获得正收益,你应该如何设定买卖价差?
分析框架:
做市商的收益 = 价差收入 - 逆向选择损失 - 库存风险成本
$$\text{最优价差} = \frac{2 \times \text{逆向选择成本} + \text{库存风险调整}}{1 - \text{竞争程度}}$$
经典 Glosten-Milgrom 模型:
假设有知情交易者(概率为
$$P_{\text{bid}} = E[V | \text{有人要卖}] = P_{\text{low}} \cdot P(V=V_{\text{low}}|\text{sell}) + P_{\text{high}} \cdot P(V=V_{\text{high}}|\text{sell})$$ $$P_{\text{ask}} = E[V | \text{有人要买}]$$ $$\text{Spread} = P_{\text{ask}} - P_{\text{bid}} = \alpha \cdot (V_{\text{high}} - V_{\text{low}})$$
核心洞见:价差与内幕交易概率成正比。当成交流动性降低、知情交易比例上升时,做市商需要扩大价差以补偿逆向选择风险。
此处有展示代码展开 ▼
python
def optimal_spread(alpha: float, # 知情交易者比例
price_range: float, # 价值不确定范围
base_spread: float = 0.01, # 基础运营成本
competition: float = 0.5) -> float:
"""
计算最优买卖价差
Parameters
----------
alpha : float
知情交易者的概率
price_range : float
做市商对价值的不确定区间
base_spread : float
覆盖运营成本的基础价差
competition : float
竞争程度(0-1,越高价差越小)
"""
adverse_selection_cost = alpha * price_range
optimal = (2 * adverse_selection_cost + base_spread) / (1 - competition)
return max(base_spread, optimal)
# 示例
print(f"高知情交易(alpha=0.3): spread = {optimal_spread(0.3, 0.10):.4f}")
print(f"低知情交易(alpha=0.1): spread = {optimal_spread(0.1, 0.10):.4f}")
print(f"高竞争(comp=0.8): spread = {optimal_spread(0.2, 0.10, competition=0.8):.4f}")点击展开可浏览运行结果
高知情交易(alpha=0.3): spread = 0.1400 低知情交易(alpha=0.1): spread = 0.0600 高竞争(comp=0.8): spread = 0.2500
策略设计题
策略设计题是面试中最开放、最见功力的环节。面试官给出一个市场条件或数据环境,要求你设计交易策略。
典型题目:设计一个统计套利策略
题目:给定两支高度相关的股票 A 和 B,设计一个统计套利策略。需要考虑哪些因素?
回答框架:
1. 价差定义
其中
2. 交易信号
$$Z_t = \frac{\text{Spread}_t - \mu_{\text{spread}}}{\sigma_{\text{spread}}}$$ $$Z_t > 2.0: \text{做空A,做多B}$$ $$Z_t < -2.0: \text{做多A,做空B}$$ $$|Z_t| < 0.5: \text{平仓}$$
3. 需要考虑的实践问题
- 协整的稳定性:使用滚动 Johansen 检验确认协整关系是否持续存在。
- 价差的均值回归半衰期:如果半衰期太长,资金使用效率低。
- 交易成本:双边交易的成本(佣金、印花税、滑点)必须被价差覆盖。
- 做空成本:融券费率和可获得性。A 股融券成本成为策略的关键制约。
- 融资成本:保证金占用产生的机会成本。
- 相关性崩溃(Correlation Breakdown):领先市场压力期,相关性可能突然瓦解。需要止损机制。
此处有展示代码展开 ▼
python
class PairsTradingStrategy:
"""配对交易策略原型实现"""
def __init__(self, stock_a: pd.Series, stock_b: pd.Series,
lookback: int = 120, entry_z: float = 2.0,
exit_z: float = 0.5, stop_loss_z: float = 3.5):
"""
Parameters
----------
stock_a, stock_b : pd.Series
两只股票的对数价格序列
lookback : int
用于估计回归参数的窗口
entry_z : float
入场Z-score阈值
exit_z : float
出场Z-score阈值
stop_loss_z : float
止损Z-score阈值(价差继续扩大)
"""
self.log_a = np.log(stock_a)
self.log_b = np.log(stock_b)
self.lookback = lookback
self.entry_z = entry_z
self.exit_z = exit_z
self.stop_loss_z = stop_loss_z
def compute_signals(self) -> pd.DataFrame:
"""生成交易信号"""
signals = pd.DataFrame(index=self.log_a.index)
for i in range(self.lookback, len(self.log_a)):
# 滚动窗口内的回归
y = self.log_a.iloc[i-self.lookback:i].values
x = self.log_b.iloc[i-self.lookback:i].values
X = np.column_stack([np.ones(len(x)), x])
# OLS回归
beta = np.linalg.lstsq(X, y, rcond=None)[0]
# 当前价差
spread = y[-1] - (beta[0] + beta[1] * x[-1])
spread_mean = (y - (beta[0] + beta[1] * x)).mean()
spread_std = (y - (beta[0] + beta[1] * x)).std()
z_score = (spread - spread_mean) / spread_std if spread_std > 0 else 0
signals.loc[signals.index[i], 'z_score'] = z_score
signals.loc[signals.index[i], 'hedge_ratio'] = beta[1]
signals.loc[signals.index[i], 'spread'] = spread
# 信号生成
if z_score > self.entry_z:
signals.loc[signals.index[i], 'signal'] = -1 # 做空价差
elif z_score < -self.entry_z:
signals.loc[signals.index[i], 'signal'] = 1 # 做多价差
elif abs(z_score) < self.exit_z:
signals.loc[signals.index[i], 'signal'] = 0 # 平仓
else:
# 保持前一信号
signals.loc[signals.index[i], 'signal'] = \
signals['signal'].iloc[i-1] if i > 0 else 0
return signals点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:类 `PairsTradingStrategy`(配对交易策略原型实现)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
投资组合核心概念
有效前沿推导
给定
$$\max_{\mathbf{w}} \frac{\mathbf{w}^T\boldsymbol{\mu} - r_f}{\sqrt{\mathbf{w}^T\boldsymbol{\Sigma}\mathbf{w}}}, \quad \text{s.t.} \sum_i w_i = 1$$
切线组合权重(允许做空时):
$$\mathbf{w}^* = \frac{\boldsymbol{\Sigma}^{-1}(\boldsymbol{\mu} - r_f\mathbf{1})}{\mathbf{1}^T\boldsymbol{\Sigma}^{-1}(\boldsymbol{\mu} - r_f\mathbf{1})}$$
关键洞见:
- 所有投资者在有效前沿上持有的风险资产组合与切线组合成比例(两基金分离定理)。
- 投资者之间的差异仅体现在无风险资产与风险资产的配置比例上。
- 加入做空约束后,需要二次规划求解(不能使用解析解)。
多样化与风险
$$\sigma_p^2 = \frac{1}{n}\bar{\sigma}^2 + \frac{n-1}{n}\bar{\text{Cov}}$$
当
量化面试中的金融与策略题,考察的核心是"从理论到实证"的思维转换能力。理解公式只是起点,能识别公式在真实市场中的适用边界和实现陷阱才是区分优秀候选人的关键。