Compare commits

..

No commits in common. "bf86772d4b3e1b9825d65ddd191cee493dd3f43e" and "f2f7855e5444be6b87e7c1fe8f7fec4e15466e67" have entirely different histories.

2 changed files with 33 additions and 137 deletions

View File

@ -2,6 +2,8 @@
import trio import trio
import tractor import tractor
from piker.brokers.deribit.api import ( from piker.brokers.deribit.api import (
Client,
get_client,
maybe_open_oi_feed, maybe_open_oi_feed,
) )

View File

@ -112,10 +112,6 @@ def deribit_timestamp(when: datetime) -> int:
) )
def get_timestamp_int(expiry_date: str) -> int:
return int(time.mktime(time.strptime(expiry_date, '%d%b%y')))
def str_to_cb_sym(name: str) -> Symbol: def str_to_cb_sym(name: str) -> Symbol:
base, strike_price, expiry_date, option_type = name.split('-') base, strike_price, expiry_date, option_type = name.split('-')
@ -123,14 +119,13 @@ def str_to_cb_sym(name: str) -> Symbol:
if option_type == 'put': if option_type == 'put':
option_type = PUT option_type = PUT
elif option_type == 'call': elif option_type == 'call':
option_type = CALL option_type = CALL
else: else:
raise Exception("Couldn\'t parse option type") raise Exception("Couldn\'t parse option type")
new_expiry_date: int = get_timestamp_int( new_expiry_date = get_values_from_cb_normalized_date(expiry_date)
get_values_from_cb_normalized_date(expiry_date)
)
return Symbol( return Symbol(
base=base, base=base,
quote=quote, quote=quote,
@ -150,12 +145,11 @@ def piker_sym_to_cb_sym(name: str) -> Symbol:
)= tuple( )= tuple(
name.upper().split('-')) name.upper().split('-'))
new_expiry_date = get_timestamp_int(expiry_date)
quote: str = base quote: str = base
if option_type == 'P' or option_type == 'PUT': if option_type == 'P':
option_type = PUT option_type = PUT
elif option_type == 'C' or option_type == 'CALL': elif option_type == 'C':
option_type = CALL option_type = CALL
else: else:
raise Exception("Couldn\'t parse option type") raise Exception("Couldn\'t parse option type")
@ -166,7 +160,7 @@ def piker_sym_to_cb_sym(name: str) -> Symbol:
type=OPTION, type=OPTION,
strike_price=strike_price, strike_price=strike_price,
option_type=option_type, option_type=option_type,
expiry_date=new_expiry_date expiry_date=expiry_date
) )
@ -242,24 +236,9 @@ def get_config() -> dict[str, Any]:
section['log'] = {} section['log'] = {}
section['log']['filename'] = 'feedhandler.log' section['log']['filename'] = 'feedhandler.log'
section['log']['level'] = 'DEBUG' section['log']['level'] = 'DEBUG'
section['log']['disabled'] = True
return section return section
def check_if_complete(
oi: dict[str, dict[str, Decimal | None]],
) -> bool:
for strike in oi:
if (
oi[strike]['C'] == None
or
oi[strike]['P'] == None
):
return False
return True
class Client: class Client:
''' '''
@ -334,20 +313,6 @@ class Client:
return balances return balances
async def get_currencies(
self,
) -> list[dict]:
'''
Return the set of currencies for deribit.
'''
assets = {}
resp = await self._json_rpc_auth_wrapper(
'public/get_currencies',
params={}
)
return resp.result
async def get_assets( async def get_assets(
self, self,
venue: str | None = None, venue: str | None = None,
@ -360,7 +325,11 @@ class Client:
''' '''
assets = {} assets = {}
currencies = await self.get_currencies() resp = await self._json_rpc_auth_wrapper(
'public/get_currencies',
params={}
)
currencies: list[dict] = resp.result
for currency in currencies: for currency in currencies:
name: str = currency['currency'] name: str = currency['currency']
tx_tick: Decimal = digits_to_dec(currency['fee_precision']) tx_tick: Decimal = digits_to_dec(currency['fee_precision'])
@ -397,7 +366,6 @@ class Client:
currency: str = 'btc', currency: str = 'btc',
kind: str = 'option', kind: str = 'option',
expired: bool = False, expired: bool = False,
expiry_date: str = None,
) -> list[Symbol]: ) -> list[Symbol]:
""" """
@ -416,35 +384,12 @@ class Client:
resp = r.result resp = r.result
response_list = [] response_list = []
for i in range(len(resp)): for i in range(len(resp) // 10):
element = resp[i] element = resp[i]
name = f'{element["instrument_name"].split("-")[1]}' response_list.append(piker_sym_to_cb_sym(element['instrument_name']))
if not expiry_date or name == expiry_date.upper():
response_list.append(piker_sym_to_cb_sym(element['instrument_name']))
return response_list return response_list
def get_strikes_dict(
self,
instruments: list[Symbol],
) -> dict[str, dict[str, Decimal | None]]:
"""
Get a dict with strike prices as keys.
"""
response: dict[str, dict[str, Decimal | None]] = {}
for i in range(len(instruments)):
element = instruments[i]
strike = f'{str(element).split('-')[1]}'
response[f'{strike}'] = {
'C': None,
'P': None,
}
return response
async def submit_limit( async def submit_limit(
self, self,
symbol: str, symbol: str,
@ -827,15 +772,9 @@ async def maybe_open_price_feed(
async def aio_open_interest_feed_relay( async def aio_open_interest_feed_relay(
fh: FeedHandler, fh: FeedHandler,
instruments: list, instruments: list,
intrinsic_values: dict[str, Decimal],
oi_by_strikes: dict[str, dict[str, Decimal]],
from_trio: asyncio.Queue, from_trio: asyncio.Queue,
to_trio: trio.abc.SendChannel, to_trio: trio.abc.SendChannel,
) -> None: ) -> None:
max_losses: Decimal = Decimal('Infinity')
max_pain: Decimal = Decimal(0)
async def _trade( async def _trade(
trade: Trade, # cryptofeed, NOT ours from `.venues`! trade: Trade, # cryptofeed, NOT ours from `.venues`!
receipt_timestamp: int, receipt_timestamp: int,
@ -844,6 +783,12 @@ async def aio_open_interest_feed_relay(
Proxy-thru `cryptofeed.FeedHandler` "trades" to `piker`-side. Proxy-thru `cryptofeed.FeedHandler` "trades" to `piker`-side.
''' '''
# Get timestamp and convert it to isoformat
date = (datetime.utcfromtimestamp(trade.timestamp)).isoformat()
print('Trade...')
print(date)
print(trade)
print('=======================')
to_trio.send_nowait(('trade', trade)) to_trio.send_nowait(('trade', trade))
# trade and oi are user defined functions that # trade and oi are user defined functions that
@ -857,60 +802,18 @@ async def aio_open_interest_feed_relay(
Proxy-thru `cryptofeed.FeedHandler` "oi" to `piker`-side. Proxy-thru `cryptofeed.FeedHandler` "oi" to `piker`-side.
''' '''
nonlocal intrinsic_values # Get timestamp and convert it to isoformat
nonlocal oi_by_strikes date = (datetime.utcfromtimestamp(oi.timestamp)).isoformat()
nonlocal max_losses print('>>>> Open Interest...')
nonlocal max_pain print(date)
print(oi)
symbol: Symbol = str_to_cb_sym(oi.symbol) print('==========================')
piker_sym: str = cb_sym_to_deribit_inst(symbol) to_trio.send_nowait(('oi', oi))
(
base,
expiry_date,
strike_price,
option_type
) = tuple(
piker_sym.split('-')
)
open_interest: Decimal = oi.open_interest
oi_by_strikes[f'{strike_price}'][f'{option_type}'] = open_interest
is_ready = check_if_complete(oi_by_strikes)
if is_ready:
for strike in oi_by_strikes:
s: Decimal = Decimal(f'{strike}')
close_losses = Decimal(0)
closes: list[str] = sorted(oi_by_strikes.keys())
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[f'{strike}'] = {}
intrinsic_values[f'{strike}']['C'] = call_cash
intrinsic_values[f'{strike}']['P'] = put_cash
intrinsic_values[f'{strike}']['total'] = (call_cash + put_cash)
for strike in intrinsic_values:
if intrinsic_values[f'{strike}']['total'] < max_losses:
max_losses = intrinsic_values[f'{strike}']['total']
max_pain = strike
print('-----------------------------------------------')
print(f'time: {oi.timestamp}')
print(f'max_pain: {max_pain}')
print(f'max_losses: {max_losses}')
print('-----------------------------------------------')
channels = [TRADES, OPEN_INTEREST]
callbacks={TRADES: _trade, OPEN_INTEREST: _oi}
callbacks = {TRADES: _trade, OPEN_INTEREST: _oi}
fh.add_feed( fh.add_feed(
DERIBIT, DERIBIT,
channels=channels, channels=[TRADES, OPEN_INTEREST],
symbols=instruments, symbols=instruments,
callbacks=callbacks callbacks=callbacks
) )
@ -932,17 +835,10 @@ async def aio_open_interest_feed_relay(
async def open_oi_feed( async def open_oi_feed(
) -> to_asyncio.LinkedTaskChannel: ) -> to_asyncio.LinkedTaskChannel:
expiry_date: str = '20DEC24' instruments: list[Symbol]
instruments: list[Symbol] = []
intrinsic_values: dict[str, dict[str, Decimal]] = {}
oi_by_strikes: dict[str, dict[str, Decimal]]
async with get_client( async with get_client(
) as client: ) as client:
instruments = await client.get_instruments( instruments = await client.get_instruments()
expiry_date=expiry_date,
)
oi_by_strikes = client.get_strikes_dict(instruments)
fh: FeedHandler fh: FeedHandler
first: None first: None
@ -953,9 +849,7 @@ async def open_oi_feed(
partial( partial(
aio_open_interest_feed_relay, aio_open_interest_feed_relay,
fh, fh,
instruments, instruments
intrinsic_values,
oi_by_strikes,
) )
) as (first, chan) ) as (first, chan)
): ):