Merge pull request #410 from pikers/even_moar_kraken_order_fixes
Even moar `kraken` order fixesno_signal_pi_overlays
						commit
						2dac531729
					
				| 
						 | 
					@ -795,7 +795,7 @@ async def handle_order_updates(
 | 
				
			||||||
                    # 'vol_exec': exec_vlm}  # 0.0000
 | 
					                    # 'vol_exec': exec_vlm}  # 0.0000
 | 
				
			||||||
                    match update_msg:
 | 
					                    match update_msg:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        # EMS-unknown live order that needs to be
 | 
					                        # EMS-unknown LIVE order that needs to be
 | 
				
			||||||
                        # delivered and loaded on the client-side.
 | 
					                        # delivered and loaded on the client-side.
 | 
				
			||||||
                        case {
 | 
					                        case {
 | 
				
			||||||
                            'userref': reqid,
 | 
					                            'userref': reqid,
 | 
				
			||||||
| 
						 | 
					@ -849,7 +849,7 @@ async def handle_order_updates(
 | 
				
			||||||
                                ),
 | 
					                                ),
 | 
				
			||||||
                                src='kraken',
 | 
					                                src='kraken',
 | 
				
			||||||
                            )
 | 
					                            )
 | 
				
			||||||
                            apiflows[reqid].maps.append(status_msg)
 | 
					                            apiflows[reqid].maps.append(status_msg.to_dict())
 | 
				
			||||||
                            await ems_stream.send(status_msg)
 | 
					                            await ems_stream.send(status_msg)
 | 
				
			||||||
                            continue
 | 
					                            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1104,7 +1104,6 @@ async def handle_order_updates(
 | 
				
			||||||
                            'txid': [txid],
 | 
					                            'txid': [txid],
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
            case _:
 | 
					            case _:
 | 
				
			||||||
 | 
					 | 
				
			||||||
                log.warning(f'Unhandled trades update msg: {msg}')
 | 
					                log.warning(f'Unhandled trades update msg: {msg}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,6 +62,7 @@ class Pair(Struct):
 | 
				
			||||||
    lot: str  # volume lot size
 | 
					    lot: str  # volume lot size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cost_decimals: int
 | 
					    cost_decimals: int
 | 
				
			||||||
 | 
					    costmin: float
 | 
				
			||||||
    pair_decimals: int  # scaling decimal places for pair
 | 
					    pair_decimals: int  # scaling decimal places for pair
 | 
				
			||||||
    lot_decimals: int  # scaling decimal places for volume
 | 
					    lot_decimals: int  # scaling decimal places for volume
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,6 @@ from . import _paper_engine as paper
 | 
				
			||||||
from ._messages import (
 | 
					from ._messages import (
 | 
				
			||||||
    Order,
 | 
					    Order,
 | 
				
			||||||
    Status,
 | 
					    Status,
 | 
				
			||||||
    # Cancel,
 | 
					 | 
				
			||||||
    BrokerdCancel,
 | 
					    BrokerdCancel,
 | 
				
			||||||
    BrokerdOrder,
 | 
					    BrokerdOrder,
 | 
				
			||||||
    # BrokerdOrderAck,
 | 
					    # BrokerdOrderAck,
 | 
				
			||||||
| 
						 | 
					@ -581,6 +580,7 @@ class Router(Struct):
 | 
				
			||||||
        notify_on_headless: bool = True,
 | 
					        notify_on_headless: bool = True,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ) -> bool:
 | 
					    ) -> bool:
 | 
				
			||||||
 | 
					        # print(f'SUBSCRIBERS: {self.subscribers}')
 | 
				
			||||||
        to_remove: set[tractor.MsgStream] = set()
 | 
					        to_remove: set[tractor.MsgStream] = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if sub_key == 'all':
 | 
					        if sub_key == 'all':
 | 
				
			||||||
| 
						 | 
					@ -611,7 +611,8 @@ class Router(Struct):
 | 
				
			||||||
            and notify_on_headless
 | 
					            and notify_on_headless
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            log.info(
 | 
					            log.info(
 | 
				
			||||||
                'No clients attached, firing notification for {sub_key} msg:\n'
 | 
					                'No clients attached, '
 | 
				
			||||||
 | 
					                f'firing notification for {sub_key} msg:\n'
 | 
				
			||||||
                f'{msg}'
 | 
					                f'{msg}'
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            await notify_from_ems_status_msg(
 | 
					            await notify_from_ems_status_msg(
 | 
				
			||||||
| 
						 | 
					@ -741,12 +742,24 @@ async def translate_and_relay_brokerd_events(
 | 
				
			||||||
                    log.warning(f'Rx Ack for closed/unknown order?: {oid}')
 | 
					                    log.warning(f'Rx Ack for closed/unknown order?: {oid}')
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                req = status_msg.req
 | 
					                if status_msg.cancel_called:
 | 
				
			||||||
                if req and req.action == 'cancel':
 | 
					 | 
				
			||||||
                    # assign newly providerd broker backend request id
 | 
					                    # assign newly providerd broker backend request id
 | 
				
			||||||
                    # and tell broker to cancel immediately
 | 
					                    # and tell broker to cancel immediately
 | 
				
			||||||
                    status_msg.reqid = reqid
 | 
					                    status_msg.reqid = reqid
 | 
				
			||||||
                    await brokerd_trades_stream.send(req)
 | 
					
 | 
				
			||||||
 | 
					                    # NOTE: as per comment in cancel-request-block
 | 
				
			||||||
 | 
					                    # above: This is an ack to
 | 
				
			||||||
 | 
					                    # a client-already-cancelled order request so we
 | 
				
			||||||
 | 
					                    # must immediately send a cancel to the brokerd upon
 | 
				
			||||||
 | 
					                    # rx of this ACK.
 | 
				
			||||||
 | 
					                    await brokerd_trades_stream.send(
 | 
				
			||||||
 | 
					                        BrokerdCancel(
 | 
				
			||||||
 | 
					                            oid=oid,
 | 
				
			||||||
 | 
					                            reqid=reqid,
 | 
				
			||||||
 | 
					                            time_ns=time.time_ns(),
 | 
				
			||||||
 | 
					                            account=status_msg.req.account,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # 2. the order is now active and will be mirrored in
 | 
					                # 2. the order is now active and will be mirrored in
 | 
				
			||||||
                # our book -> registered as live flow
 | 
					                # our book -> registered as live flow
 | 
				
			||||||
| 
						 | 
					@ -763,8 +776,8 @@ async def translate_and_relay_brokerd_events(
 | 
				
			||||||
                'oid': oid,  # ems order-dialog id
 | 
					                'oid': oid,  # ems order-dialog id
 | 
				
			||||||
                'reqid': reqid,  # brokerd generated order-request id
 | 
					                'reqid': reqid,  # brokerd generated order-request id
 | 
				
			||||||
                'symbol': sym,
 | 
					                'symbol': sym,
 | 
				
			||||||
            } if status_msg := book._active.get(oid):
 | 
					            }:
 | 
				
			||||||
 | 
					                status_msg = book._active.get(oid)
 | 
				
			||||||
                msg = BrokerdError(**brokerd_msg)
 | 
					                msg = BrokerdError(**brokerd_msg)
 | 
				
			||||||
                log.error(fmsg)  # XXX make one when it's blank?
 | 
					                log.error(fmsg)  # XXX make one when it's blank?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -776,11 +789,21 @@ async def translate_and_relay_brokerd_events(
 | 
				
			||||||
                # about.  In most default situations, with composed orders
 | 
					                # about.  In most default situations, with composed orders
 | 
				
			||||||
                # (ex.  brackets), most brokers seem to use a oca policy.
 | 
					                # (ex.  brackets), most brokers seem to use a oca policy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # only relay to client side if we have an active
 | 
				
			||||||
 | 
					                # ongoing dialog
 | 
				
			||||||
 | 
					                if status_msg:
 | 
				
			||||||
                    status_msg.resp = 'error'
 | 
					                    status_msg.resp = 'error'
 | 
				
			||||||
                    status_msg.brokerd_msg = msg
 | 
					                    status_msg.brokerd_msg = msg
 | 
				
			||||||
                    book._active[oid] = status_msg
 | 
					                    book._active[oid] = status_msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                await router.client_broadcast(sym, status_msg)
 | 
					                    await router.client_broadcast(
 | 
				
			||||||
 | 
					                        status_msg.req.symbol,
 | 
				
			||||||
 | 
					                        status_msg,
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    log.error(f'Error for unknown order flow:\n{msg}')
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # BrokerdStatus
 | 
					            # BrokerdStatus
 | 
				
			||||||
            case {
 | 
					            case {
 | 
				
			||||||
| 
						 | 
					@ -1029,23 +1052,30 @@ async def process_client_order_cmds(
 | 
				
			||||||
        status = dark_book._active.get(oid)
 | 
					        status = dark_book._active.get(oid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        match cmd:
 | 
					        match cmd:
 | 
				
			||||||
            # existing live-broker order cancel
 | 
					            # existing LIVE CANCEL
 | 
				
			||||||
            case {
 | 
					            case {
 | 
				
			||||||
                'action': 'cancel',
 | 
					                'action': 'cancel',
 | 
				
			||||||
                'oid': oid,
 | 
					                'oid': oid,
 | 
				
			||||||
            } if (
 | 
					            } if (
 | 
				
			||||||
                status
 | 
					                status
 | 
				
			||||||
                and status.resp in ('open', 'pending')
 | 
					                and status.resp in (
 | 
				
			||||||
 | 
					                    'open',
 | 
				
			||||||
 | 
					                    'pending',
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                reqid = status.reqid
 | 
					                reqid = status.reqid
 | 
				
			||||||
                order = status.req
 | 
					                order = status.req
 | 
				
			||||||
                to_brokerd_msg = BrokerdCancel(
 | 
					
 | 
				
			||||||
                    oid=oid,
 | 
					                # XXX: cancelled-before-ack race case.
 | 
				
			||||||
                    reqid=reqid,
 | 
					                # This might be a cancel for an order that hasn't been
 | 
				
			||||||
                    time_ns=time.time_ns(),
 | 
					                # acked yet by a brokerd (so it's in the midst of being
 | 
				
			||||||
                    # account=live_entry.account,
 | 
					                # ``BrokerdAck``ed for submission but we don't have that
 | 
				
			||||||
                    account=order.account,
 | 
					                # confirmation response back yet). Set this client-side
 | 
				
			||||||
                )
 | 
					                # msg state so when the ack does show up (later)
 | 
				
			||||||
 | 
					                # logic in ``translate_and_relay_brokerd_events()`` can
 | 
				
			||||||
 | 
					                # forward the cancel request to the `brokerd` side of
 | 
				
			||||||
 | 
					                # the order flow ASAP.
 | 
				
			||||||
 | 
					                status.cancel_called = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # NOTE: cancel response will be relayed back in messages
 | 
					                # NOTE: cancel response will be relayed back in messages
 | 
				
			||||||
                # from corresponding broker
 | 
					                # from corresponding broker
 | 
				
			||||||
| 
						 | 
					@ -1054,17 +1084,16 @@ async def process_client_order_cmds(
 | 
				
			||||||
                    log.info(
 | 
					                    log.info(
 | 
				
			||||||
                        f'Submitting cancel for live order {reqid}'
 | 
					                        f'Submitting cancel for live order {reqid}'
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    await brokerd_order_stream.send(to_brokerd_msg)
 | 
					                    await brokerd_order_stream.send(
 | 
				
			||||||
 | 
					                        BrokerdCancel(
 | 
				
			||||||
 | 
					                            oid=oid,
 | 
				
			||||||
 | 
					                            reqid=reqid,
 | 
				
			||||||
 | 
					                            time_ns=time.time_ns(),
 | 
				
			||||||
 | 
					                            account=order.account,
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                else:
 | 
					            # DARK trigger CANCEL
 | 
				
			||||||
                    # this might be a cancel for an order that hasn't been
 | 
					 | 
				
			||||||
                    # acked yet by a brokerd, so register a cancel for when
 | 
					 | 
				
			||||||
                    # the order ack does show up later such that the brokerd
 | 
					 | 
				
			||||||
                    # order request can be cancelled at that time.
 | 
					 | 
				
			||||||
                    # special case for now..
 | 
					 | 
				
			||||||
                    status.req = to_brokerd_msg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # dark trigger cancel
 | 
					 | 
				
			||||||
            case {
 | 
					            case {
 | 
				
			||||||
                'action': 'cancel',
 | 
					                'action': 'cancel',
 | 
				
			||||||
                'oid': oid,
 | 
					                'oid': oid,
 | 
				
			||||||
| 
						 | 
					@ -1103,9 +1132,9 @@ async def process_client_order_cmds(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # TODO: eventually we should be receiving
 | 
					            # TODO: eventually we should be receiving
 | 
				
			||||||
            # this struct on the wire unpacked in a scoped protocol
 | 
					            # this struct on the wire unpacked in a scoped protocol
 | 
				
			||||||
            # setup with ``tractor``.
 | 
					            # setup with ``tractor`` using ``msgspec``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # live order submission
 | 
					            # LIVE order REQUEST
 | 
				
			||||||
            case {
 | 
					            case {
 | 
				
			||||||
                'oid': oid,
 | 
					                'oid': oid,
 | 
				
			||||||
                'symbol': fqsn,
 | 
					                'symbol': fqsn,
 | 
				
			||||||
| 
						 | 
					@ -1175,7 +1204,7 @@ async def process_client_order_cmds(
 | 
				
			||||||
                # that live order asap.
 | 
					                # that live order asap.
 | 
				
			||||||
                # dark_book._msgflows[oid].maps.insert(0, msg.to_dict())
 | 
					                # dark_book._msgflows[oid].maps.insert(0, msg.to_dict())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # dark-order / alert submission
 | 
					            # DARK-order / alert REQUEST
 | 
				
			||||||
            case {
 | 
					            case {
 | 
				
			||||||
                'oid': oid,
 | 
					                'oid': oid,
 | 
				
			||||||
                'symbol': fqsn,
 | 
					                'symbol': fqsn,
 | 
				
			||||||
| 
						 | 
					@ -1265,6 +1294,9 @@ async def process_client_order_cmds(
 | 
				
			||||||
                    status,
 | 
					                    status,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case _:
 | 
				
			||||||
 | 
					                log.warning(f'Rx UNHANDLED order request {cmd}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@acm
 | 
					@acm
 | 
				
			||||||
async def maybe_open_trade_relays(
 | 
					async def maybe_open_trade_relays(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,7 +143,7 @@ class Status(Struct):
 | 
				
			||||||
    # (eg. the Order/Cancel which causes this msg) and
 | 
					    # (eg. the Order/Cancel which causes this msg) and
 | 
				
			||||||
    # acts as a back-reference to the corresponding
 | 
					    # acts as a back-reference to the corresponding
 | 
				
			||||||
    # request message which was the source of this msg.
 | 
					    # request message which was the source of this msg.
 | 
				
			||||||
    req: Optional[Order | Cancel] = None
 | 
					    req: Order | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # XXX: better design/name here?
 | 
					    # XXX: better design/name here?
 | 
				
			||||||
    # flag that can be set to indicate a message for an order
 | 
					    # flag that can be set to indicate a message for an order
 | 
				
			||||||
| 
						 | 
					@ -152,6 +152,10 @@ class Status(Struct):
 | 
				
			||||||
    # might want to "track" using piker UIs/systems).
 | 
					    # might want to "track" using piker UIs/systems).
 | 
				
			||||||
    src: Optional[str] = None
 | 
					    src: Optional[str] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # set when a cancel request msg was set for this order flow dialog
 | 
				
			||||||
 | 
					    # but the brokerd dialog isn't yet in a cancelled state.
 | 
				
			||||||
 | 
					    cancel_called: bool = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # for relaying a boxed brokerd-dialog-side msg data "through" the
 | 
					    # for relaying a boxed brokerd-dialog-side msg data "through" the
 | 
				
			||||||
    # ems layer to clients.
 | 
					    # ems layer to clients.
 | 
				
			||||||
    brokerd_msg: dict = {}
 | 
					    brokerd_msg: dict = {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -293,7 +293,7 @@ class SettingsPane:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # don't log account "change" case since it'll be submitted
 | 
					            # don't log account "change" case since it'll be submitted
 | 
				
			||||||
            # on every mouse interaction.
 | 
					            # on every mouse interaction.
 | 
				
			||||||
            log.info(f'settings change: {key}: {value}')
 | 
					            log.runtime(f'settings change: {key}: {value}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # TODO: maybe return a diff of settings so if we can an error we
 | 
					        # TODO: maybe return a diff of settings so if we can an error we
 | 
				
			||||||
        # can have general input handling code to report it through the
 | 
					        # can have general input handling code to report it through the
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,6 +56,7 @@ from ._position import (
 | 
				
			||||||
from ._forms import FieldsForm
 | 
					from ._forms import FieldsForm
 | 
				
			||||||
from ._window import MultiStatus
 | 
					from ._window import MultiStatus
 | 
				
			||||||
from ..clearing._messages import (
 | 
					from ..clearing._messages import (
 | 
				
			||||||
 | 
					    # Cancel,
 | 
				
			||||||
    Order,
 | 
					    Order,
 | 
				
			||||||
    Status,
 | 
					    Status,
 | 
				
			||||||
    # BrokerdOrder,
 | 
					    # BrokerdOrder,
 | 
				
			||||||
| 
						 | 
					@ -961,15 +962,20 @@ async def process_trade_msg(
 | 
				
			||||||
    dialog: Dialog = mode.dialogs.get(oid)
 | 
					    dialog: Dialog = mode.dialogs.get(oid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    match msg:
 | 
					    match msg:
 | 
				
			||||||
        case Status(resp='dark_open' | 'open'):
 | 
					        case Status(
 | 
				
			||||||
 | 
					            resp='dark_open' | 'open',
 | 
				
			||||||
 | 
					        ) if msg.req['action'] != 'cancel':
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            order = Order(**msg.req)
 | 
					            order = Order(**msg.req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if dialog is not None:
 | 
					            if (
 | 
				
			||||||
 | 
					                dialog is not None
 | 
				
			||||||
 | 
					                and order.action != 'cancel'
 | 
				
			||||||
 | 
					            ):
 | 
				
			||||||
                # show line label once order is live
 | 
					                # show line label once order is live
 | 
				
			||||||
                mode.on_submit(oid, order=order)
 | 
					                mode.on_submit(oid, order=order)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            else:
 | 
					            elif order.action != 'cancel':
 | 
				
			||||||
                log.warning(
 | 
					                log.warning(
 | 
				
			||||||
                    f'received msg for untracked dialog:\n{fmsg}'
 | 
					                    f'received msg for untracked dialog:\n{fmsg}'
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
| 
						 | 
					@ -1005,12 +1011,12 @@ async def process_trade_msg(
 | 
				
			||||||
        case Status(resp='canceled'):
 | 
					        case Status(resp='canceled'):
 | 
				
			||||||
            # delete level line from view
 | 
					            # delete level line from view
 | 
				
			||||||
            mode.on_cancel(oid)
 | 
					            mode.on_cancel(oid)
 | 
				
			||||||
            req = Order(**msg.req)
 | 
					            action = msg.req["action"]
 | 
				
			||||||
            log.cancel(f'Canceled {req.action}:{oid}')
 | 
					            log.cancel(f'Canceled {action}:{oid}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case Status(
 | 
					        case Status(
 | 
				
			||||||
            resp='triggered',
 | 
					            resp='triggered',
 | 
				
			||||||
            # req=Order(exec_mode='dark')  # TODO:
 | 
					            # req=Order(exec_mode='dark')  # TODO: msgspec
 | 
				
			||||||
            req={'exec_mode': 'dark'},
 | 
					            req={'exec_mode': 'dark'},
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            # TODO: UX for a "pending" clear/live order
 | 
					            # TODO: UX for a "pending" clear/live order
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue