Example #1
0
    def __init__(self, pos=None, balance=None, price=None, side=None):
        assert pos is None or type(pos) in (str, Decimal, int)
        assert balance is None or type(balance) in (str, Decimal, int)
        assert price is None or type(price) in (str, Decimal, int)
        assert side is None or side in Side.sides
        if pos:
            pos = Decimal(pos)
        if balance:
            balance = Decimal(balance)
        if price:
            price = Decimal(price)

        if balance is None and price is None:
            raise RuntimeError

        if balance and price and pos:
            raise RuntimeError

        if balance is not None and pos is not None:
            self.pos = pos
            self.balance = balance
        elif pos is not None and price is not None:
            self.pos = pos
            self.balance = pos * price
        elif price is not None and balance is not None:
            self.pos = balance / price
            self.balance = balance

        if side is not None:
            self.pos = abs(self.pos) * Side.sign(side)
            self.balance = Side.opposite_sign(side) * abs(self.balance)
Example #2
0
 def exit_market(self):
     Side.apply_sides(lambda side: self.engine.broker.cancel(0, side))
     exit_side = Side.opposite_side(self.engine.pnl.position())
     price = calc_price(self.engine.book.quote(exit_side),
                        MMParams.liq_behind_exit)
     self.engine.broker.request(1, exit_side, price,
                                self.engine.pnl.abs_position)
Example #3
0
def specific_margin_price(entry_price,
                          entry_side,
                          margin,
                          entry_commisiion=0,
                          exit_commision=0):
    return entry_price \
           + Side.sign(entry_side) * (margin + entry_commisiion) \
           - Side.sign(entry_side) * exit_commision
Example #4
0
    def take_pnl(self):
        if self.pos.position() == 0:
            return Decimal('0')
        exit_side = Side.opposite_side(self.position())
        take_price = self.nbbo.side(Side.side(self.position()))
        take_order = Position(pos=self.pos.abs_position(),
                              price=take_price,
                              side=exit_side)
        take_pos = self.pos + take_order + take_order.fee_pos(self.fee)

        return take_pos.balance
Example #5
0
def enter_hedge(pnl: PNL, book: Book, side, cfg: HedgeConfig, vc: VenueConfig):
    quote = book.quote(side)
    side = quote.side
    pos = pnl.pos
    order_size = cfg.order_size.side(side)
    theo = (book.quote(Side.BID).price + book.quote(Side.ASK).price) / 2
    if pos.abs_position() < vc.min_order_size:
        # depth or ema
        order_size = adjusted_size(order_size, side, pos.abs_position())
        method, price = depth_ema_price(cfg, order_size, pnl, quote, side, vc)
        return Position(pos=order_size, side=side, price=price), method
    elif Side.opposite(
            pos.side()) == side and pos.abs_position() >= vc.min_order_size:
        # exit order
        # depth or zero
        method, price = depth_ema_price(cfg, order_size, pnl, quote, side, vc)

        add_pos = pos.oppoiste_with_price(price)
        min_margin = pos.opposite_with_margin(vc.tick_size)
        min_margin = bound_pos_to_lower_quote(quote, min_margin, vc.tick_size)

        if (pos + add_pos).balance > 0:
            return add_pos, "QUOTE"
        else:
            return min_margin, "MIN PROFIT"
    elif pos.side(
    ) == side and cfg.max_pos - pos.abs_position() >= vc.min_order_size:
        #depth
        #hedge
        #order_size = adjusted_size(order_size, side, pos.abs_position())
        method, price_depth = depth_ema_price(cfg, order_size, pnl, quote,
                                              side, vc)

        order_size = min(order_size, cfg.max_pos - pos.abs_position())
        depth_pos = Position(pos=order_size, side=side, price=price_depth)
        sign = Side.sign(pos.side())

        target_price = theo - Side.sign(pos.side()) * theo * cfg.hedge_perc
        hedge_pos = hedge_positon_size(pos, Decimal(target_price), order_size)
        hedge_pos = bound_pos_to_lower_quote(quote, hedge_pos, vc.tick_size)
        #return hedge_pos, "HEDGE HEDGE"
        if (side == Side.BID and hedge_pos.price() < depth_pos.price()) \
                or (side == Side.ASK and hedge_pos.price() > depth_pos.price()):
            return hedge_pos, "HEDGE HEDGE"
        else:
            return depth_pos, "HEDGE DEPTH"

    else:
        #zero
        return Position(side=side, pos=0, balance=0), "CANCEL"
