コード例 #1
0
  def publish_executions(symbol, entry_type, executed_count, order = None):
    entry_list = []

    if executed_count:
      entry_list.append( {
        "MDUpdateAction":"3",  # Delete Thru
        "Symbol": symbol,
        "MDEntryType": entry_type,
        "MDEntryPositionNo": executed_count,
        })

    if order:
      entry_list.append( {
        "MDUpdateAction":"1",  # Update
        "Symbol": symbol,
        "MDEntryType": entry_type,
        "MDEntryPositionNo": 1,
        "MDEntryID": order.id,
        "MDEntryPx": order.price,
        "MDEntrySize": order.leaves_qty,
        "MDEntryDate": order.created.date(),
        "MDEntryTime": order.created.time(),
        "OrderID": order.id,
        "Username": order.account_username,
        "Broker": order.broker_username
      })
    if entry_list:
      md = {
        "MsgType":"X",
        "MDBkTyp": '3', # Order Depth
        "MDIncGrp": entry_list
      }
      application.publish( 'MD_INCREMENTAL_' + symbol + '.' + entry_type , md )
コード例 #2
0
    def publish_executions(symbol, entry_type, executed_count, order=None):
        entry_list = []

        if executed_count:
            entry_list.append({
                "MDUpdateAction": "3",  # Delete Thru
                "Symbol": symbol,
                "MDEntryType": entry_type,
                "MDEntryPositionNo": executed_count,
            })

        if order:
            entry_list.append({
                "MDUpdateAction": "1",  # Update
                "Symbol": symbol,
                "MDEntryType": entry_type,
                "MDEntryPositionNo": 1,
                "MDEntryID": order.id,
                "MDEntryPx": order.price,
                "MDEntrySize": order.leaves_qty,
                "MDEntryDate": order.created.date(),
                "MDEntryTime": order.created.time(),
                "OrderID": order.id,
                "Username": order.account_username,
                "Broker": order.broker_username
            })
        if entry_list:
            md = {
                "MsgType": "X",
                "MDBkTyp": '3',  # Order Depth
                "MDIncGrp": entry_list
            }
            application.publish('MD_INCREMENTAL_' + symbol + '.' + entry_type,
                                md)
コード例 #3
0
ファイル: execution.py プロジェクト: Anderson-Juhasc/bitex
  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' )
    application.publish(order.user_id, cancel_rpt.toJson() )

    if order.user_id != order.account_id:
      application.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 ""
コード例 #4
0
  def publish_cancel_order(symbol, entry_type, order_position ):

    md = {
      "MsgType":"X",
      "MDBkTyp": '3', # Order Depth
      "MDIncGrp": [{
        "MDUpdateAction":"2",  # Delete
        "Symbol": symbol,
        "MDEntryType": entry_type,
        "MDEntryPositionNo": order_position,
        }]
    }
    application.publish( 'MD_INCREMENTAL_' + symbol + '.' + entry_type , md )
コード例 #5
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')
        application.publish(order.user_id, cancel_rpt.toJson())

        if order.user_id != order.account_id:
            application.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 ""
コード例 #6
0
    def publish_cancel_order(symbol, entry_type, order_position):

        md = {
            "MsgType":
            "X",
            "MDBkTyp":
            '3',  # Order Depth
            "MDIncGrp": [{
                "MDUpdateAction": "2",  # Delete
                "Symbol": symbol,
                "MDEntryType": entry_type,
                "MDEntryPositionNo": order_position,
            }]
        }
        application.publish('MD_INCREMENTAL_' + symbol + '.' + entry_type, md)
