QuantLib 金融计算——高级话题之模拟跳扩散过程

2023-11-07 08:40

本文主要是介绍QuantLib 金融计算——高级话题之模拟跳扩散过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • QuantLib 金融计算——高级话题之模拟跳扩散过程
    • 跳扩散过程
    • 模拟算法
    • 面临的问题
      • “脏”的方法
      • “干净”的方法
    • 实现
      • 示例
    • 参考文献

如果未做特别说明,文中的程序都是 C++11 代码。

QuantLib 金融计算——高级话题之模拟跳扩散过程

跳扩散过程

1976 年,Merton 最早在衍生品定价中引入并分析了跳扩散过程,正因为如此 QuantLib 中和跳扩散相关的随机过程类称之为 Merton76Process,一个一般的跳扩散过程可以由下面的 SDE 描述,

\[ \frac{dS(t)}{S(t-)} = \mu dt + \sigma dW(t) + dJ(t)\\ J(t) = \sum_{j=1}^{N(t)}(Y_j-1) \]

其中 \(Y_j\) 是随机变量,\(N(t)\) 是计数过程。\(dJ(t)\) 表示 \(J(t)\)\(t\) 时刻发生的跳跃幅度,如果发生一次跳,则幅度为 \(Y_j-1\);如果没有发生跳,则幅度为 0。

在应用于衍生品定价时,需要对上述 SDE 中的项做出一些特殊约定,常见的约定有:

  1. \(N(t)\) 是参数等于 \(\lambda\) 的 Poisson 过程;
  2. \(\log Y_j\) 服从正态分布 \(N(\mu_{jump}, \sigma_{jump}^{2})\)
  3. \(\mu = r - \lambda m\),其中 \(m = E[Y_j] - 1\)\(r\) 代表无风险利率

模拟算法

\(X(t) = \log S(t)\),那么

\[ \begin{aligned} X(t_{i+1}) = & X(t_i) + \left(\mu - \frac12 \sigma^2 \right)(t_{i+1} - t_i)\\ & +\sigma[W(t_{i+1}) - W(t_i)] + \sum_{j = N(t_i)+1}^{N(t_{i+1})}\log Y_j \end{aligned} \]

\(X(t_i)\) 的基础上模拟 \(X(t_{i+1})\) 的算法如下:

  1. 生成 \(Z \sim N(0,1)\)
  2. 生成 \(N \sim \text{Poisson}(\lambda(t_{i+1}-t_i))\),若 \(N=0\),则令 \(M=0\),并转到第 4 步;
  3. 生成 \(\log Y_1,\dots,\log Y_N\),令 \(M = \log Y_1+\dots+\log Y_N\)
  4. \(X(t_{i+1}) = X(t_i) + \left(\mu - \frac12 \sigma^2 \right)(t_{i+1} - t_i) +\sigma \sqrt{t_{i+1} - t_i} Z + M\)

那么

\[ \begin{aligned} S_{t_{i+1}} =& S_{t_i} e^{(r-\lambda m -\frac{1}{2}\sigma^{2})\Delta t+ \sigma Z \sqrt{\Delta t} + M}\\ =& S_{t_i} e^{(r-\frac{1}{2}\sigma^{2})\Delta t+ \sigma Z \sqrt{\Delta t}}e^{(-\lambda m)\Delta t+M} \end{aligned} \]

其中,\(\Delta t = t_{i+1} - t_i\),而 \(e^{(-\lambda m)\Delta t+M}\) 是跳扩散相对于一般 Black-Scholes-Merton 过程的修正项。

面临的问题

目前 QuantLib 中提供的 Merton76Process 类只能配合“解析定价引擎”使用,本身不具备模拟随机过程路径的功能。究其原因,问题出在 QuantLib 的编码约定和 StochasticProcess1D 提供的接口两方面:

  1. QuantLib 中约定 StochasticProcess 派生出的子类仅能描述 SDE 的结构信息,也就是 SDE 的参数、漂移和扩散项的函数形式,子类不携带有关随机数生成的信息,所有随机数生成的相关信息均由 Monte Carlo 框架中其他组件控制;
  2. 生成随机过程路径的核心函数是 evolve 方法,StochasticProcess1D 提供的接口是 evolve(Time t0, Real x0, Time dt, Real dw)。如果 Merton76Process 按约定实现 evolve 方法的话,形式必须是 evolve(Time t0, Real x0, Time dt, const Array &dw),因为模拟跳需要额外的随机性,所以 dw 必须是一个 Array。很明显,不匹配。

“脏”的方法

在不改变当前接口的前提下,若要实现模拟跳扩散过程,需要用比较“”一点儿的手段,即打破约定,让随机过程类携带一个随机数发生器,为模拟跳提供额外的随机性。

具体来说,需要声明一个 Merton76Process 的派生类,该类携带一个高斯随机数发生器。因为从数学上来讲跳扩散过程推广自一般 Black-Scholes-Merton 过程,添加了一个修正项,所以遵循“适配器模式”(或“装饰器模式”)的思想,绝大部分计算可以委托给一个 BlackScholesMertonProcess 对象,仅需要对 driftevolve 方法作必要的修改。