Example #6
0
def stop_loss_exit_strategy(book: Book,
                            pnl: PNL,
                            ac: MarketmakerConfig,
                            vc: VenueConfig,
                            loss=False):
    def volume_behind_order(min_pos: Position):
        sign = Side.sign(min_pos.side())
        return sum([
            level.volume() for level in book.quote(min_pos.side())
            if sign * level.price > sign * min_pos.price()
        ])

    pos = pnl.pos
    exit_side = Side.opposite(pos.side())
    price = price_on_a_depth(book.quote(exit_side), pos.abs_position(), ac, vc)

    add_pos = pos.oppoiste_with_price(price)
    min_margin = pos.opposite_with_margin(ac.min_profit)
    remove_pos = pos.oppoiste_with_price(book.quote(pos.side()).price)
    # if (pos + remove_pos + remove_pos.fee_pos(pnl.fee)).balance > pnl.closed_pnl:
    #     return remove_pos, "REMOVE"
    if (pos + add_pos).balance > 0 or loss:
        return add_pos, "QUOTE"
    # elif volume_behind_order(min_margin) >= config.buried_volume:
    #     return add_pos, "STOP LOSS"
    else:
        return min_margin, "MIN PROFIT"
Example #7
0
    def before(self, level):
        if level.side != self.side:
            raise RuntimeError

        if self.price == level.price:
            raise RuntimeError

        return (self.price - level.price) / abs(self.price - level.price) == Side.sign(self.side)
Example #8
0
def calc_price_for_depth(quote: Level, liq_behind):
    quote_liq = quote.size

    while quote_liq < liq_behind:
        quote = quote.next_level
        quote_liq += quote.size

    return quote.price + Side.side(quote.side) * Decimal('0.0001')
Example #9
0
    def price(self):
        if self.pos == 0:
            return Decimal('0')

        prec = Decimal('10000')
        price, reminder = divmod(prec * abs(self.balance), abs(self.pos))
        price /= prec
        if reminder != 0:
            price += Side.sign(self.side()) * Decimal('0.0001')
        return round(price, 4)
Example #10
0
    def gen_prices(side):
        sign = -Side.sign(side)
        prev_price = Decimal(median + sign * spread / 2)

        for i in range(0, levels):
            next_price = prev_price + Decimal(
                sign * randrange(1, 1000, 1) / 1000)
            final_next_price = round(Decimal(next_price), 4)
            size = round(Decimal(randrange(1, 100, 1) / 100), 2)
            yield final_next_price, size
            prev_price = final_next_price
Example #11
0
def calc_price_between_levels(quote,
                              liq_behind,
                              min_step,
                              place_to_spread=False):
    quote_liq = quote.size
    dt = abs(0 - quote.price) if place_to_spread else 0
    while quote_liq < liq_behind:
        dt = abs(quote.price - quote.next_level.price)
        quote = quote.next_level
        quote_liq += quote.size

    if dt > min_step:
        return quote.price + Side.sign(quote.side) * min_step
    else:
        return quote.price
Example #12
0
    def test_with_params(pos, enter_price):
        pnl = PNL('0.3')
        book = Book()
        book.quote_subscribers.append(pnl)
        config = MMParams({
            "min_levels": "5",
            "liq_behind_exit": "0.02",
            "liq_behind_entry": {
                "BID": "0.41",
                "ASK": "0.41"
            },
            "order_sizes": {
                "BID": "0.07",
                "ASK": "0.07"
            },
            "min_profit": "0.01",
            "min_order_size": "0.01",
            "buried_volume": "10",
            "taker_exit_profit": "0.1",
            "price_tolerance": "0.0005"
        })
        pnl.execution(Side.side(pos), abs(pos), abs(enter_price))
        median = 1000
        for i in range(0, 5):
            book.increment_level(Side.ASK, Decimal(median + i),
                                 Decimal(i / 100))
            book.increment_level(Side.BID, Decimal(median - i),
                                 Decimal(i / 100))
            book.quote_changed(Side.BID)
            book.quote_changed(Side.ASK)

        print_book_and_orders(book, Broker(OrderManager()))
        exit_price = hold_exit_price_strategy(book, pnl, config)
        pnl.execution(Side.opposite(pnl.position_side()), abs(pos), exit_price)

        return pnl.closed_pnl
Example #13
0
def enter_ema(quote: Level, ema: Decimal, ema_work_perc, vc: VenueConfig):

    sign = Decimal(Side.sign(quote.side))

    def calc_ema_price():
        return round(Decimal(ema - sign * (ema / 100 * ema_work_perc)), 4)

    def stick_to_quote(price):
        try:
            under_price = next(
                (x.price for x in quote if sign * x.price - sign * price <= 0))
            return under_price + sign * vc.tick_size if under_price != price else under_price
        except StopIteration:
            return price

    return stick_to_quote(calc_ema_price())
Example #14
0
def price_on_a_depth(top_quote, size, ac: MarketmakerConfig, vc: VenueConfig):
    quote_array = []
    quote_liq = Decimal('0')
    side = top_quote.side
    liq_adj = ac.liq_behind.side(side) - size
    prev_price = Decimal('0')

    for quote in top_quote:
        quote_liq += quote.size
        quote_array.append((quote.price, quote.size, quote_liq,
                            abs(prev_price - quote.price)))
        prev_price = quote.price
        if quote_liq >= liq_adj:
            break

    last_quote = quote_array[-1]
    if last_quote[2] > liq_adj:
        return last_quote[0] + Side.sign(side) * vc.tick_size
    else:
        return last_quote[0]