コード例 #7
0
    def generate_md_full_refresh(session, symbol, market_depth, om, entries,
                                 req_id, timestamp):
        entry_list = []

        for entry_type in entries:
            if entry_type == '0' or entry_type == '1':
                if entry_type == '0':  # Bid
                    orders = om.buy_side
                else:  # Offer
                    orders = om.sell_side

                entry_position = 0
                for order in orders:
                    if order.type == '1':  # Hide the market orders
                        continue

                    entry_position += 1

                    entry_list.append({
                        "MDEntryType": entry_type,
                        "MDEntryPositionNo": entry_position,
                        "MDEntryID": order.id,
                        "MDEntryPx": order.price,
                        "MDEntrySize": order.leaves_qty,
                        "MDEntryDate": order.created.date(),
                        "MDEntryTime": order.created.time(),
                        "OrderID": order.id,
                        "Username": order.account_username,
                        "Broker": order.broker_username
                    })

                    if entry_position >= market_depth > 0:
                        break

        md = {
            "MsgType": "W",
            "MDReqID": req_id,
            "MarketDepth": market_depth,
            "Symbol": symbol,
            "MDFullGrp": entry_list
        }
        application.publish('MD_FULL_REFRESH_' + symbol, md)

        return md
コード例 #8
0
  def generate_md_full_refresh( session, symbol, market_depth, om, entries, req_id, timestamp  ):
    entry_list = []

    for entry_type in entries:
      if entry_type == '0' or entry_type == '1':
        if entry_type == '0': # Bid
          orders = om.buy_side
        else: # Offer
          orders = om.sell_side

        entry_position = 0
        for order in orders:
          if order.type == '1': # Hide the market orders
            continue

          entry_position += 1

          entry_list.append( {
            "MDEntryType": entry_type,
            "MDEntryPositionNo": entry_position,
            "MDEntryID": order.id,
            "MDEntryPx": order.price,
            "MDEntrySize": order.leaves_qty,
            "MDEntryDate": order.created.date(),
            "MDEntryTime": order.created.time(),
            "OrderID": order.id,
            "Username": order.account_username,
            "Broker": order.broker_username
          })

          if entry_position >= market_depth > 0:
            break

    md = {
      "MsgType":"W",
      "MDReqID": req_id,
      "MarketDepth": market_depth,
      "Symbol": symbol,
      "MDFullGrp": entry_list
    }
    application.publish( 'MD_FULL_REFRESH_' + symbol , md )

    return md
コード例 #9
0
  def publish_new_order(symbol, entry_type, order_position, order ):
    md = {
      "MsgType":"X",
      "MDBkTyp": '3', # Order Depth
      "MDIncGrp": [{
        "MDUpdateAction":"0",  # new
        "Symbol": symbol,
        "MDEntryType": entry_type,
        "MDEntryPositionNo": order_position + 1,
        "MDEntryID": order.id,
        "MDEntryPx": order.price,
        "MDEntrySize": order.leaves_qty,
        "MDEntryDate": order.created.date(),
        "MDEntryTime": order.created.time(),
        "OrderID": order.id,
        "Username": order.account_username,
        "Broker": order.broker_username

      }]
    }
    application.publish( 'MD_INCREMENTAL_' + symbol + '.' + entry_type , md )
コード例 #10
0
 def publish_new_order(symbol, entry_type, order_position, order):
     md = {
         "MsgType":
         "X",
         "MDBkTyp":
         '3',  # Order Depth
         "MDIncGrp": [{
             "MDUpdateAction": "0",  # new
             "Symbol": symbol,
             "MDEntryType": entry_type,
             "MDEntryPositionNo": order_position + 1,
             "MDEntryID": order.id,
             "MDEntryPx": order.price,
             "MDEntrySize": order.leaves_qty,
             "MDEntryDate": order.created.date(),
             "MDEntryTime": order.created.time(),
             "OrderID": order.id,
             "Username": order.account_username,
             "Broker": order.broker_username
         }]
     }
     application.publish('MD_INCREMENTAL_' + symbol + '.' + entry_type, md)
