Hiram

Hiram is a free financial library built in Python that can be used for option pricing and financial instruments management.

I started to think about this project while I was studying Option Pricing at University Panthéon-Sorbonne. I quickly realised how difficult it could be to improve intuition regarding pricing and greeks. My goal with Hiram is to:

  1. Improve my intuition about options and greeks
  2. Show how easy to use Python is
  3. Show far I could go in the modeling of financial products.

The code below is the first showcase of my library. You can find the Jupyter Notebook on github. Before the creation of that blog post I shared the notebook on LinkedIn.

Table of contents

  1. Option Creation and Pricing
  2. Greeks
  3. Stock Creation
  4. Portfolio Creation
  5. Portfolio Greeks
  6. Delta Hedging of the Portfolio
  7. Market Maker Example
  8. Delta Hedging

1. Option Creation and Pricing

from option import BlackScholes, Way_option
example_call = BlackScholes(way=Way_option.call, S=100, K=105, T=1, r=0.05, sigma=0.3, )
example_call.dict() #Pydantic BaseModel function, makes the output easier to read
# Output
{'S': 100.0,
 'K': 105.0,
 'T': 1.0,
 'r': 0.05,
 'sigma': 0.3,
 'way': <Way_option.call: 'call'>,
 'stock': None,
 'quantity': 1,
 'price': 1,
 'id_': UUID('ad45fecd-e22c-4071-9e28-64799e7fbf78')}

2. Greeks

Delta

Δ=VS{\displaystyle \Delta ={\frac {\partial V}{\partial S}}}

Delta 0.53 or 53%. For 1€ rise (fall) in the spot price the value of the long call position will increase (decrease) by about 0.53€. S (spot) and V (option value) move in the same direction.

example_call.delta()
# Output
0.5338376178017635

Gamma

Γ=ΔS=2VS2\displaystyle \Gamma ={\frac {\partial \Delta }{\partial S}}={\frac {\partial ^{2}V}{\partial S^{2}}}
example_call.gamma()
# Output
0.013141252320879648

Vega

V=ΔS=2VS2\displaystyle \mathcal{V} ={\frac {\partial \Delta }{\partial S}}={\frac {\partial ^{2}V}{\partial S^{2}}}

Vega 0.39, if volatility rises (fall) by 1%, the value of the long call will increase (decrease) by about 0.39€.

example_call.gamma()
# Output
0.013141252320879648

Rho

ρ=Vr{\displaystyle \rho ={\frac {\partial V}{\partial r}}}

Rho 0.44. If interest rates rise (fall) by 1%, the value of the long call position will increase (decrease) by about 0.44€.

example_call.rho()
# Output
0.44143924313138455

Theta

Θ=Vτ{\displaystyle \Theta =-{\frac {\partial V}{\partial \tau }}}

Theta -0.22. Each day, the value of the option will fall by about 0.22€. Negative relationship

example_call.theta()
# Output
-0.02224865687685689

Compute all

example_call.compute_all()
# Output
value: 11.976881462184025, delta: 0.5338376178017635, gamma: 0.013141252320879648,
vega: 0.3942375696263895, rho: 0.44143924313138455, theta: -0.02224865687685689'

3. Stock Creation

from stock import Stock, Way_stock

example_stock = Stock(ticker="AAPL")

print(f"stock ticker:\t{example_stock.ticker}")
print(f"stock price:\t{example_stock.price}")
print(f"stock way:\t{example_stock.way}")
example_stock.hist.tail()
# output
stock ticker:	AAPL
stock price:	191.3300018310547
stock way:	Way_stock.long
|        |            | dividends  | dividends  | dividends  | dividends  | dividends | dividends  | dividends | splits |
|--------|------------|------------|------------|------------|------------|-----------|------------|-----------|--------|
| symbol | date       |            |            |            |            |           |            |           |        |
| AAPL   | 2023-06-28 | 187.929993 | 189.899994 | 187.600006 | 189.250000 | 51216800  | 189.250000 | 0.0       | 0.0    |
|        | 2023-06-29 | 189.080002 | 190.070007 | 188.940002 | 189.589996 | 46347300  | 189.589996 | 0.0       | 0.0    |
|        | 2023-06-30 | 191.630005 | 194.479996 | 191.259995 | 193.970001 | 85069600  | 193.970001 | 0.0       | 0.0    |
|        | 2023-07-03 | 193.779999 | 193.880005 | 191.759995 | 192.460007 | 31458200  | 192.460007 | 0.0       | 0.0    |
|        | 2023-07-05 | 191.570007 | 192.979996 | 190.619995 | 191.330002 | 46920300  | 191.330002 | 0.0       | 0.0    |

As you can see, the output is pretty awful. (don’t hesitate if you know a better way to render dataframes on mdx files)

# Output
stock ticker:	AAPL
stock price:	180.08999633789062
stock way:	Way_stock.long

TABLE TO ADD

Linkage to the call option

example_call.stock = example_stock
# Let's check
example_call.stock.ticker
# Output
'AAPL'
# Modification of S/K
example_call.S = example_stock.price
example_call.K = example_stock.price * 1.25