Example #15
0
def remove_exit_price_strategy(book: Book,
                               pos: Position,
                               config: MarketmakerConfig,
                               fee=Decimal(0.3)):
    # pos, last_price = remove_price(book.quote(pos.side()), pos)
    # if pos.balance > 0:
    #     remove_pos = pos.oppoiste_with_price(last_price)
    # print("fee " + str(pos * Decimal('0.3')))
    remove_pos = pos.oppoiste_with_price(book.quote(pos.side()).price)
    remove_pos_wfee = Position(pos=remove_pos.position(),
                               balance=remove_pos.balance +
                               (remove_pos.balance / 100) * fee)
    add_pos = pos.oppoiste_with_price(
        book.quote(Side.opposite(pos.side())).price)
    fee_ = remove_pos * Decimal(fee / 100)
    fin_pos = pos + remove_pos
    if (pos + remove_pos_wfee).balance > 0:
        return remove_pos
    elif (pos + add_pos).balance > 0:
        return add_pos
    else:
        return pos.opposite_with_margin(config.min_profit)
Example #16
0
 def nbbo_pnl(self):
     exit_side = Side.opposite_side(self.position())
     nbbo_price = self.nbbo.side(exit_side)
     return (self.pos + Position(pos=self.pos.abs_position(),
                                 price=nbbo_price,
                                 side=exit_side)).balance
Example #17
0
 def __init__(self, side, price, size):
     Side.check_fail(side)
     self.side = side
     self.price = price
     self.size = size
     self.next_level = None
Example #18
0
def price_not_better_than(calc_price, ema_price, side):
    sign = (calc_price - ema_price) / abs(calc_price - ema_price)
    if sign == Side.sign(side):
        return ema_price
    else:
        return calc_price
Example #19
0
def adjusted_size(order_size, order_side, pos):
    pos_side = Side.side(pos)
    if pos_side == order_side:
        return order_size - abs(pos)
    else:
        return order_size + abs(pos)
Example #20
0
 def side(self):
     return Side.side(self.pos)
Example #21
0
def test_closer_to_quote():
    assert Side.closer_to_quote(Side.BID, 10, 11) == 11
    assert Side.closer_to_quote(Side.ASK, 10, 11) == 10
    assert Side.closer_to_quote(Side.ASK, 10, 10) == 10
    assert Side.closer_to_quote(Side.BID, 11, 11) == 11

    assert Side.closer_to_quote(Side.BID, 10.01, 11.01) == 11.01
    assert Side.closer_to_quote(Side.ASK, 10.01, 11.01) == 10.01
    assert Side.closer_to_quote(Side.ASK, 10.01, 10.01) == 10.01
    assert Side.closer_to_quote(Side.BID, 11.01, 11.01) == 11.01

    assert Side.closer_to_quote(Side.BID, Decimal(10.01),
                                Decimal(11.01)) == 11.01
    assert Side.closer_to_quote(Side.ASK, Decimal(10.01),
                                Decimal(11.01)) == 10.01
    assert Side.closer_to_quote(Side.ASK, Decimal(10.01),
                                Decimal(10.01)) == 10.01
    assert Side.closer_to_quote(Side.BID, Decimal(11.01),
                                Decimal(11.01)) == 11.01
Example #22
0
 def oppoiste_with_price(self, price):
     return Position(pos=self.pos, price=price, side=Side.opposite(self.side()))
Example #23
0
def calc_target_price(theo: Decimal, pos: Position, hedge_perc: Decimal):
    #exit_side = Side.opposite(pos.side())
    sign = Side.sign(pos.side())
    theo_target = theo - Side.sign(pos.side()) * theo * hedge_perc
    pos_target = pos.price() - sign * theo * hedge_perc
    return theo_target
Example #24
0
 def position_side(self):
     return Side.side(self.position())
Example #25
0
def should_update_price(side, current_price: Decimal, new_price: Decimal,
                        barrier: Decimal):
    return current_price - new_price > barrier or Side.closer_to_quote(
        side, current_price, new_price) == new_price
Example #26
0
 def volume_behind_order(min_pos: Position):
     sign = Side.sign(min_pos.side())
     return sum([
         level.volume() for level in book.quote(min_pos.side())
         if sign * level.price > sign * min_pos.price()
     ])
Example #27
0
def ema_constraint(depth_price, ema_price, side):
    sign = Side.sign(side)

    # ema 100 price 101 side bid
    delta = sign * ema_price - sign * depth_price
    return (ema_price, "EMA") if delta < 0 else (depth_price, "ENTER")
Example #28
0
def epsilon_from_theo(theo, perc, side):
    return theo - Side.sign(side) * theo * perc