Name | qfinpy JSON |
Version |
0.0.2
JSON |
| download |
home_page | None |
Summary | A powerful, easy-to-use library for Quantitative Finance |
upload_time | 2024-10-08 16:12:30 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.8 |
license | MIT License Copyright (c) 2024 Bhawik Jani Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
keywords |
algorithmic trading
finance
option pricing
options pricing
portfolio optimization
quant
quantitative finance
time series analysis
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# Introduction
QFinPy is a powerful, easy-to-use Python library designed for quantitative finance research, analysis, and modeling. It provides a set of tools for creating options payoff diagrams, pricing derivatives, constructing portfolios, and time series analysis.
# Installation
pip install qfinpy
# Usage and Examples
```python
import qfinpy as qf
import numpy as np
import matplotlib.pyplot as plt
```
## Interest Rate
rate_to_continuous(r, t=1, compounded=1) \
rate_to_compounded(r, t) \
future_value(M, r, T, a=0.0) \
present_value(M, r, T)
A nominal interest rate of 8% per year compounded quarterly --> continuously compounded rate --> effective annual rate (EAR)
```python
r = qf.rate_to_continuous(0.08, t=1, compounded=1/4)
print('continuous rate = ', r)
ear = qf.math.exp(r) - 1
print('effective annual rate = ', ear)
```
continuous rate = 0.07921050918471892
effective annual rate = 0.08243215999999998
Continuously compounded rate --> quarterly rate --> nominal yearly rate
```python
r_quarterly = qf.rate_to_compounded(r, 1/4)
print('3 months rate = ', r_quarterly)
# Nominal annual rate
r_quarterly_nominal = 4 * r_quarterly
print('Nominal annual rate = ', r_quarterly_nominal)
```
3 months rate = 0.020000000000000018
Nominal annual rate = 0.08000000000000007
Present and Future Values: 1000 units invested for a period of 10 years at a continuously compounded rate of 7%. (future_value function also takes an optional argument 'a', which is the continuous deposit rate)
```python
fv = qf.future_value(1000, 0.07, 10)
print('Future value = ', fv)
```
Future value = 2013.7527074704767
```python
pv = qf.present_value(fv, 0.07, 10)
print('Present value = ', pv)
```
Present value = 1000.0
## Options
### Options Payoff Diagrams
C (European Calls), P (European Puts), BC (Binary Calls), and BP (Binary Puts) classes needs to be instantiated using strike price. The S (stock) class doesn't require strike price.
The function options_payoff_diagram takes an optional argument 'u_price' for the current underlying price. u_price is required when S (stock) is included.
European Call with strike 100
```python
qf.options_payoff_diagram(qf.C(100))
```
![png](README_files/README_15_0.png)
European Call with strike 60 and European Put with strike 40, and current underlying price at 50.
```python
folio = qf.C(60) + qf.P(40)
qf.options_payoff_diagram(folio, 50)
```
![png](README_files/README_17_0.png)
4 P(50) short, 4 P(70) long, 6 C(90) long, 2 C(110) short, 4 C(120) short and 1 S() short.
```python
folio = -4*qf.P(50) + 4*qf.P(70) + 6*qf.C(90) - 2*qf.C(110) - 4*qf.C(120) - qf.S()
qf.options_payoff_diagram(folio, u_price=80)
```
![png](README_files/README_19_0.png)
### Black Scholes Oprion Pricing and Greeks
black_scholes_value(type, strike, t, u_price, vol, rf_rate, u_yield=0) \
  type: 'C' (European Calls), 'P' (European Puts), 'BC' (Binary Calls), and 'BP' (Binary Puts) \
  strike: strike/exersise price \
  t: time to exersise \
  u_price: underlying asset price \
  vol: underlying asset volatility \
  rf_rate: riskfree rate of interest \
  u_yield: continuous dividend yield on the asset \
