示例#1
0
    def fundamental_value(self, orderbook):
        depth = Money('20', 'BTC')

        try:
            fundamental_value = midpoint.get_midpoint_from_orderbook(
                orderbook, depth)
        except:
            # Some very illiquid exchanges don't always have 20 BTC of depth.
            depth = Money('1', 'BTC')

            fundamental_value = midpoint.get_midpoint_from_orderbook(
                orderbook, depth)

        return fundamental_value
示例#2
0
    def test_bigger_with_depth(self):
        result = midpoint.get_midpoint_from_orderbook(
            self.bigger_book(),
            depth=Money('20', 'BTC'),
        )

        result.should.equal(Money('252', 'USD'))
示例#3
0
    def test_basic_with_depth(self):
        result = midpoint.get_midpoint_from_orderbook(
            self.basic_book(price_currency='BTC', vol_currency='ETH'),
            depth=Money('0.5', 'ETH'),
        )

        result.should.equal(Money('250', 'BTC'))
示例#4
0
def orderbook_strength_at_slippage_in_usd(orderbook, order_type, slippage):
    """
    Get the amount of liquidity (bitcoin denominated) available within [slippage]
    dollars of the top [order_type].

    Returns a decimal.
    """
    midpoint = midpoint_lib.get_midpoint_from_orderbook(
        orderbook, Money('20', 'BTC'))

    vol = Money('0', 'BTC')

    if order_type == Consts.BID:
        top_bid = orderbook['bids'][0]
        price = top_bid.price - slippage

        vol = available_volume.volume_available_at_price(
            Consts.ASK, price, orderbook)
    else:
        top_ask = orderbook['asks'][0]
        price = top_ask.price + slippage

        vol = available_volume.volume_available_at_price(
            Consts.BID, price, orderbook)

    return vol.amount * midpoint.amount
示例#5
0
def midpoint_centered_fixed_spread(orderbook, spread, quote_depth=None):
    """
    """
    midpoint = midpoint_lib.get_midpoint_from_orderbook(orderbook,
                                                        depth=quote_depth)

    bid_price = midpoint - (midpoint * spread)
    ask_price = midpoint + (midpoint * spread)

    return bid_price, ask_price
