Add brokercheck test and got deribit to dump l1 and trades to console

deribit
Guillermo Rodriguez 2022-06-05 08:51:40 -03:00
parent 7acc4e3208
commit 6df181c233
No known key found for this signature in database
GPG Key ID: EC3AB66D5D83B392
3 changed files with 163 additions and 19 deletions

View File

@ -39,6 +39,97 @@ _config_dir = click.get_app_dir('piker')
_watchlists_data_path = os.path.join(_config_dir, 'watchlists.json') _watchlists_data_path = os.path.join(_config_dir, 'watchlists.json')
@cli.command()
@click.option('--loglevel', '-l', default='info', help='Logging level')
@click.argument('broker', nargs=1, required=True)
@click.pass_obj
def brokercheck(config, loglevel, broker):
'''
Test broker apis for completeness.
'''
log = get_console_log(loglevel)
async def run_method(client, meth_name: str, **kwargs):
log.info(f'checking client for method \'{meth_name}\'...')
method = getattr(client, meth_name, None)
assert method
log.info('found!, running...')
result = await method(**kwargs)
log.info(f'done! result: {type(result)}')
return result
async def run_test(broker_name: str):
brokermod = get_brokermod(broker_name)
total = 0
passed = 0
failed = 0
log.info(f'getting client...')
if not hasattr(brokermod, 'get_client'):
log.error('fail! no \'get_client\' context manager found.')
return
async with brokermod.get_client() as client:
log.info(f'done! inside client context.')
# check for methods present on brokermod
method_list = [
'stream_messages',
'open_history_client',
'backfill_bars',
'stream_quotes',
'open_symbol_search'
]
for method in method_list:
log.info(
f'checking brokermod for method \'{method}\'...')
if not hasattr(brokermod, method):
log.error(f'fail! method \'{method}\' not found.')
failed += 1
else:
log.info('done!')
passed += 1
total += 1
# check for methods present con brokermod.Client and their
# results
syms = await run_method(client, 'symbol_info')
total += 1
if len(syms) == 0:
raise BaseException('Empty Symbol list?')
passed += 1
first_sym = tuple(syms.keys())[0]
method_list = [
('cache_symbols', {}),
('search_symbols', {'pattern': first_sym[:-1]}),
('bars', {'symbol': first_sym})
]
for method_name, method_kwargs in method_list:
try:
await run_method(client, method_name, **method_kwargs)
passed += 1
except AssertionError:
log.error(f'fail! method \'{method_name}\' not found.')
failed += 1
total += 1
log.info(f'total: {total}, passed: {passed}, failed: {failed}')
trio.run(run_test, broker)
@cli.command() @cli.command()
@click.option('--keys', '-k', multiple=True, @click.option('--keys', '-k', multiple=True,
help='Return results only for these keys') help='Return results only for these keys')
@ -193,6 +284,8 @@ def contracts(ctx, loglevel, broker, symbol, ids):
brokermod = get_brokermod(broker) brokermod = get_brokermod(broker)
get_console_log(loglevel) get_console_log(loglevel)
contracts = trio.run(partial(core.contracts, brokermod, symbol)) contracts = trio.run(partial(core.contracts, brokermod, symbol))
if not ids: if not ids:
# just print out expiry dates which can be used with # just print out expiry dates which can be used with

View File