\
black_scholes_delta(type, strike, t, u_price, vol, rf_rate, u_yield=0) \
black_scholes_gamma(type, strike, t, u_price, vol, rf_rate, u_yield=0) \
black_scholes_theta(type, strike, t, u_price, vol, rf_rate, u_yield=0) \
black_scholes_speed(type, strike, t, u_price, vol, rf_rate, u_yield=0) \
black_scholes_vega(type, strike, t, u_price, vol, rf_rate, u_yield=0) \
black_scholes_rho(type, strike, t, u_price, vol, rf_rate, u_yield=0) \
black_scholes_yield_sensitivity(type, strike, t, u_price, vol, rf_rate, u_yield=0)
Example: European Call option with \
strike = 95 \
t = 3/12 \
u_price = 100 \
vol = 0.50 \
rf_rate = 0.01 \
u_yield=0
```python
value = qf.black_scholes_value('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)
delta = qf.black_scholes_delta('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)
gamma = qf.black_scholes_gamma('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)
theta = qf.black_scholes_theta('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)
speed = qf.black_scholes_speed('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)
vega = qf.black_scholes_vega('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)
rho = qf.black_scholes_rho('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)
yield_sensitivity = qf.black_scholes_yield_sensitivity('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)
print('option value = ', value)
print('delta = ', delta)
print('gamma = ', gamma)
print('theta = ', theta)
print('speed = ', speed)
print('vega = ', vega)
print('rho = ', rho)
print('yield_sensitivity = ', yield_sensitivity)
```
option value = 12.527923392521458
delta = 0.633136941899257
gamma = 0.015060599447748629
theta = -19.33360701765983
speed = -0.000355534473275545
vega = 18.825749309685786
rho = 12.69644269935106
yield_sensitivity = -15.828423547481425
### Implied Volatility
implied_volatility(type, deriv_price, strike, t, u_price, rf_rate, u_yield=0, x0=0.1, tol=1.48e-08) \
  type: 'C' (European Calls), 'P' (European Puts), 'BC' (Binary Calls), and 'BP' (Binary Puts) \
  deriv_price: Current market price of the option \
  strike: strike/exersise price \
  t: time to exersise \
  u_price: underlying asset price \
  rf_rate: risk-free rate of interest \
  u_yield: continuous dividend yield on the asset \
  x0: initial guess of implied volatility in the Newton's method \
  tol: tol in the Newton's method
Example: A European call option, with a strike price of 50 expires in 32 days. The risk-free interest rate is 0.05 and the stock is currently trading at 51.25 and the current market price of the option is $2.00. Using a standard Black–Scholes pricing model, the volatility implied by the market price is 0.187
```python
imp_vol = qf.implied_volatility('C', 2.00, 50, 32/365, 51.25, 0.05)
print('Implied volatility = ', imp_vol)
```
Implied volatility = 0.18692284347556545
## Portfolio Optimization
portfolio_optim(m, c, expected_return=None, shortable=None, rf_rate=None, allow_borrow=False, max_leverage=1.0e3) \
  m: Returns of assets \
  c: covariance of assets \
  expected_return: expected returns for the portfolio \
  shortable: list of 0's and 1's were 1's represent the assets that can be shorted \
  rf_rate: risk-free rate \
  allow_borrow: Allow risk-free asset to be borrowed \
  max_leverage: Maximum leverage
```python
m = np.array([0.0890833, 0.213667, 0.234583])
c = np.array([[0.01080754, 0.01240721, 0.01307513],
[0.01240721, 0.05839170, 0.05542639],
[0.01307513, 0.05542639, 0.09422681]])
```
```python
result = qf.portfolio_optim(m, c, expected_return=0.15)
result.x
```
array([0.53009593, 0.35639214, 0.11351199])
## Monte Carlo Simulation
### Random series generation
#### Normal random numbers
normal(*n, mu=np.array([0.0]), sigma=np.array([1.0]), bs=None, dtype=np.float64) \
  n: Number of samples \
  mu: mean - array of shape () or (n,) or bs+(1,) or bs+(n,) \
  sigma: standard deviation - array of shape () or (1) or (n,) or bs+(1,) or bs+(n,) \
  bs: batch size/shape - int or tuple of ints \
  dtype: dtype
```python
x = qf.normal(10)
print(x)
```
[ 0.12502007 -0.14634077 1.94506428 1.38135765 0.75619115 -1.0535261
1.62612142 0.15359853 0.93958341 -1.32247783]
```python
plt.plot(qf.normal(100, mu=10.0, sigma=3.0))
```
[<matplotlib.lines.Line2D at 0x76e02d1d4bc0>]
![png](README_files/README_33_1.png)
```python
plt.plot(qf.normal(mu=np.linspace(0,10,100), sigma=1.0))
```
[<matplotlib.lines.Line2D at 0x76e02cff8950>]
![png](README_files/README_34_1.png)
```python
plt.plot(qf.normal(mu=0, sigma=np.linspace(0,10,100)))
```
[<matplotlib.lines.Line2D at 0x76e02cde72f0>]
![png](README_files/README_35_1.png)
```python
plt.plot(qf.normal(mu=np.linspace(0,10,100), sigma=np.linspace(1,5,100)))
```
[<matplotlib.lines.Line2D at 0x76e02d42f890>]
![png](README_files/README_36_1.png)
```python
x = qf.normal(10, bs=2)
print(x.shape)
print(x)
```
(2, 10)
[[-0.228296 -1.44717506 0.61397438 0.5034225 1.30331253 0.81899568
0.29335272 0.41455905 -0.87034792 -1.24794744]
[ 1.38845671 -1.71477321 -0.57896718 -0.13346501 1.19695654 0.15601694
-0.85700046 0.89089686 -0.86163866 0.37558427]]
```python
x = qf.normal(20, bs=(2,3))
print(x.shape)
```
(2, 3, 20)
#### Multivariate normal random variables
normal_multivariate(*n, mu=np.zeros(2), cov=np.eye(2), bs=None, dtype=np.float64) \
  n: Number of samples \
  mu: mean - array of shape (k) or (k,n) or bs+(k,1) or bs+(k,n) \
  cov: covariance - array of shape (k,k) or (k,k,n) or bs+(k,k,1) or bs+(k,k,n) \
  bs: batch size/shape - int or tuple of ints \
  dtype: dtype