示例#6
0
def orderbook_strength_at_slippages_in_usd(orderbook, order_type, slippages):
    """
    Same as orderbook_strength_at_slippage but instead of returning the levels as a
    bitcoin-denominated quantity, we return the levels as to the usd value of the
    bitcoins at that level, which we definine as level * 20btc midpoint.

    Returns a decimal: decimal dict.
    """

    midpoint = midpoint_lib.get_midpoint_from_orderbook(
        orderbook, Money('20', 'BTC'))

    slippage_lookup = {}

    if order_type == Consts.BID:
        top_bid = orderbook['bids'][0]
        prices = [top_bid.price - slippage for slippage in slippages]

        slippage_lookup = {(top_bid.price - slippage).amount: slippage
                           for slippage in slippages}

        levels = available_volume.volume_available_at_prices(
            Consts.ASK,
            prices,
            orderbook,
        )
    else:
        top_ask = orderbook['asks'][0]
        prices = [top_ask.price + slippage for slippage in slippages]

        slippage_lookup = {(top_ask.price + slippage).amount: slippage
                           for slippage in slippages}

        levels = available_volume.volume_available_at_prices(
            Consts.BID,
            prices,
            orderbook,
        )

    levels = {
        slippage_lookup[price].amount: value.amount * midpoint.amount
        for price, value in levels.items()
    }

    return levels
    def tick(self, current_orders, eaten_order_ids):

        self.logger.debug("--Strategy Tick--")

        # Desk can be our runtime mock, when operating without exchange...
        ob, current_orders, eaten_order_ids = self.desk.tick(
            current_orders=current_orders, eaten_orders=eaten_order_ids)

        # NOTE : we currently minimize the number of simultaneous trades, to avoid unintended tricky behavior...

        balance = self.primary_exchange.get_balance()

        midpoint = midpoint_lib.get_midpoint_from_orderbook(ob)
        #self.midpoints += midpoint

        self.logger.info("Current midpoint of orderbook : " + str(midpoint))

        self.logger.info("Ephemeral position: " +
                         str(self.position_tracker.position))

        # if self.position_tracker.position != self.primary_exchange.exchange_account.position:
        #     self.logger.warning("Exchange position: " + str(self.primary_exchange.exchange_account.position))

        # Preparing to enter BET...
        def on_bear_trend():
            # Ultimately make decision
            #self.logger.info("Attempting to enter a new position...")
            #self.position_tracker.market_enter(bid_price=midpoint, bid_volume=self.base_volume)
            pass
            # TODO : reverse trend ? or only useful for mixed currency bag as quote ??

        def on_bull_trend():
            if not self.position_tracker.position or (
                    self.position_tracker.exited
                    and not self.position_tracker.entering):
                # Ultimately make decision
                self.logger.info("Attempting to enter at market price...")
                self.position_tracker.market_enter(bid_volume=self.base_volume)

        self.market_observer.tick(midpoint,
                                  on_bull_trend=on_bull_trend,
                                  on_bear_trend=on_bear_trend)

        # If we currently track a position (from this run)
        if self.position_tracker.position and self.position_tracker.entered and not self.position_tracker.exiting:
            # we can attempt an exit
            exit_profit_price = self.position_tracker.exit_profit_price(
                quote_currency=self.quote_currency,
                volume_currency=self.volume_currency)
            self.logger.info("Targetted profit price: " +
                             str(exit_profit_price))
            if exit_profit_price:
                # TODO
                # if timeout:
                # else:
                if midpoint > exit_profit_price:
                    #if midpoint is already above, exit at market !
                    self.logger.info(
                        "Attempting to exit at targetted profit price...")
                    self.position_tracker.market_exit()
                else:
                    # else exit limit
                    self.logger.info("Attempting to exit at market price...")
                    self.position_tracker.limit_exit(exit_profit_price)
            else:
                self.logger.error("Cannot calculate exit profit price")
示例#8
0
 def test_bigger(self):
     result = midpoint.get_midpoint_from_orderbook(self.basic_book())
     result.should.equal(Money('250', 'USD'))
示例#9
0
    def test_basic_crypto_crypto(self):
        result = midpoint.get_midpoint_from_orderbook(
            self.basic_book(price_currency='BTC', vol_currency='ETH'),
        )

        result.should.equal(Money('250', 'BTC'))
示例#10
0
    def test_basic_non_btc(self):
        result = midpoint.get_midpoint_from_orderbook(
            self.basic_book(vol_currency='ETH'),
        )

        result.should.equal(Money('250', 'USD'))
