Лучшая практика для расчета дельты опциона - PullRequest
0 голосов
/ 04 мая 2019

Опцион - это производный контракт, основанный на стоимости некоторой базовой ценной бумаги (обычно цена акции).Формально в модели ценообразования цена опциона является функцией s0, текущей базовой цены ценной бумаги, лота других аргументов (волатильность, процентная ставка, ставка дивидендов и т. Д.) И некоторых возможныхkwargs.

Дельта опциона - это скорость изменения его цены по отношению к цене базовой ценной бумаги.На практике это реализуется как

(calc_price(s0 + ds, **kwargs) - calc_price(s0 - ds, **kwargs)) / (2 * ds)

Что я хочу сделать, это реализовать get_delta как метод класса Option Итак, теперь яреализовали модель ценообразования для опциона следующим образом:

class Option:
    def __init__(self, s0, lots_of_args, **kwargs):
        self.s0 = s0

        # actually there's a list of lots of args, not packed
        self.lots_of_args = lots_of_args
        # actually kwargs are unpacked either,
        self.kwargs = kwargs

    def calc_price(self):
        price = ...
        return price

    def get_delta(self, ds=.05):
        cd = Option(self.s0 - ds, self.lots_of_args, **self.kwargs).calc_price()
        cu = Option(self.s0 + ds, self.lots_of_args, **self.kwargs).calc_price()   
        return (cu - cd) / (2 * ds)

Проблема заключается в том, что на самом деле существует лот аргументов, отличных от s0 (представлен как lots_of_args , но на самом деле это не один аргумент, но их дюжина), поэтому я очень не хочу копировать их один за другим в функцию get_delta.Мне нужен способ получить подсказку об аргументах, которые передаются в __init__.Первая мысль, конечно же, заключается в использовании locals().Однако есть некоторые проблемы:

  1. дополнительно self аргумент включен.

  2. kwargs не распаковано.

  3. Документ на locals() не советует изменять dict, возвращаемый locals(), поэтому я не думаю, что это хорошая идеяdel self arg и update распакованный kwargs.

Кто-нибудь может помочь?Благодаря.

Ответы [ 3 ]

2 голосов
/ 04 мая 2019

как насчет копирования?

import copy

class Option:
    def __init__(self, s0, lots_of_args, **kwargs):
        self.s0 = s0

    def calc_price(self):
        price = ...
        return price

    def get_delta(self, ds=.05):
        cd = copy.copy(self)
        cd.s0 -= ds
        cu = copy.copy(self)
        cu.s0 += ds

        return (cu.calc_price() - cd.calc_price()) / (2 * ds)

Если в вашем классе есть некоторые атрибуты dict / list (или атрибуты, использующие другие изменяемые классы), вы можете вместо этого использовать copy.deepcopy (например, если calc_price() изменяет эти атрибуты).

И вы можете определить __copy__ метод, чтобы настроить способ создания копии.

1 голос
/ 04 мая 2019

Если вам нужно просто скопировать эти «много аргументов», не меняя их, то вы можете использовать подход, аналогичный namedtuple 's _replace метод:

>>> import collections
>>> Option = collections.namedtuple('Option', 'a b c d e f')
>>> opt = Option(a=1, b=2, c=3, d=4, e=5, f=6)
>>> opt
Option(a=1, b=2, c=3, d=4, e=5, f=6)
>>> new_opt = opt._replace(a=74)
>>> new_opt
Option(a=74, b=2, c=3, d=4, e=5, f=6)  # only 'a' changed, all other args remained the same

Тогда ваш метод get_delta() будет выглядеть следующим образом:

def get_delta(self, ds=.05):
    cd = self._replace(s0=self.s0 - ds).calc_price()
    cu = self._replace(s0=self.s0 + ds).calc_price()   
    return (cu - cd) / (2 * ds)

Независимо от того, наследовать ли вам напрямую от именованного кортежа или создать свой собственный _replace -подобный метод, решать только вам.

0 голосов
/ 04 мая 2019

Почему бы не изменить метод calc_price для включения ds? Затем get_delta упрощается до вызова calc_price с положительным и отрицательным ds:

def calc_price(self, ds=0):
    s0 = self.s0 + ds 
    price = ... return price 

def get_delta(self, ds=.05): 
    cd = self.calc_price(-ds)
    cu = self.calc_price(ds) 
    return (cu - cd) / (2 * ds) here
...