```python
x = qf.normal_multivariate(10, mu=np.ones(2), cov=np.eye(2))
print(x.shape)
print(x)
```
(2, 10)
[[ 0.27708532 1.37296767 1.23605607 2.20384309 0.27086975 2.48326163
0.24278957 1.14429597 0.44646873 0.9791976 ]
[ 0.45751257 2.1814746 -1.31716061 1.59821137 1.16358675 0.56363219
2.0968775 0.16555374 2.46605888 0.73515972]]
```python
x = qf.normal_multivariate(mu=np.stack((np.linspace(0,10,100), np.linspace(0,5,100))), cov=[[1,0.5],[0.5,2]])
plt.plot(x[0])
plt.plot(x[1])
plt.show()
```
![png](README_files/README_41_0.png)
```python
x = qf.normal_multivariate(10, mu=np.ones(2), cov=np.eye(2), bs=(5,7))
print(x.shape)
```
(5, 7, 2, 10)
#### Lognormal (=exp(normal))
```python
x = qf.lognormal(10)
print(x)
```
[2.26366853 2.60529974 1.35796926 1.85062364 2.29085821 5.42070832
1.75876349 1.16463658 0.33037263 0.92489459]
```python
x = qf.lognormal_multivariate(10, mu=np.ones(2), cov=np.eye(2), bs=(5,7))
print(x.shape)
```
(5, 7, 2, 10)
### Random Walk
#### Additive Random Walk
random_walk(series, x0=0.0) \
  series: random step size \
  x0: starting point
```python
ret = qf.normal(100)
x = qf.random_walk(ret, x0=0.0)
plt.plot(x)
```
[<matplotlib.lines.Line2D at 0x76e02c9f9190>]
![png](README_files/README_48_1.png)
#### Geometric Random Walk
random_walk_geometric(series, x0=1.0)
  series: random returns \
  x0: starting point
