Allow `brokerd` runtime switch to paper mode

Previously you couldn't have a brokerd backend which defined
`.trades_dialogue()` but which could also indicate that the paper
clearing engine should be used. This adds that support by allowing the
endpoint task to return a simple `'paper'` string, in which case the ems
will boot a paperboi.

The obvious useful case for this is if you have a broker you want to use
but do not have actual broker credentials setup (yet) with that provider
in your `brokers.toml`; demonstrated here with the adjustment to
`kraken`'s startup to no longer raise a runtime error B)
master
Tyler Goodlet 2023-05-09 18:29:28 -04:00
parent 361fc4645c
commit 769b292dca
3 changed files with 36 additions and 15 deletions

View File

@ -429,8 +429,8 @@ async def trades_dialogue(
async with get_client() as client:
if not client._api_key:
raise RuntimeError(
'Missing Kraken API key in `brokers.toml`!?!?')
await ctx.started('paper')
return
# TODO: make ems flip to paper mode via
# some returned signal if the user only wants to use

View File

@ -413,8 +413,6 @@ async def stream_quotes(
topic, quote = normalize(ohlc_last)
task_status.started((init_msgs, quote))
# lol, only "closes" when they're margin squeezing clients ;P
feed_is_live.set()
# keep start of last interval for volume tracking

View File

@ -407,11 +407,7 @@ class Router(Struct):
yield relay
return
trades_endpoint = getattr(brokermod, 'trades_dialogue', None)
if (
trades_endpoint is None
or exec_mode == 'paper'
):
def mk_paper_ep():
# for logging purposes
brokermod = paper
@ -426,26 +422,53 @@ class Router(Struct):
# load the paper trading engine as a subactor of this emsd
# actor to simulate the real IPC load it'll have when also
# pulling data from feeds
open_trades_endpoint = paper.open_paperboi(
return paper.open_paperboi(
fqme=fqme,
loglevel=loglevel,
)
else:
trades_endpoint = getattr(brokermod, 'trades_dialogue', None)
if (
trades_endpoint is not None
or exec_mode != 'paper'
):
# open live brokerd trades endpoint
open_trades_endpoint = portal.open_context(
trades_endpoint,
loglevel=loglevel,
)
# open trades-dialog endpoint with backend broker
else:
exec_mode: str = 'paper'
@acm
async def maybe_open_paper_ep():
if exec_mode == 'paper':
async with mk_paper_ep() as msg:
yield msg
return
# open trades-dialog endpoint with backend broker
async with open_trades_endpoint as msg:
ctx, first = msg
# runtime indication that the backend can't support live
# order ctrl yet, so boot the paperboi B0
if first == 'paper':
async with mk_paper_ep() as msg:
yield msg
return
else:
# working live ep case B)
yield msg
return
positions: list[BrokerdPosition]
accounts: tuple[str]
async with (
open_trades_endpoint as (
maybe_open_paper_ep() as (
brokerd_ctx,
(positions, accounts,),
(positions, accounts),
),
brokerd_ctx.open_stream() as brokerd_trades_stream,
):