【问题标题】:How to price a down-and-out leveraged barrier call option using Brownian motion in Python?如何在 Python 中使用布朗运动为向下和向外的杠杆障碍看涨期权定价?
【发布时间】:2020-06-29 20:53:03
【问题描述】:

我正在尝试使用几何布朗运动为一种杠杆下行和下行 (LDAO) 障碍看涨期权定价。

我的 python 脚本如下。我不确定如何正确模拟不断增加的障碍B 和在股价上涨时倍增收益的杠杆因子。

该选项的特点如下。

  1. LDAO 的“杠杆”部分如下所示。当您买入看涨期权时,您只需支付标的资产的部分现货价格S0。卖家提供资金F0 购买其余部分。也就是说,期权的买入价P为:P = S -/- F
  2. 作为买家,您在融资水平上支付利息iF
  3. “down-and-out”部分的结构如下。当标的价格S 跌破障碍B 时,期权被取消,标的资产以活跃市场价格卖出。当现货价S1低于融资F时,你的终值为零。如果现货价格高于融资,您的支付是S1 - F1(F1 包括利息)。您的付款不能为负数。
  4. 障碍 B 每天增加融资级别的利息金额F。所以B1 = B0 + F*(1 + i)^t
  5. 壁垒 B 始终低于标的资产价格,但高于融资水平:S0 > B > F

我尝试在下面的 Python 3 脚本中实现这一点。有关如何正确处理此问题的任何建议?

import numpy as np
from math import log, e

P = 30 # This is what you pay (S -/- F)
S = 360 # spot price of the stock
K = 340 Exercise price is equal to the stop-loss barrier (as far as I understand it)
B = 340 # the stop-loss barrier at which the option is cancelled
F = 330 # The financing level
T = 1 # Time to maturity. But in priciple, the option runs indefintely as long as S > B
i = 0.02 # Annualised interest rate on the financing F
r = 0.00135 # Risk-free rate of return
impliedVolatility = 0.3
num_reps = 100 

def barrier_option(option_type, s0, strike, B, F, maturity, i, r, sigma, num_reps):
    payoff_sum = 0
    for j in range(num_reps):
        st = S
        st = st*e**((r-0.5*sigma**2)*maturity + sigma*np.sqrt(maturity)*np.random.normal(0, 1))
        B_shift = B + F*(1+i)*np.sqrt(maturity) # Here the interest I on F gets adjusted by increasing B
        non_touch = (np.min(st) > B_shift)*1
        if option_type == 'c':
            payoff = max(0,st-strike)
        elif option_type == 'p':
            payoff = max(0,strike-st)
        payoff_sum += non_touch * payoff
    premium = (payoff_sum/float(num_reps))*e**(-r*maturity)
    return premium

