Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions examples/appl_PDF_set_exmaple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from oipd import RND, MarketInputs, ModelParams , RNDResultSet
import matplotlib.pyplot as plt
from datetime import date


ticker_ = "AAPL"

# 3 INPUTS:
# 1. market parameters
# 2. model parameters
# 3. column mapping

market = MarketInputs(
valuation_date=date.today(),
expiry_date=date(2026, 3, 20),
risk_free_rate=0.04199, # US 3-month nominal Treasury yield
)

# estimate RND Set
est_appl = RNDResultSet.set_from_ticker(ticker_,market)



est_appl.plot()

plt.show()
3 changes: 2 additions & 1 deletion oipd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

# Optional: explicitly re-export vendor-specific errors later if needed

from oipd.estimator import RND, ModelParams, RNDResult
from oipd.estimator import RND, ModelParams, RNDResult , RNDResultSet
from oipd.market_inputs import (
MarketInputs,
VendorSnapshot,
Expand Down Expand Up @@ -42,4 +42,5 @@
"FillMode", # Fill mode literal type
"ModelParams",
"RNDResult",
"RNDResultSet",
]
113 changes: 113 additions & 0 deletions oipd/estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1383,3 +1383,116 @@ def iv_smile(
along with observed bid/ask implied volatilities when available.
"""
return self.result.iv_smile(strikes, num_points=num_points)


from datetime import date


class RNDResultSet:
def __init__(self, rnd_list: list[tuple[RNDResult , date]] | None = None):
if rnd_list is None:
self.RND_list = []
else:
self.RND_list = rnd_list

@classmethod
def set_from_ticker(
cls,
ticker: str,
market: MarketInputs,
*,
model: Optional[ModelParams] = None,
vendor: str = "yfinance",
fill: FillMode = "missing",
echo: Optional[bool] = None,
verbose: bool = True,
cache_enabled: bool = True,
cache_ttl_minutes: int = 15,
)->RNDResultSet:
"""
Generate a Set of RND for every available expiry date
"""
expiry_dates = RND.list_expiry_dates(ticker)

RND_list = []
from dataclasses import replace


for e_date in expiry_dates:

expiry = date.fromisoformat(e_date.strip())

if expiry <= date.today():
continue

market = replace(market, expiry_date= expiry)

RND_entity = RND.from_ticker(
ticker,
market,
model=model,
vendor=vendor,
fill=fill,
echo=echo,
verbose=verbose,
cache_enabled=cache_enabled,
cache_ttl_minutes=cache_ttl_minutes,
)

RND_date_tuple = (RND_entity,expiry)

RND_list.append(RND_date_tuple)

result_set = RNDResultSet(RND_list)

return result_set


def plot(self):
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

x_points = []
y_points = []
z_points = []

# Store max PDF points per date
max_pdf_dates = []
max_pdf_prices = []
max_pdf_values = []

lowest_date = mdates.date2num(date.today())

for data in self.RND_list:

date_cord = mdates.date2num(data[1]) - lowest_date

date_repeated = np.full_like(data[0].pdf, date_cord)

x_points.extend(date_repeated)
y_points.extend(data[0].prices)
z_points.extend(data[0].pdf)

# Find max PDF for this date
max_idx = np.argmax(data[0].pdf)
max_pdf_dates.append(date_cord)
max_pdf_prices.append(data[0].prices[max_idx])
max_pdf_values.append(data[0].pdf[max_idx])

# 3D scatter
scatter = ax.scatter(x_points, y_points, z_points, c=x_points, cmap='viridis', marker='o')

# Draw line connecting max PDF points
ax.plot(max_pdf_dates, max_pdf_prices, max_pdf_values, color='red', linewidth=2, label='Max PDF per date')

ax.set_xlabel('Date(days)')
ax.set_ylabel('Price')
ax.set_zlabel('Density')
ax.set_title('Ticker Date')

ax.legend()
plt.tight_layout()