Rewrite order ctl tests as a parametrization
More or less a complete rework which allows passing a detailed clearing/fills input and allows for *not* rebooting the runtime / ems between each position check. Some further enhancements: - use (unit) fractional sizes to simulate both the more realistic and more "complex position calculation" case; since this is crypto. - add a no-fqme-found test. - factor cross-session/offline pos storage (pps.toml) checks into a `load_and_check_pos()` helper which does all entry loading directly from a provided `BrokerdPosition` msg. - use the new `OrderClient.send()` async api.rekt_pps
							parent
							
								
									e524c6fe4f
								
							
						
					
					
						commit
						30af91a82c
					
				| 
						 | 
					@ -18,7 +18,6 @@ from exceptiongroup import BaseExceptionGroup
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
import tractor
 | 
					import tractor
 | 
				
			||||||
from uuid import uuid4
 | 
					from uuid import uuid4
 | 
				
			||||||
from functools import partial
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from piker.service import Services
 | 
					from piker.service import Services
 | 
				
			||||||
from piker.log import get_logger
 | 
					from piker.log import get_logger
 | 
				
			||||||
| 
						 | 
					@ -53,14 +52,15 @@ async def open_pikerd(
 | 
				
			||||||
        yield services
 | 
					        yield services
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def submit_order(
 | 
					async def order_and_and_wait_for_ppmsg(
 | 
				
			||||||
    client: OrderClient,
 | 
					    client: OrderClient,
 | 
				
			||||||
    trades_stream: tractor.MsgStream,
 | 
					    trades_stream: tractor.MsgStream,
 | 
				
			||||||
    fqme: str,
 | 
					    fqme: str,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    action: Literal['buy', 'sell'],
 | 
					    action: Literal['buy', 'sell'],
 | 
				
			||||||
    price: float = 30000.,
 | 
					    price: float = 100e3,  # just a super high price.
 | 
				
			||||||
    executions: int = 1,
 | 
					 | 
				
			||||||
    size: float = 0.01,
 | 
					    size: float = 0.01,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    exec_mode: str = 'live',
 | 
					    exec_mode: str = 'live',
 | 
				
			||||||
    account: str = 'paper',
 | 
					    account: str = 'paper',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,51 +73,49 @@ async def submit_order(
 | 
				
			||||||
    sent: list[Order] = []
 | 
					    sent: list[Order] = []
 | 
				
			||||||
    broker, key, suffix = unpack_fqme(fqme)
 | 
					    broker, key, suffix = unpack_fqme(fqme)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for _ in range(executions):
 | 
					    order = Order(
 | 
				
			||||||
 | 
					        exec_mode=exec_mode,
 | 
				
			||||||
 | 
					        action=action,  # TODO: remove this from our schema?
 | 
				
			||||||
 | 
					        oid=str(uuid4()),
 | 
				
			||||||
 | 
					        account=account,
 | 
				
			||||||
 | 
					        size=size,
 | 
				
			||||||
 | 
					        symbol=fqme,
 | 
				
			||||||
 | 
					        price=price,
 | 
				
			||||||
 | 
					        brokers=[broker],
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    sent.append(order)
 | 
				
			||||||
 | 
					    await client.send(order)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        order = Order(
 | 
					    # TODO: i guess we should still test the old sync-API?
 | 
				
			||||||
            exec_mode=exec_mode,
 | 
					    # client.send_nowait(order)
 | 
				
			||||||
            action=action,
 | 
					 | 
				
			||||||
            oid=str(uuid4()),
 | 
					 | 
				
			||||||
            account=account,
 | 
					 | 
				
			||||||
            size=size,
 | 
					 | 
				
			||||||
            symbol=fqme,
 | 
					 | 
				
			||||||
            price=price,
 | 
					 | 
				
			||||||
            brokers=[broker],
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        sent.append(order)
 | 
					 | 
				
			||||||
        await client.send(order)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # TODO: i guess we should still test the old sync-API?
 | 
					    # Wait for position message before moving on to verify flow(s)
 | 
				
			||||||
        # client.send_nowait(order)
 | 
					    # for the multi-order position entry/exit.
 | 
				
			||||||
 | 
					    msgs: list[Status | BrokerdPosition] = []
 | 
				
			||||||
 | 
					    async for msg in trades_stream:
 | 
				
			||||||
 | 
					        match msg:
 | 
				
			||||||
 | 
					            case {'name': 'position'}:
 | 
				
			||||||
 | 
					                ppmsg = BrokerdPosition(**msg)
 | 
				
			||||||
 | 
					                msgs.append(ppmsg)
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Wait for position message before moving on to verify flow(s)
 | 
					            case {'name': 'status'}:
 | 
				
			||||||
        # for the multi-order position entry/exit.
 | 
					                msgs.append(Status(**msg))
 | 
				
			||||||
        msgs: list[Status | BrokerdPosition] = []
 | 
					 | 
				
			||||||
        async for msg in trades_stream:
 | 
					 | 
				
			||||||
            match msg:
 | 
					 | 
				
			||||||
                case {'name': 'position'}:
 | 
					 | 
				
			||||||
                    ppmsg = BrokerdPosition(**msg)
 | 
					 | 
				
			||||||
                    msgs.append(ppmsg)
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                case {'name': 'status'}:
 | 
					 | 
				
			||||||
                    msgs.append(Status(**msg))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return sent, msgs
 | 
					    return sent, msgs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def run_and_catch(
 | 
					def run_and_tollerate_cancels(
 | 
				
			||||||
    fn: Callable[..., Awaitable],
 | 
					    fn: Callable[..., Awaitable],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expect_errs: tuple[Exception] = (
 | 
					    expect_errs: tuple[Exception] | None = None,
 | 
				
			||||||
        KeyboardInterrupt,
 | 
					    tollerate_errs: tuple[Exception] = (tractor.ContextCancelled,),
 | 
				
			||||||
        tractor.ContextCancelled,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    Close position and assert empty position in pps
 | 
					    Run ``trio``-``piker`` runtime with potential tolerance for
 | 
				
			||||||
 | 
					    inter-actor cancellation during teardown (normally just
 | 
				
			||||||
 | 
					    `tractor.ContextCancelled`s).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    if expect_errs:
 | 
					    if expect_errs:
 | 
				
			||||||
| 
						 | 
					@ -127,7 +125,10 @@ def run_and_catch(
 | 
				
			||||||
        for err in exc_info.value.exceptions:
 | 
					        for err in exc_info.value.exceptions:
 | 
				
			||||||
            assert type(err) in expect_errs
 | 
					            assert type(err) in expect_errs
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        trio.run(fn)
 | 
					        try:
 | 
				
			||||||
 | 
					            trio.run(fn)
 | 
				
			||||||
 | 
					        except tollerate_errs:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@cm
 | 
					@cm
 | 
				
			||||||
| 
						 | 
					@ -139,22 +140,28 @@ def load_and_check_pos(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with open_pps(ppmsg.broker, ppmsg.account) as table:
 | 
					    with open_pps(ppmsg.broker, ppmsg.account) as table:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # NOTE: a special case is here since the `PpTable.pps` are
 | 
					        if ppmsg.size == 0:
 | 
				
			||||||
        # normally indexed by the particular broker's
 | 
					            assert ppmsg.symbol not in table.pps
 | 
				
			||||||
        # `Position.bs_mktid: str` (a unique market / symbol id provided
 | 
					            yield None
 | 
				
			||||||
        # by their systems/design) but for the paper engine case, this
 | 
					            return
 | 
				
			||||||
        # is the same the fqme.
 | 
					 | 
				
			||||||
        pp: Position = table.pps[ppmsg.symbol]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert ppmsg.size == pp.size
 | 
					        else:
 | 
				
			||||||
        assert ppmsg.avg_price == pp.ppu
 | 
					            # NOTE: a special case is here since the `PpTable.pps` are
 | 
				
			||||||
 | 
					            # normally indexed by the particular broker's
 | 
				
			||||||
 | 
					            # `Position.bs_mktid: str` (a unique market / symbol id provided
 | 
				
			||||||
 | 
					            # by their systems/design) but for the paper engine case, this
 | 
				
			||||||
 | 
					            # is the same the fqme.
 | 
				
			||||||
 | 
					            pp: Position = table.pps[ppmsg.symbol]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        yield pp
 | 
					            assert ppmsg.size == pp.size
 | 
				
			||||||
 | 
					            assert ppmsg.avg_price == pp.ppu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            yield pp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.trio
 | 
					@pytest.mark.trio
 | 
				
			||||||
async def test_ems_err_on_bad_broker(
 | 
					async def test_ems_err_on_bad_broker(
 | 
				
			||||||
    open_pikerd: Services,
 | 
					    open_test_pikerd: Services,
 | 
				
			||||||
    loglevel: str,
 | 
					    loglevel: str,
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
| 
						 | 
					@ -168,9 +175,60 @@ async def test_ems_err_on_bad_broker(
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def atest_buy(
 | 
					async def match_ppmsgs_on_ems_boot(
 | 
				
			||||||
 | 
					    ppmsgs: list[BrokerdPosition],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					) -> None:
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    Given a list of input position msgs, verify they match
 | 
				
			||||||
 | 
					    what is loaded from the EMS on connect.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    by_acct: dict[tuple, list[BrokerdPosition]] = {}
 | 
				
			||||||
 | 
					    for msg in ppmsgs:
 | 
				
			||||||
 | 
					        by_acct.setdefault(
 | 
				
			||||||
 | 
					            (msg.broker, msg.account),
 | 
				
			||||||
 | 
					            [],
 | 
				
			||||||
 | 
					        ).append(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # TODO: actually support multi-mkts to `open_ems()`
 | 
				
			||||||
 | 
					    # but for now just pass the first fqme.
 | 
				
			||||||
 | 
					    fqme = msg.symbol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # disconnect from EMS, reconnect and ensure we get our same
 | 
				
			||||||
 | 
					    # position relayed to us again in the startup msg.
 | 
				
			||||||
 | 
					    async with (
 | 
				
			||||||
 | 
					        open_ems(
 | 
				
			||||||
 | 
					            fqme,
 | 
				
			||||||
 | 
					            mode='paper',
 | 
				
			||||||
 | 
					            loglevel='info',
 | 
				
			||||||
 | 
					        ) as (
 | 
				
			||||||
 | 
					            _,  # OrderClient
 | 
				
			||||||
 | 
					            _,  # tractor.MsgStream
 | 
				
			||||||
 | 
					            startup_pps,
 | 
				
			||||||
 | 
					            accounts,
 | 
				
			||||||
 | 
					            _,  # dialogs,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
 | 
					        for (broker, account), ppmsgs in by_acct.items():
 | 
				
			||||||
 | 
					            assert account in accounts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # lookup all msgs rx-ed for this account
 | 
				
			||||||
 | 
					            rx_msgs = startup_pps[(broker, account)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for expect_ppmsg in ppmsgs:
 | 
				
			||||||
 | 
					                rx_msg = BrokerdPosition(**rx_msgs[expect_ppmsg.symbol])
 | 
				
			||||||
 | 
					                assert rx_msg == expect_ppmsg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def submit_and_check(
 | 
				
			||||||
 | 
					    fills: tuple[dict],
 | 
				
			||||||
    loglevel: str,
 | 
					    loglevel: str,
 | 
				
			||||||
):
 | 
					
 | 
				
			||||||
 | 
					) -> tuple[
 | 
				
			||||||
 | 
					    BrokerdPosition,
 | 
				
			||||||
 | 
					    Position,
 | 
				
			||||||
 | 
					]:
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    Enter a trade and assert entries are made in pps and ledger files.
 | 
					    Enter a trade and assert entries are made in pps and ledger files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,125 +261,108 @@ async def atest_buy(
 | 
				
			||||||
        assert not startup_pps
 | 
					        assert not startup_pps
 | 
				
			||||||
        assert 'paper' in accounts
 | 
					        assert 'paper' in accounts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sent, msgs = await submit_order(
 | 
					        od: dict
 | 
				
			||||||
            client,
 | 
					        for od in fills:
 | 
				
			||||||
            trades_stream,
 | 
					            print(f'Sending order {od} for fill')
 | 
				
			||||||
            fqme,
 | 
					            sent, msgs = await order_and_and_wait_for_ppmsg(
 | 
				
			||||||
            action='buy',
 | 
					                client,
 | 
				
			||||||
            size=0.01,
 | 
					                trades_stream,
 | 
				
			||||||
        )
 | 
					                fqme,
 | 
				
			||||||
 | 
					                action='buy',
 | 
				
			||||||
        last_order = sent[-1]
 | 
					                size=od['size'],
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        last_order: Order = sent[-1]
 | 
				
			||||||
        last_resp = msgs[-1]
 | 
					        last_resp = msgs[-1]
 | 
				
			||||||
        assert isinstance(last_resp, BrokerdPosition)
 | 
					        assert isinstance(last_resp, BrokerdPosition)
 | 
				
			||||||
 | 
					        ppmsg = last_resp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # check that pps.toml for account has been updated
 | 
					        # check that pps.toml for account has been updated
 | 
				
			||||||
 | 
					        # and all ems position msgs match that state.
 | 
				
			||||||
        with load_and_check_pos(
 | 
					        with load_and_check_pos(
 | 
				
			||||||
            last_order,
 | 
					            last_order,
 | 
				
			||||||
            last_resp,
 | 
					            ppmsg,
 | 
				
			||||||
        ) as pos:
 | 
					        ) as pos:
 | 
				
			||||||
            return pos
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # disconnect from EMS, then reconnect and ensure we get our same
 | 
					    return ppmsg, pos
 | 
				
			||||||
    # position relayed to us again.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # _run_test_and_check(
 | 
					 | 
				
			||||||
    #     partial(
 | 
					 | 
				
			||||||
    #         _async_main,
 | 
					 | 
				
			||||||
    #         open_test_pikerd_and_ems=open_test_pikerd_and_ems,
 | 
					 | 
				
			||||||
    #         action='buy',
 | 
					 | 
				
			||||||
    #         assert_entries=True,
 | 
					 | 
				
			||||||
    #     ),
 | 
					 | 
				
			||||||
    # )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # await _async_main(
 | 
					 | 
				
			||||||
    #     open_test_pikerd_and_ems=open_test_pikerd_and_ems,
 | 
					 | 
				
			||||||
    #     assert_pps=True,
 | 
					 | 
				
			||||||
    # )
 | 
					 | 
				
			||||||
    # _run_test_and_check(
 | 
					 | 
				
			||||||
    #     partial(
 | 
					 | 
				
			||||||
    #         _async_main,
 | 
					 | 
				
			||||||
    #         open_test_pikerd_and_ems=open_test_pikerd_and_ems,
 | 
					 | 
				
			||||||
    #         assert_pps=True,
 | 
					 | 
				
			||||||
    #     ),
 | 
					 | 
				
			||||||
    # )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_open_long(
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    'fills',
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					        # buy and leave
 | 
				
			||||||
 | 
					        ({'size': 0.001},),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # sell short, then buy back to net-zero in dst
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            {'size': -0.001},
 | 
				
			||||||
 | 
					            {'size': 0.001},
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # multi-partial entry and exits.
 | 
				
			||||||
 | 
					        (
 | 
				
			||||||
 | 
					            # enters
 | 
				
			||||||
 | 
					            {'size': 0.001},
 | 
				
			||||||
 | 
					            {'size': 0.002},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # partial exit
 | 
				
			||||||
 | 
					            {'size': -0.001},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # partial enter
 | 
				
			||||||
 | 
					            {'size': 0.0015},
 | 
				
			||||||
 | 
					            {'size': 0.001},
 | 
				
			||||||
 | 
					            {'size': 0.002},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # exits to get back to zero.
 | 
				
			||||||
 | 
					            {'size': -0.001},
 | 
				
			||||||
 | 
					            {'size': -0.025},
 | 
				
			||||||
 | 
					            {'size': -0.0195},
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    ids='fills={}'.format,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					def test_multi_fill_positions(
 | 
				
			||||||
    open_test_pikerd: AsyncContextManager,
 | 
					    open_test_pikerd: AsyncContextManager,
 | 
				
			||||||
    loglevel: str,
 | 
					    loglevel: str,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fills: tuple[dict],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    check_cross_session: bool = True,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
) -> None:
 | 
					) -> None:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ppmsg: BrokerdPosition
 | 
				
			||||||
 | 
					    pos: Position
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    accum_size: float = 0
 | 
				
			||||||
 | 
					    for fill in fills:
 | 
				
			||||||
 | 
					        accum_size += fill['size']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def atest():
 | 
					    async def atest():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # export to outer scope for audit on second runtime-boot.
 | 
				
			||||||
 | 
					        nonlocal ppmsg, pos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        async with (
 | 
					        async with (
 | 
				
			||||||
            open_test_pikerd() as (_, _, _, services),
 | 
					            open_test_pikerd() as (_, _, _, services),
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            assert await atest_buy(loglevel)
 | 
					            ppmsg, pos = await submit_and_check(
 | 
				
			||||||
 | 
					                fills=fills,
 | 
				
			||||||
 | 
					                loglevel=loglevel,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            assert ppmsg.size == accum_size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Teardown piker like a user would from cli
 | 
					    run_and_tollerate_cancels(atest)
 | 
				
			||||||
            # raise KeyboardInterrupt
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    run_and_catch(
 | 
					    if check_cross_session or accum_size != 0:
 | 
				
			||||||
        atest,
 | 
					        # rerun just to check that position info is persistent for the paper
 | 
				
			||||||
        expect_errs=None,
 | 
					        # account (i.e. a user can expect to see paper pps persist across
 | 
				
			||||||
    )
 | 
					        # runtime sessions.
 | 
				
			||||||
    # Open ems another time and assert existence of prior
 | 
					        async def just_check_pp():
 | 
				
			||||||
    # pps entries confirming they persisted
 | 
					            async with (
 | 
				
			||||||
 | 
					                open_test_pikerd() as (_, _, _, services),
 | 
				
			||||||
 | 
					            ):
 | 
				
			||||||
 | 
					                await match_ppmsgs_on_ems_boot([ppmsg])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        run_and_tollerate_cancels(just_check_pp)
 | 
				
			||||||
 | 
					 | 
				
			||||||
# def test_sell(
 | 
					 | 
				
			||||||
#     open_test_pikerd_and_ems: AsyncContextManager,
 | 
					 | 
				
			||||||
# ):
 | 
					 | 
				
			||||||
#     '''
 | 
					 | 
				
			||||||
#     Sell position and ensure pps are zeroed.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#     '''
 | 
					 | 
				
			||||||
#     _run_test_and_check(
 | 
					 | 
				
			||||||
#         partial(
 | 
					 | 
				
			||||||
#             _async_main,
 | 
					 | 
				
			||||||
#             open_test_pikerd_and_ems=open_test_pikerd_and_ems,
 | 
					 | 
				
			||||||
#             action='sell',
 | 
					 | 
				
			||||||
#             price=1,
 | 
					 | 
				
			||||||
#         ),
 | 
					 | 
				
			||||||
#     )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#     _run_test_and_check(
 | 
					 | 
				
			||||||
#         partial(
 | 
					 | 
				
			||||||
#             _async_main,
 | 
					 | 
				
			||||||
#             open_test_pikerd_and_ems=open_test_pikerd_and_ems,
 | 
					 | 
				
			||||||
#             assert_zeroed_pps=True,
 | 
					 | 
				
			||||||
#         ),
 | 
					 | 
				
			||||||
#     )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# def test_multi_sell(
 | 
					 | 
				
			||||||
#     open_test_pikerd_and_ems: AsyncContextManager,
 | 
					 | 
				
			||||||
# ):
 | 
					 | 
				
			||||||
#     '''
 | 
					 | 
				
			||||||
#     Make 5 market limit buy orders and
 | 
					 | 
				
			||||||
#     then sell 5 slots at the same price.
 | 
					 | 
				
			||||||
#     Finally, assert cleared positions.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#     '''
 | 
					 | 
				
			||||||
#     _run_test_and_check(
 | 
					 | 
				
			||||||
#         partial(
 | 
					 | 
				
			||||||
#             _async_main,
 | 
					 | 
				
			||||||
#             open_test_pikerd_and_ems=open_test_pikerd_and_ems,
 | 
					 | 
				
			||||||
#             action='buy',
 | 
					 | 
				
			||||||
#             executions=5,
 | 
					 | 
				
			||||||
#         ),
 | 
					 | 
				
			||||||
#     )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#     _run_test_and_check(
 | 
					 | 
				
			||||||
#         partial(
 | 
					 | 
				
			||||||
#             _async_main,
 | 
					 | 
				
			||||||
#             open_test_pikerd_and_ems=open_test_pikerd_and_ems,
 | 
					 | 
				
			||||||
#             action='sell',
 | 
					 | 
				
			||||||
#             executions=5,
 | 
					 | 
				
			||||||
#             price=1,
 | 
					 | 
				
			||||||
#             assert_zeroed_pps=True,
 | 
					 | 
				
			||||||
#         ),
 | 
					 | 
				
			||||||
#     )
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue