Add brokercheck test and got deribit to dump l1 and trades to console
parent
f970b7c563
commit
8f338b334a
|
@ -39,6 +39,97 @@ _config_dir = click.get_app_dir('piker')
|
|||
_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()
|
||||
@click.option('--keys', '-k', multiple=True,
|
||||
help='Return results only for these keys')
|
||||
|
@ -193,6 +284,8 @@ def contracts(ctx, loglevel, broker, symbol, ids):
|
|||
brokermod = get_brokermod(broker)
|
||||
get_console_log(loglevel)
|
||||
|
||||
|
||||
|
||||
contracts = trio.run(partial(core.contracts, brokermod, symbol))
|
||||
if not ids:
|
||||
# just print out expiry dates which can be used with
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
Deribit backend
|
||||
|
||||
"""
|
||||
import asyncio
|
||||
from contextlib import asynccontextmanager as acm
|
||||
from datetime import datetime
|
||||
from typing import (
|
||||
Any, Union, Optional,
|
||||
Any, Union, Optional, List,
|
||||
AsyncGenerator, Callable,
|
||||
)
|
||||
import time
|
||||
|
@ -33,10 +34,12 @@ import asks
|
|||
from fuzzywuzzy import process as fuzzy
|
||||
import numpy as np
|
||||
import tractor
|
||||
from tractor import to_asyncio
|
||||
from pydantic.dataclasses import dataclass
|
||||
from pydantic import BaseModel
|
||||
import wsproto
|
||||
|
||||
from .. import config
|
||||
from .._cacheables import open_cached_client
|
||||
from ._util import resproc, SymbolNotFound
|
||||
from ..log import get_logger, get_console_log
|
||||
|
@ -50,7 +53,31 @@ from cryptofeed.callback import (
|
|||
L1BookCallback,
|
||||
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__)
|
||||
|
@ -126,16 +153,13 @@ class Client:
|
|||
|
||||
# will retrieve all symbols by default
|
||||
params = {
|
||||
'currency': currency.to_upper(),
|
||||
'currency': currency.upper(),
|
||||
'kind': kind,
|
||||
'expired': expired
|
||||
'expired': str(expired).lower()
|
||||
}
|
||||
|
||||
resp = await self._api(
|
||||
'get_instrument', params=params)
|
||||
|
||||
if 'result' in resp:
|
||||
raise SymbolNotFound
|
||||
'get_instruments', params=params)
|
||||
|
||||
results = resp['result']
|
||||
|
||||
|
@ -246,20 +270,43 @@ async def open_aio_cryptofeed_relay(
|
|||
instruments: List[str] = []
|
||||
) -> 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({
|
||||
'type': 'trade',
|
||||
instrument: data,
|
||||
data.symbol: data.to_dict(),
|
||||
'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({
|
||||
'type': 'l1_book',
|
||||
instrument: data,
|
||||
'receipt': receipt_timestamp})
|
||||
data.symbol: data.to_dict(),
|
||||
'receipt': receipt_timestamp})
|
||||
|
||||
|
||||
fh = FeedHandler()
|
||||
fh = FeedHandler(config=conf)
|
||||
fh.run(start_loop=False)
|
||||
|
||||
fh.add_feed(
|
||||
|
@ -281,7 +328,7 @@ async def open_aio_cryptofeed_relay(
|
|||
|
||||
|
||||
@acm
|
||||
async def open_cryptofeeds():
|
||||
async def open_cryptofeeds(instruments: List[str]):
|
||||
|
||||
# try:
|
||||
event_table = {}
|
||||
|
@ -290,7 +337,7 @@ async def open_cryptofeeds():
|
|||
to_asyncio.open_channel_from(
|
||||
open_aio_cryptofeed_relay,
|
||||
event_consumers=event_table,
|
||||
instruments=['BTC-10JUN22-30000-C']
|
||||
instruments=instruments
|
||||
) as (first, chan),
|
||||
trio.open_nursery() as n,
|
||||
):
|
||||
|
@ -303,7 +350,7 @@ async def open_cryptofeeds():
|
|||
|
||||
n.start_soon(relay_events)
|
||||
|
||||
yield None
|
||||
yield chan
|
||||
|
||||
await chan.send(None)
|
||||
|
||||
|
@ -372,12 +419,15 @@ async def stream_quotes(
|
|||
async with (
|
||||
open_cached_client('deribit') as client,
|
||||
send_chan as send_chan,
|
||||
open_cryptofeeds(symbols) as feed_chan
|
||||
):
|
||||
|
||||
# keep client cached for real-time section
|
||||
cache = await client.cache_symbols()
|
||||
|
||||
breakpoint()
|
||||
async with feed_chan.subscribe() as msg_stream:
|
||||
async for msg in msg_stream:
|
||||
print(msg)
|
||||
|
||||
|
||||
@tractor.context
|
||||
|
|
Loading…
Reference in New Issue