def get_price_offset3(self, index): """按仓位等级来设置价格""" L = [1, 3, 5, 7, 9, 11, 13, 15, 17] if abs(index) > 10: logger.error("ORDER_PAIRS cannot over 10") self.exit() avgCostPrice = self.exchange.get_position()['avgCostPrice'] if (avgCostPrice % 0.5 == 0): start_position = avgCostPrice else: start_position = avgCostPrice - 0.25 if index < 0 else avgCostPrice + 0.25 if (index > 0 and start_position < self.start_position_sell): start_position = self.start_position_sell if (index < 0 and start_position > self.start_position_buy): start_position = self.start_position_buy if settings.MAINTAIN_SPREADS: # First positions (index 1, -1) should start right at start_position, others should branch from there index = index + 1 if index < 0 else index - 1 print('start_position: %s ' % start_position) if index > 0: return math.toNearest(start_position + L[index - 1] * 0.5, self.instrument['tickSize']) if index < 0: return math.toNearest(start_position - L[abs(index) - 1] * 0.5, self.instrument['tickSize']) if index == 0: return math.toNearest(start_position, self.instrument['tickSize'])
def get_price_offset2(self, index): """根据index依次设置每一个价格,这里为差价依次增大""" #L = [2, 5, 9, 15, 24, 40, 70, 100] L = [10, 20, 105] if abs(index) > 3: logger.error("index cannot over 3") self.exit() BXBT_MA15 = self.get_BXBT_MA15() if index > 0: L[0] = self.get_5th_max_MA15_defference() L[1] = 2 * L[0] if (BXBT_MA15 + L[index - 1] < self.start_position_sell): return math.toNearest(self.start_position_sell, self.instrument['tickSize']) else: return math.toNearest(BXBT_MA15 + L[index - 1], self.instrument['tickSize']) elif index < 0: L[0] = abs(self.get_5th_min_MA15_defference()) L[1] = 2 * L[0] if (BXBT_MA15 - L[abs(index) - 1] > self.start_position_buy): return math.toNearest(self.start_position_buy, self.instrument['tickSize']) else: return math.toNearest(BXBT_MA15 - L[abs(index) - 1], self.instrument['tickSize']) else: logger.error("offset2_index(%s) cannot 0" % index) self.exit()
def place_orders(self): """Create order items for use in convergence.""" fund = self.exchange.get_margin() ticker = self.exchange.get_ticker() instrument = self.exchange.get_instrument() position = self.exchange.get_delta() tickSize = instrument['tickSize'] # inorder to determine spread, one need to update return first self.update_ret() px_list = settings.PX_LIST qty_list = settings.QTY_LIST buy_px = [math.toNearest(ticker["buy"] * (1 - i * self.neg_ret), tickSize) for i in px_list] sell_px = [math.toNearest(ticker["sell"] * (1 + i * self.pos_ret), tickSize) for i in px_list] # total_available = 0 if self.exchange.dry_run: total_available = self.size_mul * fund['availableFunds'] / (self.instrument['highPrice'] * self.instrument['initMargin']) else: total_available = self.size_mul * fund['availableMargin'] / (self.instrument['highPrice'] * self.instrument['initMargin']) total_long = max(0, total_available - 1 * position) total_short = max(0, total_available + 1 * position) # qty_unit = math.toNearest(self.size_mul * total_available / sum(qty_list), 50) long_unit = math.toNearest(total_long / sum(qty_list), 50) short_unit = math.toNearest(total_short / sum(qty_list), 50) buy_qty = [i*long_unit for i in qty_list] sell_qty = [i*short_unit for i in qty_list] buy_orders = [{'price': price, 'orderQty': quantity, 'side': "Buy"} for price, quantity in zip(buy_px, buy_qty)] sell_orders = [{'price': price, 'orderQty': quantity, 'side': "Sell"} for price, quantity in zip(sell_px, sell_qty)] return self.converge_orders(buy_orders, sell_orders)
def get_price_offset2(self, index): """根据index依次设置每一个价格,这里为差价依次增大,为上一差价2倍""" # Maintain existing spreads for max profit if settings.MAINTAIN_SPREADS: start_position = self.start_position_buy if index < 0 else self.start_position_sell # First positions (index 1, -1) should start right at start_position, others should branch from there index = index + 1 if index < 0 else index - 1 else: # Offset mode: ticker comes from a reference exchange and we define an offset. start_position = self.start_position_buy if index < 0 else self.start_position_sell # If we're attempting to sell, but our sell price is actually lower than the buy, # move over to the sell side. if index > 0 and start_position < self.start_position_buy: start_position = self.start_position_sell # Same for buys. if index < 0 and start_position > self.start_position_sell: start_position = self.start_position_buy if (self.running_qty != 0): avgCostPrice = self.exchange.get_position()['avgCostPrice'] if (avgCostPrice % 1 == 0.5): start_position = avgCostPrice else: start_position = avgCostPrice - 0.25 if index < 0 else avgCostPrice + 0.25 if index > 0: return math.toNearest( start_position + (2**index - 1) * settings.OFFSET_SPREAD, self.instrument['tickSize']) if index < 0: return math.toNearest( start_position - (2**abs(index) - 1) * settings.OFFSET_SPREAD, self.instrument['tickSize']) if index == 0: return math.toNearest(start_position, self.instrument['tickSize'])
def get_price_offset3(self, index): """按仓位等级来设置价格, 每0.5设置一个价格""" avgCostPrice = self.exchange.get_position()['avgCostPrice'] if (avgCostPrice % 0.5 == 0): start_position = avgCostPrice else: start_position = avgCostPrice - 0.25 if index < 0 else avgCostPrice + 0.25 if (index > 0 and start_position < self.start_position_sell): start_position = self.start_position_sell + settings.INTERVAL2 elif (index < 0 and start_position > self.start_position_buy): start_position = self.start_position_buy - settings.INTERVAL2 elif index > 0: start_position = start_position + settings.INTERVAL2 elif index < 0: start_position = start_position - settings.INTERVAL2 if settings.MAINTAIN_SPREADS: # First positions (index 1, -1) should start right at start_position, others should branch from there index = index + 1 if index < 0 else index - 1 print('start_position: %s ' % start_position) if index > 0: return math.toNearest(start_position + index * 0.5, self.instrument['tickSize']) if index < 0: return math.toNearest(start_position - abs(index) * 0.5, self.instrument['tickSize']) if index == 0: return math.toNearest(start_position, self.instrument['tickSize'])
def get_fibonacci_price_offset(self, index): """Given an index (1, -1, 2, -2, etc.) return the price for that side of the book. Negative is a buy, positive is a sell.""" # Maintain existing spreads for max profit if settings.MAINTAIN_SPREADS: start_position = self.start_position_buy if index < 0 else self.start_position_sell else: # Offset mode: ticker comes from a reference exchange and we define an offset. start_position = self.start_position_buy if index < 0 else self.start_position_sell # If we're attempting to sell, but our sell price is actually lower than the buy, # move over to the sell side. if index > 0 and start_position < self.start_position_buy: start_position = self.start_position_sell # Same for buys. if index < 0 and start_position > self.start_position_sell: start_position = self.start_position_buy if index > 0: return math.toNearest( start_position + start_position * settings.INTERVAL * (fib(index) - 1), self.instrument['tickSize']) else: return math.toNearest( start_position - start_position * settings.INTERVAL * (fib(index) - 1), self.instrument['tickSize'])
def get_price_offset3(self, index): avgCostPrice = self.exchange.get_position()['avgCostPrice'] if (avgCostPrice == None): return None BXBT_MA15 = self.get_BXBT_MA15() if index > 0: if ((BXBT_MA15 + (self.get_avg_MA15_defference_postive() if self.buy_only_flag == False else self.get_5th_max_MA15_defference())) < avgCostPrice + 1): return math.toNearest(avgCostPrice + index, self.instrument['tickSize']) else: return math.toNearest( BXBT_MA15 + (self.get_avg_MA15_defference_postive() if self.buy_only_flag == False else self.get_5th_max_MA15_defference()), self.instrument['tickSize']) elif index < 0: if (( BXBT_MA15 - (self.get_avg_MA15_defference_negative() if self.sell_only_flag == False else self.get_5th_min_MA15_defference())) > avgCostPrice - 1): return math.toNearest(avgCostPrice - abs(index), self.instrument['tickSize']) else: return math.toNearest( BXBT_MA15 - (self.get_avg_MA15_defference_negative() if self.sell_only_flag == False else self.get_5th_min_MA15_defference()), self.instrument['tickSize']) else: logger.error("offset3_index(%s) cannot 0" % index) self.exit()
def get_price_offset(self, index, quantity): """Given an index (1, -1, 2, -2, etc.) return the price for that side of the book. Negative is a buy, positive is a sell.""" # Maintain existing spreads for max profit orderbook = self.exchange.ftx.market_depth(self.exchange.ftx.symbol) askprice = orderbook["asks"][0][0] bidprice = orderbook["bids"][0][0] if settings.MAINTAIN_SPREADS: #start_position = self.start_position_buy if index < 0 else self.start_position_sell start_position = bidprice if index < 0 else askprice # First positions (index 1, -1) should start right at start_position, others should branch from there index = index + 1 if index < 0 else index - 1 return math.toNearest( start_position * (1 + settings.INTERVAL)**index, 0.0001) else: start_position = bidprice if index > 0 else askprice # Offset mode: ticker comes from a reference exchange and we define an offset. # If we're attempting to sell, but our sell price is actually lower than the buy, # move over to the sell side. if index > 0 and start_position < self.start_position_buy: start_position = self.start_position_sell # Same for buys. if index < 0 and start_position > self.start_position_sell: start_position = self.start_position_buy return math.toNearest( start_position * (1 - settings.INTERVAL)**index, 0.0001)
def make_orders(self) -> None: #force a recalculation #self.get_ticker() buyprice = math.toNearest(self.start_position_buy, self.instrument['tickSize']) sellprice = math.toNearest(self.start_position_sell, self.instrument['tickSize']) self.prices_to_orders(buyprice, sellprice)
def place_orders(self) -> None: order_qty = 100 a = 707.477466 b = 19.8732468 half_spread = 0.0108980949 depth = 0.05 ticker = self.get_ticker() market_depth = self.exchange.get_market_depth() buy = sum( map( lambda x: x['size'], filter( lambda x: x['side'] == 'Buy' and x['price'] > ticker['mid'] * (1 - depth), market_depth))) sell = sum( map( lambda x: x['size'], filter( lambda x: x['side'] == 'Sell' and x['price'] < ticker[ 'mid'] * (1 + depth), market_depth))) excessive_buy = (buy - sell) / 100000000 skew = self.running_qty / settings.MAX_POSITION * b * -1 quote_mid_price = ticker['last'] + a * excessive_buy + skew new_bid_price = min(quote_mid_price * (1 - half_spread), ticker['last'] - self.instrument['tickSize']) new_ask_price = max(quote_mid_price * (1 + half_spread), ticker['last'] + self.instrument['tickSize']) new_bid_price = math.toNearest(new_bid_price, self.instrument['tickSize']) new_ask_price = math.toNearest(new_ask_price, self.instrument['tickSize']) buy_orders = [] sell_orders = [] if not self.long_position_limit_exceeded(): buy_orders.append({ 'price': new_bid_price, 'orderQty': order_qty, 'side': "Buy" }) if not self.short_position_limit_exceeded(): sell_orders.append({ 'price': new_ask_price, 'orderQty': order_qty, 'side': "Sell" }) self.converge_orders(buy_orders, sell_orders)
def get_price_offset(self, index): """Given an index (1, -1) return the price for that side of the book. -1 is a buy, 1 is a sell.""" # Offset mode: We define a naive quoting and execution method which is basically try to chase the best bids. start_position = self.start_position_buy if index < 0 else self.start_position_sell return math.toNearest(start_position, self.instrument['tickSize'])
def get_ticker(self, instrument, symbol=None): ''' Return a ticker dictionary with last, buy, sell and mid. Generated from instrument. NOTE: Values are rounded up with tick size I.E. {'last': 10563.5, 'buy': 10563.5, 'sell': 10564.0, 'mid': 10564.0} ''' if symbol is None: symbol = self.symbol # instrument = self.get_instrument(symbol) # If this is an index, we have to get the data from the last trade. if instrument['symbol'][0] == '.': ticker = {} ticker['mid'] = ticker['buy'] = ticker['sell'] = ticker[ 'last'] = instrument['markPrice'] # Normal instrument else: bid = instrument['bidPrice'] or instrument['lastPrice'] ask = instrument['askPrice'] or instrument['lastPrice'] ticker = { "last": instrument['lastPrice'], "buy": bid, "sell": ask, "mid": (bid + ask) / 2 } # The instrument has a tickSize. Use it to round values. #print({k: toNearest(float(v or 0), instrument['tickSize']) for k, v in iteritems(ticker)}) return { k: toNearest(float(v or 0), instrument['tickSize']) for k, v in iteritems(ticker) }
def get_price_offset(self, index): """Given an index (1, -1, 2, -2, etc.) return the price for that side of the book. Negative is a buy, positive is a sell.""" # Maintain existing spreads for max profit if settings.MAINTAIN_SPREADS: start_position = self.start_position_buy if index < 0 else self.start_position_sell # First positions (index 1, -1) should start right at start_position, others should branch from there index = index + 1 if index < 0 else index - 1 else: # Offset mode: ticker comes from a reference exchange and we define an offset. start_position = self.start_position_buy if index < 0 else self.start_position_sell # If we're attempting to sell, but our sell price is actually lower than the buy, # move over to the sell side. if index > 0 and start_position < self.start_position_buy: start_position = self.start_position_sell # Same for buys. if index < 0 and start_position > self.start_position_sell: start_position = self.start_position_buy interval = settings.INTERVAL if (self.running_qty > 600 and index > 0) or (self.running_qty < -600 and index > 0): interval = settings.INTERVAL_BALANCE return math.toNearest(start_position * (1 + interval) ** index, self.instrument['tickSize'])
def get_ticker(self, symbol): '''Return a ticker object. Generated from instrument.''' instrument = self.get_instrument(symbol) # If this is an index, we have to get the data from the last trade. if instrument['symbol'][0] == '.': ticker = {} ticker['mid'] = ticker['buy'] = ticker['sell'] = ticker[ 'last'] = instrument['markPrice'] # Normal instrument else: bid = instrument['bidPrice'] or instrument['lastPrice'] ask = instrument['askPrice'] or instrument['lastPrice'] ticker = { "last": instrument['lastPrice'], "buy": bid, "sell": ask, "mid": (bid + ask) / 2 } # The instrument has a tickSize. Use it to round values. return { k: toNearest(float(v or 0), instrument['tickSize']) for k, v in iteritems(ticker) }
def get_ticker(self, symbol): """Return a ticker object. Generated from instrument.""" instrument = self.get_instrument(symbol) # If this is an index, we have to get the data from the last trade. if instrument["symbol"][0] == ".": ticker = {} ticker["mid"] = ticker["buy"] = ticker["sell"] = ticker[ "last"] = instrument["markPrice"] # Normal instrument else: bid = instrument["bidPrice"] or instrument["lastPrice"] ask = instrument["askPrice"] or instrument["lastPrice"] ticker = { "last": instrument["lastPrice"], "buy": bid, "sell": ask, "mid": (bid + ask) / 2, } # The instrument has a tickSize. Use it to round values. return { k: toNearest(float(v or 0), instrument["tickSize"]) for k, v in iteritems(ticker) }
def get_price_offset2(self, index): """建仓""" if abs(index) > 1: logger.error("index cannot over 1") self.exit() ma = self.get_MA20() up, dn = self.get_UP20_DN20() md = self.get_MD20() if(md < 6): up = ma + 12 dn = ma - 12 if(self.mode_number == 0): #标准模式,买DN,卖UP;卖UP,买DN buy_price = dn sell_price = up elif(self.mode_number == 1): #上涨模式,买MA,卖UP+2 buy_price = ma if(index > 0): return None elif(self.mode_number == 2): #超涨模式,卖UP+3 return None elif(self.mode_number == 3): #下跌模式,卖MA,买DN-2 sell_price = ma if(index < 0): return None elif(self.mode_number == 4): #超跌模式,买DN-3 return None elif(self.mode_number == 5): #平稳模式 return None else: print('Error mode_number') self.exit() if index > 0: if(sell_price < self.start_position_sell+1): return math.toNearest(self.start_position_sell+1, self.instrument['tickSize']) else: return math.toNearest(sell_price, self.instrument['tickSize']) elif index < 0: if(buy_price > self.start_position_buy-1): return math.toNearest(self.start_position_buy-1, self.instrument['tickSize']) else: return math.toNearest(buy_price, self.instrument['tickSize']) else: logger.error("offset2_index(%s) cannot 0" % index) self.exit()
def get_price_offset2(self, index): """根据index依次设置每一个价格,这里为差价依次增大,分别为0.5, 1, 2, 3, 5, 7, 11, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155""" L = [ 0.5, 1, 2, 3, 5, 7, 11, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155 ] if abs(index) > 37: logger.error("ORDER_PAIRS cannot over 10") self.exit() # Maintain existing spreads for max profit if settings.MAINTAIN_SPREADS: start_position = self.start_position_buy if index < 0 else self.start_position_sell # First positions (index 1, -1) should start right at start_position, others should branch from there index = index + 1 if index < 0 else index - 1 else: # Offset mode: ticker comes from a reference exchange and we define an offset. start_position = self.start_position_buy if index < 0 else self.start_position_sell # If we're attempting to sell, but our sell price is actually lower than the buy, # move over to the sell side. if index > 0 and start_position < self.start_position_buy: start_position = self.start_position_sell # Same for buys. if index < 0 and start_position > self.start_position_sell: start_position = self.start_position_buy if (self.running_qty != 0): avgCostPrice = self.exchange.get_position()['avgCostPrice'] if (avgCostPrice % 1 == 0.5): start_position = avgCostPrice else: start_position = avgCostPrice - 0.25 if index < 0 else avgCostPrice + 0.25 if index > 0: return math.toNearest(start_position + L[index - 1], self.instrument['tickSize']) if index < 0: return math.toNearest(start_position - L[abs(index) - 1], self.instrument['tickSize']) if index == 0: return math.toNearest(start_position, self.instrument['tickSize'])
def get_price_offset3(self, index): avgCostPrice = self.exchange.get_position()['avgCostPrice'] if(avgCostPrice == None): return None ma = self.get_MA20() up, dn = self.get_UP20_DN20() md = self.get_MD20() if(self.mode_number == 0): #标准模式,买DN,卖UP;卖UP,买DN buy_price = dn sell_price = up elif(self.mode_number == 1): #上涨模式,买MA,卖UP+2 buy_price = avgCostPrice sell_price = up+2 elif(self.mode_number == 2): #超涨模式,卖UP+3 buy_price = avgCostPrice sell_price = up+3 elif(self.mode_number == 3): #下跌模式,卖MA,买DN-2 buy_price = dn-2 sell_price = avgCostPrice elif(self.mode_number == 4): #超跌模式,买DN-3 buy_price = dn-3 sell_price = avgCostPrice elif(self.mode_number == 5): #平稳模式 sell_price = self.start_position_sell buy_price = self.start_position_buy else: print('Error mode_number') self.exit() if index > 0: if(sell_price < self.start_position_sell+1 and avgCostPrice < self.start_position_sell+1): return math.toNearest(self.start_position_sell+1, self.instrument['tickSize']) elif(sell_price < avgCostPrice and self.start_position_sell+1 < avgCostPrice): return math.toNearest(avgCostPrice, self.instrument['tickSize']) else: return math.toNearest(sell_price, self.instrument['tickSize']) elif index < 0: if(buy_price > self.start_position_buy-1 and avgCostPrice > self.start_position_buy-1): return math.toNearest(self.start_position_buy-1, self.instrument['tickSize']) elif(buy_price > avgCostPrice and self.start_position_buy-1 > avgCostPrice): return math.toNearest(avgCostPrice, self.instrument['tickSize']) else: return math.toNearest(buy_price, self.instrument['tickSize']) else: logger.error("offset3_index(%s) cannot 0" % index) self.exit()
def get_price_offset(self, index): """Given an index (1, -1, 2, -2, etc.) return the price for that side of the book. Negative is a buy, positive is a sell.""" # Maintain existing spreads for max profit if settings.MAINTAIN_SPREADS: start_position = self.start_position_buy if index < 0 else self.start_position_sell # First positions (index 1, -1) should start right at start_position, others should branch from there index = index + 1 if index < 0 else index - 1 else: # Offset mode: ticker comes from a reference exchange and we define an offset. start_position = self.start_position_buy if index < 0 else self.start_position_sell # If we're attempting to sell, but our sell price is actually lower than the buy, # move over to the sell side. if index > 0 and start_position < self.start_position_buy: start_position = self.start_position_sell # Same for buys. if index < 0 and start_position > self.start_position_sell: start_position = self.start_position_buy return math.toNearest(start_position * (1 + settings.INTERVAL) ** index, self.instrument['tickSize'])
def get_ticker(self, symbol): '''Return a ticker object. Generated from instrument.''' instrument = self.get_instrument(symbol) # If this is an index, we have to get the data from the last trade. if instrument['symbol'][0] == '.': ticker = {} ticker['mid'] = ticker['buy'] = ticker['sell'] = ticker['last'] = instrument['markPrice'] # Normal instrument else: bid = instrument['bidPrice'] or instrument['lastPrice'] ask = instrument['askPrice'] or instrument['lastPrice'] ticker = { "last": instrument['lastPrice'], "buy": bid, "sell": ask, "mid": (bid + ask) / 2 } # The instrument has a tickSize. Use it to round values. return {k: toNearest(float(v or 0), instrument['tickSize']) for k, v in iteritems(ticker)}
def place_orders(self): """Create order items for use in convergence.""" buy_orders = [] sell_orders = [] buy_stop_order = {} sell_stop_order = {} order_status = 0 """order_status参数说明 0: running_qty为0, 维持原样 1: self.running_qty > 0, 买卖都变化, 买单按照offset2, 卖单按照offset3 2: 买单维持不变, 卖单按照offset3 3: self.running_qty < 0, 买卖都变化, 买单按照offset3, 卖单按照offset2 4: 卖单维持不变, 买单按照offset3 5: 追加指定订单 6: 取消指定订单 7: self.running_qty > 0, 买单按照offset2, 卖单不变 8: self.running_qty < 0, 买单不变, 卖单按照offset2 9: self.running_qty > 0, 买单维持不变, 卖单变化, 不追加 10: self.running_qty < 0, 卖单维持不变, 买单变化, 不追加 11: 订单变化, 不可追加 """ # Create orders from the outside in. This is intentional - let's say the inner order gets taken; # then we match orders from the outside in, ensuring the fewest number of orders are amended and only # a new order is created in the inside. If we did it inside-out, all orders would be amended # down and a new order would be created at the outside. avgCostPrice = self.exchange.get_position()['avgCostPrice'] print ('running_qty: %s ' % self.running_qty) print ('ORDER_START_SIZE: %s ' % self.ORDER_START_SIZE) print ('wave_coefficient: %s ' % self.get_wave_coefficient()) self.mode_number = self.select_mode() print ('select_mode: %s ' % self.mode_number) schedule.run_pending() if(((self.get_ticker()['last'] - self.get_MA20()) > 100) and self.running_qty == 0 and self.stop_market_maker_flag == False): self.stop_market_maker_flag = True if (len(self.exchange.get_orders()) != 0): self.exchange.cancel_all_orders() tg_send_important_message('超涨模式大于100,暂停交易') self.stop_price_flag = True elif(self.get_ticker()['last'] < (self.stop_order_price+50) and self.running_qty == 0 and self.stop_market_maker_flag == False): self.stop_market_maker_flag = True if (len(self.exchange.get_orders()) != 0): self.exchange.cancel_all_orders() tg_send_important_message('触发止损,暂停交易') self.stop_price_flag = True elif(self.stop_market_maker_flag == True and self.cancel_all_orders_flag == True): if (len(self.exchange.get_orders()) != 0): self.exchange.cancel_all_orders() logger.info("Cancel all orders") elif(self.stop_market_maker_flag == True and self.clear_position_flag == True): if(self.running_qty != 0): self.clear_position(buy_orders, sell_orders) else: if (len(self.exchange.get_orders()) != 0): self.exchange.cancel_all_orders() logger.info("Market_maker has stopped. No orders, no positions now") elif(self.stop_market_maker_flag == True): if(self.running_qty > 0): if avgCostPrice != None: sell_stop_order = self.prepare_stop_order(math.toNearest(avgCostPrice - STOP_SIZE, self.instrument['tickSize']), "Sell", abs(self.running_qty)) order_status = 4 elif(self.running_qty < 0): if avgCostPrice != None: buy_stop_order = self.prepare_stop_order(math.toNearest(avgCostPrice + STOP_SIZE, self.instrument['tickSize']), "Buy", abs(self.running_qty)) order_status = 2 elif(self.running_qty == 0 and self.last_running_qty == 0): if(self.stop_price_flag == True): pass elif (len(self.exchange.get_orders()) != 0): self.exchange.cancel_all_orders() logger.info("Market_maker has stopped. No orders, no positions now") elif(self.running_qty == 0 and self.restart_flag == False): self.ORDER_START_SIZE = self.start_XBt // 100000 * START_SIZE_MAGNIFICATION #新算法, 每次初始交易重新设定ORDER_START_SIZE order_status = 0 if not(self.sell_only_flag == True): buy_orders.append(self.prepare_order(-1, order_status)) if not(self.buy_only_flag == True): sell_orders.append(self.prepare_order(1, order_status)) self.restart_flag = True self.countdown_restart = 5 if(self.change_order_flag == True and self.last_mode_number2 == self.mode_number): order_status = 11 self.change_order_flag = True if(self.last_running_qty > 0): tg_send_message_alias('最后成交价格:%s' % self.last_sell_orders[0]['price']) elif(self.last_running_qty < 0): tg_send_message_alias('最后成交价格:%s' % self.last_buy_orders[0]['price']) self.countdown_180 = 180 elif(self.running_qty == 0 and self.restart_flag == True): self.countdown_restart = self.countdown_restart - 1 if(self.countdown_restart <= 0): self.restart_flag = False return elif(self.running_qty != 0 and self.last_running_qty == 0): if(self.running_qty > 0): order_status = 2 sell_orders.append(self.prepare_order(1, order_status)) if avgCostPrice != None: sell_stop_order = self.prepare_stop_order(math.toNearest(avgCostPrice - STOP_SIZE, self.instrument['tickSize']), "Sell", abs(self.running_qty)) elif(self.running_qty < 0): order_status = 4 buy_orders.append(self.prepare_order(-1, order_status)) if avgCostPrice != None: buy_stop_order = self.prepare_stop_order(math.toNearest(avgCostPrice + STOP_SIZE, self.instrument['tickSize']), "Buy", abs(self.running_qty)) self.restart_flag = False self.change_order_flag = False elif(self.running_qty != 0 and self.running_qty == self.last_running_qty and self.delay_order_check == True and False): #可以重新挂非清仓方向的价格, 目前只有一级仓位,所以不需要 i = abs(self.running_qty) // (self.ORDER_START_SIZE) + 1 if(self.running_qty > 0): order_status = 7 if(i <= 1): buy_orders.append(self.prepare_order(-i, order_status)) if(self.running_qty < 0): order_status = 8 if(i <= 1): sell_orders.append(self.prepare_order(i, order_status)) self.cycleclock = 30 self.delay_order_check = False else: if(self.running_qty > 0): if(self.running_qty != self.ORDER_START_SIZE): #部分成交, 不操作等待全部成交 return if(self.reset == True): order_status = 0 else: if(self.countdown_180 > 0): self.countdown_180 = self.countdown_180 - 1 return else: self.countdown_180 = 180 order_status = 9 sell_orders.append(self.prepare_order(1, order_status)) if(self.buy_only_flag == True): #仅挂买单的场合, 成交后平仓的卖单价格不降低 if(sell_orders[0]['price'] < self.last_sell_orders[0]['price']): return if avgCostPrice != None: sell_stop_order = self.prepare_stop_order(math.toNearest(avgCostPrice - STOP_SIZE, self.instrument['tickSize']), "Sell", abs(self.running_qty)) elif(self.running_qty < 0): if(abs(self.running_qty) != self.ORDER_START_SIZE): #部分成交, 不操作等待全部成交 return if(self.reset == True): order_status = 0 else: if(self.countdown_180 > 0): self.countdown_180 = self.countdown_180 - 1 return else: self.countdown_180 = 180 order_status = 10 buy_orders.append(self.prepare_order(-1, order_status)) if avgCostPrice != None: buy_stop_order = self.prepare_stop_order(math.toNearest(avgCostPrice + STOP_SIZE, self.instrument['tickSize']), "Buy", abs(self.running_qty)) if(self.last_running_qty != self.running_qty): self.send_tg_message() self.last_running_qty = self.running_qty self.last_mode_number2 = self.last_mode_number self.reset = False buy_orders = list(filter(None.__ne__, buy_orders)) #去除None sell_orders = list(filter(None.__ne__, sell_orders)) #去除None print(buy_orders) print(sell_orders) if((self.last_buy_orders == buy_orders and self.last_sell_orders == sell_orders) or (buy_orders == [] and sell_orders == [])): print('order no change, return') return else: self.last_buy_orders = buy_orders self.last_sell_orders = sell_orders self.converge_stop_order(buy_stop_order, sell_stop_order) return self.converge_orders(buy_orders, sell_orders, order_status)
def make_orders(self) -> None: #force a recalculation #self.get_ticker() tickLog = self.exchange.get_instrument()['tickLog'] to_amend = [] to_create = [] existing_orders = self.exchange.get_orders() buyprice = math.toNearest(self.start_position_buy, self.instrument['tickSize']) sellprice = math.toNearest(self.start_position_sell, self.instrument['tickSize']) buy_present = sell_present = False if len(existing_orders) > 1: for order in existing_orders: if order['side'] == "Buy": if order['price'] != buyprice: neworder = { 'orderID': order['orderID'], 'orderQty': settings.ORDER_START_SIZE, 'price': buyprice, 'side': "Buy" } if not buy_present: buy_present = True to_amend.append(neworder) else: #neworder['orderQty'] = 0 pass else: buy_present = True else: if order['price'] != sellprice: neworder = { 'orderID': order['orderID'], 'orderQty': settings.ORDER_START_SIZE, 'price': sellprice, 'side': "Sell" } if not sell_present: sell_present = True to_amend.append(neworder) else: #neworder['orderQty'] = 0 pass else: sell_present = True if len(to_amend) > 0: for amended_order in reversed(to_amend): reference_order = [ o for o in existing_orders if o['orderID'] == amended_order['orderID'] ][0] logger.info( "Amending %4s: %d @ %.*f to %d @ %.*f (%+.*f)" % (amended_order['side'], reference_order['leavesQty'], tickLog, reference_order['price'], (amended_order['orderQty'] - reference_order['cumQty'] ), tickLog, amended_order['price'], tickLog, (amended_order['price'] - reference_order['price']))) # This can fail if an order has closed in the time we were processing. # The API will send us `invalid ordStatus`, which means that the order's status (Filled/Canceled) # made it not amendable. # If that happens, we need to catch it and re-tick. try: self.exchange.amend_bulk_orders(to_amend) except requests.exceptions.HTTPError as e: errorObj = e.response.json() if errorObj['error']['message'] == 'Invalid ordStatus': logger.warn( "Amending failed. Waiting for order data to converge and retrying." ) sleep(0.5) return self.place_orders() else: logger.error("Unknown error on amend: %s. Exiting" % errorObj) sys.exit(1) elif len(existing_orders) == 1: for order in existing_orders: side = "Buy" if order['side'] == "Sell" else "Sell" price = buyprice if order['side'] == "Sell" else sellprice neworder = { 'price': price, 'orderQty': settings.ORDER_START_SIZE, 'side': side } to_create.append(neworder) else: #cancel existing orders and create new ones logger.info("Length of existing orders: %d" % (len(existing_orders))) self.exchange.cancel_all_orders() buyorder = { 'price': buyprice, 'orderQty': settings.ORDER_START_SIZE, 'side': "Buy" } sellorder = { 'price': sellprice, 'orderQty': settings.ORDER_START_SIZE, 'side': "Sell" } to_create.append(buyorder) to_create.append(sellorder) if len(to_create) > 0: logger.info("Creating %d orders:" % (len(to_create))) #compare_logger.info("Creating %d orders:" % (len(to_create))) for order in reversed(to_create): logger.info("%4s %d @ %.*f" % (order['side'], order['orderQty'], tickLog, order['price'])) #compare_logger.info("%4s %d @ %.*f" % (order['side'], order['orderQty'], tickLog, order['price'])) self.exchange.create_bulk_orders(to_create)
def place_orders(self): """Converge the orders we currently have in the book with what we want to be in the book. This involves amending any open orders and creating new ones if any have filled completely. We start from the closest orders outward.""" tickLog = self.exchange.get_instrument()['tickLog'] to_amend = [] to_create = [] to_cancel = [] buys_matched = 0 sells_matched = 0 existing_orders = self.exchange.get_orders() position = self.exchange.get_position() if position['avgEntryPrice'] == 0: self.exchange.cancel_bulk_orders(existing_orders) self.running_entry = 0 self.starting_qty = 0 self.running_qty = 0 return # Check if the position was modified. if abs(self.running_entry - position['avgEntryPrice']) / self.running_qty > 0.01: logger.info('The position is modified. Reset all params.') self.exchange.cancel_bulk_orders(existing_orders) existing_orders = [] self.running_qty = self.starting_qty = self.exchange.get_delta() self.running_entry = position['avgEntryPrice'] pending_vol = sum( [o['leavesQty'] for o in existing_orders if o['side'] == 'Sell']) remaining_vol = self.starting_qty * settings.POSITION_PERCENTAGE - ( self.starting_qty - self.running_qty) - pending_vol if remaining_vol == 0: return # Check the current profit level # If the profit is larger than 1%, place orders at PROFIT_LEVEL+delta # If not, place orders at ENTRY+delta current_pl = (self.start_position_mid - self.running_entry) / self.running_entry logger.info('Current profit: {:.2f}'.format(current_pl)) if current_pl > settings.PROFIT_THRESHOLD: self.start_position_sell = self.running_entry * ( 1.0002 + settings.PROFIT_LEVEL) else: # Price falling, getting out at even. self.start_position_sell = min(self.start_position_sell, self.running_entry * 1.001) to_cancel = [] # Cancel orders at the profit level for o in existing_orders: if o['price'] >= self.running_entry * ( 1 + settings.PROFIT_THRESHOLD): to_cancel.append(o) existing_orders.remove(o) remaining_vol += o['orderQty'] if to_cancel: self.exchange.cancel_bulk_orders(to_cancel) logger.info('Start selling at {:.2f}'.format(self.start_position_sell)) logger.info('Remaining quantity(excluding placed orders): {}'.format( remaining_vol)) buy_orders = [] sell_orders = [] # Create orders from the outside in. This is intentional - let's say the inner order gets taken; # then we match orders from the outside in, ensuring the fewest number of orders are amended and only # a new order is created in the inside. If we did it inside-out, all orders would be amended # down and a new order would be created at the outside. for i in reversed(range(1, settings.ORDER_PAIRS + 1)): if not self.long_position_limit_exceeded(): buy_orders.append(self.prepare_order(-i)) if not self.short_position_limit_exceeded(): sell_orders.append(self.prepare_order(i)) # Check all existing orders and match them up with what we want to place. # If there's an open one, we might be able to amend it to fit what we want. for order in existing_orders: try: if order['side'] == 'Buy': desired_order = buy_orders[buys_matched] buys_matched += 1 else: desired_order = sell_orders[sells_matched] sells_matched += 1 except IndexError: # Will throw if there isn't a desired order to match. In that case, cancel it. to_cancel.append(order) # while buys_matched < len(buy_orders): # to_create.append(buy_orders[buys_matched]) # buys_matched += 1 while sells_matched < len(sell_orders): to_create.append(sell_orders[sells_matched]) sells_matched += 1 if len(to_create) > 0: new_vol = sum( [o['orderQty'] for o in to_create if o['side'] == 'Sell']) if remaining_vol < new_vol: for o in to_create: o['orderQty'] = int(remaining_vol / len(to_create)) if remaining_vol < settings.ORDER_START_SIZE: min_price = min([o['price'] for o in to_create]) to_create[0]['price'] = math.toNearest( min_price, self.instrument['tickSize']) to_create[0]['orderQty'] = remaining_vol to_create = [to_create[0]] logger.info("Creating %d orders:" % (len(to_create))) for order in reversed(to_create): logger.info("%4s %d @ %.*f" % (order['side'], order['orderQty'], tickLog, order['price'])) self.exchange.create_bulk_orders(to_create) # Could happen if we exceed a delta limit if len(to_cancel) > 0: logger.info("Canceling %d orders:" % (len(to_cancel))) for order in reversed(to_cancel): logger.info("%4s %d @ %.*f" % (order['side'], order['leavesQty'], tickLog, order['price'])) self.exchange.cancel_bulk_orders(to_cancel)
def get_avg_index(URLS): prices = [get_price(url) for url in URLS if get_price(url)] print(prices) avg_price = sum(prices)/len(prices) avg_price = math.toNearest(avg_price,0.01) return avg_price
def place_orders(self): """Create order items for use in convergence.""" buy_orders = [] sell_orders = [] # Create orders from the outside in. This is intentional - let's say the inner order gets taken; # then we match orders from the outside in, ensuring the fewest number of orders are amended and only # a new order is created in the inside. If we did it inside-out, all orders would be amended # down and a new order would be created at the outside. # if not self.check_stable(): # print('Current not stable') # return # existing_orders = self.exchange.get_orders() position = self.exchange.get_position() margin = self.exchange.get_margin() margin_available = margin["marginBalance"] margin_used_pct = margin["marginUsedPcnt"] wallet_balance = margin["walletBalance"] liq_price = position[ "liquidationPrice"] if "liquidationPrice" in position and position[ "liquidationPrice"] else 0.0 write_json_to_shm(margin, 'margin.json') write_json_to_shm(position, 'position.json') cost = 0 if position['currentQty'] != 0: cost = float(position['avgCostPrice']) print(datetime.utcnow()) print('position %d, cost %f, midprice %f, liq price %f' % (position['currentQty'] if position['currentQty'] else 0.0, cost, self.start_position_mid, liq_price)) print( 'margin used percent %f, margin available %.6f, wallet balance %.6f' % (margin_used_pct, XBt_to_XBT(margin_available), XBt_to_XBT(wallet_balance))) # print(margin) if self.last_position != position['currentQty']: self.last_position_change_time = datetime.now() ticker = self.exchange.get_ticker() write_json_to_shm(ticker, 'ticker.json') print('Settingssss:', settings.MAX_POSITION, settings.ORDER_SIZE) # No position's open if position['currentQty'] == 0: buy_total = 0 buy_price = ticker['buy'] while buy_total < settings.MAX_POSITION: buy_price = math.toNearest( buy_price - buy_price * settings.INTERVAL, self.instrument['tickSize']) buy_size = settings.ORDER_SIZE buy_total += buy_size buy_orders.append({ 'price': buy_price, 'orderQty': buy_size, 'side': "Buy" }) sell_total = 0 sell_price = ticker['sell'] while sell_total < abs(settings.MIN_POSITION): sell_price = math.toNearest( sell_price + sell_price * settings.INTERVAL, self.instrument['tickSize']) sell_size = settings.ORDER_SIZE sell_total += sell_size sell_orders.append({ 'price': sell_price, 'orderQty': sell_size, 'side': "Sell" }) # long position elif position['currentQty'] > 0: buy_total = position['currentQty'] buy_price = ticker['buy'] while buy_total < settings.MAX_POSITION: buy_price = math.toNearest( buy_price - buy_price * settings.INTERVAL, self.instrument['tickSize']) if buy_price <= liq_price: break buy_size = settings.ORDER_SIZE buy_total += buy_size buy_orders.append({ 'price': buy_price, 'orderQty': buy_size, 'side': "Buy" }) sell_total = -position['currentQty'] sell_price = ticker['sell'] while sell_total < abs(settings.MIN_POSITION): sell_price = math.toNearest( sell_price + sell_price * settings.INTERVAL, self.instrument['tickSize']) sell_size = settings.ORDER_SIZE if sell_price >= cost and abs( position['currentQty']) >= sell_size * 2: sell_size = sell_size * 2 sell_total += sell_size sell_orders.append({ 'price': sell_price, 'orderQty': sell_size, 'side': "Sell" }) # short position elif position['currentQty'] < 0: buy_total = position['currentQty'] buy_price = ticker['buy'] while buy_total < settings.MAX_POSITION: buy_price = math.toNearest( buy_price - buy_price * settings.INTERVAL, self.instrument['tickSize']) buy_size = settings.ORDER_SIZE if buy_price <= cost and abs( position['currentQty']) >= buy_size * 2: buy_size = buy_size * 2 buy_total += buy_size buy_orders.append({ 'price': buy_price, 'orderQty': buy_size, 'side': "Buy" }) sell_total = -position['currentQty'] sell_price = ticker['sell'] while sell_total < abs(settings.MIN_POSITION): sell_price = math.toNearest( sell_price + sell_price * settings.INTERVAL, self.instrument['tickSize']) if sell_price >= liq_price: break sell_size = settings.ORDER_SIZE sell_total += sell_size sell_orders.append({ 'price': sell_price, 'orderQty': sell_size, 'side': "Sell" }) # print(buy_orders) # print(sell_orders) self.last_position = position['currentQty'] return self.converge_orders(buy_orders, sell_orders, self.martin_signal)
def place_orders(self): """Create order items for use in convergence.""" buy_orders = [] sell_orders = [] buy_stop_order = {} sell_stop_order = {} order_status = 0 """order_status参数说明 0: running_qty为0, 维持原样 1: self.running_qty > 0, 买卖都变化, 买单按照offset2, 卖单按照offset3 2: 买单维持不变, 卖单按照offset3 3: self.running_qty < 0, 买卖都变化, 买单按照offset3, 卖单按照offset2 4: 卖单维持不变, 买单按照offset3 5: 追加指定订单 6: 取消指定订单 7: self.running_qty > 0, 买单按照offset2, 卖单不变 8: self.running_qty < 0, 买单不变, 卖单按照offset2 """ # Create orders from the outside in. This is intentional - let's say the inner order gets taken; # then we match orders from the outside in, ensuring the fewest number of orders are amended and only # a new order is created in the inside. If we did it inside-out, all orders would be amended # down and a new order would be created at the outside. position_grade = self.get_position_grade() avgCostPrice = self.exchange.get_position()['avgCostPrice'] print('position_grade: %s ' % position_grade) print('running_qty: %s ' % self.running_qty) print('ORDER_START_SIZE: %s ' % self.ORDER_START_SIZE) schedule.run_pending() if (self.countdown == True ): #设置倒数计时, 60秒后delay_order_check设为True, 可以重新挂非清仓方向的价格 self.cycleclock = self.cycleclock - 1 if (self.cycleclock <= 0): if (self.check_last_price_upordown() == True): self.cycleclock = 5 else: self.countdown = False self.delay_order_check = True if (self.get_ticker()['last'] > STOP_PRICE and self.buy_only_flag == False): self.buy_only_flag = True if (self.running_qty < 0): self.clear_position(buy_orders, sell_orders) return self.converge_orders(buy_orders, sell_orders, order_status) if (self.get_5th_max_MA15_defference(getmessage=1) > 100): self.stop_market_maker_flag = True self.cancel_all_orders_flag = True self.buy_only_flag = False self.sell_only_flag = False tg_important_message('上涨差值超过100,暂停交易') if (self.stop_market_maker_flag == True and self.cancel_all_orders_flag == True): if (len(self.exchange.get_orders()) != 0): self.exchange.cancel_all_orders() logger.info("Cancel all orders") elif (self.stop_market_maker_flag == True and self.clear_position_flag == True): if (self.running_qty != 0): self.clear_position(buy_orders, sell_orders) else: if (len(self.exchange.get_orders()) != 0): self.exchange.cancel_all_orders() logger.info( "Market_maker has stopped. No orders, no positions now") elif (self.stop_market_maker_flag == True): if (self.running_qty > 0): if avgCostPrice != None: sell_stop_order = self.prepare_stop_order( math.toNearest(avgCostPrice - STOP_SIZE, self.instrument['tickSize']), "Sell", abs(self.running_qty)) order_status = 4 elif (self.running_qty < 0): if avgCostPrice != None: buy_stop_order = self.prepare_stop_order( math.toNearest(avgCostPrice + STOP_SIZE, self.instrument['tickSize']), "Buy", abs(self.running_qty)) order_status = 2 elif (self.running_qty == 0 and self.last_running_qty == 0): if (len(self.exchange.get_orders()) != 0): self.exchange.cancel_all_orders() logger.info( "Market_maker has stopped. No orders, no positions now") elif (self.running_qty == 0 and self.restart_flag == False): if (self.check_last_price_upordown() == True): self.restart_flag = True self.countdown_restart = 5 return self.ORDER_START_SIZE = self.start_XBt // 1000000 * START_SIZE_MAGNIFICATION #新算法, 每次初始交易重新设定ORDER_START_SIZE order_status = 0 if not (self.sell_only_flag == True): buy_orders.append(self.prepare_order(-1, order_status)) if not (self.buy_only_flag == True): sell_orders.append(self.prepare_order(1, order_status)) self.countdown = False self.restart_flag = True self.countdown_restart = 30 elif (self.running_qty == 0 and self.restart_flag == True): self.countdown_restart = self.countdown_restart - 1 if (self.countdown_restart <= 0): self.restart_flag = False return elif (self.running_qty != 0 and self.running_qty != self.last_running_qty ): #仓位变动后开始倒计时60秒, 60秒后delay_order_check为True, 可以重新挂非清仓方向的价格 if (self.running_qty > 0): order_status = 2 sell_orders.append(self.prepare_order(1, order_status)) elif (self.running_qty < 0): order_status = 4 buy_orders.append(self.prepare_order(-1, order_status)) self.cycleclock = 60 self.countdown = True self.restart_flag = False self.delay_order_check = False elif (self.running_qty != 0 and self.running_qty == self.last_running_qty and self.delay_order_check == True): #可以重新挂非清仓方向的价格 i = abs(self.running_qty) // (self.ORDER_START_SIZE // 4) + 1 if (self.running_qty > 0): order_status = 7 if (i <= 3): buy_orders.append(self.prepare_order(-i, order_status)) if (self.running_qty < 0): order_status = 8 if (i <= 3): sell_orders.append(self.prepare_order(i, order_status)) self.cycleclock = 30 self.countdown = True self.delay_order_check = False else: if (self.running_qty > 0): order_status = 2 sell_orders.append(self.prepare_order(1, order_status)) elif (self.running_qty < 0): order_status = 4 buy_orders.append(self.prepare_order(-1, order_status)) if (self.last_running_qty != self.running_qty): self.send_tg_message() self.last_running_qty = self.running_qty self.reset = False buy_orders = list(filter(None.__ne__, buy_orders)) #去除None sell_orders = list(filter(None.__ne__, sell_orders)) #去除None print('BXBT_MA15: %s' % self.get_BXBT_MA15()) print(buy_orders) print(sell_orders) if ((self.last_buy_orders == buy_orders and self.last_sell_orders == sell_orders) or (buy_orders == [] and sell_orders == [])): print('order no change, return') return else: self.last_buy_orders = buy_orders self.last_sell_orders = sell_orders self.converge_stop_order(buy_stop_order, sell_stop_order) return self.converge_orders(buy_orders, sell_orders, order_status)