阅读更多

在 http://uqer.io 中经过前几日的学习,我们已经熟悉了Python中一些常用数值计算库的用法。本篇中,作为Quant中的Q宗(P Quant 和 Q Quant 到底哪个是未来?),我们将尝试把之前的介绍的工具串联起来,小试牛刀。

您将可以体验到:

  1. 如何使用python内置的数学函数计算期权的价格;
  2. 利用 numpy 加速数值计算;
  3. 利用 scipy 进行仿真模拟;
  4. 使用 scipy 求解器计算隐含波动率;

穿插着,我们也会使用matplotlib绘制精美的图标。

1. 关心的问题

我们想知道下面的一只期权的价格:

  • 当前价 spot : 2.45
  • 行权价 strike : 2.50
  • 到期期限 maturity : 0.25
  • 无风险利率 r : 0.05
  • 波动率 vol : 0.25

关于这样的简单欧式期权的定价,有经典的Black - Scholes [1] 公式:

 

Call(S,K,r,τ,σ)d1d2= SN(d1)KerτN(d2),=ln(S/K)+(r+12σ2)τστ,=d1στ.

 

其中S为标的价格,K为执行价格,r为无风险利率,τ=Tt为剩余到期时间。 N(x)为标准正态分布的累积概率密度函数。Call(S,K,r,τ,σ)为看涨期权的价格。

 
 
 
 
 
1
# 参数
2
spot = 2.45
3
strike = 2.50
4
maturity = 0.25
5
r = 0.05
6
vol = 0.25
 
 

观察上面的公式,需要使用一些数学函数,我们把它分为两部分:

  • log,sqrt,exp,这三个函数我们可以从标准库math中找到
  • 标准正态分布的累计概率密度函数,我们使用scipy库中的stats.norm.cdf函数
 
 
 
 
 
1
# 基于Black - Scholes 公式的期权定价公式
2
from math import log, sqrt, exp
3
from scipy.stats import norm
4
5
def call_option_pricer(spot, strike, maturity, r, vol):
6
    
7
    d1 = (log(spot/strike) + (r + 0.5 * vol *vol) * maturity) / vol / sqrt(maturity)
8
    d2 = d1 - vol * sqrt(maturity)
9
    
10
    price = spot * norm.cdf(d1) - strike * exp(-r*maturity) * norm.cdf(d2)
11
    return price
 
 

我们可以使用这个函数计算我们关注期权的结果:

 
 
 
 
 
1
print '期权价格 : %.4f' % call_option_pricer(spot, strike, maturity, r, vol)
 
 
期权价格 : 0.1133
 

2. 使用numpy加速批量计算

大部分的时候,我们不止关心一个期权的价格,而是关心一个组合(成千上万)的期权。我们想知道, 随着期权组合数量的增长,我们计算时间的增长会有多块?

2.1 使用循环的方式

 
 
 
 
 
1
import time
2
import numpy as np
3
4
portfolioSize = range(1, 10000, 500)
5
timeSpent = []
6
7
for size in portfolioSize:
8
    now = time.time()
9
    strikes = np.linspace(2.0,3.0,size)
10
    for i in range(size):
11
        res = call_option_pricer(spot, strikes[i], maturity, r, vol)
12
    timeSpent.append(time.time() - now)
 
 

从下图中可以看出,计算时间的增长可以说是随着组合规模的增长线性上升。

 
 
 
 
 
1
from matplotlib import pylab
2
import seaborn as sns
3
font.set_size(15)
4
sns.set(style="ticks")
5
pylab.figure(figsize = (12,8))
6
pylab.bar(portfolioSize, timeSpent, color = 'r', width =300)
7
pylab.grid(True)
8
pylab.title(u'期权计算时间耗时(单位:秒)', fontproperties = font, fontsize = 18)
9
pylab.ylabel(u'时间(s)', fontproperties = font, fontsize = 15)
10
pylab.xlabel(u'组合数量', fontproperties = font, fontsize = 15)
 
 
<matplotlib.text.Text at 0xdbad950>

2.2 使用numpy向量计算

numpy的内置数学函数可以天然的运用于向量:

 
 
 
 
 
1
sample = np.linspace(1.0,100.0,5)
2
np.exp(sample)
 
 
array([ 2.71828183e+00, 1.52434373e+11, 8.54813429e+21, 4.79357761e+32, 2.68811714e+43])

利用 numpy 的数学函数,我们可以重写原先的计算公式 call_option_pricer,使得它接受向量参数。

 
 
 
 
 
1
# 使用numpy的向量函数重写Black - Scholes公式
2
def call_option_pricer_nunmpy(spot, strike, maturity, r, vol):
3
    
4
    d1 = (np.log(spot/strike) + (r + 0.5 * vol *vol) * maturity) / vol / np.sqrt(maturity)
5
    d2 = d1 - vol * np.sqrt(maturity)
6
    
7
    price = spot * norm.cdf(d1) - strike * np.exp(-r*maturity) * norm.cdf(d2)
8
    return price
 
 
 
 
 
 
 
1
timeSpentNumpy = []
2
for size in portfolioSize:
3
    now = time.time()
4
    strikes = np.linspace(2.0,3.0, size)
5
    res = call_option_pricer_nunmpy(spot, strikes, maturity, r, vol)
6
    timeSpentNumpy.append(time.time() - now)
 
 

再观察一下计算耗时,虽然时间仍然是随着规模的增长线性上升,但是增长的速度要慢许多:

 
border-right-width: 30px; border-right-style: solid; b
来自: uqer.io
0
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

Global site tag (gtag.js) - Google Analytics