async def test_stock_quoter_context(us_symbols): """Test that a quoter "context" used by the data feed daemon. """ async with qt.get_client() as client: quoter = await qt.stock_quoter(client, us_symbols) quotes = await quoter(us_symbols) match_packet(us_symbols, quotes)
async def test_batched_stock_quote(us_symbols): """Use the client stock quote api and verify quote response format. """ async with qt.get_client() as client: quotes = await client.quote(us_symbols) assert len(quotes) == len(us_symbols) match_packet(us_symbols, quotes)
async def ensure_config(): # try to refresh current token using cached brokers config # if it fails fail try using the refresh token provided by the # env var and if that fails stop the test run here. try: async with questrade.get_client(ask_user=False): pass except ( FileNotFoundError, ValueError, questrade.BrokerError, questrade.QuestradeError, trio.MultiError, ): # 3 cases: # - config doesn't have a ``refresh_token`` k/v # - cache dir does not exist yet # - current token is expired; take it form env var write_with_token(refresh_token) async with questrade.get_client(ask_user=False): pass
async def test_option_contracts(tmx_symbols): """Verify we can retrieve contracts by expiry. """ async with qt.get_client() as client: for symbol in tmx_symbols: contracts = await client.symbol2contracts(symbol) key, byroot = next(iter(contracts.items())) assert isinstance(key.id, int) assert isinstance(byroot, dict) for key in contracts: # check that datetime is same as reported in contract assert key.expiry.isoformat( timespec='microseconds') == contracts[key]['expiryDate']
async def test_option_chain(tmx_symbols): """Verify we can retrieve all option chains for a list of symbols. """ async with qt.get_client() as client: # contract lookup - should be cached contracts = await client.get_all_contracts([tmx_symbols[0]]) # chains quote for all symbols quotes = await client.option_chains(contracts) # verify contents match what we expect for quote in quotes: underlying = quote['underlying'] # XXX: sometimes it's '' for old expiries? if underlying: assert underlying in tmx_symbols for key in _ex_quotes['option']: quote.pop(key) assert not quote
async def test_concurrent_tokens_refresh(us_symbols, loglevel): """Verify that concurrent requests from mulitple tasks work alongside random token refreshing which simulates an access token expiry + refresh scenario. The API does not support concurrent requests when refreshing tokens (i.e. when hitting the auth endpoint). This tests ensures that when multiple tasks use the same client concurrency works and access token expiry will result in a reliable token set update. """ async with qt.get_client() as client: # async with tractor.open_nursery() as n: # await n.run_in_actor('other', intermittently_refresh_tokens) async with trio.open_nursery() as n: quoter = await qt.stock_quoter(client, us_symbols) async def get_quotes(): for tries in range(15): log.info(f"{tries}: GETTING QUOTES!") quotes = await quoter(us_symbols) assert quotes await trio.sleep(0.2) async def intermittently_refresh_tokens(client): while True: try: await client.ensure_access( force_refresh=True, ask_user=False) log.info(f"last token data is {client.access_data}") await trio.sleep(1) except Exception: log.exception("Token refresh failed") n.start_soon(intermittently_refresh_tokens, client) # run 2 quote polling tasks n.start_soon(get_quotes) await get_quotes() # shutdown # await n.cancel() n.cancel_scope.cancel()
async def test_option_quote_latency(tmx_symbols): """Audit option quote latencies. """ async with qt.get_client() as client: # all contracts lookup - should be cached contracts = await client.get_all_contracts(['WEED.TO']) # build single expriry contract id, by_expiry = next(iter(contracts.items())) dt, by_strike = next(iter(by_expiry.items())) single = {id: {dt: None}} for expected_latency, contract in [ # NOTE: request latency is usually 2x faster that these (5, contracts), (0.5, single) ]: for _ in range(3): # chains quote for all symbols start = time.time() await client.option_chains(contract) took = time.time() - start print(f"Request took {took}") assert took <= expected_latency await trio.sleep(0.1)