套利 Arbitrage

在某项资产的交易过程中,交易者可以在不需要期初投资支出的条件下,获得无风险利润。其中:

  • 商品市场:同一资产在两个不同的市场上进行交易,但各个市场上的交易价格不同,如果没有其他约束,就存在套利机会。
    • 商品市场套利策略:低买高卖
  • 金融市场:两项金融产品A,B,在期末有相同的现金流(称为互相复制),如果在期初的价格不同,就有套利机会。
    • 金融市场套利策略:高卖低买

无套利定价原则

在无套利市场中,如果两项金融产品在到期日的价值完全相同,则它们在到期日之前任意时刻的价值也必然相同。其中:

  • 复制:如果产品A和产品B未来的现金流状态完全相同,称A和B互相复制。

无套利定价的关键技术是所谓“复制”技术,即用一组已知价格的证券来复制待定价格的金融产品。

上述内容参考书籍:

《An Elementary Introduction to Mathematical Finance》

  • Chapter 5 Pricing Contracts via Arbitrage
  • Chapter 6 The Arbitrage Theorem

《The Mathematics for Finance: Modeling and Hedging》

  • Chapter 2 Binomial Trees, Replicating Portfolios, and Arbitrage

期权定价的二叉树模型 Binomial Tree

Example:

假设一种不支付红利的股票当前市价100元,我们得知1年后,该股票的价格可以是110元、90元,而概率未给定。即期利率为5%,问:1年后到期执行价格为100元的该股票的欧式看涨期权的公平价格是多少?$\frac{50}{7}$

欧式看跌期权呢?

一般二叉树模型

假设一个无红利支付的股票,当前时刻 t 的价值是 $S_t$ ,期末时刻 T 的价值是 $S_T$ 。有两种市场状态,即 $S_T$ 只可能取到两个值: $S_T=uS_0,u>1$ 或者 $S_T=dS_0,d<1$ 。设无风险连续年利率利率为 $r$ 。

则容易得到

证明:不等式均乘以 $S_t$ ,看作债券并获取套利。

单期二叉树模型

无套利定价法下欧式期权定价公式

证明:

构造一个由 $\Delta$ 股股票多头和一个期权空头组成的资产组合,并计算出该组合为无风险资产组合时的Δ值

其中 $f_{u},f_{d}$ 分别为期权在股票上涨和下跌时的价值。上式的 $\Delta$ 通常称为套期保值比例。

该无风险组合现值为 $(uS_t\Delta-f_u)e^{r(T-t)}$ ,与构造该组合的成本 $S_t*\Delta-f$ 相等。

Delta对冲技术

建立一个包含衍生品头寸和基础资产头寸的无风险的资产组合。若数量适当,基础资产多头的赢利就会与衍生品的空头亏损相抵,实现瞬间无风险。

无风险组合的收益率必须等于无风险利率。

风险中性定价方法:Risk Neutral Valuation

两期二叉树模型 / 多期二叉树模型

期权定价方法:倒退定价法、风险中性定价法

应用领域:欧式期权、美式期权(注意倒退定价法的价格比较)、敲出期权(注意敲出价格)

多期二叉树中的参数

股票的波动率为$\sigma$,由此可以设,当$\text{Δt}$很小时:

此为波动率假设。

期权二叉树定价 Using Python

Source:《Python for Finance》1st Edition

  • Chapter 8 5.2 Binomial Option Pricing
# model & option Parameters 参数化
S0 = 100. # initial index level
T = 1. # call option maturity
r = 0.05 # constant short rate
vola = 0.20 # constant volatility factor of diffusion

# time parameters
M = 1000 # time steps
dt = T / M # length of time interval
df = exp(-r * dt) # discount factor per time interval

# binomial parameters
u = exp(vola * sqrt(dt)) # up-movement
d = 1 / u # down-movement
q = (exp(r * dt) - d) / (u - d) # martingale probability

import numpy as np
def binomial_py(strike):
''' Binomial option pricing via looping.

Parameters
==========
strike : float
strike price of the European call option
'''
# LOOP 1 - Index Levels
S = np.zeros((M + 1, M + 1), dtype=np.float64)
# index level array
S[0, 0] = S0
z1 = 0
for j in range(1, M + 1, 1):
z1 = z1 + 1
for i in range(z1 + 1):
S[i, j] = S[0, 0] * (u ** j) * (d ** (i * 2))