“干净”的方法

当然,“干净”的方法要改变当前接口:

  1. 声明一个和 StochasticProcess1D 平行的新类 StochasticProcess1DJump,二者唯一的区别是 evolve 方法,在 StochasticProcess1DJump 中形式是 evolve(Time t0, Real x0, Time dt, const Array &dw)
  2. Merton76Process 改成继承自 StochasticProcess1DJump

实现

下面的代码实现了前面提到的“脏”的方法,因为随机数发生器的种类有很多,且没有基类提供统一的接口,所以使用了模板技术让类可以接受不同类型的随机数发生器。同时,许多计算被委托给了一个 BlackScholesMertonProcess 对象。

#ifndef MERTON76JUMPDIFFUSIONPROCESS_HPP
#define MERTON76JUMPDIFFUSIONPROCESS_HPP#include <ql/math/distributions/normaldistribution.hpp>
#include <ql/math/distributions/poissondistribution.hpp>
#include <ql/math/randomnumbers/boxmullergaussianrng.hpp>
#include <ql/math/randomnumbers/mt19937uniformrng.hpp>
#include <ql/processes/blackscholesprocess.hpp>
#include <ql/processes/merton76process.hpp>namespace QuantLib
{
template<typename GAUSS_RNG>
class Merton76JumpDiffusionProcess : public Merton76Process
{public:Merton76JumpDiffusionProcess(const Handle<Quote>& stateVariable,const Handle<YieldTermStructure>& dividendTS,const Handle<YieldTermStructure>& riskFreeTS,const Handle<BlackVolTermStructure>& blackVolTS,const Handle<Quote>& jumpInt,const Handle<Quote>& logJMean,const Handle<Quote>& logJVol,const GAUSS_RNG& gauss_rng,const ext::shared_ptr<discretization>& disc =ext::shared_ptr<discretization>(new EulerDiscretization)): Merton76Process(stateVariable,dividendTS,riskFreeTS,blackVolTS,jumpInt,logJMean,logJVol,disc), blackProcess_(new BlackScholesMertonProcess(stateVariable,dividendTS,riskFreeTS,blackVolTS,disc)), gauss_rng_(gauss_rng){}virtual ~Merton76JumpDiffusionProcess() {}Real x0() const{return blackProcess_->x0();}Time time(const Date& d) const{return blackProcess_->time(d);}Real diffusion(Time t,Real x) const{return blackProcess_->diffusion(t, x);}Real apply(Real x0,Real dx) const{return blackProcess_->apply(x0, dx);}Size factors() const{return 1;}Real drift(Time t,Real x) const{Real lambda_ = Merton76Process::jumpIntensity()->value();Real delta_ = Merton76Process::logJumpVolatility()->value();Real nu_ = Merton76Process::logMeanJump()->value();Real m_ = std::exp(nu_ + 0.5 * delta_ * delta_) - 1;return blackProcess_->drift(t, x) - lambda_ * m_;}Real evolve(Time t0,Real x0,Time dt,Real dw) const;private:const CumulativeNormalDistribution cumNormalDist_;ext::shared_ptr<GeneralizedBlackScholesProcess> blackProcess_;GAUSS_RNG gauss_rng_;
};template<typename GAUSS_RNG>
Real Merton76JumpDiffusionProcess<GAUSS_RNG>::evolve(Time t0,Real x0,Time dt,Real dw) const
{Real lambda_ = Merton76Process::jumpIntensity()->value();Real delta_ = Merton76Process::logJumpVolatility()->value();Real nu_ = Merton76Process::logMeanJump()->value();Real m_ = std::exp(nu_ + 0.5 * delta_ * delta_) - 1;Real p = cumNormalDist_(gauss_rng_.next().value);if (p < 0.0)p = 0.0;else if (p >= 1.0)p = 1.0 - QL_EPSILON;Real j = gauss_rng_.next().value;const Real n = InverseCumulativePoisson(lambda_ * dt)(p);Real retVal = blackProcess_->evolve(t0, x0, dt, dw);retVal *=std::exp(-lambda_ * m_ * dt + nu_ * n + delta_ * std::sqrt(n) * j);return retVal;
}
}
#endif // MERTON76JUMPDIFFUSIONPROCESS_HPP

示例

下面模拟两条曲线

