major refactor

all the logic now in the max_pain script
max_pain_deribit
Nelson Torres 2024-12-07 10:17:27 -03:00
parent 3e613ab2a0
commit 0563b916a3
2 changed files with 91 additions and 52 deletions

View File

@ -1,13 +1,22 @@
#!/usr/bin/env python
from decimal import (
Decimal,
)
import trio
import tractor
from pprint import pformat
from piker.brokers.deribit.api import (
get_client,
maybe_open_oi_feed,
)
async def max_pain_daemon(
) -> None:
expiry_date: str = '13DEC24'
instruments: list[Symbol] = []
oi_by_strikes: dict[str, dict[str, Decimal]]
def check_if_complete(
oi: dict[str, dict[str, Decimal | None]],
@ -22,6 +31,81 @@ async def max_pain_daemon(
return True
def get_max_pain(
oi_by_strikes: dict[str, dict[str, Decimal]]
) -> dict[str, str | Decimal]:
'''
This method requires only the strike_prices and oi for call
and puts, the closes list are the same as the strike_prices
the idea is to sum all the calls and puts cash for each strike
and the ITM strikes from that strike, the lowest value is what we
are looking for the intrinsic value.
'''
nonlocal timestamp
# We meed to find the lowest value, so we start at
# infinity to ensure that, and the max_pain must be
# an amount greater than zero.
total_intrinsic_value: Decimal = Decimal('Infinity')
max_pain: Decimal = Decimal(0)
intrinsic_values: dict[str, dict[str, Decimal]] = {}
closes: list[str] = sorted(oi_by_strikes.keys())
for strike in oi_by_strikes:
s: Decimal = Decimal(f'{strike}')
call_cash: Decimal = Decimal(0)
put_cash: Decimal = Decimal(0)
for close in closes:
c: Decimal = Decimal(f'{close}')
call_cash += max(0, (s - c) * oi_by_strikes[f'{close}']['C'])
put_cash += max(0, (c - s) * oi_by_strikes[f'{close}']['P'])
intrinsic_values[strike] = {
'C': call_cash,
'P': put_cash,
'total': call_cash + put_cash,
}
for strike in intrinsic_values:
if intrinsic_values[f'{strike}']['total'] < total_intrinsic_value:
total_intrinsic_value = intrinsic_values[f'{strike}']['total']
max_pain = strike\
return {
'timestamp': timestamp,
'expiry_date': expiry_date,
'total_intrinsic_value': total_intrinsic_value,
'max_pain': max_pain,
}
async with get_client(
) as client:
instruments = await client.get_instruments(
expiry_date=expiry_date,
)
oi_by_strikes = client.get_strikes_dict(instruments)
async with maybe_open_oi_feed(
instruments,
) as oi_feed:
async for msg in oi_feed:
if 'oi' == msg[0]:
timestamp = msg[1]['timestamp']
strike_price = msg[1]['strike_price']
option_type = msg[1]['option_type']
open_interest = msg[1]['open_interest']
oi_by_strikes[f'{strike_price}'][f'{option_type}'] = open_interest
if check_if_complete(oi_by_strikes):
max_pain = get_max_pain(oi_by_strikes)
print('-----------------------------------------------')
print(f'timestamp: {max_pain['timestamp']}')
print(f'expiry_date: {max_pain['expiry_date']}')
print(f'max_pain: {max_pain['max_pain']}')
print(f'total intrinsic value: {max_pain['total_intrinsic_value']}')
print('-----------------------------------------------')
async def main():

View File

@ -812,16 +812,10 @@ async def maybe_open_price_feed(
async def aio_open_interest_feed_relay(
fh: FeedHandler,
oi_by_strikes: dict[str, dict[str, Decimal]],
instruments: list[Symbol],
from_trio: asyncio.Queue,
to_trio: trio.abc.SendChannel,
) -> None:
intrinsic_values: dict[str, dict[str, Decimal]] = {}
total_intrinsic_value: Decimal = Decimal('Infinity')
max_pain: Decimal = Decimal(0)
async def _trade(
trade: Trade, # cryptofeed, NOT ours from `.venues`!
receipt_timestamp: int,
@ -843,11 +837,6 @@ async def aio_open_interest_feed_relay(
Proxy-thru `cryptofeed.FeedHandler` "oi" to `piker`-side.
'''
nonlocal intrinsic_values
nonlocal oi_by_strikes
nonlocal total_intrinsic_value
nonlocal max_pain
symbol: Symbol = str_to_cb_sym(oi.symbol)
piker_sym: str = cb_sym_to_deribit_inst(symbol)
(
@ -858,36 +847,13 @@ async def aio_open_interest_feed_relay(
) = tuple(
piker_sym.split('-')
)
open_interest: Decimal = oi.open_interest
oi_by_strikes[f'{strike_price}'][f'{option_type}'] = open_interest
if check_if_complete(oi_by_strikes):
closes: list[str] = sorted(oi_by_strikes.keys())
for strike in oi_by_strikes:
s: Decimal = Decimal(f'{strike}')
call_cash: Decimal = Decimal(0)
put_cash: Decimal = Decimal(0)
for close in closes:
c: Decimal = Decimal(f'{close}')
call_cash += max(0, (s - c) * oi_by_strikes[f'{close}']['C'])
put_cash += max(0, (c - s) * oi_by_strikes[f'{close}']['P'])
intrinsic_values[strike] = {
'C': call_cash,
'P': put_cash,
'total': call_cash + put_cash,
msg = {
'timestamp': oi.timestamp,
'strike_price': strike_price,
'option_type': option_type,
'open_interest': Decimal(oi.open_interest),
}
for strike in intrinsic_values:
if intrinsic_values[f'{strike}']['total'] < total_intrinsic_value:
total_intrinsic_value = intrinsic_values[f'{strike}']['total']
max_pain = strike
print('-----------------------------------------------')
print(f'expiry date: {expiry_date}')
print(f'max_pain: {max_pain}')
print(f'total intrinsic value: {total_intrinsic_value}')
print('-----------------------------------------------')
to_trio.send_nowait(('oi', msg))
channels = [TRADES, OPEN_INTEREST]
@ -917,16 +883,6 @@ async def aio_open_interest_feed_relay(
async def open_oi_feed(
instruments: list[Symbol],
) -> to_asyncio.LinkedTaskChannel:
expiry_date: str = '20DEC24'
instruments: list[Symbol] = []
oi_by_strikes: dict[str, dict[str, Decimal]]
async with get_client(
) as client:
instruments = await client.get_instruments(
expiry_date=expiry_date,
)
oi_by_strikes = client.get_strikes_dict(instruments)
fh: FeedHandler
first: None
@ -938,7 +894,6 @@ async def open_oi_feed(
aio_open_interest_feed_relay,
fh,
instruments,
oi_by_strikes,
)
) as (first, chan)
):