Reformat fake fill in paper engine,
Ensure tests pass, refactor test wrapperpaper_trade_improvements_rebase
parent
e8714c2d17
commit
c8e6312044
|
@ -260,22 +260,16 @@ class PaperBoi(Struct):
|
||||||
bsuid=key,
|
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
|
# Write to ledger toml right now
|
||||||
with open_trade_ledger(self.broker, 'paper') as ledger:
|
with (
|
||||||
ledger.update(self._trade_ledger)
|
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
|
# Write to pps toml right now
|
||||||
with open_pps(self.broker, 'piker-paper') as table:
|
table.update_from_trans({oid: t})
|
||||||
table.update_from_trans(self._txn_dict)
|
|
||||||
# save pps in local state
|
# 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
|
# Ensure we have the latest positioning data when sending pp_msg
|
||||||
pp = self._positions[key]
|
pp = self._positions[key]
|
||||||
|
|
|
@ -78,7 +78,8 @@ def get_app_dir(app_name, roaming=True, force_posix=False):
|
||||||
# within the tractor runtimes and store testing config data
|
# within the tractor runtimes and store testing config data
|
||||||
# outside of the users filesystem
|
# outside of the users filesystem
|
||||||
if "pytest" in sys.modules:
|
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 WIN:
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""
|
'''
|
||||||
Paper-mode testing
|
Paper-mode testing
|
||||||
"""
|
'''
|
||||||
|
|
||||||
import trio
|
import trio
|
||||||
import math
|
import math
|
||||||
|
@ -22,6 +22,7 @@ from piker.config import get_app_dir
|
||||||
from piker.log import get_logger
|
from piker.log import get_logger
|
||||||
from piker.clearing._messages import Order
|
from piker.clearing._messages import Order
|
||||||
from piker.pp import (
|
from piker.pp import (
|
||||||
|
PpTable,
|
||||||
open_trade_ledger,
|
open_trade_ledger,
|
||||||
open_pps,
|
open_pps,
|
||||||
)
|
)
|
||||||
|
@ -36,31 +37,33 @@ from piker.clearing._messages import BrokerdPosition
|
||||||
|
|
||||||
log = get_logger(__name__)
|
log = get_logger(__name__)
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
|
||||||
|
@pytest.fixture(scope='module')
|
||||||
def delete_testing_dir():
|
def delete_testing_dir():
|
||||||
'''This fixture removes the temp directory
|
'''This fixture removes the temp directory
|
||||||
used for storing all config/ledger/pp data
|
used for storing all config/ledger/pp data
|
||||||
created during testing sessions
|
created during testing sessions
|
||||||
'''
|
'''
|
||||||
yield
|
yield
|
||||||
app_dir = Path(get_app_dir("piker")).resolve()
|
app_dir = Path(get_app_dir('piker')).resolve()
|
||||||
if app_dir.is_dir():
|
if app_dir.is_dir():
|
||||||
rmtree(str(app_dir))
|
rmtree(str(app_dir))
|
||||||
assert not app_dir.is_dir()
|
assert not app_dir.is_dir()
|
||||||
|
|
||||||
|
|
||||||
def get_fqsn(broker, symbol):
|
def get_fqsn(broker, symbol):
|
||||||
fqsn = f"{symbol}.{broker}"
|
fqsn = f'{symbol}.{broker}'
|
||||||
return (fqsn, symbol, broker)
|
return (fqsn, symbol, broker)
|
||||||
|
|
||||||
|
|
||||||
def test_paper_trade(open_test_pikerd: AsyncContextManager):
|
def test_paper_trade(open_test_pikerd: AsyncContextManager):
|
||||||
cleared_price: float
|
oid = ''
|
||||||
test_exec_mode = "live"
|
test_exec_mode = 'live'
|
||||||
test_account = "paper"
|
test_account = 'paper'
|
||||||
test_size = 1
|
test_size = 1
|
||||||
(fqsn, symbol, broker) = get_fqsn("kraken", "xbtusdt")
|
(fqsn, symbol, broker) = get_fqsn('kraken', 'xbtusdt')
|
||||||
brokers = [broker]
|
brokers = [broker]
|
||||||
test_pp_account = "piker-paper"
|
test_pp_account = 'piker-paper'
|
||||||
positions: dict[
|
positions: dict[
|
||||||
# brokername, acctid
|
# brokername, acctid
|
||||||
tuple[str, str],
|
tuple[str, str],
|
||||||
|
@ -69,7 +72,7 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
|
||||||
|
|
||||||
async def _async_main(
|
async def _async_main(
|
||||||
open_pikerd: AsyncContextManager,
|
open_pikerd: AsyncContextManager,
|
||||||
action: Literal["buy", "sell"] | None = None,
|
action: Literal['buy', 'sell'] | None = None,
|
||||||
price: int = 30000,
|
price: int = 30000,
|
||||||
assert_entries: bool = False,
|
assert_entries: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -78,16 +81,14 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
|
||||||
that pps from previous trade exists in the ems pps.
|
that pps from previous trade exists in the ems pps.
|
||||||
Finally close the position and ensure that the position in pps.toml is closed.
|
Finally close the position and ensure that the position in pps.toml is closed.
|
||||||
'''
|
'''
|
||||||
|
nonlocal oid
|
||||||
oid: str = str(uuid4())
|
|
||||||
book: OrderBook
|
book: OrderBook
|
||||||
nonlocal cleared_price
|
|
||||||
nonlocal positions
|
nonlocal positions
|
||||||
|
|
||||||
# Set up piker and EMS
|
# Set up piker and EMS
|
||||||
async with (
|
async with (
|
||||||
open_pikerd() as (_, _, _, services),
|
open_pikerd() as (_, _, _, services),
|
||||||
open_ems(fqsn, mode="paper") as (
|
open_ems(fqsn, mode='paper') as (
|
||||||
book,
|
book,
|
||||||
trades_stream,
|
trades_stream,
|
||||||
pps,
|
pps,
|
||||||
|
@ -97,6 +98,7 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
|
||||||
):
|
):
|
||||||
# Send order to EMS
|
# Send order to EMS
|
||||||
if action:
|
if action:
|
||||||
|
oid = str(uuid4())
|
||||||
order = Order(
|
order = Order(
|
||||||
exec_mode=test_exec_mode,
|
exec_mode=test_exec_mode,
|
||||||
action=action,
|
action=action,
|
||||||
|
@ -118,17 +120,15 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
|
||||||
cleared_ledger_entry = {}
|
cleared_ledger_entry = {}
|
||||||
with open_trade_ledger(broker, test_account) as ledger:
|
with open_trade_ledger(broker, test_account) as ledger:
|
||||||
cleared_ledger_entry = ledger[oid]
|
cleared_ledger_entry = ledger[oid]
|
||||||
cleared_price = cleared_ledger_entry["price"]
|
|
||||||
|
|
||||||
assert list(ledger.keys())[-1] == oid
|
assert list(ledger.keys())[-1] == oid
|
||||||
assert cleared_ledger_entry["size"] == test_size
|
assert cleared_ledger_entry['size'] == test_size
|
||||||
assert cleared_ledger_entry["fqsn"] == fqsn
|
assert cleared_ledger_entry['fqsn'] == fqsn
|
||||||
|
|
||||||
with open_pps(broker, test_pp_account) as table:
|
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
|
# Ensure the price-per-unit (breakeven) price is close to our clearing price
|
||||||
assert math.isclose(
|
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.brokername == broker
|
||||||
assert table.acctid == test_pp_account
|
assert table.acctid == test_pp_account
|
||||||
|
@ -140,62 +140,78 @@ def test_paper_trade(open_test_pikerd: AsyncContextManager):
|
||||||
|
|
||||||
# Open piker load pps locally
|
# Open piker load pps locally
|
||||||
# and ensure last pps price is the same as ledger entry
|
# and ensure last pps price is the same as ledger entry
|
||||||
async def _open_and_assert_pps():
|
def _assert_pps(ledger, table):
|
||||||
await _async_main(open_test_pikerd)
|
return (
|
||||||
assert positions(broker, test_account)[-1] == cleared_price
|
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
|
# Close position and assert empty position in pps
|
||||||
async def _close_pp_and_assert():
|
def _run_test_and_check(exception, fn, assert_cb=None):
|
||||||
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):
|
|
||||||
with pytest.raises(exception) as exc_info:
|
with pytest.raises(exception) as exc_info:
|
||||||
trio.run(fn)
|
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:
|
for exception in exc_info.value.exceptions:
|
||||||
assert isinstance(exception, KeyboardInterrupt) or isinstance(
|
assert isinstance(exception, KeyboardInterrupt) or isinstance(
|
||||||
exception, ContextCancelled
|
exception, ContextCancelled
|
||||||
)
|
)
|
||||||
|
|
||||||
# Send and execute a trade and assert trade
|
# Setablend and execute a trade and assert trade
|
||||||
_run_test_and_check(
|
_run_test_and_check(
|
||||||
BaseExceptionGroup,
|
BaseExceptionGroup,
|
||||||
partial(
|
partial(
|
||||||
_async_main,
|
_async_main,
|
||||||
open_pikerd=open_test_pikerd,
|
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)
|
|
||||||
|
|
||||||
|
_run_test_and_check(
|
||||||
def test_paper_client(
|
BaseExceptionGroup,
|
||||||
open_test_pikerd: AsyncContextManager
|
partial(_async_main, open_pikerd=open_test_pikerd),
|
||||||
):
|
_assert_pps,
|
||||||
|
|
||||||
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, 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,
|
||||||
|
# ),
|
||||||
|
# )
|
||||||
|
|
Loading…
Reference in New Issue