Bar = barrier_option('c', S, K, B, F, (T*252)/365, i, r, impliedVolatility, num_reps)```

【问题讨论】:

    标签: python-3.x numpy simulation montecarlo quantitative-finance


    【解决方案1】:

    “有什么建议可以解决这个问题吗?”

    • 使过程迭代和s0-依赖,原来不是,
    • 使过程计算效率更高,您重新计算常量值num_reps
    • 根据 B_shift 修改过程是一个常数值,而备注表明一些演变
    • 按照st修改流程,如果不在np.min( st )中,这可能反映了原始代码设计意图的矢量化形式,这不是她添加的。
    import numpy as np
    
    P =  30       # This is what you pay (S -/- F)
    S = 360       # spot price of the stock
    K = 340       # Exercise price is equal to the stop-loss barrier (as far as I understand it)
    B = 340       # the stop-loss barrier at which the option is cancelled
    F = 330       # The financing level
    T =   1       # Time to maturity. But in priciple, the option runs indefintely as long as S > B
    i =   0.02    # Annualised interest rate on the financing F
    r =   0.00135 # Risk-free rate of return
    
    impliedVolatility =   0.3
    num_reps          = 100
    
    def barrier_option( option_type, # the option-type { 'c': CALL | 'p': PUT }
                        s0,          # the spot price of the option underlying asset
                        strike,      # the strike price
                        B,           # the stop-loss barrier at which the option is cancelled
                        F,           # the financing level
                        maturity,    # the option time to maturity
                        i,           # the annualised interest rate on financing F
                        r,           # the risk-free rate of returns
                        sigma,       # the sigma - implied volatility
                        num_reps     # the number of repetitions
                        ):
        """                                                                 __doc__ [DOC-ME] [TEST-ME] [PERF-ME]
        SYNTAX:     barrier_option( option_type, # the option-type { 'c': CALL | 'p': PUT }
                                    s0,          # the spot price of the option underlying asset
                                    strike,      # the strike price
                                    B,           # the stop-loss barrier at which the option is cancelled
                                    F,           # the financing level
                                    maturity,    # the option time to maturity
                                    i,           # the annualised interest rate on financing F
                                    r,           # the risk-free rate of returns
                                    sigma,       # the sigma - implied volatility
                                    num_reps     # the number of repetitions
                                    )
        PARAMETERS: a string        option_type, # the option-type { 'c': CALL | 'p': PUT }
                    a float-alike   s0,          # the spot price of the option underlying asset
                    a float-alike   strike,      # the strike price
                    a float-alike   B,           # the stop-loss barrier at which the option is cancelled
                    a float-alike   F,           # the financing level
                    a float-alike   maturity,    # the option time to maturity
                    a float-alike   i,           # the annualised interest rate on financing F
                    a float-alike   r,           # the risk-free rate of returns
                    a float-alike   sigma,       # the sigma - implied volatility
                    an  int-alike   num_reps     # the number of repetitions
        
        RETURNS:    a float
        
        THROWS:     ValueError on inappropriate option_type specifier
        
        EXAMPLE:    
        
        """
        if option_type not in ( 'c', 'p' ): #...............................# FUSE: protect your own code
           raise ValueError( "EXC: a call to barrier_option() contained an illegal option-type specifier {0:}".format( repr( option_type ) ) )
        
        payoff_sum = 0                                                      # initial settings
        st         = S # initial settings ..................................# shan't be here the sO-parameter from the call-signature, instead of a reference to a global S ?
        
        const_sqrtMATURITY =                 np.sqrt( maturity )
        const_1stPartOfEXP = ( r - ( sigma**2 )*0.5 )*maturity
        const_2ndPartOfEXP =         sigma *const_sqrtMATURITY
        const_B_shift      = B + F*(1 + i) *const_sqrtMATURITY
        
        for j in range( num_reps ): #.......................................# PERF:
            #t = S                                                          # removed from loop, it will restore the referenced global S into a local st for each loop again, which is re-shortcutting the process
            #t = st*e**( ( r - 0.5 * sigma**2 ) * maturity + sigma * np.sqrt( maturity ) * np.random.normal( 0, 1 ) )
            #...............................................................# improved PERF: re-use const-s, that are loop-invariant
            st*= np.exp(                          const_1stPartOfEXP        #                 100 x const re-used
                       + np.random.normal(0, 1) * const_2ndPartOfEXP        #                 100 x const re-used
                         )
            #_shift = B + F * ( 1 + i ) * np.sqrt( maturity )               # Here the interest I on F gets adjusted by increasing B
            #...............................................................#                               REVISE: THE increasing B NOT VISIBLE ANYWHERE IN THE ORIGNAL CODE - IS IT CORRECT ?
            #...............................................................# improved PERF: avoid re-calculations of a const, that is loop-invariant
            #non_touch  =                                                                               ( np.min(st) >       B_shift ) * 1     # REVISE: the code here may first meet a vector-ised kind of st: np.min(st)
            payoff_sum += ( max( 0, st - strike ) if option_type == 'c' else max( 0, strike - st ) ) if ( np.min(st) > const_B_shift ) else 0. # REVISE: the code here may first meet a vector-ised kind of st: np.min(st)
            
        #remium = (payoff_sum/float(num_reps))*e**(-r*maturity)
        #eturn premium
        #...................................................................# improved PERF: avoid creation of named variables just to RET a value ( variables & namespace management operations are non-zero expenses )
        return ( payoff_sum * np.exp( -r * maturity ) ) / float( num_reps ) # improved (im)precission
    
    Bar = barrier_option( 'c',                   
                           S, K, B, F,            
                           ( T * 252 ) / 365.,      #..... be self-consistent, if 've used float( num_reps ) inside, fuse-protect with decimal point also elsewhere, in spite of Py3 "tolerating" in how to handle the int-divisors, which Py2 is not
                           i, r, impliedVolatility, 
                           num_reps
                           )
    

    【讨论】:

    • 是的,这样好多了。效率更高。你是对的,从调用签名而不是从全局 S 中获取 s0 参数要好得多。关于B_shift 变量,我认为它可能必须在循环中。这是因为每天收取利息,因此障碍 B 每天都会略微向上移动。
    • 我想我也犯了一个错误。该期权没有时间价值,只有内在价值。所以看涨期权的价格是`` P = S - F```,其中 F 也以与 B 更新相同的每日金额更新(因此每日利息为 i / 365)。
    猜你喜欢
    • 2018-12-20
    • 2019-06-20
    • 1970-01-01
    • 1970-01-01
    • 2022-07-05
    • 2012-03-25
    • 2022-11-13
    • 1970-01-01
    相关资源
    最近更新 更多