print(f"Spot:\t{example_call.S}")
print(f"Strike:\t{example_call.K}")
# Output
Spot:	180.08999633789062
Strike:	225.11249542236328
# compute all the greeks
example_call.compute_all()
# Output
value: 10.249865700985907, delta: 0.3183163677151672, gamma: 0.006740312884853831,
vega: 0.6558137079380103, rho: 0.500148738240813, theta: -0.03380260085006635'

4. Portfolio Creation

from portfolio import Portfolio
example_port = Portfolio()
example_port.dict()
# Output
{'name': None,
 'underlyings': {'stocks': {},
  'options': {},
  'bonds': {},
  'portfolios': {},
  'hedge': {}},
 'id_': UUID('60e64398-b5c2-47d1-8a94-4ec1e7053fa3')}

Portfolio functions

There’s no option within our portfolio.

example_port.get_option_book_value()
# Output 0

Let’s add the call

example_port.add_underlying(example_call)

Now we have one option in the portfolio

len(example_port.underlyings["options"])
# Output 1
# compare the ID of the option within the port with example_call
print(example_port.underlyings["options"].keys())
print(example_call.id_)
# Output
dict_keys([UUID('ad45fecd-e22c-4071-9e28-64799e7fbf78')])
ad45fecd-e22c-4071-9e28-64799e7fbf78

5. Portfolio Greeks

print(f"delta:\t {example_port.get_delta()}")
print(f"gamma:\t {example_port.get_gamma()}")
print(f"vega:\t {example_port.get_vega()}")
print(f"rho:\t {example_port.get_rho()}")
print(f"theta:\t {example_port.get_theta()}")
print(f"\ngreeks of the option: {example_call.compute_all()}")
# Output
delta:	 {'AAPL': 0.3183163677151672}
gamma:	 0.006740312884853831
vega:	 0.6558137079380103
rho:	 0.500148738240813
theta:	 -0.03380260085006635

greeks of the option: value: 10.249865700985907, delta: 0.3183163677151672, 
gamma: 0.006740312884853831, vega: 0.6558137079380103, rho: 0.500148738240813,
theta: -0.03380260085006635

6. Delta hedging of the portfolio

To delta hedge we’ll use stocks, on which the vanilla options are written.

# this function will loop through the portfolio and add stocks into the hedge part
example_port.delta_hedge()
# Output
-0.0017675405307795765 AAPL added into the hedging part
# check if a stock has been added into hedge dict
example_port.underlyings["hedge"]
# Output
"{UUID('1d168647-1cf1-400d-b64e-4f6f6f21ca4d'): Stock(way=<Way_stock.long: 'long'>, ticker='AAPL',
"price=180.08999633789062, quantity=-0.0017675405307795765, id_=UUID('1d168647-1cf1-400d-b64e-4f6f6f21ca4d'), hist...}"
# We can also print the delta
example_port.get_delta()
# Output {'AAPL': 0.0}

7. Market Maker Example

Here’s several stocks from the french index CAC40

example_tickers = ["GLE.PA", "BNP.PA", "MC.PA", "CDI.PA"]
stocks_list = []

for ticker in example_tickers:
    temp_stock = Stock(ticker=ticker)
    stocks_list.append(temp_stock)
# import random functions
from random import choice, uniform
ways = [Way_option.call, Way_option.put]
example_port2 = Portfolio()

# let's write and add 100 options in our portfolio
for i in range(0,100):
    temp_stock = choice(stocks_list)
    temp_option = BlackScholes(way=choice(ways),
                      S = uniform(temp_stock.price * 0.5,temp_stock.price * 1.5),
                      K = uniform(temp_stock.price * 0.5,temp_stock.price * 1.5),
                      T = uniform(0.02, 3.0),
                      r = uniform(0.01, 0.15),
                      sigma = uniform(0.1, 0.75),
                      quantity = uniform(1, 2000),
                      price = uniform(10, 150),
                     stock = temp_stock)
    example_port2.add_underlying(temp_option)

We have now our list of stocks. Let’s write 100 vanilla calls/puts randomly, and add these options into the new portfolio

Portfolio informations

print(f"Portfolio option book value:\t{example_port2.get_option_book_value()}")
print(f"Portfolio delta:\t{example_port2.get_delta()}")
# Output
Portfolio option book value:	8559502.004710117
Portfolio delta:	{'MC.PA': 367904.94572213973, 'GLE.PA': 473878.5910277292,
'CDI.PA': 486671.67686180724, 'BNP.PA': 637097.4683161988}

8. Delta hedging

example_port2.delta_hedge()
# Output
-452.0271958303471 MC.PA added into the hedging part
-21908.39618187642 GLE.PA added into the hedging part
-629.1812241264478 CDI.PA added into the hedging part
-11795.917202652367 BNP.PA added into the hedging part
example_port2.get_delta()
# Output
{'MC.PA': 0.0,
 'GLE.PA': 5.820766091346741e-11,
 'CDI.PA': -1.1641532182693481e-10,
 'BNP.PA': -1.1641532182693481e-10}

Well done, portfolio is now delta hedged !