#include <iostream>#include <ql/math/randomnumbers/boxmullergaussianrng.hpp>
#include <ql/math/randomnumbers/mt19937uniformrng.hpp>
#include <ql/processes/blackscholesprocess.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/date.hpp>
#include <ql/time/daycounters/actualactual.hpp>#include "Merton76JumpDiffusionProcess.hpp"int main() {using namespace std;using namespace QuantLib;Date refDate = Date(27, Mar, 2019);Rate riskFreeRate = 0.03;Rate dividendRate = 0.01;Real spot = 52.0;Rate vol = 0.2;Calendar cal = TARGET();DayCounter dc = ActualActual();ext::shared_ptr<YieldTermStructure> rdStruct(new FlatForward(refDate, riskFreeRate, dc));ext::shared_ptr<YieldTermStructure> rqStruct(new FlatForward(refDate, dividendRate, dc));Handle<YieldTermStructure> rdHandle(rdStruct);Handle<YieldTermStructure> rqHandle(rqStruct);ext::shared_ptr<SimpleQuote> spotQuote(new SimpleQuote(spot));Handle<Quote> spotHandle(spotQuote);ext::shared_ptr<BlackVolTermStructure> volQuote(new BlackConstantVol(refDate, cal, vol, dc));Handle<BlackVolTermStructure> volHandle(volQuote);// Specify the jump intensity, jump mean and// jump volatility objectsReal jumpIntensity = 0.2;    // lambdaReal jumpVolatility = 0.3;Real jumpMean = 0.0;ext::shared_ptr<SimpleQuote> jumpInt(new SimpleQuote(jumpIntensity));ext::shared_ptr<SimpleQuote> jumpVol(new SimpleQuote(jumpVolatility));ext::shared_ptr<SimpleQuote> jumpMn(new SimpleQuote(jumpMean));Handle<Quote> jumpI(jumpInt), jumpV(jumpVol), jumpM(jumpMn);ext::shared_ptr<BlackScholesMertonProcess> bsmProcess(new BlackScholesMertonProcess(spotHandle, rqHandle, rdHandle, volHandle));unsigned long seed = 12324u;MersenneTwisterUniformRng unifMt(seed);MersenneTwisterUniformRng unifMtJ(25u);typedef BoxMullerGaussianRng<MersenneTwisterUniformRng> GAUSS;GAUSS bmGauss(unifMt);GAUSS jGauss(unifMtJ);ext::shared_ptr<Merton76JumpDiffusionProcess<GAUSS>> mtProcess(new Merton76JumpDiffusionProcess<GAUSS>(spotHandle, rqHandle, rdHandle, volHandle,jumpI, jumpM, jumpV, jGauss));Time dt = 0.004, t = 0.0;Real x = spotQuote->value();Real y = spotQuote->value();Real dw;Size numVals = 250;std::cout << "Time, Jump, NoJump" << std::endl;std::cout << t << ", " << x << ", " << y << std::endl;for (Size j = 1; j <= numVals; ++j) {dw = bmGauss.next().value;x = mtProcess->evolve(t, x, dt, dw);y = bsmProcess->evolve(t, y, dt, dw);std::cout << t + dt << ", " << x << ", " << y << std::endl;t += dt;}return EXIT_SUCCESS;
}

232518-20190331114034792-2013823195.png

参考文献

  1. 《金融工程中的蒙特卡罗方法》

转载于:https://www.cnblogs.com/xuruilong100/p/10630691.html

这篇关于QuantLib 金融计算——高级话题之模拟跳扩散过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/362475

相关文章

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI

PyInstaller打包selenium-wire过程中常见问题和解决指南

《PyInstaller打包selenium-wire过程中常见问题和解决指南》常用的打包工具PyInstaller能将Python项目打包成单个可执行文件,但也会因为兼容性问题和路径管理而出现各种运... 目录前言1. 背景2. 可能遇到的问题概述3. PyInstaller 打包步骤及参数配置4. 依赖

前端高级CSS用法示例详解

《前端高级CSS用法示例详解》在前端开发中,CSS(层叠样式表)不仅是用来控制网页的外观和布局,更是实现复杂交互和动态效果的关键技术之一,随着前端技术的不断发展,CSS的用法也日益丰富和高级,本文将深... 前端高级css用法在前端开发中,CSS(层叠样式表)不仅是用来控制网页的外观和布局,更是实现复杂交

将Mybatis升级为Mybatis-Plus的详细过程

《将Mybatis升级为Mybatis-Plus的详细过程》本文详细介绍了在若依管理系统(v3.8.8)中将MyBatis升级为MyBatis-Plus的过程,旨在提升开发效率,通过本文,开发者可实现... 目录说明流程增加依赖修改配置文件注释掉MyBATisConfig里面的Bean代码生成使用IDEA生

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

JSON Web Token在登陆中的使用过程

《JSONWebToken在登陆中的使用过程》:本文主要介绍JSONWebToken在登陆中的使用过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录JWT 介绍微服务架构中的 JWT 使用结合微服务网关的 JWT 验证1. 用户登录,生成 JWT2. 自定义过滤

java中使用POI生成Excel并导出过程

《java中使用POI生成Excel并导出过程》:本文主要介绍java中使用POI生成Excel并导出过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求说明及实现方式需求完成通用代码版本1版本2结果展示type参数为atype参数为b总结注:本文章中代码均为

SpringCloud之LoadBalancer负载均衡服务调用过程

《SpringCloud之LoadBalancer负载均衡服务调用过程》:本文主要介绍SpringCloud之LoadBalancer负载均衡服务调用过程,具有很好的参考价值,希望对大家有所帮助,... 目录前言一、LoadBalancer是什么?二、使用步骤1、启动consul2、客户端加入依赖3、以服务

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3