def bbtInit(self): self.api = cl.bbCCXTInit(n=self.n) riskDf = cl.bbtGetRiskDf(self.api, self.spotDict) for ccy in self.validCcys: if ccy in riskDf.index: self.futures.loc[ccy, 'FutDelta']=cl.bbtGetFutPos(self.api,ccy) self.liqDict[ccy] = riskDf.loc[ccy,'liq'] else: self.liqDict[ccy] = 0 self.calcFuturesDeltaUSD() ##### if self.n>=2: # trim list for auxiliary BBTs self.validCcys=list(self.futures.index[self.futures['FutDelta'] != 0]) ##### self.oneDayIncome = 0 self.prevIncome = 0 if CR_CONFIGS_DICT['IS_CALC_PAYMENTS']: pmts=pd.DataFrame() for ccy in self.validCcys: data = cl.bbtGetTradeExecutionList(self.api,ccy) if not data is None: pmts = pmts.append(pd.DataFrame(data).set_index('symbol', drop=False)) if len(pmts)>0: cl.dfSetFloat(pmts, ['fee_rate', 'exec_fee']) pmts.loc[['Sell' in z for z in pmts['order_id']],'fee_rate']*=-1 # Correction for fee_rate signs pmts['incomeUSD'] = -pmts['exec_fee'] * self.spotDict['USDT'] pmts['date'] = [datetime.datetime.fromtimestamp(int(ts) / 1000) for ts in pmts['trade_time_ms']] pmts = pmts.set_index('date').sort_index() ##### self.oneDayIncome = pmts['incomeUSD'].sum() self.prevIncome = pmts.loc[pmts.index[-1]]['incomeUSD'].sum() self.setAnnRets() ##### usdtDict=self.api.v2_private_get_wallet_balance({'coin': 'USDT'})['result']['USDT'] equity = float(usdtDict['equity']) self.nav = equity * self.spotDict['USDT'] self.spots.loc['USDT', 'SpotDelta'] = equity self.calcSpotDeltaUSD() ##### for ccy in self.validCcys: oneDayFunding = 0 prevFunding = 0 estFunding=0 estFunding2=0 if CR_CONFIGS_DICT['IS_CALC_PAYMENTS']: if len(pmts)>0: df=pmts.loc[pmts['symbol']==ccy+'USDT','fee_rate'] if len(df) > 0: oneDayFunding = df.mean() * 3 * 365 prevFunding = df[df.index[-1]].mean() * 3 * 365 ##### if CR_CONFIGS_DICT['IS_CALC_ESTS']: estFunding, estFunding2 = self.bbtGetEstFundings_fast(ccy) self.makeFundingStr(ccy, oneDayFunding, prevFunding, estFunding, estFunding2) ##### self.makeIncomesStr() self.makeLiqStr(riskDf=riskDf,availableBalance=float(usdtDict['available_balance'])) self.isDone = True
if max_size > position_value: select_id = int(risk['id']) select_lev = float(risk['max_leverage']) if int(pos['risk_id']) != select_id: api.v2_private_post_position_risk_limit({ 'symbol': sym, 'risk_id': select_id }) if lev < select_lev: api.v2_private_post_position_leverage_save({ 'symbol': sym, 'leverage': select_lev, 'leverage_only': True }) print( f'{sym} {position_value:,.0f} -> Risk limit ({max_size:,.0f}) Leverage ({select_lev})' ) break ###### # Main ###### cl.printHeader('BBAutoRiskLimit - ' + cl.getCurrentTime()) bb = cl.bbCCXTInit() BB_AutoRiskLimit(bb, sym_list)
for i in range(-100, 100): additional = i * 5000 df['unrealised_pnl_sim'] = df['unrealised_pnl'] + df['delta_value'] * (tgtLiqH - 1) df['ab_delta'] = df['unrealised_pnl_sim'].clip(None, 0) - df['unrealised_pnl'].clip(None, 0) ab = availableBalance + additional + df['ab_delta'].sum() df['cushion'] = ab + df['im_value'] - df['mm_value'] + df['unrealised_pnl_sim'].clip(0, None) if df['cushion'].min() > 0: return additional # -ve = money can leave account return 0 ###### # Init ###### apiDict=cl.getApiDict() spotDict=dict() spotDict['USDT']=cl.ftxGetMid(apiDict['ftx'],'USDT/USD') ##### riskDfs = [] for i in range(SHARED_EXCH_DICT['bbt']): riskDfs.append(cl.bbtGetRiskDfs(i + 1, spotDict)) cl.parallelRun(riskDfs) ###### # Main ###### for i in range(SHARED_EXCH_DICT['bbt']): cl.printHeader('BBT' + str(i + 1)) usdtDict=cl.bbCCXTInit(i+1).v2_private_get_wallet_balance({'coin': 'USDT'})['result']['USDT'] print('Adjustment = ',str(bbtGetAdj(riskDfs[0].riskDf, float(usdtDict['available_balance']), tgtLiqH)))
if lev[side] < select_lev: api.private_linear_post_position_set_leverage({ 'symbol': sym, side.lower() + '_leverage': select_lev, opp_side.lower() + '_leverage': lev[opp_side] }) isMod = True if isMod: print( f'{sym} {position_value:,.0f} -> Risk limit ({max_size:,.0f}) Leverage ({select_lev})' ) break ###### # Init ###### cl.printHeader('BBTAutoRiskLimit - ' + cl.getCurrentTime()) apiDict = cl.getApiDict() spotDict = dict() spotDict['USDT'] = cl.ftxGetMid(apiDict['ftx'], 'USDT/USD') # Traditional for i in range(SHARED_EXCH_DICT['bbt']): cl.printHeader('BBT' + str(i + 1)) bb = cl.bbCCXTInit(i + 1) df = cl.bbtGetRiskDf(bb, spotDict) autoRiskLimit(bb, df.index)
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
self.label = self.ccy + ': ' + str(round(self.fDict['ftxEstFunding1'] * 100)) + '//' + \ str(round(self.fDict['bbtEstFunding1'] * 100)) + '/' + str(round(self.fDict['bbtEstFunding2'] * 100)) + \ '; sb=' + str(round(sbBps)) + \ '; yield=' + cl.fmtPct(self.yld, None) self.label += '; turn=$' + str(round(self.tickersDf.loc[self.ccy, 'turnover_24h'] / 1e6)) + 'M' if len(self.df) > 0: self.label += '; fut=$' + str(round(self.futDeltaUSD / 1000)) + 'K' if self.futDeltaUSD>0: color = 'red' self.label = termcolor.colored(self.label, color) ###### # Init ###### cl.printHeader('BBTr - '+cl.getCurrentTime()) apiDict=cl.getApiDict() apiDict['bb']=cl.bbCCXTInit(2) spotDict=dict() spotDict['USDT']=cl.ftxGetMid(apiDict['ftx'],'USDT/USD') ##### riskDfs = [] for i in range(SHARED_EXCH_DICT['bbt']): riskDfs.append(cl.bbtGetRiskDfs(i + 1, spotDict)) cl.parallelRun(riskDfs) ##### ccys=[] for i in range(SHARED_EXCH_DICT['bbt']): ccys.extend(list(riskDfs[i].riskDf.index)) ##### tickersDf = pd.DataFrame(apiDict['bb'].v2PublicGetTickers()['result']).set_index('symbol') tickersDf = tickersDf[['USDT' in symbol for symbol in tickersDf.index]] myList=[ticker[:len(ticker)-4] for ticker in tickersDf.index]
def bbInit(self): def getPayments(ccy): n = 0 df = pd.DataFrame() while True: n += 1 tl = self.api.v2_private_get_execution_list({'symbol': ccy + 'USD', 'start_time': cl.getYest() * 1000, 'limit': 1000, 'page': n})['result']['trade_list'] if tl is None: break else: df = df.append(pd.DataFrame(tl)) if len(df)==0: return None else: return df.set_index('symbol', drop=False) ##### self.api = cl.bbCCXTInit() self.wallet=pd.DataFrame(self.api.v2_private_get_wallet_balance()['result']).transpose() cl.dfSetFloat(self.wallet,'equity') for ccy in self.validCcys: self.spots.loc[ccy,'SpotDelta']=self.wallet.loc[ccy,'equity'] self.calcSpotDeltaUSD() ##### futs = self.api.v2_private_get_position_list()['result'] futs = pd.DataFrame([pos['data'] for pos in futs]).set_index('symbol') cl.dfSetFloat(futs, ['size','liq_price','position_value','unrealised_pnl']) for ccy in self.validCcys: ccy2=ccy+'USD' mult = -1 if futs.loc[ccy2,'side']=='Sell' else 1 self.futures.loc[ccy, 'FutDelta'] = futs.loc[ccy2, 'size'] * mult / self.spotDict[ccy] self.liqDict[ccy] = futs.loc[ccy2,'liq_price'] / cl.bbGetMid(self.api,ccy) self.calcFuturesDeltaUSD() ##### self.oneDayIncome=0 self.prevIncome=0 if CR_CONFIGS_DICT['IS_CALC_PAYMENTS']: pmts = pd.DataFrame() for ccy in self.validCcys: pmts = pmts.append(getPayments(ccy)) if len(pmts)>0: pmts = pmts[pmts['exec_type'] == 'Funding'].copy() cl.dfSetFloat(pmts, ['fee_rate', 'exec_fee']) pmts.loc[['Sell' in z for z in pmts['order_id']],'fee_rate']*=-1 # Correction for fee_rate signs for ccy in self.validCcys: ccy2=ccy+'USD' if ccy2 in pmts.index: pmts.loc[ccy2, 'incomeUSD'] = -pmts.loc[ccy2, 'exec_fee'] * self.spotDict[ccy] pmts['date'] = [datetime.datetime.fromtimestamp(int(ts) / 1000) for ts in pmts['trade_time_ms']] pmts = pmts.set_index('date') ##### if len(pmts)>0: self.oneDayIncome = pmts['incomeUSD'].sum() self.prevIncome = pmts.loc[pmts.index[-1]]['incomeUSD'].sum() self.setAnnRets() ##### self.nav=self.spots['SpotDeltaUSD'].sum() ##### for ccy in self.validCcys: oneDayFunding = 0 prevFunding = 0 estFunding = 0 estFunding2 = 0 if CR_CONFIGS_DICT['IS_CALC_PAYMENTS']: if len(pmts) > 0: df = pmts.loc[pmts['symbol'] == ccy + 'USD', 'fee_rate'] if len(df) > 0: oneDayFunding = df.mean() * 3 * 365 prevFunding = df[df.index[-1]].mean() * 3 * 365 ##### if CR_CONFIGS_DICT['IS_CALC_ESTS']: estFunding,estFunding2 = cl.bbGetEstFundings(self.api, ccy) self.makeFundingStr(ccy, oneDayFunding, prevFunding, estFunding, estFunding2) ##### self.makeIncomesStr() self.isDone = True