import base64 import os import zmq from zmq.eventloop.zmqstream import ZMQStream from message_builder import MessageBuilder from message import JsonMessage, InvalidMessageException class TradeClientException(Exception): def __init__(self, error_message, detail = None): self.error_message = error_message self.detail = None super(TradeClientException, self).__init__() def __str__(self): if self.detail: return self.error_message + '( detail:%s)'%self.detail return self.error_message class TradeClient(object): def __init__(self, zmq_context, trade_in_socket, trade_pub = None, reopen=True): self.zmq_context = zmq_context self.connection_id = None self.trade_in_socket = trade_in_socket self.is_logged = False self.user_id = None self.reopen = reopen self.trade_pub = trade_pub self.trade_pub_socket = None self.trade_pub_socket_stream = None if self.trade_pub: self.trade_pub_socket = self.zmq_context.socket(zmq.SUB) self.trade_pub_socket.connect(self.trade_pub) self.trade_pub_socket_stream = ZMQStream(self.trade_pub_socket) self.trade_pub_socket_stream.on_recv(self._on_trade_publish) def _on_trade_publish(self, message): self.on_trade_publish(message) def on_trade_publish(self, message): pass def connect(self): if not self.trade_pub_socket and self.trade_pub: self.trade_pub_socket = self.zmq_context.socket(zmq.SUB) self.trade_pub_socket.connect(self.trade_pub) self.trade_pub_socket_stream = ZMQStream(self.trade_pub_socket) self.trade_pub_socket_stream.on_recv(self._on_trade_publish) self.trade_in_socket.send( "OPN," + base64.b32encode(os.urandom(10))) response_message = self.trade_in_socket.recv() opt_code = response_message[:3] raw_message = response_message[4:] if opt_code != 'OPN': if opt_code == 'ERR': raise TradeClientException( error_message = raw_message ) raise TradeClientException( error_message = 'Protocol Error: Unknown message opt_code received' ) self.connection_id = raw_message def close(self): if self.trade_pub_socket_stream: self.trade_pub_socket_stream.close() self.trade_pub_socket_stream = None self.trade_pub_socket.close() self.trade_pub_socket = None if self.connection_id: self.trade_in_socket.send( "CLS," + self.connection_id ) response_message = self.trade_in_socket.recv() self.connection_id = None def isConnected(self): return self.connection_id is not None def getBrokerList(self, status_list): page = 0 page_size = 100 broker_list = [] columns = [] while True: res = self.sendJSON(MessageBuilder.getBrokerList( status_list, None, page, page_size )) columns = res.get('Columns') broker_list.extend(res.get('BrokerListGrp')) if len(res.get('BrokerListGrp')) < page_size: break page += 1 return broker_list, columns def getLastTrades(self, last_trade_id, page=0): if last_trade_id is None: last_trade_id = 1 rep_msg = self.sendJSON({ 'MsgType': 'U32', 'TradeHistoryReqID': -1, 'Page': page, 'PageSize': 100 }) result_list = [] if rep_msg.isTradeHistoryResponse(): last_processed = 0 trade_list = rep_msg.get('TradeHistoryGrp') if not trade_list : return result_list for trade in trade_list: if last_trade_id <= trade[0]: last_processed = trade[0] if last_processed != last_trade_id: result_list.append(trade) if last_processed != last_trade_id: return result_list + self.getLastTrades(last_trade_id, page+1) return result_list def getSecurityList(self): resp = self.sendJSON({ 'MsgType' : 'x', 'SecurityReqID': 'getSecurityList', 'SecurityListRequestType': 0}) return resp def sendString(self, string_msg): if not self.isConnected() and self.reopen: self.connect() self.trade_in_socket.send_unicode( "REQ," + self.connection_id + ',' + string_msg) response_message = self.trade_in_socket.recv() raw_resp_message_header = response_message[:3] raw_resp_message = response_message[4:].strip() rep_msg = None if raw_resp_message: try: rep_msg = JsonMessage(raw_resp_message) except Exception: pass if raw_resp_message_header == 'CLS' and rep_msg and not rep_msg.isErrorMessage(): self.close() if self.reopen: self.connect() return rep_msg if raw_resp_message_header != 'REP': self.close() if self.reopen: self.connect() if rep_msg and rep_msg.isErrorMessage(): raise TradeClientException(rep_msg.get('Description'), rep_msg.get('Detail')) raise TradeClientException('Invalid request: ' + raw_resp_message ) if rep_msg and rep_msg.isUserResponse(): if rep_msg.get("UserStatus") == 1: self.user_id = rep_msg.get("UserID") self.is_logged = True if self.trade_pub_socket: self.trade_pub_socket.setsockopt(zmq.SUBSCRIBE, '^' + str(self.user_id) + '$') return rep_msg def sendJSON(self, json_msg): import json return self.sendString(json.dumps(json_msg)) def sendMessage(self, msg): return self.sendString(msg.raw_message)