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')
|
_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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue