Exemple #1
0
  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 ""
Exemple #2
0
  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 ""
Exemple #3
0
  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 ""
Exemple #4
0
  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 ""
Exemple #5
0
    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": ""}'
                )
Exemple #6
0
  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": ""}'
Exemple #7
0
    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": ""}'