コード例 #11
0
 def publish_trades(symbol, trades):
   md_trades = []
   for trade in trades:
     md_trades.append({
       "MDUpdateAction":"0",
       "MDEntryType": "2",  # Trade
       "Symbol": trade.symbol,
       "MDEntryPx": trade.price,
       "MDEntrySize": trade.size,
       "MDEntryDate": trade.created.date(),
       "MDEntryTime": trade.created.time(),
       "OrderID": trade.order_id,
       "Side": trade.side,
       "SecondaryOrderID": trade.counter_order_id,
       "TradeID": trade.id,
       "MDEntryBuyer": trade.buyer_username,
       "MDEntrySeller": trade.seller_username,
     })
   md = {
     "MsgType":"X",
     "MDBkTyp": '3', # Order Depth
     "MDIncGrp": md_trades
   }
   application.publish( 'MD_TRADE_' + symbol , md )
コード例 #12
0
 def publish_trades(symbol, trades):
     md_trades = []
     for trade in trades:
         md_trades.append({
             "MDUpdateAction": "0",
             "MDEntryType": "2",  # Trade
             "Symbol": trade.symbol,
             "MDEntryPx": trade.price,
             "MDEntrySize": trade.size,
             "MDEntryDate": trade.created.date(),
             "MDEntryTime": trade.created.time(),
             "OrderID": trade.order_id,
             "Side": trade.side,
             "SecondaryOrderID": trade.counter_order_id,
             "TradeID": trade.id,
             "MDEntryBuyer": trade.buyer_username,
             "MDEntrySeller": trade.seller_username,
         })
     md = {
         "MsgType": "X",
         "MDBkTyp": '3',  # Order Depth
         "MDIncGrp": md_trades
     }
     application.publish('MD_TRADE_' + symbol, md)
コード例 #13
0
    def match(self, session, order):
        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
        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.

            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 bitex.json_encoder import JsonEncoder
                    from models import Currency

                    qty_currency = order.symbol[:3]
                    formatted_qty = Currency.format_number(
                        session, qty_currency, order.order_qty / 1.e8)

                    price_currency = order.symbol[3:]
                    formatted_price = Currency.format_number(
                        session, price_currency, order.price / 1.e8)

                    formatted_total_price = Currency.format_number(
                        session, price_currency,
                        order.order_qty / 1.e8 * order.price / 1.e8)

                    email_subject = 'E'
                    email_template = "order-execution"
                    email_params = {
                        'username': order.user.username,
                        'order_id': order.id,
                        'trade_id': trade.id,
                        '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.user_id,
                                 subject=email_data[0],
                                 template=email_data[1],
                                 language=options.global_email_language,
                                 params=email_data[2])

                email_data = generate_email_subject_and_body(
                    session, counter_order, trade)
                UserEmail.create(session=session,
                                 user_id=counter_order.user_id,
                                 subject=email_data[0],
                                 template=email_data[1],
                                 language=options.global_email_language,
                                 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.has_leaves_qty:
                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.has_leaves_qty:
            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:
            application.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 ""
コード例 #14
0
ファイル: execution.py プロジェクト: Anderson-Juhasc/bitex
  def match(self, session, order):
    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
    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.

      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 bitex.json_encoder import  JsonEncoder
          from models import Currency

          qty_currency = order.symbol[:3]
          formatted_qty = Currency.format_number( session, qty_currency, order.order_qty / 1.e8 )

          price_currency = order.symbol[3:]
          formatted_price = Currency.format_number( session, price_currency, order.price / 1.e8 )

          formatted_total_price = Currency.format_number( session, price_currency, order.order_qty/1.e8 * order.price / 1.e8 )

          email_subject =  'E'
          email_template = "order-execution"
          email_params = {
            'username': order.user.username,
            'order_id': order.id,
            'trade_id': trade.id,
            '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.user_id,
                          subject = email_data[0],
                          template= email_data[1],
                          language= options.global_email_language,
                          params  = email_data[2])

        email_data = generate_email_subject_and_body(session, counter_order, trade)
        UserEmail.create( session = session,
                          user_id = counter_order.user_id,
                          subject = email_data[0],
                          template= email_data[1],
                          language= options.global_email_language,
                          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.has_leaves_qty:
        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.has_leaves_qty:
      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:
      application.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 ""