# LOOP 2 - Inner Values
iv = np.zeros((M + 1, M + 1), dtype=np.float64)
# inner value array
z2 = 0
for j in range(0, M + 1, 1):
for i in range(z2 + 1):
iv[i, j] = max(S[i, j] - strike, 0)
z2 = z2 + 1

# LOOP 3 - Valuation
pv = np.zeros((M + 1, M + 1), dtype=np.float64)
# present value array
pv[:, M] = iv[:, M] # initialize last time point
z3 = M + 1
for j in range(M - 1, -1, -1):
z3 = z3 - 1
for i in range(z3):
pv[i, j] = (q * pv[i, j + 1] +
(1 - q) * pv[i + 1, j + 1]) * df
return pv[0, 0]

%time round(binomial_py(100), 3) #计算European Call Option现值,保留三位小数,并给出时间

'''
CPU times: user 1.58 s, sys: 30 ms, total: 1.61 s
Wall time: 1.64 s
10.449
'''
def binomial_np(strike):
''' Binomial option pricing with NumPy.

Parameters
==========
strike : float
strike price of the European call option
'''
# Index Levels with NumPy
mu = np.arange(M + 1)
mu = np.resize(mu, (M + 1, M + 1))
md = np.transpose(mu)
mu = u ** (mu - md)
md = d ** md
S = S0 * mu * md

# Valuation Loop
pv = np.maximum(S - strike, 0)

z = 0
for t in range(M - 1, -1, -1): # backwards iteration
pv[0:M - z, t] = (q * pv[0:M - z, t + 1]
+ (1 - q) * pv[1:M - z + 1, t + 1]) * df
z += 1
return pv[0, 0]

M = 4 # four time steps only
mu = np.arange(M + 1)
mu

mu = np.resize(mu, (M + 1, M + 1))
mu

md = np.transpose(mu)
md

mu = u ** (mu - md)
mu.round(3)
'''
array([[ 1. , 1.006, 1.013, 1.019, 1.026],
[ 0.994, 1. , 1.006, 1.013, 1.019],
[ 0.987, 0.994, 1. , 1.006, 1.013],
[ 0.981, 0.987, 0.994, 1. , 1.006],
[ 0.975, 0.981, 0.987, 0.994, 1. ]])
'''

md = d ** md
md.round(3)
'''
array([[ 1. , 1. , 1. , 1. , 1. ],
[ 0.994, 0.994, 0.994, 0.994, 0.994],
[ 0.987, 0.987, 0.987, 0.987, 0.987],
[ 0.981, 0.981, 0.981, 0.981, 0.981],
[ 0.975, 0.975, 0.975, 0.975, 0.975]])
'''

S = S0 * mu * md
S.round(3)
'''
array([[ 100. , 100.634, 101.273, 101.915, 102.562],
[ 98.743, 99.37 , 100. , 100.634, 101.273],
[ 97.502, 98.121, 98.743, 99.37 , 100. ],
[ 96.276, 96.887, 97.502, 98.121, 98.743],
[ 95.066, 95.669, 96.276, 96.887, 97.502]])
'''
# 这之中只有上三角矩阵matter.
# Although we do more calculations with this approach than are needed in principle, the approach is, as expected, much faster than the first version, which relies heavily on nested loops on the Python level:

M = 1000 # reset number of time steps
%time round(binomial_np(100), 3)
'''
CPU times: user 91.5 ms, sys: 15.2 ms, total: 107 ms
Wall time: 106 ms
10.449
'''

以上部分参考书目:

《数理金融》(Paul Wilmott)

  • Chapter 15 二叉树模型

《Options, Futures and Other Derivatives》

《The Mathematics of Finance: Modeling and Hedging》

  • Chapter 2 Binomial Trees, Replicating Portfolios, and Arbitrage
  • Chapter 3 Tree Models for Stock and Options
  • Chapter 4 Using Spread Sheets to Compute Stock and Options

《Introduction to the Mathematics of Finance》

  • Chapter 2 Binomial Model

FRM《4 Valuation and Risk Models》

  • Chapter 14 Binomial Trees

《Mathematical Models of Financial Derivatives》

  • Chapter 6 Numerical Schemes for Pricing Options