Найти градиент функции: Sympy vs. Jax

У меня есть функция Black_Cox() который вызывает другие функции, как показано ниже:

import numpy as np
from scipyimport stats

# Parameters
D = 100
r = 0.05
γ = 0.1

# Normal CDF
N = lambda x: stats.norm.cdf(x)

H = lambda V, T, L, σ: np.exp(-r*T) * N( (np.log(V/L) + (r-0.5*σ**2)*T) / (σ*np.sqrt(T)) )

# Black-Scholes
def C_BS(V, K, T, σ):
    d1 = (np.log(V/K) + (r + 0.5*σ**2)*T ) / ( σ*np.sqrt(T) )
    d2 = d1 - σ*np.sqrt(T)
    return V*N(d1) - np.exp(-r*T)*K*N(d2)

def BL(V, T, D, L, σ):
    return L * H(V, T, L, σ) - L * (L/V)**(2*r/σ**2-1) * H(L**2/V, T, L, σ) \
              + C_BS(V, L, T, σ) - (L/V)**(2*r/σ**2-1) * C_BS(L**2/V, L, T, σ) \
              - C_BS(V, D, T, σ) + (L/V)**(2*r/σ**2-1) * C_BS(L**2/V, D, T, σ)

def Bb(V, T, C, γ, σ, a):
    b = (np.log(C/V) - γ*T) / σ
    μ = (r - a - 0.5*σ**2 - γ) / σ
    m = np.sqrt(μ**2 + 2*r)
    return C*np.exp(b*(μ-m)) * ( N((b-m*T)/np.sqrt(T)) + np.exp(2*m*b)*N((b+m*T)/np.sqrt(T)) )

def Black_Cox(V, T, C=160, σ=0.1, a=0):
    return np.exp(γ*T)*BL(V*np.exp(-γ*T), T, D*np.exp(-γ*T), C*np.exp(-γ*T), σ) + Bb(V, T, C, γ, σ, a)

Мне нужно работать с производной от Black_Cox функция по V. Точнее, мне нужно оценить эту производную по тысячам путей, где я изменяю другие аргументы, нахожу производную и оцениваю некоторыеV.

Как лучше всего продолжить?

  • Должен ли я использовать sympy найти эту производную, а затем оценить на моем V выбора, как и в Mathematica: D[BlackCox[V, 10, 100, 160], V] /. V -> 180, или

  • Должен ли я просто использовать jax?

Если sympy, как бы вы посоветовали мне это сделать?

С jax Я понимаю, что мне нужно выполнить следующий импорт:

import jax.numpy as np
from jax.scipyimport stats
from jax import grad

и переоценить мои функции перед получением градиента:

func = lambda x: Black_Cox(x,10,160,0.1)
grad(func)(180.0)

Если мне все еще нужно будет работать с numpy версии функций, мне нужно будет создать по 2 экземпляра каждой функции или есть элегантный способ дублировать функцию для jax цели?

1 ответ

Jax не предоставляет встроенного способа перекомпиляции функции numpy с использованием jax-версий numpy и scipy. Но вы можете использовать фрагмент, подобный следующему, чтобы сделать это автоматически:

import inspect
from functools import wraps
import numpy as np
import jax.numpy

def replace_globals(func, globals_):
  """Recompile a function with replaced global values."""
  namespace = func.__globals__.copy()
  namespace.update(globals_)
  source = inspect.getsource(func)
  exec(source, namespace)
  return wraps(func)(namespace[func.__name__])

Это работает так:

def numpy_func(N):
  return np.arange(N) ** 2

jax_func = replace_globals(numpy_func, {"np": jax.numpy})

Теперь вы можете оценить версию numpy:

numpy_func(10)
# array([ 0,  1,  4,  9, 16, 25, 36, 49, 64, 81])

и версия jax:

jax_func(10)
# DeviceArray([ 0,  1,  4,  9, 16, 25, 36, 49, 64, 81], dtype=int32)

Просто убедитесь, что вы заменили все соответствующие глобальные переменные при переносе более сложной функции.

Другие вопросы по тегам