Skip to content

20.3 金融与策略题

量化面试中的金融与策略考察的是"将金融知识转化为量化模型"的能力。面试官希望看到你不仅理解金融理论,而且能用数学语言精确表达、用代码快速实现、并对边界条件和实际限制有清醒认识。

期权定价

Black-Scholes 公式核心推导思路

Black-Scholes 期权定价模型的推导基于以下核心思想:

  1. 构建一个delta对冲组合:持有 1 份期权多头,同时卖空 Δ=CS 份标的资产。
  2. 该组合在瞬间是无风险的,因此其收益应等于无风险利率。
  3. 由此得到 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$$
  1. 解此 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}$$

其中 N() 是标准正态分布的累积分布函数。

Put-Call Parity(买卖权平价关系)

Put-Call Parity 是无套利关系中最重要的一对:

$$C - P = S_0 - K \cdot e^{-rT}$$

理解:做多看涨期权 + 做空看跌期权 = 远期多头。如果这个等式不成立,存在套利机会。

面试常见追问

  • 如果 CP>S0KerT,如何套利?(卖 call、买 put、买股票、借入 K 的现值)
  • Put-Call Parity 的假设是什么?(欧式期权、无股息、无交易成本、可以卖空、同一执行价格和到期日)

Greeks 的含义与应用

Greeks公式含义面试要点
Delta (Δ)N(d1)期权价格对标的价格的敏感度ATM 期权 Delta ≈ 0.5
Gamma (Γ)N(d1)SσTDelta 对标的价格的敏感度衡量对冲频率需求
Theta (Θ)SN(d1)σ2TrKerTN(d2)时间衰减买方的"痛苦"指标
Vega (ν)STN(d1)对波动率的敏感度不是希腊字母但很重要
Rho (ρ)KTerTN(d2)对无风险利率的敏感度通常影响较小
PYTHON117 行 · 4.0 KB
📄此处有展示代码117 行 · 4.0 KB展开 ▼
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 模型

假设有知情交易者(概率为 α)和噪声交易者(概率为 1α),知情交易者知道资产的真实价值 V(在 VhighVlow 之间),做市商设定买卖价格:

$$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}})$$

核心洞见:价差与内幕交易概率成正比。当成交流动性降低、知情交易比例上升时,做市商需要扩大价差以补偿逆向选择风险。

PYTHON27 行 · 1007 B
📄此处有展示代码27 行 · 1007 B展开 ▼
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. 价差定义

Spreadt=log(PtA)βlog(PtB)

其中 β 通过回归或协整分析确定。也可以使用卡尔曼滤波动态估计 β

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):领先市场压力期,相关性可能突然瓦解。需要止损机制。
PYTHON64 行 · 2.5 KB
📄此处有展示代码64 行 · 2.5 KB展开 ▼
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`(配对交易策略原型实现)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

投资组合核心概念

有效前沿推导

给定 n 个风险资产,期望收益向量 μ,协方差矩阵 Σ,无风险利率 rf

$$\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})}$$

关键洞见

  • 所有投资者在有效前沿上持有的风险资产组合与切线组合成比例(两基金分离定理)。
  • 投资者之间的差异仅体现在无风险资产与风险资产的配置比例上。
  • 加入做空约束后,需要二次规划求解(不能使用解析解)。

多样化与风险

n 个风险资产等权组合的方差:

$$\sigma_p^2 = \frac{1}{n}\bar{\sigma}^2 + \frac{n-1}{n}\bar{\text{Cov}}$$

n 时,组合方差趋近于平均协方差 Cov¯。单个资产的特质风险被分散,但系统性风险(资产间的共同波动)无法被分散。这就是分散化的数学本质——也是为什么即使持有 500 只股票,也无法消除市场风险。

量化面试中的金融与策略题,考察的核心是"从理论到实证"的思维转换能力。理解公式只是起点,能识别公式在真实市场中的适用边界和实现陷阱才是区分优秀候选人的关键。