def cancel(self, session, order): if not order: # Generate an Order Cancel Reject - Order not found return # let's find the order position self_side = [] if order.is_buy: self_side = self.buy_side elif order.is_sell: self_side = self.sell_side order_found = False order_pos = bisect.bisect_left(self_side, order) for x in xrange( order_pos, len(self_side)): tmp_order = self_side[x] if tmp_order.id == order.id: order_found = True break if tmp_order.price != order.price: break order_pos += 1 if not order_found: # Generate an Order Cancel Reject - Order not found return # update the order order.cancel_qty( order.leaves_qty ) session.commit() # remove the order from the book self_side.pop( order_pos ) # Generate a cancel report cancel_rpt = ExecutionReport( order, '1' if order.is_buy else '2' ) TradeApplication.instance().publish(order.user_id, cancel_rpt.toJson() ) if order.user_id != order.account_id: TradeApplication.instance().publish(order.account_id, cancel_rpt.toJson() ) # market data md_entry_type = '0' if order.is_buy else '1' MarketDataPublisher.publish_cancel_order( self.symbol, md_entry_type, order_pos+1 ) return ""
def match(self, session, order, order_matcher_disabled=False): other_side = [] self_side = [] if order.is_buy: self_side = self.buy_side other_side = self.sell_side elif order.is_sell: other_side = self.buy_side self_side = self.sell_side execution_reports = [] trades_to_publish = [] execution_side = '1' if order.is_buy else '2' rpt_order = ExecutionReport( order, execution_side ) execution_reports.append( ( order.user_id, rpt_order.toJson() ) ) if order.user_id != order.account_id: execution_reports.append( ( order.account_id, rpt_order.toJson() ) ) is_last_match_a_partial_execution_on_counter_order = False execution_counter = 0 number_of_filled_counter_market_orders = 0 if not order_matcher_disabled: for execution_counter in xrange(0, len(other_side) + 1): if execution_counter == len(other_side): break # workaround to make the execution_counter be counted until the last order. if not order.leaves_qty > 0: break counter_order = other_side[execution_counter] if not order.has_match(counter_order): break # check for self execution if order.account_id == counter_order.account_id: # self execution.... let's cancel the counter order counter_order.cancel_qty( counter_order.leaves_qty ) # generate a cancel report cancel_rpt_counter_order = ExecutionReport( counter_order, execution_side ) execution_reports.append( ( counter_order.user_id, cancel_rpt_counter_order.toJson() ) ) if counter_order.user_id != counter_order.account_id: execution_reports.append( ( counter_order.account_id, cancel_rpt_counter_order.toJson() ) ) # go to the next order is_last_match_a_partial_execution_on_counter_order = False continue # Get the desired executed price and qty, by matching against the counter_order executed_qty = order.match( counter_order, order.leaves_qty) if counter_order.type == '1': # Market Order executed_price = order.price number_of_filled_counter_market_orders += 1 else: executed_price = counter_order.price # let's get the available qty to execute on the order side available_qty_on_order_side = order.get_available_qty_to_execute(session, '1' if order.is_buy else '2', executed_qty, executed_price ) qty_to_cancel_from_order = 0 if available_qty_on_order_side < executed_qty: # ops ... looks like the order.user didn't have enough to execute the order executed_qty = available_qty_on_order_side # cancel the remaining qty qty_to_cancel_from_order = order.leaves_qty - executed_qty # check if the order got fully cancelled if not executed_qty: order.cancel_qty( qty_to_cancel_from_order ) cancel_rpt_order = ExecutionReport( order, execution_side ) execution_reports.append( ( order.user_id, cancel_rpt_order.toJson() ) ) if order.user_id != order.account_id: execution_reports.append( ( order.account_id, cancel_rpt_order.toJson() ) ) break # let's get the available qty to execute on the counter side available_qty_on_counter_side = counter_order.get_available_qty_to_execute(session, '1' if counter_order.is_buy else '2', executed_qty, executed_price ) qty_to_cancel_from_counter_order = 0 if available_qty_on_counter_side < executed_qty: if qty_to_cancel_from_order: qty_to_cancel_from_order -= executed_qty - available_qty_on_order_side # ops ... looks like the counter_order.user didn't have enough to execute the order executed_qty = available_qty_on_counter_side # cancel the remaining qty qty_to_cancel_from_counter_order = counter_order.leaves_qty - executed_qty # check if the counter order was fully cancelled due the lack if not executed_qty: # just cancel the counter order, and go to the next order. counter_order.cancel_qty( qty_to_cancel_from_counter_order ) # generate a cancel report cancel_rpt_counter_order = ExecutionReport( counter_order, execution_side ) execution_reports.append( ( counter_order.user_id, cancel_rpt_counter_order.toJson() ) ) if counter_order.user_id != counter_order.account_id: execution_reports.append( ( counter_order.account_id, cancel_rpt_counter_order.toJson() ) ) # go to the next order is_last_match_a_partial_execution_on_counter_order = False continue # lets perform the execution if executed_qty: order.execute( executed_qty, executed_price ) counter_order.execute(executed_qty, executed_price ) trade = Trade.create(session, order, counter_order, self.symbol, executed_qty, executed_price ) trades_to_publish.append(trade) rpt_order = ExecutionReport( order, execution_side ) execution_reports.append( ( order.user_id, rpt_order.toJson() ) ) if order.user_id != order.account_id: execution_reports.append( ( order.account_id, rpt_order.toJson() ) ) rpt_counter_order = ExecutionReport( counter_order, execution_side ) execution_reports.append( ( counter_order.user_id, rpt_counter_order.toJson() ) ) if counter_order.user_id != counter_order.account_id: execution_reports.append( ( counter_order.account_id, rpt_counter_order.toJson() ) ) def generate_email_subject_and_body( session, order, trade ): from json import dumps from pyblinktrade.json_encoder import JsonEncoder from models import Currency qty_currency = order.symbol[:3] formatted_qty = Currency.format_number( session, qty_currency, trade.size / 1.e8 ) price_currency = order.symbol[3:] formatted_price = Currency.format_number( session, price_currency, trade.price / 1.e8 ) formatted_total_price = Currency.format_number( session, price_currency, trade.size/1.e8 * trade.price/1.e8 ) email_subject = 'E' email_template = "order-execution" email_params = { 'username': order.user.username, 'order_id': order.id, 'trade_id': trade.id, 'side': order.side, 'executed_when': trade.created, 'qty': formatted_qty, 'price': formatted_price, 'total': formatted_total_price } return email_subject, email_template, dumps(email_params, cls=JsonEncoder) email_data = generate_email_subject_and_body(session, order, trade) UserEmail.create( session = session, user_id = order.account_id, broker_id = order.broker_id, subject = email_data[0], template= email_data[1], language= order.email_lang, params = email_data[2]) email_data = generate_email_subject_and_body(session, counter_order, trade) UserEmail.create( session = session, user_id = counter_order.account_id, broker_id = counter_order.broker_id, subject = email_data[0], template= email_data[1], language= counter_order.email_lang, params = email_data[2]) # # let's do the partial cancels # # Cancel the qty from the current order if qty_to_cancel_from_order: order.cancel_qty(qty_to_cancel_from_order) # generate a cancel report cancel_rpt_order = ExecutionReport( order, execution_side ) execution_reports.append( ( order.user_id, cancel_rpt_order.toJson() ) ) if order.user_id != order.account_id: execution_reports.append( ( order.account_id, cancel_rpt_order.toJson() ) ) if qty_to_cancel_from_counter_order: counter_order.cancel_qty(qty_to_cancel_from_counter_order) # generate a cancel report cancel_rpt_counter_order = ExecutionReport( counter_order, execution_side ) execution_reports.append( ( counter_order.user_id, cancel_rpt_counter_order.toJson() ) ) if counter_order.user_id != counter_order.account_id: execution_reports.append( ( counter_order.account_id, cancel_rpt_counter_order.toJson() ) ) if counter_order.leaves_qty > 0: is_last_match_a_partial_execution_on_counter_order = True md_entry_type = '0' if order.is_buy else '1' counter_md_entry_type = '1' if order.is_buy else '0' # let's include the order in the book if the order is not fully executed. if order.leaves_qty > 0: insert_pos = bisect.bisect_right(self_side, order) self_side.insert( insert_pos, order ) if order.type == '2': # Limited orders go to the book. MarketDataPublisher.publish_new_order( self.symbol, md_entry_type , insert_pos, order) # don't send the first execution report (NEW) if the order was fully cancelled if order.is_cancelled and order.cum_qty == 0: execution_reports.pop(0) # Publish all execution reports for user_id, execution_report in execution_reports: TradeApplication.instance().publish( user_id, execution_report ) # Publish Market Data for the counter order if execution_counter: if is_last_match_a_partial_execution_on_counter_order: del other_side[0: execution_counter-1] MarketDataPublisher.publish_executions( self.symbol, counter_md_entry_type, execution_counter - 1 - number_of_filled_counter_market_orders, other_side[0] ) else: del other_side[0: execution_counter] MarketDataPublisher.publish_executions( self.symbol, counter_md_entry_type, execution_counter - number_of_filled_counter_market_orders ) if trades_to_publish: MarketDataPublisher.publish_trades(self.symbol, trades_to_publish) return ""
def match(self, session, order, order_matcher_disabled=False): other_side = [] self_side = [] if order.is_buy: self_side = self.buy_side other_side = self.sell_side elif order.is_sell: other_side = self.buy_side self_side = self.sell_side execution_reports = [] trades_to_publish = [] execution_side = '1' if order.is_buy else '2' rpt_order = ExecutionReport( order, execution_side ) execution_reports.append( ( order.user_id, rpt_order.toJson() ) ) if order.user_id != order.account_id: execution_reports.append( ( order.account_id, rpt_order.toJson() ) ) is_last_match_a_partial_execution_on_counter_order = False execution_counter = 0 number_of_filled_counter_market_orders = 0 if not order_matcher_disabled: for execution_counter in xrange(0, len(other_side) + 1): if execution_counter == len(other_side): break # workaround to make the execution_counter be counted until the last order. if not order.leaves_qty > 0: break counter_order = other_side[execution_counter] if not order.has_match(counter_order): break # check for self execution if order.account_id == counter_order.account_id: # self execution.... let's cancel the counter order counter_order.cancel_qty( counter_order.leaves_qty ) # generate a cancel report cancel_rpt_counter_order = ExecutionReport( counter_order, execution_side ) execution_reports.append( ( counter_order.user_id, cancel_rpt_counter_order.toJson() ) ) if counter_order.user_id != counter_order.account_id: execution_reports.append( ( counter_order.account_id, cancel_rpt_counter_order.toJson() ) ) # go to the next order is_last_match_a_partial_execution_on_counter_order = False continue # Get the desired executed price and qty, by matching against the counter_order executed_qty = order.match( counter_order, order.leaves_qty) if counter_order.type == '1': # Market Order executed_price = order.price number_of_filled_counter_market_orders += 1 else: executed_price = counter_order.price # let's get the available qty to execute on the order side available_qty_on_order_side = order.get_available_qty_to_execute(session, '1' if order.is_buy else '2', executed_qty, executed_price ) qty_to_cancel_from_order = 0 if available_qty_on_order_side < executed_qty: # ops ... looks like the order.user didn't have enough to execute the order executed_qty = available_qty_on_order_side # cancel the remaining qty qty_to_cancel_from_order = order.leaves_qty - executed_qty # check if the order got fully cancelled if not executed_qty: order.cancel_qty( qty_to_cancel_from_order ) cancel_rpt_order = ExecutionReport( order, execution_side ) execution_reports.append( ( order.user_id, cancel_rpt_order.toJson() ) ) if order.user_id != order.account_id: execution_reports.append( ( order.account_id, cancel_rpt_order.toJson() ) ) break # let's get the available qty to execute on the counter side available_qty_on_counter_side = counter_order.get_available_qty_to_execute(session, '1' if counter_order.is_buy else '2', executed_qty, executed_price ) qty_to_cancel_from_counter_order = 0 if available_qty_on_counter_side < executed_qty: if qty_to_cancel_from_order: qty_to_cancel_from_order -= executed_qty - available_qty_on_order_side # ops ... looks like the counter_order.user didn't have enough to execute the order executed_qty = available_qty_on_counter_side # cancel the remaining qty qty_to_cancel_from_counter_order = counter_order.leaves_qty - executed_qty # check if the counter order was fully cancelled due the lack if not executed_qty: # just cancel the counter order, and go to the next order. counter_order.cancel_qty( qty_to_cancel_from_counter_order ) # generate a cancel report cancel_rpt_counter_order = ExecutionReport( counter_order, execution_side ) execution_reports.append( ( counter_order.user_id, cancel_rpt_counter_order.toJson() ) ) if counter_order.user_id != counter_order.account_id: execution_reports.append( ( counter_order.account_id, cancel_rpt_counter_order.toJson() ) ) # go to the next order is_last_match_a_partial_execution_on_counter_order = False continue # lets perform the execution if executed_qty: order.execute( executed_qty, executed_price ) counter_order.execute(executed_qty, executed_price ) trade = Trade.create(session, order, counter_order, self.symbol, executed_qty, executed_price ) trades_to_publish.append(trade) rpt_order = ExecutionReport( order, execution_side ) execution_reports.append( ( order.user_id, rpt_order.toJson() ) ) if order.user_id != order.account_id: execution_reports.append( ( order.account_id, rpt_order.toJson() ) ) rpt_counter_order = ExecutionReport( counter_order, execution_side ) execution_reports.append( ( counter_order.user_id, rpt_counter_order.toJson() ) ) if counter_order.user_id != counter_order.account_id: execution_reports.append( ( counter_order.account_id, rpt_counter_order.toJson() ) ) def generate_email_subject_and_body( session, order, trade ): from json import dumps from pyblinktrade.json_encoder import JsonEncoder from models import Currency qty_currency = order.symbol[:3] formatted_qty = Currency.format_number( session, qty_currency, trade.size / 1.e8 ) price_currency = order.symbol[3:] formatted_price = Currency.format_number( session, price_currency, trade.price / 1.e8 ) formatted_total_price = Currency.format_number( session, price_currency, trade.size/1.e8 * trade.price/1.e8 ) email_subject = 'E' email_template = "order-execution" email_params = { 'username': order.user.username, 'order_id': order.id, 'trade_id': trade.id, 'side': order.side, 'executed_when': trade.created, 'qty': formatted_qty, 'price': formatted_price, 'total': formatted_total_price } return email_subject, email_template, dumps(email_params, cls=JsonEncoder) email_data = generate_email_subject_and_body(session, counter_order, trade) UserEmail.create( session = session, user_id = counter_order.account_id, broker_id = counter_order.broker_id, subject = email_data[0], template= email_data[1], language= counter_order.email_lang, params = email_data[2]) # # let's do the partial cancels # # Cancel the qty from the current order if qty_to_cancel_from_order: order.cancel_qty(qty_to_cancel_from_order) # generate a cancel report cancel_rpt_order = ExecutionReport( order, execution_side ) execution_reports.append( ( order.user_id, cancel_rpt_order.toJson() ) ) if order.user_id != order.account_id: execution_reports.append( ( order.account_id, cancel_rpt_order.toJson() ) ) if qty_to_cancel_from_counter_order: counter_order.cancel_qty(qty_to_cancel_from_counter_order) # generate a cancel report cancel_rpt_counter_order = ExecutionReport( counter_order, execution_side ) execution_reports.append( ( counter_order.user_id, cancel_rpt_counter_order.toJson() ) ) if counter_order.user_id != counter_order.account_id: execution_reports.append( ( counter_order.account_id, cancel_rpt_counter_order.toJson() ) ) if counter_order.leaves_qty > 0: is_last_match_a_partial_execution_on_counter_order = True md_entry_type = '0' if order.is_buy else '1' counter_md_entry_type = '1' if order.is_buy else '0' # let's include the order in the book if the order is not fully executed. if order.leaves_qty > 0: insert_pos = bisect.bisect_right(self_side, order) self_side.insert( insert_pos, order ) if order.type == '2': # Limited orders go to the book. MarketDataPublisher.publish_new_order( self.symbol, md_entry_type , insert_pos, order) # don't send the first execution report (NEW) if the order was fully cancelled if order.is_cancelled and order.cum_qty == 0: execution_reports.pop(0) # Publish all execution reports for user_id, execution_report in execution_reports: TradeApplication.instance().publish( user_id, execution_report ) # Publish Market Data for the counter order if execution_counter: if is_last_match_a_partial_execution_on_counter_order: del other_side[0: execution_counter-1] MarketDataPublisher.publish_executions( self.symbol, counter_md_entry_type, execution_counter - 1 - number_of_filled_counter_market_orders, other_side[0] ) else: del other_side[0: execution_counter] MarketDataPublisher.publish_executions( self.symbol, counter_md_entry_type, execution_counter - number_of_filled_counter_market_orders ) if trades_to_publish: MarketDataPublisher.publish_trades(self.symbol, trades_to_publish) return ""
def run(self): from pyblinktrade.message import JsonMessage, InvalidMessageException from market_data_publisher import MarketDataPublisher from execution import OrderMatcher from models import Order orders = self.db_session.query(Order).filter(Order.status.in_(("0", "1"))).order_by(Order.created) for order in orders: OrderMatcher.get(order.symbol).match(self.db_session, order, self.order_matcher_disabled) while True: raw_message = self.input_socket.recv() msg_header = raw_message[:3] session_id = raw_message[4:20] json_raw_message = raw_message[21:].strip() try: msg = None if json_raw_message: try: msg = JsonMessage(json_raw_message) except InvalidMessageException, e: self.log("IN", "TRADE_IN_REQ_ERROR", raw_message) raise InvalidMessageError() # never write passwords in the log file if msg.has("Password"): raw_message = raw_message.replace(msg.get("Password"), "*") if msg.has("NewPassword"): raw_message = raw_message.replace(msg.get("NewPassword"), "*") self.log("IN", "TRADE_IN_REQ", raw_message) if msg: if msg.isMarketDataRequest(): # Market Data Request req_id = msg.get("MDReqID") market_depth = msg.get("MarketDepth") instruments = msg.get("Instruments") entries = msg.get("MDEntryTypes") transact_time = msg.get("TransactTime") timestamp = None if transact_time: timestamp = transact_time else: trade_date = msg.get("TradeDate") if not trade_date: trade_date = time.strftime("%Y%m%d", time.localtime()) self.log("OUT", "TRADEDATE", trade_date) timestamp = datetime.datetime.strptime(trade_date, "%Y%m%d") self.log("OUT", "TIMESTAMP", timestamp) if len(instruments) > 1: raise InvalidMessageError() instrument = instruments[0] om = OrderMatcher.get(instrument) response_message = MarketDataPublisher.generate_md_full_refresh( self.db_session, instrument, market_depth, om, entries, req_id, timestamp ) response_message = "REP," + json.dumps(response_message, cls=JsonEncoder) elif msg.isTradeHistoryRequest(): page = msg.get("Page", 0) page_size = msg.get("PageSize", 100) offset = page * page_size columns = [ "TradeID", "Market", "Side", "Price", "Size", "BuyerID", "SellerID", "BuyerUsername", "SellerUsername", "Created", "OrderId", "CounterOrderID", ] trade_list = MarketDataPublisher.generate_trade_history(self.db_session, page_size, offset) response_message = "REP," + json.dumps( { "MsgType": "U33", # TradeHistoryResponse "TradeHistoryReqID": -1, "Page": page, "PageSize": page_size, "Columns": columns, "TradeHistoryGrp": trade_list, }, cls=JsonEncoder, ) else: response_message = self.session_manager.process_message(msg_header, session_id, msg) else: response_message = self.session_manager.process_message(msg_header, session_id, msg) except TradeRuntimeError, e: self.db_session.rollback() self.session_manager.close_session(session_id) response_message = ( 'ERR,{"MsgType":"ERROR", "Description":"' + e.error_description.replace("'", "") + '", "Detail": ""}' )
def run(self): from bitex.message import JsonMessage, InvalidMessageException from market_data_publisher import MarketDataPublisher from execution import OrderMatcher from models import Order orders = self.db_session.query(Order).filter(Order.status.in_(("0", "1"))).order_by(Order.created) for order in orders: OrderMatcher.get( order.symbol ).match(self.db_session, order) while True: raw_message = self.input_socket.recv() msg_header = raw_message[:3] session_id = raw_message[4:20] json_raw_message = raw_message[21:].strip() try: msg = None if json_raw_message: try: msg = JsonMessage(json_raw_message) except InvalidMessageException, e: self.log('IN', 'TRADE_IN_REQ_ERROR', raw_message) raise InvalidMessageError() # never write passwords in the log file if msg.has('Password'): raw_message = raw_message.replace(msg.get('Password'), '*') if msg.has('NewPassword'): raw_message = raw_message.replace(msg.get('NewPassword'), '*') self.log('IN', 'TRADE_IN_REQ' ,raw_message ) if msg: if msg.isMarketDataRequest(): # Market Data Request req_id = msg.get('MDReqID') market_depth = msg.get('MarketDepth') instruments = msg.get('Instruments') entries = msg.get('MDEntryTypes') transact_time = msg.get('TransactTime') timestamp = None if transact_time: timestamp = transact_time else: trade_date = msg.get('TradeDate') if not trade_date: trade_date = time.strftime("%Y%m%d", time.localtime()) self.log('OUT', 'TRADEDATE', trade_date) timestamp = datetime.datetime.strptime(trade_date, "%Y%m%d") self.log('OUT', 'TIMESTAMP', timestamp ) if len(instruments) > 1: raise InvalidMessageError() instrument = instruments[0] om = OrderMatcher.get(instrument) response_message = MarketDataPublisher.generate_md_full_refresh( application.db_session, instrument, market_depth, om, entries, req_id, timestamp ) response_message = 'REP,' + json.dumps( response_message , cls=JsonEncoder) elif msg.isTradeHistoryRequest(): page = msg.get('Page', 0) page_size = msg.get('PageSize', 100) offset = page * page_size columns = [ 'TradeID' , 'Market', 'Side', 'Price', 'Size', 'Buyer' , 'Seller', 'Created' ] trade_list = MarketDataPublisher.generate_trade_history(application.db_session, page_size, offset ) response_message = 'REP,' + json.dumps( { 'MsgType' : 'U33', # TradeHistoryResponse 'TradeHistoryReqID' : -1, 'Page' : page, 'PageSize' : page_size, 'Columns' : columns, 'TradeHistoryGrp' : trade_list }, cls=JsonEncoder ) else: response_message = self.session_manager.process_message( msg_header, session_id, msg ) else: response_message = self.session_manager.process_message( msg_header, session_id, msg ) except TradeRuntimeError, e: self.db_session.rollback() self.session_manager.close_session(session_id) response_message = 'ERR,{"MsgType":"ERROR", "Description":"' + e.error_description.replace("'", "") + '", "Detail": ""}'
def run(self): from message import JsonMessage, InvalidMessageException from market_data_publisher import MarketDataPublisher from execution import OrderMatcher from models import Order orders = self.db_session.query(Order).filter( Order.status.in_(("0", "1"))).order_by(Order.created) for order in orders: OrderMatcher.get(order.symbol).match(self.db_session, order, self.order_matcher_disabled) while True: raw_message = self.input_socket.recv() msg_header = raw_message[:3] session_id = raw_message[4:20] json_raw_message = raw_message[21:].strip() try: msg = None if json_raw_message: try: msg = JsonMessage(json_raw_message) except InvalidMessageException, e: self.log('IN', 'TRADE_IN_REQ_ERROR', raw_message) raise InvalidMessageError() # never write passwords in the log file if msg.has('Password'): raw_message = raw_message.replace( msg.get('Password'), '*') if msg.has('NewPassword'): raw_message = raw_message.replace( msg.get('NewPassword'), '*') self.log('IN', 'TRADE_IN_REQ', raw_message) if msg: if msg.isMarketDataRequest(): # Market Data Request req_id = msg.get('MDReqID') market_depth = msg.get('MarketDepth') instruments = msg.get('Instruments') entries = msg.get('MDEntryTypes') transact_time = msg.get('TransactTime') timestamp = None if transact_time: timestamp = transact_time else: trade_date = msg.get('TradeDate') if not trade_date: trade_date = time.strftime( "%Y%m%d", time.localtime()) self.log('OUT', 'TRADEDATE', trade_date) timestamp = datetime.datetime.strptime( trade_date, "%Y%m%d") self.log('OUT', 'TIMESTAMP', timestamp) if len(instruments) > 1: raise InvalidMessageError() instrument = instruments[0] om = OrderMatcher.get(instrument) response_message = MarketDataPublisher.generate_md_full_refresh( self.db_session, instrument, market_depth, om, entries, req_id, timestamp) response_message = 'REP,' + json.dumps( response_message, cls=JsonEncoder) elif msg.isTradeHistoryRequest(): page = msg.get('Page', 0) page_size = msg.get('PageSize', 100) offset = page * page_size columns = [ 'TradeID', 'Market', 'Side', 'Price', 'Size', 'BuyerID', 'SellerID', 'BuyerUsername', 'SellerUsername', 'Created', 'OrderId', 'CounterOrderID' ] trade_list = MarketDataPublisher.generate_trade_history( self.db_session, page_size, offset) response_message = 'REP,' + json.dumps( { 'MsgType': 'U33', # TradeHistoryResponse 'TradeHistoryReqID': -1, 'Page': page, 'PageSize': page_size, 'Columns': columns, 'TradeHistoryGrp': trade_list }, cls=JsonEncoder) else: response_message = self.session_manager.process_message( msg_header, session_id, msg) else: response_message = self.session_manager.process_message( msg_header, session_id, msg) except TradeRuntimeError, e: self.db_session.rollback() self.session_manager.close_session(session_id) response_message = 'ERR,{"MsgType":"ERROR", "Description":"' + e.error_description.replace( "'", "") + '", "Detail": ""}'