|
| 1 | +from datetime import datetime as dt |
| 2 | +import logging |
| 3 | +from threading import Timer |
| 4 | + |
| 5 | +from omega_client.messaging.common_types import AccountBalancesReport, \ |
| 6 | + AccountCredentials, AccountDataReport, AuthorizationGrant, \ |
| 7 | + AuthorizationRefresh, CompletedOrdersReport, ExchangePropertiesReport, \ |
| 8 | + ExecutionReport, LogoffAck, LogonAck, OpenPositionsReport, SystemMessage,\ |
| 9 | + WorkingOrdersReport |
| 10 | +from omega_client.messaging.response_handler import ResponseHandler |
| 11 | + |
| 12 | +logger = logging.getLogger(__name__) |
| 13 | + |
| 14 | + |
| 15 | +class SingleClientResponseHandler(ResponseHandler): |
| 16 | + ########################################################################### |
| 17 | + # # |
| 18 | + # ~~~~~~~~~~~~~~~~~~~~~~~~~ Incoming OmegaMessages ~~~~~~~~~~~~~~~~~~~~~~ # |
| 19 | + # # |
| 20 | + ########################################################################### |
| 21 | + def __init__(self, refresh_buffer_time: float = 30.): |
| 22 | + self._command_dispatcher = { |
| 23 | + 'heartbeat': self.on_heartbeat, |
| 24 | + 'test': self.on_test_message, |
| 25 | + 'serverTime': self.on_server_time, |
| 26 | + 'system': self.on_system_message, |
| 27 | + 'logonAck': self._on_logon_ack, |
| 28 | + 'logoffAck': self.on_logoff_ack, |
| 29 | + 'executionReport': self.on_exec_report, |
| 30 | + 'accountDataReport': self.on_account_data, |
| 31 | + 'workingOrdersReport': self.on_working_orders_report, |
| 32 | + 'accountBalancesReport': self.on_account_balances, |
| 33 | + 'openPositionsReport': self.on_open_positions, |
| 34 | + 'completedOrdersReport': self.on_completed_orders_report, |
| 35 | + 'exchangePropertiesReport': self.on_exchange_properties_report, |
| 36 | + 'authorizationGrant': self._on_authorization_grant |
| 37 | + } |
| 38 | + self._request_sender = None |
| 39 | + self._refresh_token = None |
| 40 | + self._REFRESH_BUFFER_TIME = refresh_buffer_time |
| 41 | + |
| 42 | + def set_request_sender(self, request_sender): |
| 43 | + self._request_sender = request_sender |
| 44 | + |
| 45 | + def _on_logon_ack(self, |
| 46 | + logon_ack: LogonAck, |
| 47 | + client_id: int, |
| 48 | + sender_comp_id: str, |
| 49 | + request_id: int): |
| 50 | + """ |
| 51 | + Internal |
| 52 | + :param logon_ack: (LogonAck) LogonAck message from Omega. |
| 53 | + :param client_id: (int) client_id of the response. |
| 54 | + :param sender_comp_id: (str) sender_comp_id of the response. |
| 55 | + :param request_id: (int) request_id which requested this response |
| 56 | + :return: |
| 57 | + """ |
| 58 | + if (logon_ack and logon_ack.success and logon_ack.authorization_grant |
| 59 | + and logon_ack.authorization_grant.success |
| 60 | + ): |
| 61 | + self._request_sender.set_access_token( |
| 62 | + logon_ack.authorization_grant.access_token) |
| 63 | + self._refresh_token = logon_ack.authorization_grant.refresh_token |
| 64 | + self._send_authorization_refresh() |
| 65 | + else: |
| 66 | + if not logon_ack.success: |
| 67 | + logger.error('logon_ack error: ', |
| 68 | + extra={'message': logon_ack.message}) |
| 69 | + if not logon_ack.authorization_grant.success: |
| 70 | + logger.error( |
| 71 | + 'authorization_grant error: ', |
| 72 | + extra={'message': logon_ack.authorization_grant.message}) |
| 73 | + self.on_logon_ack( |
| 74 | + logon_ack=logon_ack, |
| 75 | + client_id=client_id, |
| 76 | + sender_comp_id=sender_comp_id, |
| 77 | + request_id=request_id) |
| 78 | + |
| 79 | + def _on_authorization_grant(self, |
| 80 | + authorization_grant: AuthorizationGrant, |
| 81 | + client_id: int, |
| 82 | + sender_comp_id: str, |
| 83 | + request_id: int): |
| 84 | + """ |
| 85 | + Override in subclass to handle Omega AuthorizationGrant response. |
| 86 | + :param authorization_grant: AuthorizationGrant python object |
| 87 | + :param client_id: (int) client_id of the response. |
| 88 | + :param sender_comp_id: (str) sender_comp_id of the response. |
| 89 | + :param request_id: (int) request_id which requested this response |
| 90 | + """ |
| 91 | + if authorization_grant and authorization_grant.success: |
| 92 | + self._request_sender.set_access_token( |
| 93 | + authorization_grant.access_token) |
| 94 | + self._refresh_token = authorization_grant.refresh_token |
| 95 | + self._token_expire_time = authorization_grant.expire_at |
| 96 | + time_until_session_refresh = ( |
| 97 | + self._token_expire_time - dt.utcnow().timestamp() - |
| 98 | + self._REFRESH_BUFFER_TIME) |
| 99 | + Timer(time_until_session_refresh, |
| 100 | + self._send_authorization_refresh).start() |
| 101 | + else: |
| 102 | + if not authorization_grant.success: |
| 103 | + logger.error( |
| 104 | + 'authorization_grant error: ', |
| 105 | + extra={'message': authorization_grant.message}) |
| 106 | + self.on_authorization_grant( |
| 107 | + authorization_grant=authorization_grant, |
| 108 | + client_id=client_id, |
| 109 | + sender_comp_id=sender_comp_id, |
| 110 | + request_id=request_id) |
| 111 | + |
| 112 | + def _send_authorization_refresh(self): |
| 113 | + self._request_sender.request_authorization_refresh( |
| 114 | + auth_refresh=AuthorizationRefresh( |
| 115 | + refresh_token=self._refresh_token) |
| 116 | + ) |
0 commit comments