Reformat fake fill in paper engine,

Ensure tests pass, refactor test wrapper
paper_trade_improvements_rebase
jaredgoldman 2023-02-24 13:42:44 -05:00
parent e8714c2d17
commit c8e6312044
3 changed files with 92 additions and 81 deletions

View File

@ -260,22 +260,16 @@ class PaperBoi(Struct):
bsuid=key,
)
# Update in memory ledger per trade
ledger_entry = {oid: t.to_dict()}
# Store txn in state for PP update
self._txn_dict[oid] = t
self._trade_ledger.update(ledger_entry)
# Write to ledger toml right now
with open_trade_ledger(self.broker, 'paper') as ledger:
ledger.update(self._trade_ledger)
with (
open_trade_ledger(self.broker, 'paper') as ledger,
open_pps(self.broker, 'piker-paper') as table
):
ledger.update({oid: t.to_dict()})
# Write to pps toml right now
with open_pps(self.broker, 'piker-paper') as table:
table.update_from_trans(self._txn_dict)
table.update_from_trans({oid: t})
# save pps in local state
self._positions = table.pps
self._positions.update(table.pps)
# Ensure we have the latest positioning data when sending pp_msg
pp = self._positions[key]

View File

@ -78,7 +78,8 @@ def get_app_dir(app_name, roaming=True, force_posix=False):
# within the tractor runtimes and store testing config data
# outside of the users filesystem
if "pytest" in sys.modules:
app_name += TEST_CONFIG_DIR_PATH
log.info("TESTING")
os.path.join(app_name, TEST_CONFIG_DIR_PATH)
# if WIN:
if platform.system() == 'Windows':

View File

@ -1,6 +1,6 @@
"""
'''
Paper-mode testing
"""
'''
import trio
import math
@ -22,6 +22,7 @@ from piker.config import get_app_dir
from piker.log import get_logger
from piker.clearing._messages import Order
from piker.pp import (
PpTable,
open_trade_ledger,
open_pps,
)
@ -36,31 +37,33 @@ from piker.clearing._messages import BrokerdPosition
log = get_logger(__name__)
@pytest.fixture(scope="module")
@pytest.fixture(scope='module')
def delete_testing_dir():
'''This fixture removes the temp directory
used for storing all config/ledger/pp data
created during testing sessions
'''
yield
app_dir = Path(get_app_dir("piker")).resolve()
app_dir = Path(get_app_dir('piker')).resolve()
if app_dir.is_dir():
rmtree(str(app_dir))
assert not app_dir.is_dir()
def get_fqsn(broker, symbol):
fqsn = f"{symbol}.{broker}"
fqsn = f'{symbol}.{broker}'
return (fqsn, symbol, broker)
def test_paper_trade(open_test_pikerd: AsyncContextManager):
cleared_price: float
test_exec_mode = "live"
test_account = "paper"
oid = ''
test_exec_mode = 'live'
test_account = 'paper'
test_size = 1
(fqsn, symbol, broker) = get_fqsn("kraken", "xbtusdt")
(fqsn, symbol, broker) = get_fqsn('kraken', 'xbtusdt')
brokers = [broker]
test_pp_account = "piker-paper"
test_pp_account = 'piker-paper'
positions: dict[
# brokername, acctid
tuple[str, str],
@ -69,7 +72,7 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
async def _async_main(
open_pikerd: AsyncContextManager,
action: Literal["buy", "sell"] | None = None,
action: Literal['buy', 'sell'] | None = None,
price: int = 30000,
assert_entries: bool = False,
) -> None:
@ -78,16 +81,14 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
that pps from previous trade exists in the ems pps.
Finally close the position and ensure that the position in pps.toml is closed.
'''
oid: str = str(uuid4())
nonlocal oid
book: OrderBook
nonlocal cleared_price
nonlocal positions
# Set up piker and EMS
async with (
open_pikerd() as (_, _, _, services),
open_ems(fqsn, mode="paper") as (
open_ems(fqsn, mode='paper') as (
book,
trades_stream,
pps,
@ -97,6 +98,7 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
):
# Send order to EMS
if action:
oid = str(uuid4())
order = Order(
exec_mode=test_exec_mode,
action=action,
@ -118,17 +120,15 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
cleared_ledger_entry = {}
with open_trade_ledger(broker, test_account) as ledger:
cleared_ledger_entry = ledger[oid]
cleared_price = cleared_ledger_entry["price"]
assert list(ledger.keys())[-1] == oid
assert cleared_ledger_entry["size"] == test_size
assert cleared_ledger_entry["fqsn"] == fqsn
assert cleared_ledger_entry['size'] == test_size
assert cleared_ledger_entry['fqsn'] == fqsn
with open_pps(broker, test_pp_account) as table:
pp_price = table.conf[broker][test_pp_account][fqsn]["ppu"]
pp_price = table.conf[broker][test_pp_account][fqsn]['ppu']
# Ensure the price-per-unit (breakeven) price is close to our clearing price
assert math.isclose(
pp_price, cleared_ledger_entry["size"], rel_tol=1
pp_price, cleared_ledger_entry['size'], rel_tol=1
)
assert table.brokername == broker
assert table.acctid == test_pp_account
@ -140,62 +140,78 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
# Open piker load pps locally
# and ensure last pps price is the same as ledger entry
async def _open_and_assert_pps():
await _async_main(open_test_pikerd)
assert positions(broker, test_account)[-1] == cleared_price
def _assert_pps(ledger, table):
return (
positions[(broker, test_account)][-1]['avg_price'] == ledger[oid]['price']
)
def _assert_no_pps(ledger, table):
return len(table.pps) == 0
# Close position and assert empty position in pps
async def _close_pp_and_assert():
await _async_main(open_test_pikerd, "sell", 1)
with open_pps(broker, test_pp_account) as table:
assert len(table.pps) == 0
def _run_test_and_check(exception, fn):
def _run_test_and_check(exception, fn, assert_cb=None):
with pytest.raises(exception) as exc_info:
trio.run(fn)
with (
open_trade_ledger(broker, test_account) as ledger,
open_pps(broker, test_pp_account) as table,
):
if assert_cb:
assert assert_cb(ledger, table)
for exception in exc_info.value.exceptions:
assert isinstance(exception, KeyboardInterrupt) or isinstance(
exception, ContextCancelled
)
# Send and execute a trade and assert trade
# Setablend and execute a trade and assert trade
_run_test_and_check(
BaseExceptionGroup,
partial(
_async_main,
open_pikerd=open_test_pikerd,
action="buy",
action='buy',
),
)
_run_test_and_check(BaseExceptionGroup, _open_and_assert_pps)
_run_test_and_check(BaseExceptionGroup, _close_pp_and_assert)
def test_paper_client(
open_test_pikerd: AsyncContextManager
):
async def _async_main(
open_pikerd: AsyncContextManager,
):
(fqsn, symbol, broker) = get_fqsn("kraken", "xbtusdt")
async with (
open_pikerd() as (_, _, _, services),
open_ems(fqsn, mode="paper") as (
book,
trades_stream,
pps,
accounts,
dialogs,
),
):
async with open_cached_client(broker) as client:
symbol_info = await client.symbol_info()
print(f'client: {symbol_info["XBTUSDT"]}')
trio.run(partial(
_async_main,
open_pikerd=open_test_pikerd,
),
_run_test_and_check(
BaseExceptionGroup,
partial(_async_main, open_pikerd=open_test_pikerd),
_assert_pps,
)
_run_test_and_check(
BaseExceptionGroup,
partial(_async_main, open_pikerd=open_test_pikerd, action='sell', price=1),
_assert_no_pps,
)
# def test_paper_client(
# open_test_pikerd: AsyncContextManager
# ):
#
# async def _async_main(
# open_pikerd: AsyncContextManager,
# ):
# (fqsn, symbol, broker) = get_fqsn('kraken', 'xbtusdt')
# async with (
# open_pikerd() as (_, _, _, services),
# open_ems(fqsn, mode='paper') as (
# book,
# trades_stream,
# pps,
# accounts,
# dialogs,
# ),
# ):
# async with open_cached_client(broker) as client:
# symbol_info = await client.symbol_info()
# print(f'client: {symbol_info['XBTUSDT']}')
#
# trio.run(partial(
# _async_main,
# open_pikerd=open_test_pikerd,
# ),
# )