def sendOrders(apiDict,isFTXSpot,ftxSide,exch,side,api,ccy,trade_qty): if exch=='bbt': fill = cl.bbtRelOrder(side, api, ccy, trade_qty, maxChases=888, distance=CT_CONFIGS_DICT['BBT_LEG1_DISTANCE_TICKS']) elif exch=='kut': fill = cl.kutRelOrder(side, api, ccy, trade_qty, maxChases=888, distance=CT_CONFIGS_DICT['KUT_LEG1_DISTANCE_TICKS']) else: sys.exit(1) fill*=cl.ftxGetMid(apiDict['ftx'], 'USDT/USD') if side == 'SELL': shortFill = fill else: longFill = fill ##### if isFTXSpot: ftxTicker = ccy + '/USD' ftxDistance = CT_CONFIGS_DICT['SPOT_LEG2_DISTANCE_TICKS'] else: ftxTicker = ccy + '-PERP' ftxDistance = CT_CONFIGS_DICT['FTX_LEG2_DISTANCE_TICKS'] fill = cl.ftxRelOrder(ftxSide, apiDict['ftx'], ftxTicker, trade_qty, maxChases=888, distance=ftxDistance) if ftxSide == 'SELL': shortFill = fill else: longFill = fill return longFill, shortFill
sys.exit(1) ###### # Main ###### for i in range(SHARED_EXCH_DICT['bbt']): n = i + 1 cl.printHeader('BBT' + str(n)) bb = cl.bbCCXTInit(n) while True: bbtPos = cl.bbtGetFutPos(bb, ccy) ftxPos = ftxGetPos(unwindExch) if bbtPos < -qty and ftxPos > qty: cl.bbtRelOrder('BUY', bb, ccy, qty, maxChases=888, distance=bbtDistance) print() cl.ftxRelOrder('SELL', ftx, ftxTicker, qty, maxChases=888, distance=ftxDistance) print() else: break print('BBT Unwind finished!') cl.speak('B B T Unwind finished')
def bbtCrossOrder(bbNB, bbNS, ccy, trade_qty, distance=0): @retry(wait_fixed=1000, stop_max_attempt_number=SHARED_ETC_DICT['RETRY_MAX_ATTEMPTS']) def getSymbols(bb): return pd.DataFrame(bb.v2PublicGetSymbols()['result']).set_index('name') ###### @retry(wait_fixed=1000, stop_max_attempt_number=SHARED_ETC_DICT['RETRY_MAX_ATTEMPTS']) def getData(bb, ticker): return bb.v2PublicGetTickers({'symbol': ticker})['result'][0] ###### # Do not use @retry def getIsReduceOnly(bb, ticker, side, qty): df = pd.DataFrame(bb.private_linear_get_position_list({'symbol': ticker})['result']).set_index('side') oppSide = 'Sell' if side == 'BUY' else 'Buy' return qty <= float(df.loc[oppSide, 'size']) ##### # Do not use @retry def placeOrder(bb, ticker, side, qty, limitPrice): return bb.private_linear_post_order_create({'side': side.capitalize(), 'symbol': ticker, 'order_type': 'Limit', 'qty': qty, 'price': limitPrice, 'time_in_force': 'GoodTillCancel', 'reduce_only': bool(getIsReduceOnly(bb, ticker, side, qty)), 'close_on_trigger': False})['result']['order_id'] ##### # Do not use @retry def cancelOrder(bb, ticker, orderId): try: bb.private_linear_post_order_cancel({'symbol': ticker, 'order_id': orderId}) except: pass ##### @retry(wait_fixed=1000, stop_max_attempt_number=SHARED_ETC_DICT['RETRY_MAX_ATTEMPTS']) def getOrder(bb, ticker, orderId): return bb.private_linear_get_order_search({'symbol': ticker, 'order_id': orderId})['result'] ##### # Do not use @retry def calcFill(orderStatus): filledSize = float(orderStatus['cum_exec_qty']) filledValue = float(orderStatus['cum_exec_value']) if filledSize == 0: return 0 else: return filledValue / filledSize ##### if bbNB==bbNS: print('Cannot cross against oneself!') sys.exit(1) bbB=cl.bbCCXTInit(bbNB) bbS=cl.bbCCXTInit(bbNS) ticker = ccy+'USDT' symbols = getSymbols(bbB) maxTradingQty=float(symbols.loc[ticker, 'lot_size_filter']['max_trading_qty']) qty = round(min(trade_qty,maxTradingQty), 3) data = getData(bbB, ticker) bid = float(data['bid_price']) ask = float(data['ask_price']) isUpTick = 'Plus' in data['last_tick_direction'] limitPrice = ask if isUpTick else bid suffix1 = ' (qty=' + str(qty) + ') ....' suffix2 = '; price=' + str(limitPrice) + '] ' if not isUpTick: print(cl.timeTag('Sending buy order in BBT' + str(bbNB) + suffix1)) print(cl.timeTag('Sending sell order in BBT' + str(bbNS) + suffix1)) buyOrderId = placeOrder(bbB, ticker, 'BUY', qty, limitPrice) sellOrderId = placeOrder(bbS, ticker, 'SELL', qty, limitPrice) print(cl.timeTag('[DEBUG: buyOrderId=' + buyOrderId + suffix2)) print(cl.timeTag('[DEBUG: sellOrderId=' + sellOrderId + suffix2)) else: print(cl.timeTag('Sending sell order in BBT' + str(bbNS) + suffix1)) print(cl.timeTag('Sending buy order in BBT' + str(bbNB) + suffix1)) sellOrderId = placeOrder(bbS, ticker, 'SELL', qty, limitPrice) buyOrderId = placeOrder(bbB, ticker, 'BUY', qty, limitPrice) print(cl.timeTag('[DEBUG: sellOrderId=' + sellOrderId + suffix2)) print(cl.timeTag('[DEBUG: buyOrderId=' + buyOrderId + suffix2)) time.sleep(3) cancelOrder(bbB, ticker, buyOrderId) cancelOrder(bbS, ticker, sellOrderId) buyOrderStatus = getOrder(bbB, ticker, buyOrderId) sellOrderStatus = getOrder(bbS, ticker, sellOrderId) leavesQtyB=qty-float(buyOrderStatus['cum_exec_qty']) leavesQtyS=qty-float(sellOrderStatus['cum_exec_qty']) # Fix rounding issues threshold=500 if (leavesQtyB*limitPrice)<threshold: leavesQtyB=0 if (leavesQtyS*limitPrice)<threshold: leavesQtyS=0 fillB1 = calcFill(buyOrderStatus) fillS1 = calcFill(sellOrderStatus) if leavesQtyB==0 and leavesQtyS==0: print(cl.timeTag('[DEBUG: clean cross!]')) return 0 # zero slippage elif leavesQtyB>0 and leavesQtyS==0: fillB2=cl.bbtRelOrder('BUY',bbB,ccy,leavesQtyB,maxChases=888,distance=distance) fillBAvg=(fillB1*(qty-leavesQtyB) + fillB2*leavesQtyB)/qty fillSAvg=fillS1 elif leavesQtyB==0 and leavesQtyS>0: fillS2 = cl.bbtRelOrder('SELL', bbS, ccy, leavesQtyS, maxChases=888, distance=distance) fillSAvg = (fillS1 * (qty - leavesQtyS) + fillS2 * leavesQtyS) / qty fillBAvg=fillB1 else: # partial fills for both print('bbtCrossOrder abnormal termination!') sys.exit(1) return fillBAvg / fillSAvg - 1 # slippage