```python
ret = qf.normal(100, mu=0.005, sigma=0.05)
x = qf.random_walk_geometric(ret, x0=1.0)
plt.plot(x)
```
[<matplotlib.lines.Line2D at 0x76e02c96bef0>]
![png](README_files/README_50_1.png)
### Monte Carlo Option Pricing
```python
strike = 95
t = 3/12
u_price = 100
vol = 0.50
rf_rate = 0.01
```
```python
n=1000
bs=10000
mu = rf_rate*t/n
sigma = vol*(t/n)**0.5
ret = qf.normal(n, mu=mu, sigma=sigma, bs=bs)
sim = qf.random_walk_geometric(ret, x0=u_price)
print(sim.shape)
```
(10000, 1001)
```python
plt.plot(sim[0])
```
[<matplotlib.lines.Line2D at 0x76e02c374c20>]
![png](README_files/README_54_1.png)
```python
value = qf.present_value(np.maximum(0, sim[:,-1] - strike).mean(), rf_rate, t)
print(value)
```
12.51337611387072
Since intermediate values of geometric random walk are not required for option value calculation, we can use lognormal distribution to save time and memory. In this case standard deviations of both log returns and normal returns are same, but (the mean of log returns) = (mean of normal returns) - (variance of returns)/2
```python
n=1
bs=1000000
sigma = vol*(t**0.5)
mu = rf_rate*t - (sigma**2)/2
sim = u_price * qf.lognormal(n, mu=mu, sigma=sigma, bs=bs)
print(sim.shape)
```
(1000000, 1)
```python
value = qf.present_value(np.maximum(0, sim - strike).mean(), rf_rate, t)
print('option value = ', value)
```
option value = 12.491332565313673
## Time Series Analysis
```python
from qfinpy import tsa
```
### Moving Average MA(q)
ma(series, theta, mu=0.0, e0=None)
```python
e = qf.normal(150, bs=5)
theta = [0.6, 0.2, 0.1]
w = tsa.ma(e, theta, mu=0.0)
print(e.shape)
print(w.shape)
```
(5, 150)
(5, 147)
```python
plt.plot(e[0])
```
[<matplotlib.lines.Line2D at 0x76e02c654680>]
![png](README_files/README_63_1.png)
```python
plt.plot(w[0])
```
[<matplotlib.lines.Line2D at 0x76e02c4d8ad0>]
![png](README_files/README_64_1.png)
```python
e_m = qf.normal_multivariate(150, mu=np.zeros(2), cov=np.eye(2))
theta_m = [[[0.3,0.1],[0.1,0.3]], [[0.2,0.1],[0.1,0.2]], [[0.1,0.1],[0.1,0.1]]]
w_m = tsa.ma(e_m, theta_m)
print(e_m.shape)
print(w_m.shape)
```
(2, 150)
(2, 147)
### Autoregrassive AR(p)
ar(series, phi, mu=0.0, x0=None)
```python
phi = [0.4, 0.2]
x = tsa.ar(w, phi, mu=0.0)
print(x.shape)
```
(5, 147)
```python
plt.plot(x[0])
```
[<matplotlib.lines.Line2D at 0x76e024a593a0>]
![png](README_files/README_68_1.png)
```python
phi_m = [[[0.4, 0.1],[0.1,0.4]], [[0.2, 0.1],[0.1,0.2]]]
x_m = tsa.ar(w_m, phi_m)
print(x_m.shape)
```
(2, 147)
### Inverse MA and AR
ma_inverse(series, theta, mu=0.0) \
ar_inverse(series, phi, mu=0.0)
```python
inverse_x = tsa.ar_inverse(x, phi)
print(inverse_x.shape)
```
(5, 147)
```python
plt.plot(w[0])
plt.plot(inverse_x[0])
plt.show()
```
![png](README_files/README_72_0.png)
```python
inverse_w = tsa.ma_inverse(w, theta)
print(inverse_w.shape)
```
(5, 147)
```python
plt.plot(e[0][-147:])
plt.plot(inverse_w[0])
plt.show()
```
![png](README_files/README_74_0.png)
#### Other Tools
sliding_window(a, window) \
normal_cdf(x, mu=0.0, sigma=1.0) \
normal_pdf(x, mu=0.0, sigma=1.0)
```python
x = qf.normal(10)
x
```
array([-1.81506319, -0.06177757, 0.81406117, -0.13047454, -0.08597478,
-0.18929597, 0.84590606, 0.92444569, 0.88397027, -0.39034777])
```python
qf.sliding_window(x, 4)
```
array([[-1.81506319, -0.06177757, 0.81406117, -0.13047454],
[-0.06177757, 0.81406117, -0.13047454, -0.08597478],
[ 0.81406117, -0.13047454, -0.08597478, -0.18929597],
[-0.13047454, -0.08597478, -0.18929597, 0.84590606],
[-0.08597478, -0.18929597, 0.84590606, 0.92444569],
[-0.18929597, 0.84590606, 0.92444569, 0.88397027],
[ 0.84590606, 0.92444569, 0.88397027, -0.39034777]])
```python
qf.normal_cdf(0, mu=0.0, sigma=1.0)
```
0.5
```python
qf.normal_pdf(0, mu=0.0, sigma=1.0)
```
0.3989422804014327
```python
```
Raw data
{
"_id": null,
"home_page": null,
"name": "qfinpy",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "Algorithmic Trading, Finance, Option Pricing, Options Pricing, Portfolio Optimization, Quant, Quantitative Finance, Time Series Analysis",
"author": null,
"author_email": "Bhawik Jani <bhawikjani1@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/f6/72/6077d64c046f8079c5865a9a6c884a3483089da39da9d0499f34792705d6/qfinpy-0.0.2.tar.gz",
"platform": null,
"description": "# Introduction\nQFinPy is a powerful, easy-to-use Python library designed for quantitative finance research, analysis, and modeling. It provides a set of tools for creating options payoff diagrams, pricing derivatives, constructing portfolios, and time series analysis.\n\n# Installation\npip install qfinpy\n\n# Usage and Examples\n\n\n```python\nimport qfinpy as qf\nimport numpy as np\nimport matplotlib.pyplot as plt\n```\n\n## Interest Rate\nrate_to_continuous(r, t=1, compounded=1) \\\nrate_to_compounded(r, t) \\\nfuture_value(M, r, T, a=0.0) \\\npresent_value(M, r, T) \n\nA nominal interest rate of 8% per year compounded quarterly --> continuously compounded rate --> effective annual rate (EAR)\n\n\n```python\nr = qf.rate_to_continuous(0.08, t=1, compounded=1/4)\nprint('continuous rate = ', r)\near = qf.math.exp(r) - 1\nprint('effective annual rate = ', ear)\n```\n\n continuous rate = 0.07921050918471892\n effective annual rate = 0.08243215999999998\n\n\nContinuously compounded rate --> quarterly rate --> nominal yearly rate\n\n\n```python\nr_quarterly = qf.rate_to_compounded(r, 1/4)\nprint('3 months rate = ', r_quarterly)\n# Nominal annual rate\nr_quarterly_nominal = 4 * r_quarterly\nprint('Nominal annual rate = ', r_quarterly_nominal)\n```\n\n 3 months rate = 0.020000000000000018\n Nominal annual rate = 0.08000000000000007\n\n\nPresent and Future Values: 1000 units invested for a period of 10 years at a continuously compounded rate of 7%. (future_value function also takes an optional argument 'a', which is the continuous deposit rate)\n\n\n```python\nfv = qf.future_value(1000, 0.07, 10)\nprint('Future value = ', fv)\n```\n\n Future value = 2013.7527074704767\n\n\n\n```python\npv = qf.present_value(fv, 0.07, 10)\nprint('Present value = ', pv)\n```\n\n Present value = 1000.0\n\n\n## Options\n\n### Options Payoff Diagrams\nC (European Calls), P (European Puts), BC (Binary Calls), and BP (Binary Puts) classes needs to be instantiated using strike price. The S (stock) class doesn't require strike price.\nThe function options_payoff_diagram takes an optional argument 'u_price' for the current underlying price. u_price is required when S (stock) is included.\n\nEuropean Call with strike 100\n\n\n```python\nqf.options_payoff_diagram(qf.C(100))\n```\n\n\n \n![png](README_files/README_15_0.png)\n \n\n\nEuropean Call with strike 60 and European Put with strike 40, and current underlying price at 50.\n\n\n```python\nfolio = qf.C(60) + qf.P(40)\nqf.options_payoff_diagram(folio, 50)\n```\n\n\n \n![png](README_files/README_17_0.png)\n \n\n\n4 P(50) short, 4 P(70) long, 6 C(90) long, 2 C(110) short, 4 C(120) short and 1 S() short.\n\n\n```python\nfolio = -4*qf.P(50) + 4*qf.P(70) + 6*qf.C(90) - 2*qf.C(110) - 4*qf.C(120) - qf.S()\nqf.options_payoff_diagram(folio, u_price=80)\n```\n\n\n \n![png](README_files/README_19_0.png)\n \n\n\n### Black Scholes Oprion Pricing and Greeks\nblack_scholes_value(type, strike, t, u_price, vol, rf_rate, u_yield=0) \\\n  type: 'C' (European Calls), 'P' (European Puts), 'BC' (Binary Calls), and 'BP' (Binary Puts) \\\n  strike: strike/exersise price \\\n  t: time to exersise \\\n  u_price: underlying asset price \\\n  vol: underlying asset volatility \\\n  rf_rate: riskfree rate of interest \\\n  u_yield: continuous dividend yield on the asset \\\n\\\nblack_scholes_delta(type, strike, t, u_price, vol, rf_rate, u_yield=0) \\\nblack_scholes_gamma(type, strike, t, u_price, vol, rf_rate, u_yield=0) \\\nblack_scholes_theta(type, strike, t, u_price, vol, rf_rate, u_yield=0) \\\nblack_scholes_speed(type, strike, t, u_price, vol, rf_rate, u_yield=0) \\\nblack_scholes_vega(type, strike, t, u_price, vol, rf_rate, u_yield=0) \\\nblack_scholes_rho(type, strike, t, u_price, vol, rf_rate, u_yield=0) \\\nblack_scholes_yield_sensitivity(type, strike, t, u_price, vol, rf_rate, u_yield=0)\n\nExample: European Call option with \\\nstrike = 95 \\\nt = 3/12 \\\nu_price = 100 \\\nvol = 0.50 \\\nrf_rate = 0.01 \\\nu_yield=0 \n\n\n```python\nvalue = qf.black_scholes_value('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)\ndelta = qf.black_scholes_delta('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)\ngamma = qf.black_scholes_gamma('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)\ntheta = qf.black_scholes_theta('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)\nspeed = qf.black_scholes_speed('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)\nvega = qf.black_scholes_vega('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)\nrho = qf.black_scholes_rho('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)\nyield_sensitivity = qf.black_scholes_yield_sensitivity('C', 95, 3/12, 100, 0.50, 0.01, u_yield=0)\nprint('option value = ', value)\nprint('delta = ', delta)\nprint('gamma = ', gamma)\nprint('theta = ', theta)\nprint('speed = ', speed)\nprint('vega = ', vega)\nprint('rho = ', rho)\nprint('yield_sensitivity = ', yield_sensitivity)\n```\n\n option value = 12.527923392521458\n delta = 0.633136941899257\n gamma = 0.015060599447748629\n theta = -19.33360701765983\n speed = -0.000355534473275545\n vega = 18.825749309685786\n rho = 12.69644269935106\n yield_sensitivity = -15.828423547481425\n\n\n### Implied Volatility\nimplied_volatility(type, deriv_price, strike, t, u_price, rf_rate, u_yield=0, x0=0.1, tol=1.48e-08) \\\n  type: 'C' (European Calls), 'P' (European Puts), 'BC' (Binary Calls), and 'BP' (Binary Puts) \\\n  deriv_price: Current market price of the option \\\n  strike: strike/exersise price \\\n  t: time to exersise \\\n  u_price: underlying asset price \\\n  rf_rate: risk-free rate of interest \\\n  u_yield: continuous dividend yield on the asset \\\n  x0: initial guess of implied volatility in the Newton's method \\\n  tol: tol in the Newton's method \n\nExample: A European call option, with a strike price of 50 expires in 32 days. The risk-free interest rate is 0.05 and the stock is currently trading at 51.25 and the current market price of the option is $2.00. Using a standard Black\u2013Scholes pricing model, the volatility implied by the market price is 0.187\n\n\n```python\nimp_vol = qf.implied_volatility('C', 2.00, 50, 32/365, 51.25, 0.05)\nprint('Implied volatility = ', imp_vol)\n```\n\n Implied volatility = 0.18692284347556545\n\n\n## Portfolio Optimization\n\nportfolio_optim(m, c, expected_return=None, shortable=None, rf_rate=None, allow_borrow=False, max_leverage=1.0e3) \\\n  m: Returns of assets \\\n  c: covariance of assets \\\n  expected_return: expected returns for the portfolio \\\n  shortable: list of 0's and 1's were 1's represent the assets that can be shorted \\\n  rf_rate: risk-free rate \\\n  allow_borrow: Allow risk-free asset to be borrowed \\\n  max_leverage: Maximum leverage\n\n\n```python\nm = np.array([0.0890833, 0.213667, 0.234583])\nc = np.array([[0.01080754, 0.01240721, 0.01307513],\n [0.01240721, 0.05839170, 0.05542639],\n [0.01307513, 0.05542639, 0.09422681]])\n```\n\n\n```python\nresult = qf.portfolio_optim(m, c, expected_return=0.15)\nresult.x\n```\n\n\n\n\n array([0.53009593, 0.35639214, 0.11351199])\n\n\n\n## Monte Carlo Simulation\n\n### Random series generation\n\n#### Normal random numbers\nnormal(*n, mu=np.array([0.0]), sigma=np.array([1.0]), bs=None, dtype=np.float64) \\\n  n: Number of samples \\\n  mu: mean - array of shape () or (n,) or bs+(1,) or bs+(n,) \\\n  sigma: standard deviation - array of shape () or (1) or (n,) or bs+(1,) or bs+(n,) \\\n  bs: batch size/shape - int or tuple of ints \\\n  dtype: dtype\n\n\n```python\nx = qf.normal(10)\nprint(x)\n```\n\n [ 0.12502007 -0.14634077 1.94506428 1.38135765 0.75619115 -1.0535261\n 1.62612142 0.15359853 0.93958341 -1.32247783]\n\n\n\n```python\nplt.plot(qf.normal(100, mu=10.0, sigma=3.0))\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02d1d4bc0>]\n\n\n\n\n \n![png](README_files/README_33_1.png)\n \n\n\n\n```python\nplt.plot(qf.normal(mu=np.linspace(0,10,100), sigma=1.0))\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02cff8950>]\n\n\n\n\n \n![png](README_files/README_34_1.png)\n \n\n\n\n```python\nplt.plot(qf.normal(mu=0, sigma=np.linspace(0,10,100)))\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02cde72f0>]\n\n\n\n\n \n![png](README_files/README_35_1.png)\n \n\n\n\n```python\nplt.plot(qf.normal(mu=np.linspace(0,10,100), sigma=np.linspace(1,5,100)))\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02d42f890>]\n\n\n\n\n \n![png](README_files/README_36_1.png)\n \n\n\n\n```python\nx = qf.normal(10, bs=2)\nprint(x.shape)\nprint(x)\n```\n\n (2, 10)\n [[-0.228296 -1.44717506 0.61397438 0.5034225 1.30331253 0.81899568\n 0.29335272 0.41455905 -0.87034792 -1.24794744]\n [ 1.38845671 -1.71477321 -0.57896718 -0.13346501 1.19695654 0.15601694\n -0.85700046 0.89089686 -0.86163866 0.37558427]]\n\n\n\n```python\nx = qf.normal(20, bs=(2,3))\nprint(x.shape)\n```\n\n (2, 3, 20)\n\n\n#### Multivariate normal random variables\nnormal_multivariate(*n, mu=np.zeros(2), cov=np.eye(2), bs=None, dtype=np.float64) \\\n  n: Number of samples \\\n  mu: mean - array of shape (k) or (k,n) or bs+(k,1) or bs+(k,n) \\\n  cov: covariance - array of shape (k,k) or (k,k,n) or bs+(k,k,1) or bs+(k,k,n) \\\n  bs: batch size/shape - int or tuple of ints \\\n  dtype: dtype\n\n\n```python\nx = qf.normal_multivariate(10, mu=np.ones(2), cov=np.eye(2))\nprint(x.shape)\nprint(x)\n```\n\n (2, 10)\n [[ 0.27708532 1.37296767 1.23605607 2.20384309 0.27086975 2.48326163\n 0.24278957 1.14429597 0.44646873 0.9791976 ]\n [ 0.45751257 2.1814746 -1.31716061 1.59821137 1.16358675 0.56363219\n 2.0968775 0.16555374 2.46605888 0.73515972]]\n\n\n\n```python\nx = qf.normal_multivariate(mu=np.stack((np.linspace(0,10,100), np.linspace(0,5,100))), cov=[[1,0.5],[0.5,2]])\nplt.plot(x[0])\nplt.plot(x[1])\nplt.show()\n```\n\n\n \n![png](README_files/README_41_0.png)\n \n\n\n\n```python\nx = qf.normal_multivariate(10, mu=np.ones(2), cov=np.eye(2), bs=(5,7))\nprint(x.shape)\n```\n\n (5, 7, 2, 10)\n\n\n#### Lognormal (=exp(normal))\n\n\n```python\nx = qf.lognormal(10)\nprint(x)\n```\n\n [2.26366853 2.60529974 1.35796926 1.85062364 2.29085821 5.42070832\n 1.75876349 1.16463658 0.33037263 0.92489459]\n\n\n\n```python\nx = qf.lognormal_multivariate(10, mu=np.ones(2), cov=np.eye(2), bs=(5,7))\nprint(x.shape)\n```\n\n (5, 7, 2, 10)\n\n\n### Random Walk\n\n#### Additive Random Walk\nrandom_walk(series, x0=0.0) \\\n  series: random step size \\\n  x0: starting point\n\n\n```python\nret = qf.normal(100)\nx = qf.random_walk(ret, x0=0.0)\nplt.plot(x)\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02c9f9190>]\n\n\n\n\n \n![png](README_files/README_48_1.png)\n \n\n\n#### Geometric Random Walk\nrandom_walk_geometric(series, x0=1.0)\n  series: random returns \\\n  x0: starting point\n\n\n```python\nret = qf.normal(100, mu=0.005, sigma=0.05)\nx = qf.random_walk_geometric(ret, x0=1.0)\nplt.plot(x)\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02c96bef0>]\n\n\n\n\n \n![png](README_files/README_50_1.png)\n \n\n\n### Monte Carlo Option Pricing\n\n\n```python\nstrike = 95\nt = 3/12\nu_price = 100\nvol = 0.50\nrf_rate = 0.01\n```\n\n\n```python\nn=1000\nbs=10000\nmu = rf_rate*t/n\nsigma = vol*(t/n)**0.5\nret = qf.normal(n, mu=mu, sigma=sigma, bs=bs)\nsim = qf.random_walk_geometric(ret, x0=u_price)\nprint(sim.shape)\n```\n\n (10000, 1001)\n\n\n\n```python\nplt.plot(sim[0])\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02c374c20>]\n\n\n\n\n \n![png](README_files/README_54_1.png)\n \n\n\n\n```python\nvalue = qf.present_value(np.maximum(0, sim[:,-1] - strike).mean(), rf_rate, t)\nprint(value)\n```\n\n 12.51337611387072\n\n\nSince intermediate values of geometric random walk are not required for option value calculation, we can use lognormal distribution to save time and memory. In this case standard deviations of both log returns and normal returns are same, but (the mean of log returns) = (mean of normal returns) - (variance of returns)/2\n\n\n```python\nn=1\nbs=1000000\nsigma = vol*(t**0.5)\nmu = rf_rate*t - (sigma**2)/2\nsim = u_price * qf.lognormal(n, mu=mu, sigma=sigma, bs=bs)\nprint(sim.shape)\n```\n\n (1000000, 1)\n\n\n\n```python\nvalue = qf.present_value(np.maximum(0, sim - strike).mean(), rf_rate, t)\nprint('option value = ', value)\n```\n\n option value = 12.491332565313673\n\n\n## Time Series Analysis\n\n\n```python\nfrom qfinpy import tsa\n```\n\n### Moving Average MA(q)\nma(series, theta, mu=0.0, e0=None)\n\n\n```python\ne = qf.normal(150, bs=5)\ntheta = [0.6, 0.2, 0.1]\nw = tsa.ma(e, theta, mu=0.0)\nprint(e.shape)\nprint(w.shape)\n```\n\n (5, 150)\n (5, 147)\n\n\n\n```python\nplt.plot(e[0])\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02c654680>]\n\n\n\n\n \n![png](README_files/README_63_1.png)\n \n\n\n\n```python\nplt.plot(w[0])\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e02c4d8ad0>]\n\n\n\n\n \n![png](README_files/README_64_1.png)\n \n\n\n\n```python\ne_m = qf.normal_multivariate(150, mu=np.zeros(2), cov=np.eye(2))\ntheta_m = [[[0.3,0.1],[0.1,0.3]], [[0.2,0.1],[0.1,0.2]], [[0.1,0.1],[0.1,0.1]]]\nw_m = tsa.ma(e_m, theta_m)\nprint(e_m.shape)\nprint(w_m.shape)\n```\n\n (2, 150)\n (2, 147)\n\n\n### Autoregrassive AR(p)\nar(series, phi, mu=0.0, x0=None)\n\n\n```python\nphi = [0.4, 0.2]\nx = tsa.ar(w, phi, mu=0.0)\nprint(x.shape)\n```\n\n (5, 147)\n\n\n\n```python\nplt.plot(x[0])\n```\n\n\n\n\n [<matplotlib.lines.Line2D at 0x76e024a593a0>]\n\n\n\n\n \n![png](README_files/README_68_1.png)\n \n\n\n\n```python\nphi_m = [[[0.4, 0.1],[0.1,0.4]], [[0.2, 0.1],[0.1,0.2]]]\nx_m = tsa.ar(w_m, phi_m)\nprint(x_m.shape)\n```\n\n (2, 147)\n\n\n### Inverse MA and AR\nma_inverse(series, theta, mu=0.0) \\\nar_inverse(series, phi, mu=0.0)\n\n\n```python\ninverse_x = tsa.ar_inverse(x, phi)\nprint(inverse_x.shape)\n```\n\n (5, 147)\n\n\n\n```python\nplt.plot(w[0])\nplt.plot(inverse_x[0])\nplt.show()\n```\n\n\n \n![png](README_files/README_72_0.png)\n \n\n\n\n```python\ninverse_w = tsa.ma_inverse(w, theta)\nprint(inverse_w.shape)\n```\n\n (5, 147)\n\n\n\n```python\nplt.plot(e[0][-147:])\nplt.plot(inverse_w[0])\nplt.show()\n```\n\n\n \n![png](README_files/README_74_0.png)\n \n\n\n#### Other Tools\nsliding_window(a, window) \\\nnormal_cdf(x, mu=0.0, sigma=1.0) \\\nnormal_pdf(x, mu=0.0, sigma=1.0) \n\n\n```python\nx = qf.normal(10)\nx\n```\n\n\n\n\n array([-1.81506319, -0.06177757, 0.81406117, -0.13047454, -0.08597478,\n -0.18929597, 0.84590606, 0.92444569, 0.88397027, -0.39034777])\n\n\n\n\n```python\nqf.sliding_window(x, 4)\n```\n\n\n\n\n array([[-1.81506319, -0.06177757, 0.81406117, -0.13047454],\n [-0.06177757, 0.81406117, -0.13047454, -0.08597478],\n [ 0.81406117, -0.13047454, -0.08597478, -0.18929597],\n [-0.13047454, -0.08597478, -0.18929597, 0.84590606],\n [-0.08597478, -0.18929597, 0.84590606, 0.92444569],\n [-0.18929597, 0.84590606, 0.92444569, 0.88397027],\n [ 0.84590606, 0.92444569, 0.88397027, -0.39034777]])\n\n\n\n\n```python\nqf.normal_cdf(0, mu=0.0, sigma=1.0)\n```\n\n\n\n\n 0.5\n\n\n\n\n```python\nqf.normal_pdf(0, mu=0.0, sigma=1.0)\n```\n\n\n\n\n 0.3989422804014327\n\n\n\n\n```python\n\n```\n",
"bugtrack_url": null,
"license": "MIT License Copyright (c) 2024 Bhawik Jani Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"summary": "A powerful, easy-to-use library for Quantitative Finance",
"version": "0.0.2",
"project_urls": {
"Homepage": "https://github.com/bhawik-jani/qfinpy"
},
"split_keywords": [
"algorithmic trading",
" finance",
" option pricing",
" options pricing",
" portfolio optimization",
" quant",
" quantitative finance",
" time series analysis"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0bc07738e46fc065d488553d1c5a7ba9e8cf1e9a9613a3c1a4d163a9f8b0599c",
"md5": "a5e5a23d6a441f121b2431dfb42797f0",
"sha256": "faa2413ca3d1d643a8cca152f1d07874049526466adad70c229c8c05d6b71e5b"
},
"downloads": -1,
"filename": "qfinpy-0.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "a5e5a23d6a441f121b2431dfb42797f0",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 12147,
"upload_time": "2024-10-08T16:12:26",
"upload_time_iso_8601": "2024-10-08T16:12:26.383313Z",
"url": "https://files.pythonhosted.org/packages/0b/c0/7738e46fc065d488553d1c5a7ba9e8cf1e9a9613a3c1a4d163a9f8b0599c/qfinpy-0.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f6726077d64c046f8079c5865a9a6c884a3483089da39da9d0499f34792705d6",
"md5": "763b654a8755b8b50274c5a55b9330b3",
"sha256": "40e19ca90fe84e1a752fb35ee6f6ac8294cc036847fc16848debc41a27fbbf28"
},
"downloads": -1,
"filename": "qfinpy-0.0.2.tar.gz",
"has_sig": false,
"md5_digest": "763b654a8755b8b50274c5a55b9330b3",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 565807,
"upload_time": "2024-10-08T16:12:30",
"upload_time_iso_8601": "2024-10-08T16:12:30.525574Z",
"url": "https://files.pythonhosted.org/packages/f6/72/6077d64c046f8079c5865a9a6c884a3483089da39da9d0499f34792705d6/qfinpy-0.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-08 16:12:30",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "bhawik-jani",
"github_project": "qfinpy",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "qfinpy"
}