Skip to content

Commit 90a7511

Browse files
authored
Interpolated yield curve (#81)
1 parent 27929ce commit 90a7511

25 files changed

Lines changed: 556 additions & 137 deletions

app/api/cointegration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ async def cointegration(
3030
fmp: FMPDep,
3131
redis: RedisDep,
3232
frequency: FMP.freq = Query(
33-
FMP.freq.daily,
33+
FMP.freq.DAILY,
3434
description="Price sampling frequency.",
3535
),
3636
) -> CointegrationResponse:

docs/examples/heston_volatility_pricer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
# Price an ATM call option at time to maturity 1.0
1919
price = pricer.price(
20-
option_type=OptionType.call,
20+
option_type=OptionType.CALL,
2121
strike=100.0,
2222
forward=100.0,
2323
ttm=1.0,

docs/examples/wiener_volatility_pricer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
# Price an ATM call option at time to maturity 1.0
1010
price = pricer.price(
11-
option_type=OptionType.call,
11+
option_type=OptionType.CALL,
1212
strike=100.0,
1313
forward=100.0,
1414
ttm=1.0,

quantflow/data/deribit.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ def parse_maturity(v: str) -> datetime:
3131
class InstrumentKind(enum.StrEnum):
3232
"""Instrument kind for Deribit API."""
3333

34-
future = enum.auto()
35-
option = enum.auto()
36-
spot = enum.auto()
37-
future_combo = enum.auto()
38-
option_combo = enum.auto()
34+
FUTURE = enum.auto()
35+
OPTION = enum.auto()
36+
SPOT = enum.auto()
37+
FUTURE_COMBO = enum.auto()
38+
OPTION_COMBO = enum.auto()
3939

4040

4141
@dataclass
@@ -158,18 +158,18 @@ async def volatility_surface_loader(
158158
)
159159
if inverse:
160160
futures = await self.get_book_summary_by_currency(
161-
currency=currency, kind=InstrumentKind.future
161+
currency=currency, kind=InstrumentKind.FUTURE
162162
)
163163
options = await self.get_book_summary_by_currency(
164-
currency=currency, kind=InstrumentKind.option
164+
currency=currency, kind=InstrumentKind.OPTION
165165
)
166166
instruments = await self.get_instruments(currency=currency)
167167
else:
168168
futures = await self.get_book_summary_by_currency(
169-
currency="usdc", kind=InstrumentKind.future, base=currency
169+
currency="usdc", kind=InstrumentKind.FUTURE, base=currency
170170
)
171171
options = await self.get_book_summary_by_currency(
172-
currency="usdc", kind=InstrumentKind.option, base=currency
172+
currency="usdc", kind=InstrumentKind.OPTION, base=currency
173173
)
174174
instruments = await self.get_instruments(currency="usdc", base=currency)
175175
instrument_map = {i["instrument_name"]: i for i in instruments}
@@ -226,9 +226,9 @@ async def volatility_surface_loader(
226226
utc=True,
227227
).to_pydatetime(),
228228
option_type=(
229-
OptionType.call
229+
OptionType.CALL
230230
if meta["option_type"] == "call"
231-
else OptionType.put
231+
else OptionType.PUT
232232
),
233233
bid=round_to_step(bid_, tick_size),
234234
ask=round_to_step(ask_, tick_size),

quantflow/data/fmp.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ class FMP(AioHttpClient):
2525
class freq(StrEnum):
2626
"""FMP historical frequencies"""
2727

28-
one_min = "1min"
29-
five_min = "5min"
30-
fifteen_min = "15min"
31-
thirty_min = "30min"
32-
one_hour = "1hour"
33-
four_hour = "4hour"
34-
daily = "daily"
28+
ONE_MIN = "1min"
29+
FIVE_MIN = "5min"
30+
FIFTEEN_MIN = "15min"
31+
THIRTY_MIN = "30min"
32+
ONE_HOUR = "1hour"
33+
FOUR_HOUR = "4hour"
34+
DAILY = "daily"
3535

3636
@classmethod
3737
def crate(cls, s: str | None) -> Self:
3838
if s is None:
39-
return cls.daily
39+
return cls.DAILY
4040
try:
4141
return cls(s)
4242
except ValueError:
43-
return cls.daily
43+
return cls.DAILY
4444

4545
async def market_risk_premium(self) -> list[dict]:
4646
"""Market risk premium"""
@@ -204,7 +204,7 @@ async def prices(
204204
freq = self.freq.crate(frequency)
205205
path = (
206206
"historical-price-eod/full"
207-
if freq is self.freq.daily
207+
if freq is self.freq.DAILY
208208
else f"historical-chart/{freq}"
209209
)
210210
data = await self.get_path(

quantflow/data/fred.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ class Fred(AioHttpClient):
2222
class freq(StrEnum):
2323
"""Fred historical frequencies"""
2424

25-
d = "d"
26-
w = "w"
27-
bw = "bw"
28-
m = "m"
29-
q = "q"
30-
sa = "sa"
31-
a = "a"
25+
D = "d"
26+
W = "w"
27+
BW = "bw"
28+
M = "m"
29+
Q = "q"
30+
SA = "sa"
31+
A = "a"
3232

3333
async def categiories(self, **kw: Any) -> dict:
3434
"""Get categories"""

quantflow/data/yahoo.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,17 @@ class Yahoo(HttpxClient):
6262
class freq(StrEnum):
6363
"""Yahoo Finance chart intervals"""
6464

65-
one_min = "1m"
66-
two_min = "2m"
67-
five_min = "5m"
68-
fifteen_min = "15m"
69-
thirty_min = "30m"
70-
one_hour = "1h"
71-
one_day = "1d"
72-
five_day = "5d"
73-
one_week = "1wk"
74-
one_month = "1mo"
75-
three_month = "3mo"
65+
ONE_MIN = "1m"
66+
TWO_MIN = "2m"
67+
FIVE_MIN = "5m"
68+
FIFTEEN_MIN = "15m"
69+
THIRTY_MIN = "30m"
70+
ONE_HOUR = "1h"
71+
ONE_DAY = "1d"
72+
FIVE_DAY = "5d"
73+
ONE_WEEK = "1wk"
74+
ONE_MONTH = "1mo"
75+
THREE_MONTH = "3mo"
7676

7777
async def option_chain(
7878
self,
@@ -160,8 +160,8 @@ def loader_from_chain(
160160
.replace(hour=20, tzinfo=timezone.utc)
161161
)
162162
for option_type, contracts in (
163-
(OptionType.call, expiry.get("calls", [])),
164-
(OptionType.put, expiry.get("puts", [])),
163+
(OptionType.CALL, expiry.get("calls", [])),
164+
(OptionType.PUT, expiry.get("puts", [])),
165165
):
166166
for c in contracts:
167167
bid_ = c.get("bid")
@@ -187,7 +187,7 @@ async def prices(
187187
*,
188188
interval: Annotated[
189189
str | freq, Doc("Bar interval — use Yahoo.freq members or a raw string")
190-
] = freq.one_day,
190+
] = freq.ONE_DAY,
191191
from_date: Annotated[date | None, Doc("Start date (inclusive)")] = None,
192192
to_date: Annotated[date | None, Doc("End date (inclusive)")] = None,
193193
range: Annotated[

quantflow/options/inputs.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,25 @@
1818
class Side(enum.StrEnum):
1919
"""Side of the market"""
2020

21-
bid = enum.auto()
22-
ask = enum.auto()
21+
BID = enum.auto()
22+
ASK = enum.auto()
2323

2424

2525
class OptionType(enum.StrEnum):
2626
"""Type of option"""
2727

28-
call = enum.auto()
29-
put = enum.auto()
28+
CALL = enum.auto()
29+
PUT = enum.auto()
3030

3131
def is_call(self) -> bool:
32-
return self is OptionType.call
32+
return self is OptionType.CALL
3333

3434
def is_put(self) -> bool:
35-
return self is OptionType.put
35+
return self is OptionType.PUT
3636

3737
def call_put(self) -> int:
3838
"""Return 1 for call options and -1 for put options"""
39-
return 1 if self is OptionType.call else -1
39+
return 1 if self is OptionType.CALL else -1
4040

4141

4242
class OptionMetadata(BaseModel):
@@ -65,9 +65,9 @@ def is_in_the_money(self, forward: Decimal) -> bool:
6565
class VolSecurityType(enum.StrEnum):
6666
"""Type of security for the volatility surface"""
6767

68-
spot = enum.auto()
69-
forward = enum.auto()
70-
option = enum.auto()
68+
SPOT = enum.auto()
69+
FORWARD = enum.auto()
70+
OPTION = enum.auto()
7171

7272

7373
class VolSurfaceSecurity(BaseModel):
@@ -84,7 +84,7 @@ def forward(cls) -> Self:
8484

8585
class DefaultVolSecurity(VolSurfaceSecurity):
8686
security_type: VolSecurityType = Field(
87-
default=VolSecurityType.spot,
87+
default=VolSecurityType.SPOT,
8888
description="Type of security for the volatility surface",
8989
)
9090

@@ -93,22 +93,22 @@ def vol_surface_type(self) -> VolSecurityType:
9393

9494
@classmethod
9595
def spot(cls) -> Self:
96-
return cls(security_type=VolSecurityType.spot)
96+
return cls(security_type=VolSecurityType.SPOT)
9797

9898
@classmethod
9999
def forward(cls) -> Self:
100-
return cls(security_type=VolSecurityType.forward)
100+
return cls(security_type=VolSecurityType.FORWARD)
101101

102102
@classmethod
103103
def option(cls) -> Self:
104-
return cls(security_type=VolSecurityType.option)
104+
return cls(security_type=VolSecurityType.OPTION)
105105

106106

107107
class SpotInput(PriceVolume):
108108
"""Input data for a spot contract in the volatility surface"""
109109

110110
security_type: VolSecurityType = Field(
111-
default=VolSecurityType.spot,
111+
default=VolSecurityType.SPOT,
112112
description="Type of security for the volatility surface",
113113
)
114114

@@ -118,7 +118,7 @@ class ForwardInput(PriceVolume):
118118

119119
maturity: datetime = Field(description="Expiry date of the forward contract")
120120
security_type: VolSecurityType = Field(
121-
default=VolSecurityType.forward,
121+
default=VolSecurityType.FORWARD,
122122
description="Type of security for the volatility surface",
123123
)
124124

@@ -127,7 +127,7 @@ class OptionInput(PriceVolume, OptionMetadata):
127127
"""Input data for an option in the volatility surface"""
128128

129129
security_type: VolSecurityType = Field(
130-
default=VolSecurityType.option,
130+
default=VolSecurityType.OPTION,
131131
description="Type of security for the volatility surface",
132132
)
133133
iv_bid: DecimalNumber | None = Field(

quantflow/options/pricer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def intrinsic_value(self) -> float:
103103
For a put option, the intrinsic value is non-negative when the moneyness
104104
is positive, i.e. when the strike is above the forward price.
105105
"""
106-
if self.option_type == OptionType.call:
106+
if self.option_type == OptionType.CALL:
107107
return max(0.0, self.parity)
108108
else:
109109
return max(0.0, -self.parity)
@@ -118,7 +118,7 @@ def as_option_type(
118118
"""Convert the option price to the given option type via put-call parity."""
119119
if self.option_type == option_type:
120120
return self
121-
if self.option_type == OptionType.call:
121+
if self.option_type == OptionType.CALL:
122122
new_price = self.price - self.parity
123123
new_delta = self.delta - 1.0
124124
else:
@@ -161,7 +161,7 @@ def price(
161161
log_strike = float((strike_ / forward_).ln())
162162
result = self.pricing.call_greeks(log_strike)
163163
return ModelOptionPrice(
164-
option_type=OptionType.call,
164+
option_type=OptionType.CALL,
165165
strike=strike_,
166166
forward=forward_,
167167
log_strike=log_strike,

quantflow/options/strategies/butterfly.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def _option_type_for_log_strike(mid_log_strike: float) -> OptionType:
1717
1818
Calls for body above ATM, puts for body below ATM, calls at ATM.
1919
"""
20-
return OptionType.put if mid_log_strike < 0 else OptionType.call
20+
return OptionType.PUT if mid_log_strike < 0 else OptionType.CALL
2121

2222

2323
class Butterfly(Strategy, frozen=True):

0 commit comments

Comments
 (0)