def get_clipped_alt_volume(self, orders, desired_alt_volume): """ desired_alt_volume is usually 0.011, because alt in this case is a proper "base" that is actually listed on the exchange. we want the total alts traded to equal this. Example: suppose exchange lists A_B (min_vol = 0.1) but we want to get min_vol for B_A. flipped_depth = a list of orders (sorted by best price) [(P1,V1), (P2,V2), (P3,V3)] for B_A. P1 * V1 = units A (either given or received) hopefully P1 * V1 > min_vol(A_B) if not, then we have to compute the difference diff = min_vol(A_B) - (P1 * V1) = remaining units of A that we need to spend/give on the remaining orders. iterate through the rest of the orders as long as min vol is not satisfied! """ i = 1 while utils.total_alt_volume(orders[:i]) < desired_alt_volume: i += 1 if i > len(orders): # not enough orders in the orderbook! print( 'Not enough orders in orderbook to satisfy required alt volume!' ) break # more than likely, adding on the last order tacked on a bit of overshoot. # the remainder MUST be spanned by last order (i.e. cannot be in the second # to last otherwise we would have caught it) alt_remainder = utils.total_alt_volume(orders[:i]) - desired_alt_volume # convert back to units base and subtract from last order orders[i - 1].v -= alt_remainder / orders[i - 1].p return sum([o.v for o in orders[:i]])
def get_clipped_alt_volume(self, orders, desired_alt_volume): """ desired_alt_volume is usually 0.011, because alt in this case is a proper "base" that is actually listed on the exchange. we want the total alts traded to equal this. Example: suppose exchange lists A_B (min_vol = 0.1) but we want to get min_vol for B_A. flipped_depth = a list of orders (sorted by best price) [(P1,V1), (P2,V2), (P3,V3)] for B_A. P1 * V1 = units A (either given or received) hopefully P1 * V1 > min_vol(A_B) if not, then we have to compute the difference diff = min_vol(A_B) - (P1 * V1) = remaining units of A that we need to spend/give on the remaining orders. iterate through the rest of the orders as long as min vol is not satisfied! """ i = 1 while utils.total_alt_volume(orders[:i]) < desired_alt_volume: i += 1 if i > len(orders): # not enough orders in the orderbook! print('Not enough orders in orderbook to satisfy required alt volume!') break # more than likely, adding on the last order tacked on a bit of overshoot. # the remainder MUST be spanned by last order (i.e. cannot be in the second # to last otherwise we would have caught it) alt_remainder = utils.total_alt_volume(orders[:i]) - desired_alt_volume # convert back to units base and subtract from last order orders[i-1].v -= alt_remainder/orders[i-1].p return sum([o.v for o in orders[:i]])
def get_best_type2_roundtrip(self): """ [Buy(C_B)Buy(A_C)] Sell(A_B) """ A, B = self.pair # use A_B notation instead of base, alt b = self.broker alt = B tx = 1 - b.xchg.trading_fee bids_ab = b.get_orders((A, B), "bids") # people who are selling A_B for C, spread in self.type2_spreads.items(): if spread > config.PROFIT_THRESH[B]: self.type2_roundtrips[C] = {} asks_cb = b.get_orders((C, B), "asks") # people who are buying C_B asks_ac = b.get_orders((A, C), "asks") # people who are buying A_C # minimum volume constraints min_cb = b.xchg.get_min_vol((A, C), asks_cb) # how much DOGE we have to sell in the first trade min_ac = b.xchg.get_min_vol((C, B), asks_ac) # how much LTC we have to sell in the second trade min_ab = b.xchg.get_min_vol((A, B), bids_ab) # how much DOGE we have to buy in the third trade asks_cb_clipped = b.xchg.get_clipped_base_volume(asks_cb, min_cb) # buy exactly minimum quantity asks_ac_clipped = b.xchg.get_clipped_alt_volume( asks_ac, min_cb * tx ) # can probably spend less than 0.01 LTC buying 0.01 DOGE v3 = utils.total_base_volume(asks_ac_clipped) * tx # total DOGE we receive bids_ab_clipped = b.xchg.get_clipped_base_volume(bids_ab, v3) # sell all the DOGE for BTC # construct the orders that we submit o1 = Order( utils.highest_price(asks_cb_clipped), utils.total_base_volume(asks_cb_clipped), type="buy", pair=(C, B), ) o2 = Order( utils.highest_price(asks_ac_clipped), utils.total_base_volume(asks_ac_clipped), type="buy", pair=(A, C), ) o3 = Order( utils.lowest_price(bids_ab_clipped), utils.total_base_volume(bids_ab_clipped), type="sell", pair=(A, B), ) self.type2_roundtrips[C]["orders"] = [o1, o2, o3] # these calculations should adequately take volume into account netA = o2.v * tx - o3.v netB = -utils.total_alt_volume(asks_cb_clipped) + utils.total_alt_volume(bids_ab_clipped) * tx netC = o1.v * tx - utils.total_alt_volume(asks_ac_clipped) self.type2_roundtrips[C]["profit"] = netB print("check ... ") # loop through C and choose the one with the largest profit return self._get_highest_profit(self.type2_roundtrips)
def get_best_type1_roundtrip(self): """ sell(AC), sell(CB) buy(AB) """ A, B = self.pair # use A_B notation instead of base, alt b = self.broker alt = B tx = 1 - b.xchg.trading_fee asks_ab = b.get_orders((A, B), "asks") # people who are selling A_B for C, spread in self.type1_spreads.items(): if spread > config.PROFIT_THRESH[alt]: self.type1_roundtrips[C] = {} bids_ac = b.get_orders((A, C), "bids") # people who are buying A_C bids_cb = b.get_orders((C, B), "bids") # people who are buying C_B # minimum volume constraints min_ac = b.xchg.get_min_vol((A, C), bids_ac) # how much DOGE we have to sell in the first trade min_cb = b.xchg.get_min_vol((C, B), bids_cb) # how much LTC we have to sell in the second trade min_ab = b.xchg.get_min_vol((A, B), asks_ab) # how much DOGE we have to buy in the third trade # assuming value A << value C, first trade has to acquire enough LTC to perform the second trade bids_ac_clipped = b.xchg.get_clipped_alt_volume(bids_ac, min_ac / tx) # how much DOGE we sold to acquire 0.01 LTC v1 = utils.total_base_volume(bids_ac) # performing the second trade will net enough BTC to buy back at least 0.01 DOGE bids_cb_clipped = b.xchg.get_clipped_base_volume(bids_cb, min_ac) # buy back exactly how much DOGE we spent in the first place asks_ab_clipped = b.xchg.get_clipped_base_volume(asks_ab, v1 / tx) # construct the orders o1 = Order( utils.lowest_price(bids_ac_clipped), utils.total_base_volume(bids_ac_clipped), type="sell", pair=(A, C), ) o2 = Order( utils.lowest_price(bids_cb_clipped), utils.total_base_volume(bids_cb_clipped), type="sell", pair=(C, B), ) o3 = Order( utils.highest_price(asks_ab_clipped), utils.total_base_volume(asks_ab_clipped), type="buy", pair=(A, B), ) # test orders for profitability self.type1_roundtrips[C]["orders"] = [o1, o2, o3] netA = -o1.v + o3.v * tx netB = utils.total_alt_volume(bids_cb_clipped) * tx - utils.total_alt_volume(asks_ab_clipped) netC = utils.total_alt_volume(bids_ac_clipped) * tx - o2.v self.type1_roundtrips[C]["profit"] = netB print("check...") return self._get_highest_profit(self.type1_roundtrips)
def get_best_type2_roundtrip(self): """ [Buy(C_B)Buy(A_C)] Sell(A_B) """ A, B = self.pair # use A_B notation instead of base, alt b = self.broker alt = B tx = 1 - b.xchg.trading_fee bids_ab = b.get_orders((A, B), 'bids') # people who are selling A_B for C, spread in self.type2_spreads.items(): if spread > config.PROFIT_THRESH[B]: self.type2_roundtrips[C] = {} asks_cb = b.get_orders((C, B), 'asks') # people who are buying C_B # people who are buying A_C #asks_ac = b.get_orders((A,C), 'asks') asks_ac = b.get_orders((C, A), 'asks') # minimum volume constraints # how much DOGE we have to sell in the first trade #min_cb = b.xchg.get_min_vol((A,C), asks_cb) min_cb = b.xchg.get_min_vol((C, A), asks_cb) # how much LTC we have to sell in the second trade min_ac = b.xchg.get_min_vol((C, B), asks_ac) min_ab = b.xchg.get_min_vol( (A, B), bids_ab) # how much DOGE we have to buy in the third trade asks_cb_clipped = b.xchg.get_clipped_base_volume( asks_cb, min_cb) # buy exactly minimum quantity asks_ac_clipped = b.xchg.get_clipped_alt_volume( asks_ac, min_cb * tx ) # can probably spend less than 0.01 LTC buying 0.01 DOGE #print ('type of asks_cb_clipped: %s ' % str(type(asks_cb_clipped))) #print ('type of asks_ac_clipped: %s ' % str(type(asks_ac_clipped))) # total DOGE we receive v3 = utils.total_base_volume(asks_ac_clipped) * tx bids_ab_clipped = b.xchg.get_clipped_base_volume( bids_ab, v3) # sell all the DOGE for BTC #print ('type of bids_ab_clipped: %s ' % str(type(bids_ab_clipped))) # construct the orders that we submit o1 = Order(utils.highest_price(asks_cb_clipped), utils.total_base_volume(asks_cb_clipped), order_type="buy", pair=(C, B)) o2 = Order(utils.highest_price(asks_ac_clipped), utils.total_base_volume(asks_ac_clipped), order_type="buy", pair=(A, C)) o3 = Order(utils.lowest_price(bids_ab_clipped), utils.total_base_volume(bids_ab_clipped), order_type="sell", pair=(A, B)) self.type2_roundtrips[C]["orders"] = [o1, o2, o3] # these calculations should adequately take volume into account netA = o2.v * tx - o3.v netB = -utils.total_alt_volume( asks_cb_clipped) + utils.total_alt_volume( bids_ab_clipped) * tx netC = o1.v * tx - utils.total_alt_volume(asks_ac_clipped) self.type2_roundtrips[C]["profit"] = netB #print('check ... ') # loop through C and choose the one with the largest profit return self._get_highest_profit(self.type2_roundtrips)
def get_best_type1_roundtrip(self): """ sell(AC), sell(CB) buy(AB) """ A, B = self.pair # use A_B notation instead of base, alt b = self.broker alt = B tx = 1 - b.xchg.trading_fee asks_ab = b.get_orders((A, B), 'asks') # people who are selling A_B for C, spread in self.type1_spreads.items(): if spread > config.PROFIT_THRESH[alt]: self.type1_roundtrips[C] = {} bids_ac = b.get_orders((A, C), 'bids') # people who are buying A_C bids_cb = b.get_orders((C, B), 'bids') # people who are buying C_B # minimum volume constraints min_ac = b.xchg.get_min_vol( (A, C), bids_ac ) # how much DOGE we have to sell in the first trade min_cb = b.xchg.get_min_vol( (C, B), bids_cb ) # how much LTC we have to sell in the second trade min_ab = b.xchg.get_min_vol( (A, B), asks_ab) # how much DOGE we have to buy in the third trade # assuming value A << value C, first trade has to acquire enough LTC to perform the second trade bids_ac_clipped = b.xchg.get_clipped_alt_volume( bids_ac, min_ac / tx) # how much DOGE we sold to acquire 0.01 LTC v1 = utils.total_base_volume(bids_ac) # performing the second trade will net enough BTC to buy back at least 0.01 DOGE bids_cb_clipped = b.xchg.get_clipped_base_volume( bids_cb, min_ac) # buy back exactly how much DOGE we spent in the first place asks_ab_clipped = b.xchg.get_clipped_base_volume( asks_ab, v1 / tx) # construct the orders o1 = Order(utils.lowest_price(bids_ac_clipped), utils.total_base_volume(bids_ac_clipped), order_type="sell", pair=(A, C)) o2 = Order(utils.lowest_price(bids_cb_clipped), utils.total_base_volume(bids_cb_clipped), order_type="sell", pair=(C, B)) o3 = Order(utils.highest_price(asks_ab_clipped), utils.total_base_volume(asks_ab_clipped), order_type="buy", pair=(A, B)) # test orders for profitability self.type1_roundtrips[C]["orders"] = [o1, o2, o3] netA = -o1.v + o3.v * tx netB = utils.total_alt_volume( bids_cb_clipped) * tx - utils.total_alt_volume( asks_ab_clipped) netC = utils.total_alt_volume(bids_ac_clipped) * tx - o2.v self.type1_roundtrips[C]["profit"] = netB #print('check...') return self._get_highest_profit(self.type1_roundtrips)