| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- import time
- from calcTools import *
- from osTools import *
- from web3Tools import *
- class MaxProfitUtils:
- # 判断两个数组是否有交集
- @staticmethod
- def has_intersection(arr1, arr2):
- return len(set(arr1) & set(arr2)) > 0
- # 若二维数组中所有数组与指定数组没有交集,返回True
- @staticmethod
- def all_has_no_intersection(swap_details_list, check_swap_details):
- for swap_details in swap_details_list:
- if MaxProfitUtils.has_intersection(swap_details['swapPath'], check_swap_details['swapPath']):
- return False
- return True
- # 求和swap详情list的利润并返回
- @staticmethod
- def get_profit_sum(swap_details_list):
- profit_sum = 0
- for swap_details in swap_details_list:
- profit_sum += swap_details['profit']
- return profit_sum
- @staticmethod
- def get_max_profit_swap_details_list(x, y):
- return x if MaxProfitUtils.get_profit_sum(x) > MaxProfitUtils.get_profit_sum(y) else y
- # 得出指定数据结构中的最大利润path
- @staticmethod
- def max_profit_path_list(origin_swap_details_list, level=0, swap_details_list=None):
- # first level
- if time.time() - initbestTradeListTime>60:
- printTime('max_profit_path_list loong')
- if swap_details_list is None:
- swap_details_list = []
- # last level
- # >=
- if level == len(origin_swap_details_list):
- return swap_details_list
- # 此层的swap_path与当前的swap_path_list内的所有swap_path都没有交集的话,将此层的加入为x路径
- x = []
- if MaxProfitUtils.all_has_no_intersection(swap_details_list, origin_swap_details_list[level]):
- new_swap_details_list = json.loads(json.dumps(swap_details_list))
- new_swap_details_list.append(origin_swap_details_list[level])
- x = MaxProfitUtils.max_profit_path_list(origin_swap_details_list, level+1, new_swap_details_list)
- # 不将此层加入的y路径
- y = MaxProfitUtils.max_profit_path_list(origin_swap_details_list, level+1, swap_details_list)
- return MaxProfitUtils.get_max_profit_swap_details_list(x, y)
- def calOnlyLpInRouterArray(routerArray):
- onlyLpArray = []
- for router in routerArray:
- for lpInfo in router:
- lp = lpInfo['lp']
- if lp in onlyLpArray:
- continue
- if lp in nowBlockLpRes:
- continue
- onlyLpArray.append(lp)
- return onlyLpArray
- def calRouterProfit(router):
- # 整理LP信息
- for lpInfo in router:
- lpAddress = lpInfo['lp']
- r0 = nowBlockLpRes[lpAddress][0]
- r1 = nowBlockLpRes[lpAddress][1]
- if lpAddress not in topLpInfo:
- return False
- lpInfo['fee'] = topLpInfo[lpAddress]['fee']
- if lpInfo['inToken'] < lpInfo['outToken']:
- lpInfo['rIn'] = r0
- lpInfo['rOut'] = r1
- else:
- lpInfo['rIn'] = r1
- lpInfo['rOut'] = r0
- # ABA
- if len(router) == 2:
- tokenLoan = router[1]['outToken']
- tokenIn0 = router[0]['inToken']
- tokenLoanETHPrice = baseTokenInfo[tokenLoan]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** baseTokenInfo[tokenLoan]['decimals']
- # WETH - A - WETH
- tradeInfo = calBestAmountV2V2(router[0]['rIn'], router[0]['rOut'], router[0]['fee'], router[1]['rIn'], router[1]['rOut'], router[1]['fee'] )
- profit = tradeInfo['profit']
- tradeInfo['ethProfit'] = profit * tokenLoanETHPrice
- #printTime(router, amountIn0, amountOut0, amountOut1, profit)
- if tradeInfo['ethProfit'] < tradeMinProfit:
- return False
- else:
- tradeInfo['lp0'] = router[0]['lp']
- tradeInfo['lp1'] = router[1]['lp']
- tradeInfo['fee0'] = router[0]['fee']
- tradeInfo['fee1'] = router[1]['fee']
- tradeInfo['indexIn0'] = router[0]['indexIn']
- tradeInfo['indexIn1'] = router[1]['indexIn']
- tradeInfo['tokenLoan'] = tokenLoan
- tradeInfo['tokenIn0'] = tokenIn0
- tradeInfo['tradeToken0'] = router[0]['outToken']
- tradeInfo['type'] = 'type2'
- return tradeInfo
- # ABCA
- elif len(router) == 3:
- tokenLoan = router[2]['outToken']
- tokenIn0 = router[0]['inToken']
- tokenLoanETHPrice = baseTokenInfo[tokenLoan]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** baseTokenInfo[tokenLoan]['decimals']
- tradeInfo = calBestAmountABCA(router[0]['rIn'], router[0]['rOut'], router[0]['fee'],
- router[1]['rIn'], router[1]['rOut'], router[1]['fee'],
- router[2]['rIn'], router[2]['rOut'], router[2]['fee'])
- profit = tradeInfo['profit']
- tradeInfo['ethProfit'] = profit * tokenLoanETHPrice
- #printTime(router, amountIn0, amountOut0, amountOut1, amountOut2, profit)
- if tradeInfo['ethProfit'] < tradeMinProfit:
- return False
- else:
- tradeInfo['lp0'] = router[0]['lp']
- tradeInfo['lp1'] = router[1]['lp']
- tradeInfo['lp2'] = router[2]['lp']
- tradeInfo['fee0'] = router[0]['fee']
- tradeInfo['fee1'] = router[1]['fee']
- tradeInfo['fee2'] = router[2]['fee']
- tradeInfo['indexIn0'] = router[0]['indexIn']
- tradeInfo['indexIn1'] = router[1]['indexIn']
- tradeInfo['indexIn2'] = router[2]['indexIn']
- tradeInfo['tokenLoan'] = tokenLoan
- tradeInfo['tokenIn0'] = tokenIn0
- tradeInfo['tradeToken0'] = router[0]['outToken']
- tradeInfo['tradeToken1'] = router[1]['outToken']
- tradeInfo['type'] = 'type3'
- return tradeInfo
- def callABCA(lp0, lp1, lpLoan, tokenIn0, tokenLoan, fee0, fee1, fee2, lp0InIndex, lp1InIndex, lp2InIndex, minProfit, block = 'latest'):
- function = '0x1d650c35'
- inputData = encodeInput(lp0, lp1, lpLoan, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- fee0, fee1, fee2, lp0InIndex, lp1InIndex, lp2InIndex,
- tokenIn0, tokenLoan, minProfit, 0)
- inputData = function + inputData
- r = gasCal(myAddress, v3CCAddress, inputData, block)
- tradeInfo = {'type':3, 'lp0': lp0, 'lp1': lp1, 'lpLoan':lpLoan, 'tokenIn':tokenIn0, 'tokenLoan':tokenLoan, 'profit':0, 'sumValue':0}
- if len(r['info']) != 23 or r['info'][-1] == 0:
- return tradeInfo
- sumValue = r['info'][3] + r['info'][4] + r['info'][5] + r['info'][6] + r['info'][7] + r['info'][8]
- tradeInfo['sumValue'] = sumValue
- tradeInfo['profit'] = r['info'][-1]
- tradeInfo['gasUsed'] = r['gasUsed']
- tradeInfo['inputData'] = inputData
- return tradeInfo
- def callABA(lp0, lp1, tokenIn0, tokenLoan, fee0, fee1, lp0InIndex, lp1InIndex, minProfit, block = 'latest'):
- function = '0xa628df6d'
- inputData = encodeInput(lp0, lp1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- fee0, fee1, 0, lp0InIndex, lp1InIndex, 0,
- tokenIn0, tokenLoan, minProfit, 0)
- inputData = function + inputData
- r = gasCal(myAddress, v3CCAddress, inputData, block)
- tradeInfo = {'type':2, 'lp0': lp0, 'lpLoan':lp1, 'tokenIn':tokenIn0, 'tokenLoan':tokenLoan, 'profit':0, 'sumValue':0}
- if len(r['info']) != 23 or r['info'][-1] == 0:
- return tradeInfo
- sumValue = r['info'][3] + r['info'][4] + r['info'][5] + r['info'][6] + r['info'][7] + r['info'][8]
- tradeInfo['sumValue'] = sumValue
- tradeInfo['profit'] = r['info'][-1]
- tradeInfo['gasUsed'] = r['gasUsed']
- tradeInfo['inputData'] = inputData
- return tradeInfo
- def readABA():
- array = []
- for i in baseTokenInfo:
- i = i.lower()
- iiArray = readText('aba' + i + i)
- array = array + iiArray
- array = array + readText('aba' + WETHW + WETH)
- array = array + readText('aba' + WETH + WETHW)
- return array
- def readABCA():
- array = []
- for i in baseTokenInfo:
- i = i.lower()
- iiArray = readText('abca' + i + i)
- array = array + iiArray
- array = array + readText('abca' + WETHW + WETH)
- array = array + readText('abca' + WETH + WETHW)
- return array
- topLpInfo = readText('topLP')
- lpRouterInfo = readABCA()
- lpRouterInfo = lpRouterInfo + readABA()
- printTime('v3 start')
- v3CCAddress = '0xB4971D0dda22359Ad86867362b7FC3206eA0d86B'
- dataUsed = []
- nowBlockLpRes = {}
- initBlock = w3.eth.blockNumber
- while True:
- try:
- if time.time() % 60 > 50 and time.time() % 60 < 55:
- topLpInfo = readText('topLP')
- lpRouterInfo = readABCA()
- lpRouterInfo = lpRouterInfo + readABA()
- blockNumber = w3.eth.blockNumber
- if blockNumber == initBlock:
- time.sleep(0.1)
- continue
- initBlock = blockNumber
- baseGasPrice = getBaseGasPrice(blockNumber) * 1.5
- if baseGasPrice < 1.6 * 1e9:
- baseGasPrice = 1.6 * 1e9
- nowBlockLpRes = {}
- # 找出有关该LP的路由
- lpRouterArray = lpRouterInfo # findLpRouter(nowBlockLpTradeI, lpRouterInfo)
- # 过滤需要获取余额的路由
- lpOnlyRouterArray = calOnlyLpInRouterArray(lpRouterArray)
- # printTime(len(lpOnlyRouterArray), len(lpRouterArray))
- # 获取余额
- lpResArray = w3.dex.getPairSBalance(lpOnlyRouterArray, blockNumber)
- # 余额进行缓存
- for lpResI in lpResArray:
- nowBlockLpRes[lpResI] = lpResArray[lpResI]
- #计算每一个路由的利润
- tradeInfoArray = []
- initForTime = time.time()
- for lpRouter in lpRouterArray:
- if time.time() - initForTime > 60:
- printTime('lpRouterArray long time')
- tradeInfo = calRouterProfit(lpRouter)
- if tradeInfo:
- type = tradeInfo['type']
- if type == 'type2':
- result = callABA(tradeInfo['lp0'], tradeInfo['lp1'],
- tradeInfo['tokenIn0'], tradeInfo['tokenLoan'],
- tradeInfo['fee0'], tradeInfo['fee1'],
- tradeInfo['indexIn0'], tradeInfo['indexIn1'],
- baseTokenInfo[tradeInfo['tokenIn0']]['profitMin'], blockNumber)
- if result['profit'] < tradeMinProfit:
- continue
- sumValue = result['sumValue']
- if sumValue in dataUsed:
- continue
- tokenLoanETHPrice = baseTokenInfo[tradeInfo['tokenLoan']]['price'] * 10 ** baseTokenInfo[WETH]['decimals'] / 10 ** \
- baseTokenInfo[tradeInfo['tokenLoan']]['decimals']
- result['ethProfit'] = result['profit'] * tokenLoanETHPrice
- result['ethProfit-E18'] = result['profit'] * tokenLoanETHPrice / 1e18
- result['tureProfit'] = result['ethProfit'] - result['gasUsed'] * baseGasPrice
- result['maxPrice'] = result['ethProfit'] / result['gasUsed']
- if result['tureProfit'] < tradeMinProfit:
- continue
- tradeInfoArray.append(result)
- if type == 'type3':
- result = callABCA(tradeInfo['lp0'], tradeInfo['lp1'], tradeInfo['lp2'],
- tradeInfo['tokenIn0'], tradeInfo['tokenLoan'],
- tradeInfo['fee0'], tradeInfo['fee1'],tradeInfo['fee2'],
- tradeInfo['indexIn0'], tradeInfo['indexIn1'], tradeInfo['indexIn2'],
- baseTokenInfo[tradeInfo['tokenIn0']]['profitMin'], blockNumber)
- if result['profit'] < tradeMinProfit:
- continue
- sumValue = result['sumValue']
- if sumValue in dataUsed:
- continue
- tokenLoanETHPrice = baseTokenInfo[tradeInfo['tokenLoan']]['price'] * 10 ** baseTokenInfo[WETH][
- 'decimals'] / 10 ** \
- baseTokenInfo[tradeInfo['tokenLoan']]['decimals']
- result['ethProfit'] = result['profit'] * tokenLoanETHPrice
- result['ethProfit-E18'] = result['profit'] * tokenLoanETHPrice / 1e18
- result['tureProfit'] = result['ethProfit'] - result['gasUsed'] * baseGasPrice
- result['maxPrice'] = result['ethProfit'] / result['gasUsed']
- if result['tureProfit'] < tradeMinProfit:
- continue
- tradeInfoArray.append(result)
- if len(tradeInfoArray) != 0 :
- #printTime('trade List' ,blockNumber, tradeInfoArray)
- tradeList = []
- initForTime = time.time()
- for tradeInfoI in tradeInfoArray:
- if tradeInfoI['type'] == 2:
- tradeList.append({"swapPath": [tradeInfoI['lp0'], tradeInfoI['lpLoan']], "profit": tradeInfoI['tureProfit'], 'data':tradeInfoI})
- if tradeInfoI['type'] == 3:
- tradeList.append(
- {"swapPath": [tradeInfoI['lp0'], tradeInfoI['lp1'],tradeInfoI['lpLoan']], "profit": tradeInfoI['tureProfit'], 'data':tradeInfoI})
- newMinProfit = tradeMinProfit
- while len(tradeList) > 50:
- totalProfit = 0
- newMinProfit = newMinProfit * 1.1
- newTradeList = []
- for tradeI in tradeList:
- if tradeI['profit'] > newMinProfit:
- newTradeList.append(tradeI)
- totalProfit = totalProfit + tradeI['profit']
- tradeList = newTradeList
- initbestTradeListTime = time.time()
- bestTradeList = MaxProfitUtils.max_profit_path_list(tradeList)
- initForTime = time.time()
- for bestTradeI in bestTradeList:
- if time.time() - initForTime > 60:
- printTime('bestTradeList long time')
- printTime(blockNumber, 'bset', bestTradeI['swapPath'], bestTradeI['profit'])
- sumValue = bestTradeI['data']['sumValue']
- inputData = bestTradeI['data']['inputData']
- nowGasPrice = bestTradeI['data']['maxPrice'] * 0.2
- if nowGasPrice < baseGasPrice *1.2:
- nowGasPrice = baseGasPrice * 1.2
- if nowGasPrice > baseGasPrice * 1.8:
- nowGasPrice = baseGasPrice * 1.8
- gasLimit = 1e6 + bestTradeI['data']['maxPrice'] / 1e9 + 1
- if gasLimit > 1e6 + 2000:
- gasLimit = 1e6 + 2000
- params = {}
- params['method'] = 'send'
- params['params'] = {'toAddress': v3CCAddress, 'inputData': inputData,
- 'gasPrice': nowGasPrice, 'gasLimit': gasLimit}
- try:
- hs = requests.post(url='http://127.0.0.1:410/operation', json=params).text
- if len(hs)>50:
- printTime(blockNumber, 'https://www.oklink.com/en/ethw/tx/' + str(hs))
- dataUsed.append(sumValue)
- except:
- hs = 'err seed'
- printTime('-' * 50)
- except BaseException as err:
- printTime(traceback.format_exc())
- printTime('loop', )
- time.sleep(20)
-
|