Uma biblioteca Python para finanças matemáticas.
https://pypi.org/project/QFin/
pip install qfin
O QFin está sendo reconstruído para aproveitar mais princípios da programação orientada a objetos. Vários módulos nesta versão estão obsoletos junto com as soluções para PDEs/SDEs (principalmente no módulo de opções).
O QFin agora contém um módulo chamado 'estocástica' que será em grande parte responsável pela calibração do modelo e precificação de opções. Um Cython/C++ equivalente ao QFin também está sendo construído, então fique atento!
As equações diferenciais estocásticas que modelam a dinâmica dos ativos subjacentes estendem a classe 'StochasticModel' e possuem uma lista de parâmetros e funções do modelo para precificação de vanillas, calibração para superfícies de volatilidade implícita e simulações de Monte Carlo (particularmente úteis após calibração para opções dependentes do caminho de precificação).
Abaixo está um exemplo trivial usando ArithmeticBrownianMotion - primeiro importe o StochasticModel...
de qfin.stochastics importar ArithmeticBrownianMotion
Em seguida, inicialize o objeto da classe parametrizando o modelo...
# abm parametrizado por Bachelier vol = .3abm = ArithmeticBrownianMotion([.3])
O abm agora pode ser usado para precificar uma opção de compra/venda vanilla (o padrão dos preços é "CALL") sob o conjunto de parâmetros fornecido...
# F0 = 101# X = 100# T = 1abm.vanilla_pricing(101, 100, 1, "CALL")# Preço da chamada: 1.0000336233656906
Usando preços de venda com paridade de call-put também podem ser obtidos...
# F0 = 99# X = 100# T = 1abm.vanilla_pricing(99, 100, 1, "PUT")# Preço de venda: 1.0000336233656952
A calibração e subsequente simulação do processo também estão disponíveis - observe que alguns processos têm volatilidade estática e não podem ser calibrados para uma superfície ivol.
O movimento browniano aritmético pode ser simulado da seguinte forma...
# F0 = 100# n (etapas) = 10000# dt = 1/252# T = 1abm.simulate(100, 10000, 1/252, 1)
Os resultados da simulação junto com as características da simulação são armazenados na tupla 'path_characteristics': (paths, n, dt, T).
Usando as características do caminho armazenado, podemos encontrar o preço de uma opção de compra exatamente como antes, calculando a média de cada retorno do caminho descontado (assumindo um processo de estoque) com taxas zero, podemos evitar o desconto como segue e encontrar o valor da opção como segue...
# lista de payoffspayoffs do caminho = []# preço de exercício da opçãoX = 99# iteração através dos valores do caminho terminal para identificar o payofffor path em abm.path_characteristics[0]: # anexando CALL payoff payoffs.append(max((path[-1] - X ), 0))# valor da opção hojenp.average(payoffs)# Preço da chamada: 1.0008974837343871
Podemos ver aqui que o preço simulado está convergindo para o preço próximo.
A precificação teórica de opções para ações sem pagamento de dividendos está disponível por meio das classes BlackScholesCall e BlackScholesPut.
from qfin.options import BlackScholesCallfrom qfin.options import BlackScholesPut# 100 - preço inicial do ativo subjacente# .3 - volatilidade subjacente do ativo# 100 - preço de exercício da opção# 1 - tempo até o vencimento (ano)# .01 - taxa de juros livre de riscoeuro_call = BlackScholesCall(100, 0,3, 100, 1, 0,01)euro_put = BlackScholesPut (100, 0,3, 100, 1, 0,01)
print('Preço da chamada: ', euro_call.price)print('Preço da opção de venda: ', euro_put.price)
Call price: 12.361726191532611 Put price: 11.366709566449416
Estão disponíveis derivadas parciais de primeira ordem e algumas derivadas parciais de segunda ordem do modelo de precificação Black-Scholes.
Derivada parcial de primeira ordem em relação ao preço do ativo subjacente.
print('Chamar delta: ', euro_call.delta)print('Colocar delta: ', euro_put.delta)
Call delta: 0.5596176923702425 Put delta: -0.4403823076297575
Derivada parcial de segunda ordem em relação ao preço do ativo subjacente.
print('Chamar gama: ', euro_call.gamma)print('Colocar gama: ', euro_put.gamma)
Call gamma: 0.018653923079008084 Put gamma: 0.018653923079008084
Derivada parcial de primeira ordem em relação à volatilidade do ativo subjacente.
print('Chamar vega: ', euro_call.vega)print('Colocar vega: ', euro_put.vega)
Call vega: 39.447933090788894 Put vega: 39.447933090788894
Derivada parcial de primeira ordem em relação ao prazo até o vencimento.
print('Chame theta: ', euro_call.theta)print('Coloque theta: ', euro_put.theta)
Call theta: -6.35319039407325 Put theta: -5.363140560324083
A simulação de caminhos de ativos está disponível usando processos estocásticos comuns.
Modelo padrão para implementação do movimento geométrico browniano.
de qfin.simulations import GeometricBrownianMotion# 100 - preço inicial do ativo subjacente# 0 - desvio do ativo subjacente (mu)# .3 - volatilidade do ativo subjacente# 1/52 - intervalos de tempo (dt)# 1 - tempo até o vencimento (ano)gbm = Movimento Geométrico Browniano (100, 0, 0,3, 1/52, 1)
imprimir(gbm.simulated_path)
[107.0025048205179, 104.82320056538235, 102.53591127422398, 100.20213816642244, 102.04283245358256, 97.75115579923988, 95.19613943526382, 96.9876745495834, 97.46055174410736, 103.93032659279226, 107.36331603194304, 108.95104494118915, 112.42823319947456, 109.06981862825943, 109.10124426285238, 114.71465058375804, 120.00234814086286, 116.91730159923688, 118.67452601825876, 117.89233466917202, 118.93541257993591, 124.36106523035058, 121.26088015675688, 120.53641952983601, 113.73881043255554, 114.91724168548876, 112.94192281337791, 113.55773877160591, 107.49491796151044, 108.0715118831013, 113.01893111071472, 110.39204535739405, 108.63917240906524, 105.8520395233433, 116.2907247951675, 114.07340779267213, 111.06821275009212, 109.65530380775077, 105.78971667172465, 97.75385009989282, 97.84501925249452, 101.90695475825825, 106.0493833583297, 105.48266575656817, 106.62375752876223, 112.39829297429974, 111.22855058562658, 109.89796974828265, 112.78068777325248, 117.80550869036715, 118.4680557054793, 114.33258212280838]
Modelo de volatilidade estocástica baseado no artigo de Heston (1993).
de qfin.simulations import StochasticVarianceModel# 100 - preço inicial do ativo subjacente# 0 - desvio do ativo subjacente (mu)# .01 - taxa de juros livre de risco# .05 - dividendo contínuo# 2 - taxa na qual a variância reverte para o longo prazo implícito variância# .25 - variância implícita de longo prazo conforme o tempo tende ao infinito# -.7 - correlação de movimento gerada# .3 - Volatilidade da variância# 1/52 - passos de tempo (dt)# 1 - tempo até o vencimento (ano)svm = StochasticVarianceModel(100, 0, 0,01, 0,05, 2, 0,25, -0,7, 0,3, 0,09, 1/52, 1)
imprimir(svm.simulated_path)
[98.21311553503577, 100.4491317019877, 89.78475515902066, 89.0169762497475, 90.70468848525869, 86.00821802256675, 80.74984494892573, 89.05033807013137, 88.51410029337134, 78.69736798230346, 81.90948751054125, 83.02502248913251, 83.46375102829755, 85.39018282900138, 78.97401642238059, 78.93505221741903, 81.33268688455111, 85.12156706038515, 79.6351983987908, 84.2375291273571, 82.80206517176038, 89.63659376223292, 89.22438477640516, 89.13899271995662, 94.60123239511816, 91.200165507022, 96.0578905115345, 87.45399399599378, 97.908745925816, 97.93068975065052, 103.32091104292813, 110.58066464778392, 105.21520242908348, 99.4655106985056, 106.74882010453683, 112.0058519886151, 110.20930861932342, 105.11835510815085, 113.59852610881678, 107.13315204738092, 108.36549026977205, 113.49809943785571, 122.67910031073885, 137.70966794451425, 146.13877267735612, 132.9973784430374, 129.75750117504984, 128.7467891695649, 127.13115959080305, 130.47967713110302, 129.84273088908265, 129.6411527208744]
A simulação de preços para opções exóticas está disponível sob as premissas associadas aos respectivos processos estocásticos. O movimento browniano geométrico é a base do processo estocástico usado em cada simulação de Monte Carlo. No entanto, caso sejam fornecidos parâmetros adicionais, o processo estocástico apropriado será usado para gerar cada caminho de amostra.
from qfin.simulations import MonteCarloCallfrom qfin.simulations import MonteCarloPut# 100 - preço de exercício# 1000 - número de caminhos de preços simulados# 0,01 - taxa de juros livre de risco# 100 - preço inicial do ativo subjacente# 0 - desvio do ativo subjacente (mu)# .3 - volatilidade do ativo subjacente# 1/52 - intervalos de tempo (dt)# 1 - tempo até o vencimento (ano)call_option = MonteCarloCall(100, 1000, .01, 100, 0, .3, 1/52, 1)# Esses parâmetros adicionais gerarão um preço de Monte Carlo baseado em um processo de volatilidade estocástica# 2 - taxa na qual a variância reverte para o longo implícito variação de execução# 0,25 - variação implícita de longo prazo conforme o tempo tende ao infinito# -0,5 - correlação de movimento gerada# 0,02 - dividendo contínuo# .3 - Volatilidade da variânciaput_option = MonteCarloPut(100, 1000, 0,01, 100, 0, 0,3, 1/52, 1, 2, 0,25, -0,5, 0,02, 0,3)
imprimir(call_option.price)print(put_option.price)
12.73812121792851 23.195814963576286
from qfin.simulations import MonteCarloBinaryCallfrom qfin.simulations import MonteCarloBinaryPut# 100 - preço de exercício# 50 - pagamento da opção binária# 1000 - número de caminhos de preços simulados# .01 - taxa de juros livre de risco# 100 - preço inicial do ativo subjacente# 0 - subjacente desvio de ativos (mu)# .3 - volatilidade do ativo subjacente # 1/52 - intervalos de tempo (dt)# 1 - tempo até o vencimento (ano)binary_call = MonteCarloBinaryCall(100, 50, 1000, 0,01, 100, 0, 0,3, 1/52, 1)binary_put = MonteCarloBinaryPut(100, 50, 1000, 0,01, 100, 0 , 0,3, 1/52, 1)
imprimir(binary_call.price)print(binary_put.price)
22.42462873441866 27.869902820039087
from qfin.simulations import MonteCarloBarrierCallfrom qfin.simulations import MonteCarloBarrierPut# 100 - preço de exercício# 50 - pagamento da opção binária# 1000 - número de caminhos de preços simulados# .01 - taxa de juros livre de risco# 100 - preço inicial do ativo subjacente# 0 - subjacente desvio de ativos (mu)# .3 - volatilidade do ativo subjacente# 1/52 - intervalos de tempo (dt)# 1 - tempo até o vencimento (ano)# Verdadeiro/Falso - A barreira está alta ou baixa# Verdadeiro/Falso - A barreira está dentro ou forabarrier_call = MonteCarloBarrierCall(100, 1000, 150, .01, 100, 0, .3, 1/52, 1 , up=Verdadeiro, saída=Verdadeiro)barrier_put = MonteCarloBarrierCall(100, 1000, 95, 0,01, 100, 0, 0,3, 1/52, 1, up=Falso, out=Falso)
imprimir(binary_call.price)print(binary_put.price)
4.895841997908933 5.565856754630819
from qfin.simulations import MonteCarloAsianCallfrom qfin.simulations import MonteCarloAsianPut# 100 - preço de exercício# 1000 - número de caminhos de preços simulados# 0,01 - taxa de juros livre de risco# 100 - preço inicial do ativo subjacente# 0 - desvio do ativo subjacente (mu)# .3 - volatilidade do ativo subjacente# 1/52 - intervalos de tempo (dt)# 1 - tempo até o vencimento (ano)asian_call = MonteCarloAsianCall(100, 1000, 0,01, 100, 0, 0,3, 1/52, 1)asian_put = MonteCarloAsianPut(100, 1000, 0,01, 100, 0, 0,3, 1/52, 1 )
imprimir (asian_call.price) imprimir (asian_put.price)
6.688201154529573 7.123274528125894
from qfin.simulations import MonteCarloExtendibleCallfrom qfin.simulations import MontecarloExtendiblePut# 100 - preço de exercício# 1000 - número de caminhos de preços simulados# 0,01 - taxa de juros livre de risco# 100 - preço inicial do ativo subjacente# 0 - desvio do ativo subjacente (mu)# .3 - volatilidade do ativo subjacente# 1/52 - intervalos de tempo (dt)# 1 - tempo até o vencimento (annum)# .5 - extensão se estiver sem dinheiro na expiraçãoextendible_call = MonteCarloExtendibleCall(100, 1000, .01, 100, 0, .3, 1/52, 1, .5)extendible_put = MonteCarloExtendiblePut(100, 1000, . 01, 100, 0, 0,3, 1/52, 1, 0,5)
imprimir(extendible_call.price)print(extendible_put.price)
13.60274931789973 13.20330578685724