@ -18,10 +18,11 @@
Deribit backend Deribit backend
""" """
import asyncio
from contextlib import asynccontextmanager as acm from contextlib import asynccontextmanager as acm
from datetime import datetime from datetime import datetime
from typing import ( from typing import (
Any, Union, Optional, Any, Union, Optional, List,
AsyncGenerator, Callable, AsyncGenerator, Callable,
) )
import time import time
@ -33,10 +34,12 @@ import asks
from fuzzywuzzy import process as fuzzy from fuzzywuzzy import process as fuzzy
import numpy as np import numpy as np
import tractor import tractor
from tractor import to_asyncio
from pydantic.dataclasses import dataclass from pydantic.dataclasses import dataclass
from pydantic import BaseModel from pydantic import BaseModel
import wsproto import wsproto
from .. import config
from .._cacheables import open_cached_client from .._cacheables import open_cached_client
from ._util import resproc, SymbolNotFound from ._util import resproc, SymbolNotFound
from ..log import get_logger, get_console_log from ..log import get_logger, get_console_log
@ -50,7 +53,31 @@ from cryptofeed.callback import (
L1BookCallback, L1BookCallback,
TradeCallback TradeCallback
) )
from cryptofeed.defines import DERIBIT, L1_BOOK, TRADES from cryptofeed.defines import (
DERIBIT, L1_BOOK, TRADES, OPTION, CALL, PUT
)
from cryptofeed.symbols import Symbol
_spawn_kwargs = {
'infect_asyncio': True,
}
def get_config() -> dict[str, Any]:
conf, path = config.load()
section = conf.get('deribit')
if section is None:
log.warning(f'No config section found for deribit in {path}')
return {}
conf['log'] = {}
conf['log']['filename'] = 'feedhandler.log'
conf['log']['level'] = 'WARNING'
return conf
log = get_logger(__name__) log = get_logger(__name__)
@ -126,16 +153,13 @@ class Client:
# will retrieve all symbols by default # will retrieve all symbols by default
params = { params = {
'currency': currency.to_upper(), 'currency': currency.upper(),
'kind': kind, 'kind': kind,
'expired': expired 'expired': str(expired).lower()
} }
resp = await self._api( resp = await self._api(
'get_instrument', params=params) 'get_instruments', params=params)
if 'result' in resp:
raise SymbolNotFound
results = resp['result'] results = resp['result']
@ -246,20 +270,43 @@ async def open_aio_cryptofeed_relay(
instruments: List[str] = [] instruments: List[str] = []
) -> None: ) -> None:
async def trade_cb(feed, instrument, data: dict, receipt_timestamp): conf = get_config()
def format_sym(name: str) -> str:
base, expiry_date, strike_price, option_type = tuple(
name.upper().split('-'))
quote = base
if option_type == 'P':
option_type = PUT
elif option_type == 'C':
option_type = CALL
else:
raise BaseException("Instrument name must end in 'c' for calls or 'p' for puts")
return Symbol(
base, quote,
type=OPTION,
strike_price=strike_price,
option_type=option_type,
expiry_date=expiry_date.upper()).normalized
instruments = [format_sym(i) for i in instruments]
async def trade_cb(data: dict, receipt_timestamp):
to_trio.send_nowait({ to_trio.send_nowait({
'type': 'trade', 'type': 'trade',
instrument: data, data.symbol: data.to_dict(),
'receipt': receipt_timestamp}) 'receipt': receipt_timestamp})
async def l1_book_cb(feed, instrument, data: dict, receipt_timestamp): async def l1_book_cb(data: dict, receipt_timestamp):
to_trio.send_nowait({ to_trio.send_nowait({
'type': 'l1_book', 'type': 'l1_book',
instrument: data, data.symbol: data.to_dict(),
'receipt': receipt_timestamp}) 'receipt': receipt_timestamp})
fh = FeedHandler(config=conf)
fh = FeedHandler()
fh.run(start_loop=False) fh.run(start_loop=False)
fh.add_feed( fh.add_feed(
@ -281,7 +328,7 @@ async def open_aio_cryptofeed_relay(
@acm @acm
async def open_cryptofeeds(): async def open_cryptofeeds(instruments: List[str]):
# try: # try:
event_table = {} event_table = {}
@ -290,7 +337,7 @@ async def open_cryptofeeds():
to_asyncio.open_channel_from( to_asyncio.open_channel_from(
open_aio_cryptofeed_relay, open_aio_cryptofeed_relay,
event_consumers=event_table, event_consumers=event_table,
instruments=['BTC-10JUN22-30000-C'] instruments=instruments
) as (first, chan), ) as (first, chan),
trio.open_nursery() as n, trio.open_nursery() as n,
): ):
@ -303,7 +350,7 @@ async def open_cryptofeeds():
n.start_soon(relay_events) n.start_soon(relay_events)
yield None yield chan
await chan.send(None) await chan.send(None)
@ -372,12 +419,15 @@ async def stream_quotes(
async with ( async with (
open_cached_client('deribit') as client, open_cached_client('deribit') as client,
send_chan as send_chan, send_chan as send_chan,
open_cryptofeeds(symbols) as feed_chan
): ):
# keep client cached for real-time section # keep client cached for real-time section
cache = await client.cache_symbols() cache = await client.cache_symbols()
breakpoint() async with feed_chan.subscribe() as msg_stream:
async for msg in msg_stream:
print(msg)
@tractor.context @tractor.context

View File

@ -62,6 +62,7 @@ setup(
# brokers # brokers
'asks==2.4.8', 'asks==2.4.8',
'ib_insync', 'ib_insync',
'cryptofeed',
# numerics # numerics
'pendulum', # easier datetimes 'pendulum', # easier datetimes