示例#11
0
    def tick(self, current_orders):

        self.logger.debug("--Strategy Tick--")
        self.logger.info("Current Orders: " + str(current_orders))
        # Question : Can we detect fulfilled orders ?
        # upon fulfilled order we can increase spread base on volatility
        # otherwise we should probably decrease spread to get order fulfilled....

        ob = self.primary_exchange.get_orderbook()

        self.midpoints += midpoint_lib.get_midpoint_from_orderbook(ob)

        # SAFETY
        # if (hasattr(self, 'last_ask_price') and self.last_ask_price < self.midpoint) or (hasattr(self, 'last_bid_price') and self.last_bid_price > self.midpoint):
        #     # spread was not high enough ! We likely lost money here -> correct quickly
        #     self.logger.warning("HIGH VOLATILITY encountered -> adjusting spread")
        #     self.spread *= self.spread_coef_on_loss
        #     #TODO : maybe terminate instead, with advice to change spread ? by some amount ?

        # TODO : calculate local volatility... (or reuse some indicator ??? -> see TA-lib)
        # Then based on volatility adjust spread | base_volume | tick_sleep, within exchange/user acceptable limits...
        # since we cancel and reopen order, we only need local volatility.

        # Note we probably do not want to slow down tick_sleep to not miss trend/volatility changes.
        # -> We should play on spread + base_volume only

        # OPTIMIZATION
        if self.midpoints.volatility(last=1):
            self.volat += self.midpoints.volatility(
                last=1)  # TODO : since last successful order...

            if self.volat.last()[1] < 0:
                self.logger.info("Price went down. skipping this tick...")
                # TODO : manage bear markets with shorts and leverage...

            elif self.volat.last(
            )[1] > 0:  # we only want bull micro market for now
                # We bet on the volatility to come to be the same as the one past,
                print("Volatility derivative :" + str(self.volat.deriv()))
                # TODO : define what value derivative of volatility should be

                #  and set the spread based on that.
                self.spread = self.volat.last()[1] / 2
                # TODO : reduce spread if expectation failed (order not passed), to maximize likelyhood to pass order...
                # TODO: increase spread if successful order passed, trying to maximize profit on volatile markets

                # for constant tick period, we need increased spread, and reduced base_volume
                #self.spread = self.spread_adjust_coef * (self.volat - self.last_volat) + self.spread  # adjusting spread relative to volatility

                self.logger.info("Volatility: " + str(self.volat))
                self.logger.info("Spread: " + str(self.spread))

                # TODO : take fees into account to remain profitable
                exchange_fees = self.primary_exchange.exchange_wrapper.fee
                if self.spread < exchange_fees * self.base_volume:

                    self.logger.info("Fees would be too high : " +
                                     str(exchange_fees * self.base_volume) +
                                     " vs spread of " + str(self.spread))

                else:
                    self.logger.info("Spread : " + str(self.spread) +
                                     " is larger than expected fees : " +
                                     str(exchange_fees * self.base_volume))

                    # Base volume increase means increased risk (maybe more than spread decrease).
                    # We want to increase base volume when volatility doesnt change 'much'...
                    # TODO : self.relative_volat_change = abs(self.volat - self.last_volat) / self.last_volat
                    # relative change of base_volume
                    # TODO : self.base_volume = self.base_volume_adjust_coef * (1-self.relative_volat_change) * self.base_volume + self.base_volume
                    # TODO : have a minimum volume to exchange + slowly limit to that when volatility detected.
                    # TODO : increase volume on non volatility/'less volatile than expected'... + profit ? how to measure that here ?

                    # TODO:  use profit measurement to adjust the adjust_coefs (machine learning stuff ?)...

                    # #Note : the speed of adjustment is critical to be in front of order fullfilment.
                    # -> Check control theory for a converging / asymptotic optimisation of control (yet easily reversible if needed...)

                    bid_price, ask_price = mm.midpoint_centered_fixed_spread(
                        ob, self.spread)
                    # TODO : improve by doing everything based on ohlcv since last check...

                    bid_volume, ask_volume = mm.simple_position_responsive_sizing(
                        self.base_volume,
                        self.position,
                    )
                    self.logger.info("balance: " +
                                     str(self.primary_exchange.get_balance()))
                    self.logger.info("bid volume: " + str(bid_volume) +
                                     " price: " + str(bid_price))
                    self.logger.info("ask volume: " + str(ask_volume) +
                                     " price: " + str(ask_price))

                    placeable_bid = self.primary_exchange.get_balance().get(
                        bid_price.currency
                    ).amount >= bid_price.amount * bid_volume.amount
                    placeable_ask = self.primary_exchange.get_balance().get(
                        ask_volume.currency).amount >= ask_volume.amount

                    # TODO : maybe we do not need to cancel everything everytime ?
                    self.primary_exchange.cancel_all_open_orders()

                    # Place order only if we can...
                    if placeable_bid:
                        self.primary_exchange.limit_order(
                            Consts.BID, bid_volume, bid_price)

                    # Place order only if we can...
                    if placeable_ask:
                        self.primary_exchange.limit_order(
                            Consts.ASK, ask_volume, ask_price)

                    self.last_bid_price = bid_price
                    self.last_ask_price = ask_price