├── README.md ├── images ├── thousandTrading.jpg ├── thousandTrading.png ├── wallet.jpg └── wallet.png ├── margin_spot_strategy └── margin_dig_btc.py ├── the_king_of_banzhuan └── BanZhuanKing.py └── trend_strategy └── strategy.py /README.md: -------------------------------------------------------------------------------- 1 | # thousandTrading 2 | Quantized transaction strategy open source 3 | 4 | 微信公众号《千千的量化世界》,致力于提供免费的量化交易策略源码。 5 | 6 | 关注微信公众号或哔哩哔哩可以查看最新量化策略讲解视频,欢迎量化爱好者进入我们的讨论群。 7 | 8 | 进群请联系管理员微信thousandtrading 9 | 10 | ![image](https://github.com/thousandTrading/thousandTrading/blob/master/images/thousandTrading.jpg) 11 | 12 | 开源不易,适当赞赏可以提升千千的更新动力 13 | 14 | ![image](https://github.com/thousandTrading/thousandTrading/blob/master/images/wallet.jpg) 15 | -------------------------------------------------------------------------------- /images/thousandTrading.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinjuo/thousandTrading/3a2d7e3d8d88ddef8b0fb4e57ec01b9f75879fb4/images/thousandTrading.jpg -------------------------------------------------------------------------------- /images/thousandTrading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinjuo/thousandTrading/3a2d7e3d8d88ddef8b0fb4e57ec01b9f75879fb4/images/thousandTrading.png -------------------------------------------------------------------------------- /images/wallet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinjuo/thousandTrading/3a2d7e3d8d88ddef8b0fb4e57ec01b9f75879fb4/images/wallet.jpg -------------------------------------------------------------------------------- /images/wallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinjuo/thousandTrading/3a2d7e3d8d88ddef8b0fb4e57ec01b9f75879fb4/images/wallet.png -------------------------------------------------------------------------------- /margin_spot_strategy/margin_dig_btc.py: -------------------------------------------------------------------------------- 1 | #作者:千千量化 2 | #高频交易程序,历史业绩最高一天80%,最低一天20%,最大回撤5%,平均3天翻一倍 3 | #原理比较简单,现在已经不赚了,千万不要盲目实盘去跑,原因就不说了,免费开源,有兴趣看看 4 | #这个策略实盘的时候是加了现货杠杆,10个账号,4个币对,总共40个机器人在20台服务器上运行,另外还有一个风控监控程序独立运行 5 | from fcoin3 import Fcoin 6 | import ccxt 7 | import time 8 | import logging 9 | import threading 10 | import random 11 | 12 | class MyThread(threading.Thread): 13 | def __init__(self, func, args=()): 14 | super(MyThread, self).__init__() 15 | self.func = func 16 | self.args = args 17 | 18 | def run(self): 19 | self.result = self.func(*self.args) 20 | 21 | def get_result(self): 22 | try: 23 | return self.result 24 | except: 25 | return {'asks':[[0, 0]],'bids':[[0, 0]]} 26 | 27 | 28 | # super params 29 | SYMBOL = 'BTC/USDT' 30 | symbol = 'btcusdt' 31 | price_increment = 0.1 32 | level = 10 33 | ratio = 10 34 | interval = 0.2 35 | s_amount = 0.02 36 | min_amount = 0.005 37 | 38 | logger = logging.getLogger(__name__) 39 | logger.setLevel(level=logging.DEBUG) 40 | console = logging.StreamHandler() 41 | console.setLevel(logging.DEBUG) 42 | formatter = logging.Formatter('[%(asctime)s] %(message)s') 43 | handler = logging.FileHandler("btc_%s.txt" % time.strftime("%Y-%m-%d %H-%M-%S")) 44 | handler.setLevel(logging.DEBUG) 45 | handler.setFormatter(formatter) 46 | logger.addHandler(console) 47 | logger.addHandler(handler) 48 | 49 | f = open('accounts.txt') 50 | lines = f.readlines() 51 | acct_id = int(lines[-1]) 52 | api_key = lines[acct_id*2 - 2].strip('\n') 53 | seceret_key = lines[acct_id*2 - 1].strip('\n') 54 | fcoin = Fcoin() 55 | fcoin.auth(api_key, seceret_key) # fcoin.margin_buy('ethusdt', 0.01, 10) 56 | ex0 = ccxt.fcoin() 57 | ex1 = ccxt.okex3() 58 | ex2 = ccxt.binance() 59 | ex3 = ccxt.huobipro() 60 | type = 'limit' 61 | pre_trend = 0 62 | pre_price_1 = 0 63 | pre_price_2 = 0 64 | pre_price_3 = 0 65 | pre_price_4 = 0 66 | pre_price_5 = 0 67 | buy_id = [] 68 | sell_id = [] 69 | loop = 0 70 | while True: 71 | try: 72 | amount = s_amount + random.randint(0, 99) / 100000 73 | # cancel order 74 | for id in buy_id: 75 | try: 76 | result = fcoin.cancel_order(id) 77 | if result == None:logger.info('closing') 78 | if result['status'] == 0:logger.info('canceled') 79 | except: 80 | pass 81 | for id in sell_id: 82 | try: 83 | result = fcoin.cancel_order(id) 84 | if result == None:logger.info('closing') 85 | if result['status'] == 0:logger.info('canceled') 86 | except: 87 | pass 88 | buy_id = [] 89 | sell_id = [] 90 | 91 | # fetch orderbook 92 | t = [] 93 | result = [] 94 | t.append(MyThread(ex0.fetch_order_book, args=(SYMBOL,))) 95 | t.append(MyThread(ex1.fetch_order_book, args=(SYMBOL,))) 96 | t.append(MyThread(ex2.fetch_order_book, args=(SYMBOL,))) 97 | t.append(MyThread(ex3.fetch_order_book, args=(SYMBOL,))) 98 | for i in t: 99 | i.setDaemon(True) 100 | i.start() 101 | for i in t: 102 | i.join() 103 | result.append(i.get_result()) 104 | price_bid = result[0]['bids'][0][0] 105 | price_ask = result[0]['asks'][0][0] 106 | price = (price_bid + price_ask) / 2 107 | price_1 = (result[1]['bids'][0][0] + result[1]['asks'][0][0]) / 2 108 | price_2 = (result[2]['bids'][0][0] + result[2]['asks'][0][0]) / 2 109 | price_3 = (result[3]['bids'][0][0] + result[3]['asks'][0][0]) / 2 110 | bidq0, askq0 = result[0]['bids'][0][1], result[0]['asks'][0][1] 111 | bidq1, askq1 = result[1]['bids'][0][1], result[1]['asks'][0][1] 112 | bidq2, askq2 = result[2]['bids'][0][1], result[2]['asks'][0][1] 113 | bidq3, askq3 = result[3]['bids'][0][1], result[3]['asks'][0][1] 114 | # choose trend 115 | trend, trend1, trend2, trend3 = 0, 0, 0, 0 116 | if price_1 > pre_price_1 + level * price_increment: trend1 = 1 117 | if price_2 > pre_price_2 + level * price_increment: trend2 = 1 118 | if price_3 > pre_price_3 + level * price_increment: trend3 = 1 119 | if price_1 < pre_price_1 - level * price_increment: trend1 = -1 120 | if price_2 < pre_price_2 - level * price_increment: trend2 = -1 121 | if price_3 < pre_price_3 - level * price_increment: trend3 = -1 122 | trend = trend1 + trend2 + trend3 123 | # logger.info('***%s || trend:%d price:%4.3f || trend1:%d trend2:%d trend3:%d' % ( 124 | # time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), trend, price, trend1, trend2, trend3)) 125 | 126 | # create order 127 | if trend > 0 and loop > 0: 128 | try: 129 | result = fcoin.margin_buy(symbol, round(price_bid + ratio * price_increment, 1), round(amount, 4)) 130 | buy_id.append(result['data']) 131 | logger.info('>> buy ' + str(price_bid) + ' ' + str(amount)) 132 | except Exception as e: 133 | try: 134 | # balance = fcoin.get_margin_balance() 135 | # for i in balance['data']: 136 | # if i['currency']=='usdt':USDT_amount = float(i['available']) 137 | # if i['currency']=='btc':BTC_amount = float(i['available']) 138 | # buy_amount = USDT_amount/price_ask -0.00001 139 | # if buy_amount > min_amount: 140 | result = fcoin.margin_buy(symbol, round(price_bid + ratio * price_increment, 1), round(min_amount, 4)) 141 | buy_id.append(result['data']) 142 | logger.info('>> buy ' + str(price_bid) + ' ' + str(min_amount)) 143 | except: 144 | pass 145 | if trend < 0 and loop > 0: 146 | try: 147 | result = fcoin.margin_sell(symbol, round(price_ask - ratio * price_increment, 1), round(amount, 4)) 148 | sell_id.append(result['data']) 149 | logger.info('>> sell ' + str(price_ask) + ' ' + str(amount)) 150 | except Exception as e: 151 | try: 152 | # balance = fcoin.get_margin_balance() 153 | # for i in balance['data']: 154 | # if i['currency']=='usdt':USDT_amount = float(i['available']) 155 | # if i['currency']=='btc':BTC_amount = float(i['available']) 156 | # sell_amount = BTC_amount -0.00001 157 | # if sell_amount> min_amount: 158 | result = fcoin.margin_sell(symbol, round(price_ask - ratio * price_increment, 1), round(min_amount, 4)) 159 | sell_id.append(result['data']) 160 | logger.info('>> sell ' + str(price_ask) + ' ' + str(min_amount)) 161 | except: 162 | pass 163 | 164 | # record price 165 | pre_price_1 = price_1 166 | pre_price_2 = price_2 167 | pre_price_3 = price_3 168 | pre_trend = trend 169 | 170 | # sleep 171 | time.sleep(interval) 172 | 173 | # 174 | loop += 1 175 | 176 | except Exception as e: 177 | logger.error(e) 178 | -------------------------------------------------------------------------------- /the_king_of_banzhuan/BanZhuanKing.py: -------------------------------------------------------------------------------- 1 | # 作者:千千量化 2 | # 说明:这是一个实盘月化3-5%以上的套利策略,策略特点:稳健、高收益、低风险。 3 | # 策略包含:三角套利、跨市双边、跨市三角。 4 | import ccxt # 导入ccxt开源库,封装了各交易所rest api,通过 pip install ccxt安装 5 | import time # 导入time库,用于获取计时和定时睡眠 6 | import logging # 导入logging库,用于记录日志 7 | import threading # 导入threading库,用于多线程询价和下单 8 | 9 | class MyThread(threading.Thread): # 创建一个多线程调用类,便于后续进行多线程询价和下单 10 | def __init__(self,func,args=()): 11 | super(MyThread,self).__init__() 12 | self.func = func 13 | self.args = args 14 | 15 | def run(self): 16 | self.result = self.func(*self.args) 17 | 18 | def get_result(self): # 这个方法用于返回多线程运行结果 19 | try: 20 | return self.result # 如果子线程不使用join方法,此处可能会报没有self.result的错误 21 | except Exception as e: 22 | return e 23 | 24 | class BanZhuanKing: # 套利策略主类库 25 | def __init__(self, exchange_name,api_key,seceret_key,passphrase,check_box,ratio=0.5,fee_ratio_box=[1,1,1]): 26 | self.exchange_name = exchange_name #存放交易所名称 27 | self.api_key = api_key # 存放 apikey 28 | self.seceret_key= seceret_key #存放 seceretkey 29 | self.passphrase = passphrase #存放password 30 | self.check_box = check_box #存放搜索的币对 31 | self.ratio = ratio # 吃单比例不能为1,否则补单的时候需要溢价补单 ,钱不够就出错了 32 | self.fee_ratio_box = fee_ratio_box 33 | self.num = 0 #记录循环次数 34 | self.signal_num = 0 #记录发现开仓信号次数 35 | self.open_num = 0 #记录开仓次数 36 | self.open_fail = 0 #记录下单错误次数 37 | self.maker_fail = 0 #记录补单次数(如果限价单下单后没有全部成交,则需要进行补单) 38 | self.error_num = 0 # 出错次数 39 | self.handle_open = 1 #是否处理未成交订单 40 | self.wait_time = 6 #每次下单后的等待时间,一般5~10秒 41 | self.win = {} # 存储盈利信息 42 | self.win['BTC'] = 0 43 | self.win['USDT'] = 0 44 | self.version = 'V1.2.0' 45 | self.init_total = {} # 存放初始币量 46 | 47 | def ChooseExchange(self): 48 | mode = self.num % 3 49 | if mode == 0: 50 | self.box = self.check_box[0] 51 | self.exchange_name_1 = self.exchange_name[0] 52 | self.exchange_name_2 = self.exchange_name[1] 53 | self.exchange_name_3 = self.exchange_name[2] 54 | self.api_key_1 = self.api_key[0] 55 | self.api_key_2 = self.api_key[1] 56 | self.api_key_3 = self.api_key[2] 57 | self.seceret_key_1 = self.seceret_key[0] 58 | self.seceret_key_2 = self.seceret_key[1] 59 | self.seceret_key_3 = self.seceret_key[2] 60 | self.passphrase_1 = self.passphrase[0] 61 | self.passphrase_2 = self.passphrase[1] 62 | self.passphrase_3 = self.passphrase[2] 63 | self.fee_ratio_1 = self.fee_ratio_box[0] 64 | self.fee_ratio_2 = self.fee_ratio_box[1] 65 | if mode == 1: 66 | self.box = self.check_box[1] 67 | self.exchange_name_1 = self.exchange_name[0] 68 | self.exchange_name_2 = self.exchange_name[2] 69 | self.exchange_name_3 = self.exchange_name[1] 70 | self.api_key_1 = self.api_key[0] 71 | self.api_key_2 = self.api_key[2] 72 | self.api_key_3 = self.api_key[1] 73 | self.seceret_key_1 = self.seceret_key[0] 74 | self.seceret_key_2 = self.seceret_key[2] 75 | self.seceret_key_3 = self.seceret_key[1] 76 | self.passphrase_1 = self.passphrase[0] 77 | self.passphrase_2 = self.passphrase[2] 78 | self.passphrase_3 = self.passphrase[1] 79 | self.fee_ratio_1 = self.fee_ratio_box[0] 80 | self.fee_ratio_2 = self.fee_ratio_box[2] 81 | if mode == 2: 82 | self.box = self.check_box[2] 83 | self.exchange_name_1 = self.exchange_name[1] 84 | self.exchange_name_2 = self.exchange_name[2] 85 | self.exchange_name_3 = self.exchange_name[0] 86 | self.api_key_1 = self.api_key[1] 87 | self.api_key_2 = self.api_key[2] 88 | self.api_key_3 = self.api_key[0] 89 | self.seceret_key_1 = self.seceret_key[1] 90 | self.seceret_key_2 = self.seceret_key[2] 91 | self.seceret_key_3 = self.seceret_key[0] 92 | self.passphrase_1 = self.passphrase[1] 93 | self.passphrase_2 = self.passphrase[2] 94 | self.passphrase_3 = self.passphrase[0] 95 | self.fee_ratio_1 = self.fee_ratio_box[1] 96 | self.fee_ratio_2 = self.fee_ratio_box[2] 97 | self.log.debug('====================') 98 | self.log.debug("eat ratio :%f" % self.ratio) 99 | self.log.debug("fee ratio 1 :%f" % self.fee_ratio_1) 100 | self.log.debug("fee ratio 2 :%f" % self.fee_ratio_2) 101 | self.log.debug("exchange1: %s" % self.exchange_name_1) 102 | self.log.debug("exchange2: %s" % self.exchange_name_2) 103 | self.log.debug(self.box) 104 | self.log.debug('====================') 105 | # 实例化ccxt 106 | exchange_name = self.exchange_name_1 107 | if exchange_name == 'okex': self.exchange_1 = ccxt.okex( 108 | {"apiKey": self.api_key_1, "secret": self.seceret_key_1, "password": self.passphrase_1}) 109 | if exchange_name == 'okex3': self.exchange_1 = ccxt.okex3( 110 | {"apiKey": self.api_key_1, "secret": self.seceret_key_1, "password": self.passphrase_1}) 111 | if exchange_name == 'huobi': self.exchange_1 = ccxt.huobipro( 112 | {"apiKey": self.api_key_1, "secret": self.seceret_key_1}) 113 | if exchange_name == 'binance': self.exchange_1 = ccxt.binance( 114 | {"apiKey": self.api_key_1, "secret": self.seceret_key_1}) 115 | if exchange_name == 'gateio': self.exchange_1 = ccxt.gateio( 116 | {"apiKey": self.api_key_1, "secret": self.seceret_key_1}) 117 | if exchange_name == 'fcoin': self.exchange_1 = ccxt.fcoin( 118 | {"apiKey": self.api_key_1, "secret": self.seceret_key_1}) 119 | exchange_name = self.exchange_name_2 120 | if exchange_name == 'okex': self.exchange_2 = ccxt.okex( 121 | {"apiKey": self.api_key_2, "secret": self.seceret_key_2, "password": self.passphrase_2}) 122 | if exchange_name == 'okex3': self.exchange_2 = ccxt.okex3( 123 | {"apiKey": self.api_key_2, "secret": self.seceret_key_2, "password": self.passphrase_2}) 124 | if exchange_name == 'huobi': self.exchange_2 = ccxt.huobipro( 125 | {"apiKey": self.api_key_2, "secret": self.seceret_key_2}) 126 | if exchange_name == 'binance': self.exchange_2 = ccxt.binance( 127 | {"apiKey": self.api_key_2, "secret": self.seceret_key_2}) 128 | if exchange_name == 'gateio': self.exchange_2 = ccxt.gateio( 129 | {"apiKey": self.api_key_2, "secret": self.seceret_key_2}) 130 | if exchange_name == 'fcoin': self.exchange_2 = ccxt.fcoin( 131 | {"apiKey": self.api_key_2, "secret": self.seceret_key_2}) 132 | exchange_name = self.exchange_name_3 #实例化另一个交易所,用来计算总资产 133 | if exchange_name == 'okex': self.exchange_3 = ccxt.okex( 134 | {"apiKey": self.api_key_3, "secret": self.seceret_key_3, "password": self.passphrase_3}) 135 | if exchange_name == 'okex3': self.exchange_3 = ccxt.okex3( 136 | {"apiKey": self.api_key_3, "secret": self.seceret_key_3, "password": self.passphrase_3}) 137 | if exchange_name == 'huobi': self.exchange_3 = ccxt.huobipro( 138 | {"apiKey": self.api_key_3, "secret": self.seceret_key_3}) 139 | if exchange_name == 'binance': self.exchange_3 = ccxt.binance( 140 | {"apiKey": self.api_key_3, "secret": self.seceret_key_3}) 141 | if exchange_name == 'gateio': self.exchange_3 = ccxt.gateio( 142 | {"apiKey": self.api_key_3, "secret": self.seceret_key_3}) 143 | if exchange_name == 'fcoin': self.exchange_3 = ccxt.fcoin( 144 | {"apiKey": self.api_key_3, "secret": self.seceret_key_3}) 145 | self.exchange_1.load_markets() 146 | self.exchange_2.load_markets() 147 | 148 | def InitLog(self): 149 | self.log = logging.getLogger(__name__) 150 | self.log.setLevel(logging.DEBUG) 151 | # log to txt 152 | formatter = logging.Formatter('[%(asctime)s] %(message)s') 153 | handler = logging.FileHandler("log_%s.txt" % time.strftime("%Y-%m-%d %H-%M-%S")) 154 | # handler = logging.handlers.RotatingFileHandler("log_%s.txt" % time.strftime("%Y-%m-%d %H-%M-%S"),maxBytes=1024*1024,backupCount=50) 155 | handler.setLevel(logging.DEBUG) 156 | handler.setFormatter(formatter) 157 | # log to console 158 | console = logging.StreamHandler() 159 | console.setLevel(logging.INFO) 160 | self.log.addHandler(handler) 161 | self.log.addHandler(console) 162 | self.log.debug("搬砖之王%s"%self.version) 163 | 164 | def GetLimit(self,symbol,mode): 165 | base = symbol.split('/')[0] 166 | quote = symbol.split('/')[1] 167 | if mode == 1: 168 | markets = self.markets_1 169 | exchange_name = self.exchange_name_1 170 | if mode == 2: 171 | markets = self.markets_2 172 | exchange_name = self.exchange_name_2 173 | for i in markets: 174 | if i['symbol'] == symbol: 175 | min_amt = i['limits']['amount']['min'] if 'amount' in i['limits'] else 0 176 | min_price = i['limits']['price']['min'] if 'price' in i['limits'] else 0 177 | min_cost = i['limits']['cost']['min'] if 'cost' in i['limits'] else 0 178 | if exchange_name == 'okex3': min_amt = min_cost 179 | if exchange_name == 'fcoin' and base == 'TRX': min_amt = 50 180 | if exchange_name == 'fcoin' and base == 'XLM': min_amt = 5 181 | if exchange_name == 'fcoin' and base == 'ETH' and quote == 'BTC': min_amt = 0.001 182 | if exchange_name == 'fcoin' and base == 'ETC' and quote == 'BTC': min_amt = 0.001 183 | if exchange_name == 'fcoin' and base == 'LTC' : min_amt = 0.01 184 | if exchange_name == 'fcoin' and base == 'EOS' : min_amt = 0.1 185 | if exchange_name == 'fcoin' and base == 'XRP' : min_amt = 1 186 | if exchange_name == 'gateio' and base == 'ETH': min_amt = 0.005 187 | if exchange_name == 'gateio' and base == 'TRX': min_amt = 60 188 | if exchange_name == 'gateio' and base == 'XLM': min_amt = 15 189 | if exchange_name == 'gateio' and base == 'EOS': min_amt = 0.3 190 | if exchange_name == 'gateio' and base == 'ETC': min_amt = 0.6 191 | return float(min_amt)*1.05,float(min_price),float(min_cost) 192 | 193 | def GetOrderBook(self,symbol,exchange): 194 | if exchange == 1:result = self.exchange_1.fetch_order_book(symbol=symbol,limit=None) 195 | if exchange == 2:result = self.exchange_2.fetch_order_book(symbol=symbol,limit=None) 196 | return result['bids'][0][0],result['bids'][0][1],result['asks'][0][0],result['asks'][0][1] 197 | 198 | def CreatOrder(self,symbol,exchange,type,side,amount,price): 199 | try: 200 | if exchange == 1: result = self.exchange_1.create_order(symbol, type, side, amount, price) 201 | if exchange == 2: result = self.exchange_2.create_order(symbol, type, side, amount, price) 202 | except Exception as e: 203 | self.log.debug("下单出错!") 204 | self.log.debug(e) 205 | self.open_fail += 1 206 | return result 207 | 208 | def CheckBalance(self): 209 | pass 210 | 211 | def HandleOpenFailBilateral(self, result,mode, min_amt): 212 | order_results = [] 213 | if mode == 1:exchange = self.exchange_1 214 | if mode == 2:exchange = self.exchange_2 215 | for i in result: 216 | if i is not None and self.handle_open == 1: 217 | self.maker_fail += 1 218 | self.log.debug('处理未成交订单') 219 | self.log.debug('取消订单%s' % i['id']) 220 | exchange.cancel_order(i['id'], i['symbol']) 221 | time.sleep(2) 222 | self.log.debug('交易所%d按市价补单,交易对为%s,方向为%s,数量为%f'%(mode,i['symbol'],i['side'],i['remaining'])) 223 | if i['side'] == 'buy' and i['remaining'] > min_amt: order_result = self.CreatOrder( 224 | i['symbol'], mode, 'limit', i['side'], i['remaining'], i['price'] * 1.01) 225 | if i['side'] == 'sell' and i['remaining'] > min_amt: order_result = self.CreatOrder( 226 | i['symbol'], mode, 'limit', i['side'], i['remaining'], i['price'] * 0.99) 227 | if 'id' in order_result: 228 | self.log.debug('补单成功!') 229 | order_results.append(order_result) 230 | return order_results 231 | 232 | def CheckOpenBilateral(self,symbol,min_amt_1,min_amt_2): 233 | time.sleep(self.wait_time) 234 | result = [] 235 | result_ = [] 236 | t = [] 237 | t.append(MyThread(self.exchange_1.fetch_open_orders, args=(symbol,))) 238 | t.append(MyThread(self.exchange_2.fetch_open_orders, args=(symbol,))) 239 | for i in t: 240 | i.setDaemon(True) 241 | i.start() 242 | for i in t: 243 | i.join() 244 | result.append(i.get_result()) 245 | t = [] 246 | t.append(MyThread(self.HandleOpenFailBilateral, args=(result[0],1,min_amt_1))) 247 | t.append(MyThread(self.HandleOpenFailBilateral, args=(result[1],2,min_amt_2))) 248 | for i in t: 249 | i.setDaemon(True) 250 | i.start() 251 | for i in t: 252 | i.join() 253 | result_.append(i.get_result()) 254 | time.sleep(2) 255 | 256 | def HandleOpenFail(self,result,mode,min_amt): 257 | order_results = [] 258 | if mode == 1:exchange = self.exchange_1 259 | if mode == 2:exchange = self.exchange_2 260 | for i in result: 261 | if i is not None and self.handle_open == 1: 262 | self.maker_fail += 1 263 | self.log.debug('取消未完成订单%s' % i['id']) 264 | exchange.cancel_order(i['id'], i['symbol']) 265 | time.sleep(2) 266 | self.log.debug('交易所%d按市价补单,交易对为%s,方向为%s,数量为%f'%(mode,i['symbol'],i['side'],i['remaining'])) 267 | if i['side'] == 'buy' and i['remaining'] > min_amt: order_result = self.CreatOrder( 268 | i['symbol'], mode, 'limit', i['side'], i['remaining'], i['price'] * 1.01) # 有些交易对没法按市价下单 269 | if i['side'] == 'sell' and i['remaining'] > min_amt: order_result = self.CreatOrder( 270 | i['symbol'], mode, 'limit', i['side'], i['remaining'], i['price'] * 0.99) # 如果溢价太多,可能因为余钱不够导致下单失败 271 | if 'id' in order_result: 272 | self.log.debug('补单成功!') 273 | order_results.append(order_result) 274 | return order_results 275 | 276 | def CheckOpen(self,mode1,mode2,mode3,symbol_A,symbol_B,symbol_C,min_amt_A,min_amt_B,min_amt_C): 277 | time.sleep(self.wait_time) 278 | result = [] 279 | result_ = [] 280 | t = [] 281 | if mode1 == 1: 282 | exchange1 = self.exchange_1 283 | else: 284 | exchange1 = self.exchange_2 285 | if mode2 == 1: 286 | exchange2 = self.exchange_1 287 | else: 288 | exchange2 = self.exchange_2 289 | if mode3 == 1: 290 | exchange3 = self.exchange_1 291 | else: 292 | exchange3 = self.exchange_2 293 | t.append(MyThread(exchange1.fetch_open_orders, args=(symbol_A,))) 294 | t.append(MyThread(exchange2.fetch_open_orders, args=(symbol_B,))) 295 | t.append(MyThread(exchange3.fetch_open_orders, args=(symbol_C,))) 296 | for i in t: 297 | i.setDaemon(True) 298 | i.start() 299 | for i in t: 300 | i.join() 301 | result.append(i.get_result()) 302 | self.log.debug(result) 303 | t = [] 304 | t.append(MyThread(self.HandleOpenFail, args=(result[0],mode1,min_amt_A))) 305 | t.append(MyThread(self.HandleOpenFail, args=(result[1],mode2,min_amt_B))) 306 | t.append(MyThread(self.HandleOpenFail, args=(result[2],mode3,min_amt_C))) 307 | for i in t: 308 | i.setDaemon(True) 309 | i.start() 310 | for i in t: 311 | i.join() 312 | result_.append(i.get_result()) 313 | time.sleep(2) 314 | 315 | def GetTotalBalance(self): 316 | self.log.info('====================') 317 | balance1 = self.exchange_1.fetch_balance() 318 | balance2 = self.exchange_2.fetch_balance() 319 | balance3 = self.exchange_3.fetch_balance() 320 | total_btc = balance1['BTC']['total']+balance2['BTC']['total']+balance3['BTC']['total'] 321 | total_eth = balance1['ETH']['total']+balance2['ETH']['total']+balance3['ETH']['total'] 322 | total_usdt = balance1['USDT']['total']+balance2['USDT']['total']+balance3['USDT']['total'] 323 | if self.num == 0: 324 | self.init_total['USDT'] = total_usdt 325 | self.init_total['BTC'] = total_btc 326 | self.init_total['ETH'] = total_eth 327 | self.log.info(' 当前总资产 初始总资产') 328 | self.log.info('USDT:%f %f'%(total_usdt ,self.init_total['USDT'])) 329 | self.log.info( 'BTC:%f %f'%(total_btc ,self.init_total['BTC'])) 330 | self.log.info( 'ETH:%f %f'%(total_eth ,self.init_total['ETH'])) 331 | 332 | def GetBalance(self,X,Y,Z): 333 | balance1 = self.exchange_1.fetch_balance() 334 | balance2 = self.exchange_2.fetch_balance() 335 | cur_size_11 = balance1[X]['free'] if X in balance1 else 0 336 | cur_size_12 = balance1[Y]['free'] if Y in balance1 else 0 337 | cur_size_13 = balance1[Z]['free'] if Z in balance1 else 0 338 | cur_size_21 = balance2[X]['free'] if X in balance2 else 0 339 | cur_size_22 = balance2[Y]['free'] if Y in balance2 else 0 340 | cur_size_23 = balance2[Z]['free'] if Z in balance2 else 0 341 | return cur_size_11,cur_size_12,cur_size_13,cur_size_21,cur_size_22,cur_size_23 342 | 343 | def CheckTraingle(self,X,Y,Z): 344 | time.sleep(0.2) 345 | self.log.debug('--------------------') 346 | self.log.debug('当前检测三角对:%s %s %s'%(X,Y,Z)) 347 | cur_size_11,cur_size_12,cur_size_13,cur_size_21,cur_size_22,cur_size_23 = self.GetBalance(X,Y,Z) 348 | self.log.debug('交易所1当前币量:%f %f %f' % (cur_size_11, cur_size_12, cur_size_13)) 349 | self.log.debug('交易所2当前币量:%f %f %f' % (cur_size_21, cur_size_22, cur_size_23)) 350 | symbol_A = Y + '/' + X 351 | symbol_B = Y + '/' + Z 352 | symbol_C = Z + '/' + X 353 | min_amt_A1, min_price_A1, min_cost_A1 = self.GetLimit(symbol_A, 1) # 获取交易对的限制 354 | min_amt_B1, min_price_B1, min_cost_B1 = self.GetLimit(symbol_B, 1) # 获取交易对的限制 355 | min_amt_C1, min_price_C1, min_cost_C1 = self.GetLimit(symbol_C, 1) # 获取交易对的限制 356 | min_amt_A2, min_price_A2, min_cost_A2 = self.GetLimit(symbol_A, 2) # 获取交易对的限制 357 | min_amt_B2, min_price_B2, min_cost_B2 = self.GetLimit(symbol_B, 2) # 获取交易对的限制 358 | min_amt_C2, min_price_C2, min_cost_C2 = self.GetLimit(symbol_C, 2) # 获取交易对的限制 359 | t = [] 360 | data = [] 361 | t.append(MyThread(self.GetOrderBook, args=(symbol_A,1,))) 362 | t.append(MyThread(self.GetOrderBook, args=(symbol_B,1,))) 363 | t.append(MyThread(self.GetOrderBook, args=(symbol_C,1,))) 364 | t.append(MyThread(self.GetOrderBook, args=(symbol_A,2,))) 365 | t.append(MyThread(self.GetOrderBook, args=(symbol_B,2,))) 366 | t.append(MyThread(self.GetOrderBook, args=(symbol_C,2,))) 367 | begin = time.time() 368 | for i in t: 369 | i.setDaemon(True) 370 | i.start() 371 | for i in t: 372 | i.join() 373 | data.append(i.get_result()) 374 | end = time.time() 375 | delay = float((end - begin) // 0.001) 376 | A_bestbid_1, A_bestbid_size_1, A_bestask_1, A_bestask_size_1 = data[0][0], data[0][1], data[0][2], data[0][3] 377 | B_bestbid_1, B_bestbid_size_1, B_bestask_1, B_bestask_size_1 = data[1][0], data[1][1], data[1][2], data[1][3] 378 | C_bestbid_1, C_bestbid_size_1, C_bestask_1, C_bestask_size_1 = data[2][0], data[2][1], data[2][2], data[2][3] 379 | A_bestbid_2, A_bestbid_size_2, A_bestask_2, A_bestask_size_2 = data[3][0], data[3][1], data[3][2], data[3][3] 380 | B_bestbid_2, B_bestbid_size_2, B_bestask_2, B_bestask_size_2 = data[4][0], data[4][1], data[4][2], data[4][3] 381 | C_bestbid_2, C_bestbid_size_2, C_bestask_2, C_bestask_size_2 = data[5][0], data[5][1], data[5][2], data[5][3] 382 | # 同市三角 383 | Surplus_1 = C_bestbid_1 * B_bestbid_1 / A_bestask_1 - 3 * self.fee_1['trading']['maker'] * self.fee_ratio_1 # usdt 2 trx 2 eth 2 usdt 384 | Deficit_1 = A_bestbid_1 / B_bestask_1 / C_bestask_1 - 3 * self.fee_1['trading']['maker'] * self.fee_ratio_1 # usdt 2 eth 2 trx 2 usdt 385 | Surplus_2 = C_bestbid_2 * B_bestbid_2 / A_bestask_2 - 3 * self.fee_2['trading']['maker'] * self.fee_ratio_2 # usdt 2 trx 2 eth 2 usdt 386 | Deficit_2 = A_bestbid_2 / B_bestask_2 / C_bestask_2 - 3 * self.fee_2['trading']['maker'] * self.fee_ratio_2 # usdt 2 eth 2 trx 2 usdt 387 | # 跨市三角 顺1:A1 B1 C2 逆1: C2 B1 A1 顺2: A2 B2 C1 逆2: C1 B2 A2 388 | Surplus_112 = C_bestbid_2 * B_bestbid_1 / A_bestask_1 - 2 * self.fee_1['trading']['maker']*self.fee_ratio_1 + self.fee_2['trading']['maker']*self.fee_ratio_2 # usdt 2 trx 2 eth 2 usdt 389 | Deficit_211 = A_bestbid_1 / B_bestask_1 / C_bestask_2 - 2 * self.fee_1['trading']['maker']*self.fee_ratio_1 + self.fee_2['trading']['maker']*self.fee_ratio_2 # usdt 2 trx 2 eth 2 usdt 390 | Surplus_221 = C_bestbid_1 * B_bestbid_2 / A_bestask_2 - 2 * self.fee_2['trading']['maker']*self.fee_ratio_2 + self.fee_1['trading']['maker']*self.fee_ratio_1 # usdt 2 eth 2 trx 2 usdt 391 | Deficit_122 = A_bestbid_2 / B_bestask_2 / C_bestask_1 - 2 * self.fee_2['trading']['maker']*self.fee_ratio_2 + self.fee_1['trading']['maker']*self.fee_ratio_1 # usdt 2 eth 2 trx 2 usdt 392 | # 跨市双边 symbol_A 顺:1卖2买 逆:2买1卖 symbol_B 顺:1卖 2买 逆 1买 2卖 symbol_C: 顺:1卖 2买 逆 : 1买 2卖 393 | Surplus_A = A_bestbid_1 - A_bestask_2 - A_bestbid_1 * self.fee_1['trading']['maker'] * self.fee_ratio_1 - A_bestask_2 * self.fee_2['trading']['maker'] * self.fee_ratio_2 394 | Deficit_A = A_bestbid_2 - A_bestask_1 - A_bestbid_2 * self.fee_2['trading']['maker'] * self.fee_ratio_2 - A_bestask_1 * self.fee_1['trading']['maker'] * self.fee_ratio_1 395 | Surplus_B = B_bestbid_1 - B_bestask_2 - B_bestbid_1 * self.fee_1['trading']['maker'] * self.fee_ratio_1 - B_bestask_2 * self.fee_2['trading']['maker'] * self.fee_ratio_2 396 | Deficit_B = B_bestbid_2 - B_bestask_1 - B_bestbid_2 * self.fee_2['trading']['maker'] * self.fee_ratio_2 - B_bestask_1 * self.fee_1['trading']['maker'] * self.fee_ratio_1 397 | Surplus_C = C_bestbid_1 - C_bestask_2 - C_bestbid_1 * self.fee_1['trading']['maker'] * self.fee_ratio_1 - C_bestask_2 * self.fee_2['trading']['maker'] * self.fee_ratio_2 398 | Deficit_C = C_bestbid_2 - C_bestask_1 - C_bestbid_2 * self.fee_2['trading']['maker'] * self.fee_ratio_2 - C_bestask_1 * self.fee_1['trading']['maker'] * self.fee_ratio_1 399 | # 处理信号 如果下单成功就改为False 400 | signal = True 401 | if Surplus_1 > 1 and Surplus_1 < 1.01 : # 交易所1内顺三角 加上上限是为了防止极端行情下出现损失 402 | size_1 = min(cur_size_11, cur_size_12 * A_bestask_1, cur_size_13 * C_bestbid_1, A_bestask_size_1 / A_bestask_1, 403 | B_bestbid_size_1 * A_bestask_1, C_bestbid_size_1 * C_bestbid_1) * self.ratio 404 | size_2 = size_1 / A_bestask_1 405 | size_3 = size_2 * B_bestbid_1 406 | amt_A = float(self.exchange_1.amount_to_precision(symbol_A,size_2)) 407 | amt_B = float(self.exchange_1.amount_to_precision(symbol_B,size_2)) 408 | amt_C = float(self.exchange_1.amount_to_precision(symbol_C,size_3)) 409 | price_A = float(self.exchange_1.price_to_precision(symbol_A,A_bestask_1)) 410 | price_B = float(self.exchange_1.price_to_precision(symbol_B,B_bestbid_1)) 411 | price_C = float(self.exchange_1.price_to_precision(symbol_C,C_bestbid_1)) 412 | win = size_3 * C_bestbid_1 - size_1 413 | if size_2 > min_amt_A1 and size_2 > min_amt_B1 and size_3 > min_amt_C1\ 414 | and win > 0 and delay <= 95\ 415 | and amt_A > 0 and amt_B > 0 and amt_C > 0 and price_A > 0 and price_B > 0 and price_C > 0: 416 | t = [] 417 | order_result = [] 418 | t.append(MyThread(self.CreatOrder, args=(symbol_A,1,'limit','buy' ,size_2,A_bestask_1,))) 419 | t.append(MyThread(self.CreatOrder, args=(symbol_B,1,'limit','sell',size_2,B_bestbid_1,))) 420 | t.append(MyThread(self.CreatOrder, args=(symbol_C,1,'limit','sell',size_3,C_bestbid_1,))) 421 | begin = time.time() 422 | for i in t: 423 | i.setDaemon(True) 424 | i.start() 425 | for i in t: 426 | i.join() 427 | order_result.append(i.get_result()) 428 | end = time.time() 429 | delay_ = float((end - begin) // 0.001) 430 | self.log.debug("%s发现正循环信号!"%self.exchange_name_1) 431 | self.log.debug("预估交易数量: %f %f %f" % (size_1, size_2, size_3)) 432 | self.log.debug('in : %f out : %f win : %f' % (size_1,size_3 * C_bestbid_1, win)) # 先1 3 后2 433 | self.log.debug("价差比率:%f" % (Surplus_1)) 434 | self.log.debug('询价延迟: %f ms' % delay ) 435 | self.log.debug('下单延迟: %f ms' % delay_) 436 | self.log.debug('下单参数:') 437 | self.log.debug('A: %f %f %f %f' % (size_2, A_bestask_1,amt_A,price_A)) 438 | self.log.debug('B: %f %f %f %f' % (size_2, B_bestbid_1,amt_B,price_B)) 439 | self.log.debug('C: %f %f %f %f' % (size_3, C_bestbid_1,amt_C,price_C)) 440 | self.log.debug('下单结果:') 441 | for i in order_result: 442 | if 'id' not in i: 443 | # self.log.debug('下单出错!') 444 | # self.open_fail += 1 445 | signal = False 446 | else: 447 | self.log.debug(i) 448 | self.CheckOpen(1,1,1,symbol_A,symbol_B,symbol_C,min_amt_A1,min_amt_B1,min_amt_C1) 449 | if signal:#判断是否按限价单成交,如果不是,则扯单后补市价单 450 | self.open_num += 1 451 | self.log.debug('套利前币量之总和: %f %f %f' % ( 452 | cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 453 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22)*( 454 | 0.5*A_bestbid_1+0.5*A_bestask_1) + (cur_size_13 + cur_size_23)*(0.5*C_bestask_1+0.5*C_bestbid_1) 455 | self.log.debug('币量相当于%f个%s'%(total,X)) 456 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 457 | self.log.debug('套利后币量之总和: %f %f %f' % ( 458 | cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 459 | total_= (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 460 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 461 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 462 | self.log.debug('币量相当于%f个%s' % (total_, X)) 463 | self.win[X] += total_ - total 464 | return 465 | else: 466 | self.log.debug('%s有正循环信号,但不符合条件!'%self.exchange_name_1) 467 | # self.log.debug('币1:%f 币2:%f 币3:%f A盘口:%f B盘口:%f C盘口:%f'%(cur_size_11, \ 468 | # cur_size_12 * A_bestask_1, cur_size_13 * C_bestbid_1, A_bestask_size_1 / A_bestask_1, \ 469 | # B_bestbid_size_1 * A_bestask_1, C_bestbid_size_1 * C_bestbid_1)) 470 | hand = [cur_size_11, cur_size_12 * A_bestask_1, cur_size_13 * C_bestbid_1, \ 471 | A_bestask_size_1 / A_bestask_1, B_bestbid_size_1 * A_bestask_1, C_bestbid_size_1 * C_bestbid_1] 472 | n = hand.index(min(hand)) 473 | if n == 0: 474 | self.log.info('提示:交易所%s缺少%s'%(self.exchange_name_1,X)) 475 | self.signal_num += 1 476 | elif n == 1: 477 | self.log.info('提示:交易所%s缺少%s'%(self.exchange_name_1,Y)) 478 | self.signal_num += 1 479 | elif n == 2: 480 | self.log.info('提示:交易所%s缺少%s'%(self.exchange_name_1,Z)) 481 | self.signal_num += 1 482 | else: 483 | self.log.debug('盘口深度不够') 484 | self.log.debug('size: %f %f %f' % (size_2, size_2, size_3)) 485 | self.log.debug('min_amt: %f %f %f' % (min_amt_A1, min_amt_B1, min_amt_C1)) 486 | self.log.debug('amt: %f %f %f price: %f %f %f' % (amt_A, amt_B, amt_C, price_A, price_B, price_C)) 487 | if win <= 0: self.log.debug('预估盈利太低') 488 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 489 | return 490 | if Deficit_1 > 1 and Deficit_1 < 1.01: 491 | size_1 = min(cur_size_11, cur_size_13 * C_bestask_1, cur_size_12 * A_bestbid_1, C_bestask_size_1 * C_bestask_1, 492 | B_bestask_size_1 * B_bestask_1 * C_bestask_1, A_bestbid_1 * A_bestbid_size_1) * self.ratio 493 | size_2 = size_1 / C_bestask_1 494 | size_3 = size_2 / B_bestask_1 495 | amt_A = float(self.exchange_1.amount_to_precision(symbol_A,size_3)) 496 | amt_B = float(self.exchange_1.amount_to_precision(symbol_B,size_3)) 497 | amt_C = float(self.exchange_1.amount_to_precision(symbol_C,size_2)) 498 | price_A = float(self.exchange_1.price_to_precision(symbol_A,A_bestbid_1)) 499 | price_B = float(self.exchange_1.price_to_precision(symbol_B,B_bestask_1)) 500 | price_C = float(self.exchange_1.price_to_precision(symbol_C,C_bestask_1)) 501 | win = size_3 * A_bestbid_1 - size_1 502 | if size_3 > min_amt_A1 and size_3 > min_amt_B1 and size_2 > min_amt_C1\ 503 | and win > 0 and delay <= 95\ 504 | and amt_A > 0 and amt_B>0 and amt_C>0 and price_A>0 and price_B>0 and price_C>0: 505 | t = [] 506 | order_result = [] 507 | t.append(MyThread(self.CreatOrder, args=(symbol_C,1, 'limit', 'buy' , size_2, C_bestask_1,))) 508 | t.append(MyThread(self.CreatOrder, args=(symbol_B,1, 'limit', 'buy' , size_3, B_bestask_1,))) 509 | t.append(MyThread(self.CreatOrder, args=(symbol_A,1, 'limit', 'sell', size_3, A_bestbid_1,))) 510 | begin = time.time() 511 | for i in t: 512 | i.setDaemon(True) 513 | i.start() 514 | for i in t: 515 | i.join() 516 | order_result.append(i.get_result()) 517 | end = time.time() 518 | delay_ = float((end - begin) // 0.001) 519 | self.log.debug("%s发现逆循环信号!"%self.exchange_name_1) 520 | self.log.debug("预估交易数量: %f %f %f" % (size_1, size_2, size_3)) 521 | self.log.debug('in : %f out : %f win : %f' % (size_1, size_3 * A_bestbid_1,win)) 522 | self.log.debug("价差比率:%f" % (Deficit_1)) 523 | self.log.debug('询价延迟: %f ms' % delay ) 524 | self.log.debug('下单延迟: %f ms' % delay_) 525 | self.log.debug('下单参数:') 526 | self.log.debug('C: %f %f %f %f' % (size_2, C_bestask_1, amt_C, price_C)) 527 | self.log.debug('B: %f %f %f %f' % (size_3, B_bestask_1, amt_B, price_B)) 528 | self.log.debug('A: %f %f %f %f' % (size_3, A_bestbid_1, amt_A, price_A)) 529 | self.log.debug('下单结果:') 530 | for i in order_result: 531 | if 'id' not in i: 532 | # self.log.debug('下单出错!') 533 | # self.open_fail += 1 534 | signal = False 535 | else: 536 | self.log.debug(i) 537 | self.CheckOpen(1,1,1,symbol_C,symbol_B,symbol_A,min_amt_C1,min_amt_B1,min_amt_A1) 538 | if signal: #判断是否按市价单成交 539 | self.open_num += 1 540 | self.log.debug('套利前币量之总和: %f %f %f' % ( 541 | cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 542 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 543 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 544 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 545 | self.log.debug('币量相当于%f个%s' % (total, X)) 546 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 547 | self.log.debug('套利后币量之总和: %f %f %f' % ( 548 | cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 549 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) *( 550 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 551 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 552 | self.log.debug('币量相当于%f个%s' % (total_, X)) 553 | self.win[X] += total_ - total 554 | return 555 | else: 556 | self.log.debug('%s有逆循环信号,但不符合条件!'%self.exchange_name_1) 557 | # self.log.debug('币1:%f 币2:%f 币3:%f C盘口:%f B盘口:%f A盘口:%f'%(cur_size_11, cur_size_13 * C_bestask_1, cur_size_12 * A_bestbid_1, C_bestask_size_1 * C_bestask_1, 558 | # B_bestask_size_1 * B_bestask_1 * C_bestask_1, A_bestbid_1 * A_bestbid_size_1)) 559 | hand = [cur_size_11, cur_size_12 * A_bestbid_1, cur_size_13 * C_bestask_1, C_bestask_size_1 * C_bestask_1, 560 | B_bestask_size_1 * B_bestask_1 * C_bestask_1, A_bestbid_1 * A_bestbid_size_1] 561 | n = hand.index(min(hand)) 562 | if n == 0: 563 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, X)) 564 | self.signal_num += 1 565 | elif n == 1: 566 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Y)) 567 | self.signal_num += 1 568 | elif n == 2: 569 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Z)) 570 | self.signal_num += 1 571 | else: 572 | self.log.debug('盘口深度不够') 573 | self.log.debug('size: %f %f %f'%(size_3,size_3,size_2)) 574 | self.log.debug('min_amt: %f %f %f'%(min_amt_A1,min_amt_B1,min_amt_C1)) 575 | self.log.debug('amt: %f %f %f price: %f %f %f'%(amt_A,amt_B,amt_C,price_A,price_B,price_C)) 576 | if win <= 0: self.log.debug('预估盈利太低') 577 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 578 | return 579 | if Surplus_2 > 1 and Surplus_2 < 1.01: 580 | size_1 = min(cur_size_21, cur_size_22 * A_bestask_2, cur_size_23 * C_bestbid_2, A_bestask_size_2 / A_bestask_2, 581 | B_bestbid_size_2 * A_bestask_2, C_bestbid_size_2 * C_bestbid_2) * self.ratio 582 | size_2 = size_1 / A_bestask_2 583 | size_3 = size_2 * B_bestbid_2 584 | amt_A = float(self.exchange_2.amount_to_precision(symbol_A,size_2)) 585 | amt_B = float(self.exchange_2.amount_to_precision(symbol_B,size_2)) 586 | amt_C = float(self.exchange_2.amount_to_precision(symbol_C,size_3)) 587 | price_A = float(self.exchange_2.price_to_precision(symbol_A,A_bestask_2)) 588 | price_B = float(self.exchange_2.price_to_precision(symbol_B,B_bestbid_2)) 589 | price_C = float(self.exchange_2.price_to_precision(symbol_C,C_bestbid_2)) 590 | win = size_3 * C_bestbid_2 - size_1 591 | if size_2 > min_amt_A2 and size_2 > min_amt_B2 and size_3 > min_amt_C2\ 592 | and win > 0 and delay <= 95\ 593 | and amt_A > 0 and amt_B > 0 and amt_C > 0 and price_A > 0 and price_B > 0 and price_C > 0: 594 | t = [] 595 | order_result = [] 596 | t.append(MyThread(self.CreatOrder, args=(symbol_A,2,'limit','buy' ,size_2,A_bestask_2,))) 597 | t.append(MyThread(self.CreatOrder, args=(symbol_B,2,'limit','sell',size_2,B_bestbid_2,))) 598 | t.append(MyThread(self.CreatOrder, args=(symbol_C,2,'limit','sell',size_3,C_bestbid_2,))) 599 | begin = time.time() 600 | for i in t: 601 | i.setDaemon(True) 602 | i.start() 603 | for i in t: 604 | i.join() 605 | order_result.append(i.get_result()) 606 | end = time.time() 607 | delay_ = float((end - begin) // 0.001) 608 | self.log.debug("%s发现正循环信号!"%self.exchange_name_2) 609 | self.log.debug("预估交易数量: %f %f %f" % (size_1, size_2, size_3)) 610 | self.log.debug('in : %f out : %f win : %f' % (size_1,size_3 * C_bestbid_2, win)) # 先1 3 后2 611 | self.log.debug("价差比率:%f" % (Surplus_2)) 612 | self.log.debug('询价延迟: %f ms' % delay ) 613 | self.log.debug('下单延迟: %f ms' % delay_) 614 | self.log.debug('下单参数:') 615 | self.log.debug('A: %f %f %f %f' % (size_2, A_bestask_2,amt_A,price_A)) 616 | self.log.debug('B: %f %f %f %f' % (size_2, B_bestbid_2,amt_B,price_B)) 617 | self.log.debug('C: %f %f %f %f' % (size_3, C_bestbid_2,amt_C,price_C)) 618 | self.log.debug('下单结果:') 619 | for i in order_result: 620 | if 'id' not in i: 621 | # self.log.debug('下单出错!') 622 | # self.open_fail += 1 623 | signal = False 624 | else: 625 | self.log.debug(i) 626 | self.CheckOpen(2,2,2,symbol_A,symbol_B,symbol_C,min_amt_A2, min_amt_B2, min_amt_C2) 627 | if signal:#判断是否按限价单成交,如果不是,则扯单后补市价单 628 | self.open_num += 1 629 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 630 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 631 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 632 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 633 | self.log.debug('币量相当于%f个%s' % (total, X)) 634 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 635 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 636 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 637 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 638 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 639 | self.log.debug('币量相当于%f个%s' % (total_, X)) 640 | self.win[X] += total_ - total 641 | return 642 | else: 643 | self.log.debug('%s有正循环信号,但不符合条件!'%self.exchange_name_2) 644 | # self.log.debug('币1:%f 币2:%f 币3:%f A盘口:%f B盘口:%f C盘口:%f'%(cur_size_21, cur_size_22 * A_bestask_2, cur_size_23 * C_bestbid_2, A_bestask_size_2 / A_bestask_2, 645 | # B_bestbid_size_2 * A_bestask_2, C_bestbid_size_2 * C_bestbid_2)) 646 | hand = [cur_size_21, cur_size_22 * A_bestask_2, cur_size_23 * C_bestbid_2, A_bestask_size_2 / A_bestask_2, 647 | B_bestbid_size_2 * A_bestask_2, C_bestbid_size_2 * C_bestbid_2] 648 | n = hand.index(min(hand)) 649 | if n == 0: 650 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, X)) 651 | self.signal_num += 1 652 | elif n == 1: 653 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Y)) 654 | self.signal_num += 1 655 | elif n == 2: 656 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Z)) 657 | self.signal_num += 1 658 | else: 659 | self.log.debug('盘口深度不够') 660 | self.log.debug('size: %f %f %f' % (size_2, size_2, size_3)) 661 | self.log.debug('min_amt: %f %f %f' % (min_amt_A2, min_amt_B2, min_amt_C2)) 662 | self.log.debug('amt: %f %f %f price: %f %f %f' % (amt_A, amt_B, amt_C, price_A, price_B, price_C)) 663 | if win <= 0: self.log.debug('预估盈利太低') 664 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 665 | return 666 | if Deficit_2 > 1 and Deficit_2 < 1.01: 667 | size_1 = min(cur_size_21, cur_size_23 * C_bestask_2, cur_size_22 * A_bestbid_2, C_bestask_size_2 * C_bestask_2, 668 | B_bestask_size_2 * B_bestask_2 * C_bestask_2, A_bestbid_2 * A_bestbid_size_2) * self.ratio 669 | size_2 = size_1 / C_bestask_2 670 | size_3 = size_2 / B_bestask_2 671 | amt_A = float(self.exchange_2.amount_to_precision(symbol_A,size_3)) 672 | amt_B = float(self.exchange_2.amount_to_precision(symbol_B,size_3)) 673 | amt_C = float(self.exchange_2.amount_to_precision(symbol_C,size_2)) 674 | price_A = float(self.exchange_2.price_to_precision(symbol_A,A_bestbid_2)) 675 | price_B = float(self.exchange_2.price_to_precision(symbol_B,B_bestask_2)) 676 | price_C = float(self.exchange_2.price_to_precision(symbol_C,C_bestask_2)) 677 | win = size_3 * A_bestbid_2 - size_1 678 | if size_3 > min_amt_A2 and size_3 > min_amt_B2 and size_2 > min_amt_C2\ 679 | and win > 0 and delay <= 95\ 680 | and amt_A > 0 and amt_B>0 and amt_C>0 and price_A>0 and price_B>0 and price_C>0: 681 | t = [] 682 | order_result = [] 683 | t.append(MyThread(self.CreatOrder, args=(symbol_C,2, 'limit', 'buy' , size_2, C_bestask_2,))) 684 | t.append(MyThread(self.CreatOrder, args=(symbol_B,2, 'limit', 'buy' , size_3, B_bestask_2,))) 685 | t.append(MyThread(self.CreatOrder, args=(symbol_A,2, 'limit', 'sell', size_3, A_bestbid_2,))) 686 | begin = time.time() 687 | for i in t: 688 | i.setDaemon(True) 689 | i.start() 690 | for i in t: 691 | i.join() 692 | order_result.append(i.get_result()) 693 | end = time.time() 694 | delay_ = float((end - begin) // 0.001) 695 | self.log.debug("%s发现逆循环信号!"%self.exchange_name_2) 696 | self.log.debug("预估交易数量: %f %f %f" % (size_1, size_2, size_3)) 697 | self.log.debug('in : %f out : %f win : %f' % (size_1, size_3 * A_bestbid_2,win)) 698 | self.log.debug("价差比率:%f" % (Deficit_2)) 699 | self.log.debug('询价延迟: %f ms' % delay ) 700 | self.log.debug('下单延迟: %f ms' % delay_) 701 | self.log.debug('下单参数:') 702 | self.log.debug('C: %f %f %f %f' % (size_2, C_bestask_2, amt_C, price_C)) 703 | self.log.debug('B: %f %f %f %f' % (size_3, B_bestask_2, amt_B, price_B)) 704 | self.log.debug('A: %f %f %f %f' % (size_3, A_bestbid_2, amt_A, price_A)) 705 | self.log.debug('下单结果:') 706 | for i in order_result: 707 | if 'id' not in i: 708 | # self.log.debug('下单出错!') 709 | # self.open_fail += 1 710 | signal = False 711 | else: 712 | self.log.debug(i) 713 | self.CheckOpen(2,2,2,symbol_C,symbol_B,symbol_A,min_amt_C2, min_amt_B2, min_amt_A2) 714 | if signal: #判断是否按市价单成交 715 | self.open_num += 1 716 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 717 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 718 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 719 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 720 | self.log.debug('币量相当于%f个%s' % (total, X)) 721 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 722 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 723 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 724 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 725 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 726 | self.log.debug('币量相当于%f个%s' % (total_, X)) 727 | self.win[X] += total_ - total 728 | return 729 | else: 730 | self.log.debug('%s有逆循环信号,但不符合条件!'%self.exchange_name_2) 731 | # self.log.debug('币1:%f 币2:%f 币3:%f C盘口:%f B盘口:%f A盘口:%f'%(cur_size_21, cur_size_23 * C_bestask_2, cur_size_22 * A_bestbid_2, C_bestask_size_2 * C_bestask_2, 732 | # B_bestask_size_2 * B_bestask_2 * C_bestask_2, A_bestbid_2 * A_bestbid_size_2)) 733 | hand = [cur_size_21, cur_size_22 * A_bestbid_2, cur_size_23 * C_bestask_2, C_bestask_size_2 * C_bestask_2, 734 | B_bestask_size_2 * B_bestask_2 * C_bestask_2, A_bestbid_2 * A_bestbid_size_2] 735 | n = hand.index(min(hand)) 736 | if n == 0: 737 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, X)) 738 | self.signal_num += 1 739 | elif n == 1: 740 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Y)) 741 | self.signal_num += 1 742 | elif n == 2: 743 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Z)) 744 | self.signal_num += 1 745 | else: 746 | self.log.debug('盘口深度不够') 747 | self.log.debug('size: %f %f %f'%(size_3,size_3,size_2)) 748 | self.log.debug('min_amt: %f %f %f'%(min_amt_A2,min_amt_B2,min_amt_C2)) 749 | self.log.debug('amt: %f %f %f price: %f %f %f'%(amt_A,amt_B,amt_C,price_A,price_B,price_C)) 750 | if win <= 0: self.log.debug('预估盈利太低') 751 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 752 | return 753 | if Surplus_112 > 1 and Surplus_112 < 1.01:# 跨市三角 顺1:A1 B1 C2 754 | size_1 = min(cur_size_11, cur_size_12 * A_bestask_1, cur_size_23 * C_bestbid_2, A_bestask_size_1 / A_bestask_1, 755 | B_bestbid_size_1 * A_bestask_1, C_bestbid_size_2 * C_bestbid_2) * self.ratio 756 | size_2 = size_1 / A_bestask_1 757 | size_3 = size_2 * B_bestbid_1 758 | amt_A = float(self.exchange_1.amount_to_precision(symbol_A,size_2)) 759 | amt_B = float(self.exchange_1.amount_to_precision(symbol_B,size_2)) 760 | amt_C = float(self.exchange_2.amount_to_precision(symbol_C,size_3)) 761 | price_A = float(self.exchange_1.price_to_precision(symbol_A,A_bestask_1)) 762 | price_B = float(self.exchange_1.price_to_precision(symbol_B,B_bestbid_1)) 763 | price_C = float(self.exchange_2.price_to_precision(symbol_C,C_bestbid_2)) 764 | win = size_3 * C_bestbid_2 - size_1 765 | if size_2 > min_amt_A1 and size_2 > min_amt_B1 and size_3 > min_amt_C2 and win > 0 and delay <= 95\ 766 | and amt_A > 0 and amt_B > 0 and amt_C > 0 and price_A > 0 and price_B > 0 and price_C > 0: 767 | t = [] 768 | order_result = [] 769 | t.append(MyThread(self.CreatOrder, args=(symbol_A,1,'limit','buy' ,size_2,A_bestask_1,))) 770 | t.append(MyThread(self.CreatOrder, args=(symbol_B,1,'limit','sell',size_2,B_bestbid_1,))) 771 | t.append(MyThread(self.CreatOrder, args=(symbol_C,2,'limit','sell',size_3,C_bestbid_2,))) 772 | begin = time.time() 773 | for i in t: 774 | i.setDaemon(True) 775 | i.start() 776 | for i in t: 777 | i.join() 778 | order_result.append(i.get_result()) 779 | end = time.time() 780 | delay_ = float((end - begin) // 0.001) 781 | self.log.debug("发现跨市112正循环信号!") 782 | self.log.debug("预估交易数量: %f %f %f" % (size_1, size_2, size_3)) 783 | self.log.debug('in : %f out : %f win : %f' % (size_1,size_3 * C_bestbid_2, win)) # 先1 3 后2 784 | self.log.debug("价差比率:%f" % (Surplus_112)) 785 | self.log.debug('询价延迟: %f ms' % delay ) 786 | self.log.debug('下单延迟: %f ms' % delay_) 787 | self.log.debug('下单参数:') 788 | self.log.debug('A: %f %f %f %f' % (size_2, A_bestask_1, amt_A, price_A)) 789 | self.log.debug('B: %f %f %f %f' % (size_2, B_bestbid_1, amt_B, price_B)) 790 | self.log.debug('C: %f %f %f %f' % (size_3, C_bestbid_2, amt_C, price_C)) 791 | self.log.debug('下单结果:') 792 | for i in order_result: 793 | if 'id' not in i: 794 | # self.log.debug('下单出错!') # 对下单出错要进行相应处理 795 | # self.open_fail += 1 796 | signal = False 797 | else: 798 | self.log.debug(i) 799 | self.CheckOpen(1,1,2,symbol_A,symbol_B,symbol_C,min_amt_A1, min_amt_B1, min_amt_C2) 800 | if signal:#判断是否按限价单成交,如果不是,则扯单后补市价单 801 | self.open_num += 1 802 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 803 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 804 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 805 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 806 | self.log.debug('币量相当于%f个%s' % (total, X)) 807 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 808 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 809 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 810 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 811 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 812 | self.log.debug('币量相当于%f个%s' % (total_, X)) 813 | self.win[X] += total_ - total 814 | return 815 | else: 816 | self.log.debug('有跨市112正循环信号,但不符合条件!') 817 | # self.log.debug('币1:%f 币2:%f 币3:%f A盘口:%f B盘口:%f C盘口:%f'%(cur_size_11, \ 818 | # cur_size_12 * A_bestask_1, cur_size_23 * C_bestbid_2, A_bestask_size_1 / A_bestask_1, \ 819 | # B_bestbid_size_1 * A_bestask_1, C_bestbid_size_2 * C_bestbid_2)) 820 | hand = [cur_size_11, cur_size_12 * A_bestask_1, cur_size_23 * C_bestbid_2, A_bestask_size_1 / A_bestask_1, \ 821 | B_bestbid_size_1 * A_bestask_1, C_bestbid_size_2 * C_bestbid_2] 822 | n = hand.index(min(hand)) 823 | if n == 0: 824 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, X)) 825 | self.signal_num += 1 826 | elif n == 1: 827 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Y)) 828 | self.signal_num += 1 829 | elif n == 2: 830 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Z)) 831 | self.signal_num += 1 832 | else: 833 | self.log.debug('盘口深度不够') 834 | if win <= 0: self.log.debug('预估盈利太低') 835 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 836 | return 837 | if Deficit_211 > 1 and Deficit_211 < 1.01:# 跨市三角 逆1: C2 B1 A1 838 | size_1 = min(cur_size_21, cur_size_13 * C_bestask_2, cur_size_12 * A_bestbid_1, C_bestask_size_2 * C_bestask_2, 839 | B_bestask_size_1 * B_bestask_1 * C_bestask_2, A_bestbid_1 * A_bestbid_size_1) * self.ratio 840 | size_2 = size_1 / C_bestask_2 841 | size_3 = size_2 / B_bestask_1 842 | amt_A = float(self.exchange_1.amount_to_precision(symbol_A,size_3)) 843 | amt_B = float(self.exchange_1.amount_to_precision(symbol_B,size_3)) 844 | amt_C = float(self.exchange_2.amount_to_precision(symbol_C,size_2)) 845 | price_A = float(self.exchange_1.price_to_precision(symbol_A,A_bestbid_1)) 846 | price_B = float(self.exchange_1.price_to_precision(symbol_B,B_bestask_1)) 847 | price_C = float(self.exchange_2.price_to_precision(symbol_C,C_bestask_2)) 848 | win = size_3 * A_bestbid_1 - size_1 849 | if size_3 > min_amt_A1 and size_3 > min_amt_B1 and size_2 > min_amt_C2 and win > 0 and delay <= 95\ 850 | and amt_A > 0 and amt_B>0 and amt_C>0 and price_A>0 and price_B>0 and price_C>0: 851 | t = [] 852 | order_result = [] 853 | t.append(MyThread(self.CreatOrder, args=(symbol_C,2, 'limit', 'buy' , size_2, C_bestask_2,))) 854 | t.append(MyThread(self.CreatOrder, args=(symbol_B,1, 'limit', 'buy' , size_3, B_bestask_1,))) 855 | t.append(MyThread(self.CreatOrder, args=(symbol_A,1, 'limit', 'sell', size_3, A_bestbid_1,))) 856 | begin = time.time() 857 | for i in t: 858 | i.setDaemon(True) 859 | i.start() 860 | for i in t: 861 | i.join() 862 | order_result.append(i.get_result()) 863 | end = time.time() 864 | delay_ = float((end - begin) // 0.001) 865 | self.log.debug("发现跨市211逆循环信号!") 866 | self.log.debug("预估交易数量: %f %f %f" % (size_1, size_2, size_3)) 867 | self.log.debug('in : %f out : %f win : %f' % (size_1, size_3 * A_bestbid_1,win)) 868 | self.log.debug("价差比率:%f" %(Deficit_211)) 869 | self.log.debug('询价延迟: %f ms' % delay ) 870 | self.log.debug('下单延迟: %f ms' % delay_) 871 | self.log.debug('下单参数:') 872 | self.log.debug('C: %f %f %f %f' % (size_2, C_bestask_2, amt_C, price_C)) 873 | self.log.debug('B: %f %f %f %f' % (size_3, B_bestask_1, amt_B, price_B)) 874 | self.log.debug('A: %f %f %f %f' % (size_3, A_bestbid_1, amt_A, price_A)) 875 | self.log.debug('下单结果:') 876 | for i in order_result: 877 | if 'id' not in i: 878 | # self.log.debug('下单出错!') 879 | # self.open_fail += 1 880 | signal = False 881 | else: 882 | self.log.debug(i) 883 | self.CheckOpen(2,1,1,symbol_C,symbol_B,symbol_A,min_amt_C2, min_amt_B1, min_amt_A1) 884 | if signal: #判断是否按市价单成交 885 | self.open_num += 1 886 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 887 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 888 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 889 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 890 | self.log.debug('币量相当于%f个%s' % (total, X)) 891 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 892 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 893 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 894 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 895 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 896 | self.log.debug('币量相当于%f个%s' % (total_, X)) 897 | self.win[X] += total_ - total 898 | return 899 | else: 900 | self.log.debug('有跨市211逆循环信号,但不符合条件!') 901 | # self.log.debug('币1:%f 币2:%f 币3:%f C盘口:%f B盘口:%f A盘口:%f'%(cur_size_21, \ 902 | # cur_size_12 * A_bestbid_1, cur_size_13 * C_bestask_2, C_bestask_size_2 * C_bestask_2, \ 903 | # B_bestask_size_1 * B_bestask_1 * C_bestask_2, A_bestbid_1 * A_bestbid_size_1)) 904 | hand = [cur_size_21, cur_size_12 * A_bestbid_1, cur_size_13 * C_bestask_2, C_bestask_size_2 * C_bestask_2, \ 905 | B_bestask_size_1 * B_bestask_1 * C_bestask_2, A_bestbid_1 * A_bestbid_size_1] 906 | n = hand.index(min(hand)) 907 | if n == 0: 908 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, X)) 909 | self.signal_num += 1 910 | elif n == 1: 911 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Y)) 912 | self.signal_num += 1 913 | elif n == 2: 914 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Z)) 915 | self.signal_num += 1 916 | else: 917 | self.log.debug('盘口深度不够') 918 | if win <= 0: self.log.debug('预估盈利太低') 919 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 920 | return 921 | if Surplus_221 > 1 and Surplus_221 < 1.01:# 顺2: A2 B2 C1 922 | size_1 = min(cur_size_21, cur_size_22 * A_bestask_2, cur_size_13 * C_bestbid_1, A_bestask_size_2 / A_bestask_2, 923 | B_bestbid_size_2 * A_bestask_2, C_bestbid_size_1 * C_bestbid_1) * self.ratio 924 | size_2 = size_1 / A_bestask_2 925 | size_3 = size_2 * B_bestbid_2 926 | amt_A = float(self.exchange_2.amount_to_precision(symbol_A,size_2)) 927 | amt_B = float(self.exchange_2.amount_to_precision(symbol_B,size_2)) 928 | amt_C = float(self.exchange_1.amount_to_precision(symbol_C,size_3)) 929 | price_A = float(self.exchange_2.price_to_precision(symbol_A,A_bestask_2)) 930 | price_B = float(self.exchange_2.price_to_precision(symbol_B,B_bestbid_2)) 931 | price_C = float(self.exchange_1.price_to_precision(symbol_C,C_bestbid_1)) 932 | win = size_3 * C_bestbid_1 - size_1 933 | if size_2 > min_amt_A2 and size_2 > min_amt_B2 and size_3 > min_amt_C1 and win > 0 and delay <= 95\ 934 | and amt_A > 0 and amt_B > 0 and amt_C > 0 and price_A > 0 and price_B > 0 and price_C > 0: 935 | t = [] 936 | order_result = [] 937 | t.append(MyThread(self.CreatOrder, args=(symbol_A,2,'limit','buy' ,size_2,A_bestask_2,))) 938 | t.append(MyThread(self.CreatOrder, args=(symbol_B,2,'limit','sell',size_2,B_bestbid_2,))) 939 | t.append(MyThread(self.CreatOrder, args=(symbol_C,1,'limit','sell',size_3,C_bestbid_1,))) 940 | begin = time.time() 941 | for i in t: 942 | i.setDaemon(True) 943 | i.start() 944 | for i in t: 945 | i.join() 946 | order_result.append(i.get_result()) 947 | end = time.time() 948 | delay_ = float((end - begin) // 0.001) 949 | self.log.debug("发现跨市221正循环信号!") 950 | self.log.debug("预估交易数量: %f %f %f" % (size_1, size_2, size_3)) 951 | self.log.debug('in : %f out : %f win : %f' % (size_1,size_3 * C_bestbid_1, win)) # 先1 3 后2 952 | self.log.debug("价差比率:%f" % (Surplus_221)) 953 | self.log.debug('询价延迟: %f ms' % delay ) 954 | self.log.debug('下单延迟: %f ms' % delay_) 955 | self.log.debug('下单参数:') 956 | self.log.debug('A: %f %f %f %f' % (size_2, A_bestask_2, amt_A, price_A)) 957 | self.log.debug('B: %f %f %f %f' % (size_2, B_bestbid_2, amt_B, price_B)) 958 | self.log.debug('C: %f %f %f %f' % (size_3, C_bestbid_1, amt_C, price_C)) 959 | self.log.debug('下单结果:') 960 | for i in order_result: 961 | if 'id' not in i: 962 | # self.log.debug('下单出错!') 963 | # self.open_fail += 1 964 | signal = False 965 | else: 966 | self.log.debug(i) 967 | self.CheckOpen(2,2,1,symbol_A,symbol_B,symbol_C,min_amt_A2, min_amt_B2, min_amt_C1) 968 | if signal:#判断是否按限价单成交,如果不是,则扯单后补市价单 969 | self.open_num += 1 970 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 971 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 972 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 973 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 974 | self.log.debug('币量相当于%f个%s' % (total, X)) 975 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 976 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 977 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 978 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 979 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 980 | self.log.debug('币量相当于%f个%s' % (total_, X)) 981 | self.win[X] += total_ - total 982 | return 983 | else: 984 | self.log.debug('有跨市221正循环信号,但不符合条件!') 985 | # self.log.debug('币1:%f 币2:%f 币3:%f A盘口:%f B盘口:%f C盘口:%f'%(cur_size_21, \ 986 | # cur_size_22 * A_bestask_2, cur_size_13 * C_bestbid_1, A_bestask_size_2 / A_bestask_2, \ 987 | # B_bestbid_size_2 * A_bestask_2, C_bestbid_size_1 * C_bestbid_1)) 988 | hand = [cur_size_21, cur_size_22 * A_bestask_2, cur_size_13 * C_bestbid_1, A_bestask_size_2 / A_bestask_2, \ 989 | B_bestbid_size_2 * A_bestask_2, C_bestbid_size_1 * C_bestbid_1] 990 | n = hand.index(min(hand)) 991 | if n == 0: 992 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, X)) 993 | self.signal_num += 1 994 | elif n == 1: 995 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Y)) 996 | self.signal_num += 1 997 | elif n == 2: 998 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Z)) 999 | self.signal_num += 1 1000 | else: 1001 | self.log.debug('盘口深度不够') 1002 | if win <= 0: self.log.debug('预估盈利太低') 1003 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 1004 | return 1005 | if Deficit_122 > 1 and Deficit_122 < 1.01:# 逆2: C1 B2 A2 1006 | size_1 = min(cur_size_11, cur_size_23 * C_bestask_1, cur_size_22 * A_bestbid_2, C_bestask_size_1 * C_bestask_1, 1007 | B_bestask_size_2 * B_bestask_2 * C_bestask_1, A_bestbid_2 * A_bestbid_size_2) * self.ratio 1008 | size_2 = size_1 / C_bestask_1 1009 | size_3 = size_2 / B_bestask_2 1010 | amt_A = float(self.exchange_2.amount_to_precision(symbol_A,size_3)) 1011 | amt_B = float(self.exchange_2.amount_to_precision(symbol_B,size_3)) 1012 | amt_C = float(self.exchange_1.amount_to_precision(symbol_C,size_2)) 1013 | price_A = float(self.exchange_2.price_to_precision(symbol_A,A_bestbid_2)) 1014 | price_B = float(self.exchange_2.price_to_precision(symbol_B,B_bestask_2)) 1015 | price_C = float(self.exchange_1.price_to_precision(symbol_C,C_bestask_1)) 1016 | win = size_3 * A_bestbid_2 - size_1 1017 | if size_3 > min_amt_A2 and size_3 > min_amt_B2 and size_2 > min_amt_C1 and win > 0 and delay <= 95\ 1018 | and amt_A > 0 and amt_B>0 and amt_C>0 and price_A>0 and price_B>0 and price_C>0: 1019 | t = [] 1020 | order_result = [] 1021 | t.append(MyThread(self.CreatOrder, args=(symbol_C,1, 'limit', 'buy' , size_2, C_bestask_1,))) 1022 | t.append(MyThread(self.CreatOrder, args=(symbol_B,2, 'limit', 'buy' , size_3, B_bestask_2,))) 1023 | t.append(MyThread(self.CreatOrder, args=(symbol_A,2, 'limit', 'sell', size_3, A_bestbid_2,))) 1024 | begin = time.time() 1025 | for i in t: 1026 | i.setDaemon(True) 1027 | i.start() 1028 | for i in t: 1029 | i.join() 1030 | order_result.append(i.get_result()) 1031 | end = time.time() 1032 | delay_ = float((end - begin) // 0.001) 1033 | self.log.debug("发现跨市122逆循环信号!") 1034 | self.log.debug("预估交易数量: %f %f %f" % (size_1, size_2, size_3)) 1035 | self.log.debug('in : %f out : %f win : %f' % (size_1, size_3 * A_bestbid_2,win)) 1036 | self.log.debug("价差比率:%f" % (Deficit_122)) 1037 | self.log.debug('询价延迟: %f ms' % delay ) 1038 | self.log.debug('下单延迟: %f ms' % delay_) 1039 | self.log.debug('下单参数:') 1040 | self.log.debug('C: %f %f %f %f' % (size_2, C_bestask_1, amt_C, price_C)) 1041 | self.log.debug('B: %f %f %f %f' % (size_3, B_bestask_2, amt_B, price_B)) 1042 | self.log.debug('A: %f %f %f %f' % (size_3, A_bestbid_2, amt_A, price_A)) 1043 | self.log.debug('下单结果:') 1044 | for i in order_result: 1045 | if 'id' not in i: 1046 | # self.log.debug('下单出错!') 1047 | # self.open_fail += 1 1048 | signal = False 1049 | else: 1050 | self.log.debug(i) 1051 | self.CheckOpen(1,2,2,symbol_C,symbol_B,symbol_A,min_amt_C1, min_amt_B2, min_amt_A2) 1052 | if signal: #判断是否按市价单成交 1053 | self.open_num += 1 1054 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1055 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1056 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1057 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1058 | self.log.debug('币量相当于%f个%s' % (total, X)) 1059 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 1060 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1061 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1062 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1063 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1064 | self.log.debug('币量相当于%f个%s' % (total_, X)) 1065 | self.win[X] += total_ - total 1066 | return 1067 | else: 1068 | self.log.debug('有跨市122逆循环信号,但不符合条件!') 1069 | # self.log.debug('币1:%f 币2:%f 币3:%f C盘口:%f B盘口:%f A盘口:%f'%(cur_size_11, \ 1070 | # cur_size_22 * A_bestbid_2, cur_size_23 * C_bestask_1, C_bestask_size_1 * C_bestask_1, \ 1071 | # B_bestask_size_2 * B_bestask_2 * C_bestask_1, A_bestbid_2 * A_bestbid_size_2)) 1072 | hand = [cur_size_11, cur_size_22 * A_bestbid_2, cur_size_23 * C_bestask_1, C_bestask_size_1 * C_bestask_1, \ 1073 | B_bestask_size_2 * B_bestask_2 * C_bestask_1, A_bestbid_2 * A_bestbid_size_2] 1074 | n = hand.index(min(hand)) 1075 | if n == 0: 1076 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, X)) 1077 | self.signal_num += 1 1078 | elif n == 1: 1079 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Y)) 1080 | self.signal_num += 1 1081 | elif n == 2: 1082 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Z)) 1083 | self.signal_num += 1 1084 | else: 1085 | self.log.debug('盘口深度不够') 1086 | if win <= 0: self.log.debug('预估盈利太低') 1087 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 1088 | return 1089 | if Surplus_A > 0 and Surplus_A < 0.01: # symbol A 1卖 2买 卖出主币 需要主币数量足够,买入主币需要计价货币足够,对于symbol_A主币是2,计价币是1 1090 | size = min(cur_size_12, cur_size_21/A_bestask_2, A_bestbid_size_1, A_bestask_size_2) * self.ratio 1091 | amt_1 = float(self.exchange_1.amount_to_precision(symbol_A,size)) 1092 | amt_2 = float(self.exchange_2.amount_to_precision(symbol_A,size)) 1093 | price_1 = float(self.exchange_1.price_to_precision(symbol_A, A_bestbid_1)) 1094 | price_2 = float(self.exchange_2.price_to_precision(symbol_A, A_bestask_2)) 1095 | win = size * Surplus_A 1096 | if size > min_amt_A1 and size > min_amt_A2 and amt_1>0 and amt_2>0 and price_1>0 and price_2>0 and win > 0 and delay <= 95: 1097 | t = [] 1098 | order_result = [] 1099 | t.append(MyThread(self.CreatOrder, args=(symbol_A,1,'limit','sell',size,A_bestbid_1,))) 1100 | t.append(MyThread(self.CreatOrder, args=(symbol_A,2,'limit','buy' ,size,A_bestask_2,))) 1101 | begin = time.time() 1102 | for i in t: 1103 | i.setDaemon(True) 1104 | i.start() 1105 | for i in t: 1106 | i.join() 1107 | order_result.append(i.get_result()) 1108 | end = time.time() 1109 | delay_ = float((end - begin) // 0.001) 1110 | self.log.debug("symbol_A发现正循环信号!") 1111 | self.log.debug("预估交易数量: %f %f" % (size,size)) 1112 | self.log.debug("预估交易价格: %f %f" % (A_bestbid_1,A_bestask_2)) 1113 | self.log.debug('sell cost : %f buy cost : %f win : %f' %(size*A_bestbid_1,size*A_bestask_2,win)) 1114 | self.log.debug("价差比率:%f" % (Surplus_A)) 1115 | self.log.debug('询价延迟: %f ms' % delay ) 1116 | self.log.debug('下单延迟: %f ms' % delay_) 1117 | self.log.debug('下单参数:') 1118 | self.log.debug('A: %f %f %f %f' % (size, A_bestbid_1, amt_1, price_1)) 1119 | self.log.debug('B: %f %f %f %f' % (size, A_bestask_2, amt_2, price_2)) 1120 | self.log.debug('下单结果:') 1121 | for i in order_result: 1122 | if 'id' not in i: 1123 | # self.log.debug('下单出错!') 1124 | # self.open_fail += 1 1125 | signal = False 1126 | else: 1127 | self.log.debug(i) 1128 | self.CheckOpenBilateral(symbol_A,min_amt_A1,min_amt_A2) 1129 | if signal: 1130 | self.open_num += 1 1131 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1132 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1133 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1134 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1135 | self.log.debug('币量相当于%f个%s' % (total, X)) 1136 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 1137 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1138 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1139 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1140 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1141 | self.log.debug('币量相当于%f个%s' % (total_, X)) 1142 | self.win[X] += total_ - total 1143 | return 1144 | else: 1145 | self.log.debug('symbol_A有正循环信号,但不符合条件!') 1146 | # self.log.debug('余币:%f 余钱:%f 卖一量:%f 买一量:%f'%(cur_size_12, cur_size_21/A_bestask_2, A_bestbid_size_1, A_bestask_size_2)) 1147 | hand = [cur_size_12, cur_size_21/A_bestask_2, A_bestbid_size_1, A_bestask_size_2] 1148 | n = hand.index(min(hand)) 1149 | if n == 0: 1150 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Y)) 1151 | self.signal_num += 1 1152 | elif n == 1: 1153 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, X)) 1154 | self.signal_num += 1 1155 | else: 1156 | self.log.debug('盘口深度不够') 1157 | self.log.debug('size: %f %f' % (size, size)) 1158 | self.log.debug('min_amt: %f %f' % (min_amt_A1, min_amt_A2)) 1159 | self.log.debug('amt: %f %f price: %f %f' % (amt_1, amt_2, price_1, price_2)) 1160 | if win <= 0: self.log.debug('预估盈利太低') 1161 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 1162 | return 1163 | if Deficit_A > 0 and Deficit_A < 0.01: # symbol A 1买 2卖 卖出主币 需要主币数量足够,买入主币需要计价货币足够,对于symbol_A主币是2,计价币是1 1164 | size = min(cur_size_11/A_bestask_1, cur_size_22, A_bestask_size_1, A_bestbid_size_2) * self.ratio 1165 | amt_1 = float(self.exchange_1.amount_to_precision(symbol_A,size)) 1166 | amt_2 = float(self.exchange_2.amount_to_precision(symbol_A,size)) 1167 | price_1 = float(self.exchange_1.price_to_precision(symbol_A,A_bestask_1)) 1168 | price_2 = float(self.exchange_2.price_to_precision(symbol_A,A_bestbid_2)) 1169 | win = size * Deficit_A 1170 | if size> min_amt_A1 and size > min_amt_A2 and amt_1 >0 and amt_2 >0 and price_1>0 and price_2>0 and win > 0 and delay <= 95: 1171 | t = [] 1172 | order_result = [] 1173 | t.append(MyThread(self.CreatOrder, args=(symbol_A,1,'limit','buy' ,size,A_bestask_1,))) 1174 | t.append(MyThread(self.CreatOrder, args=(symbol_A,2,'limit','sell',size,A_bestbid_2,))) 1175 | begin = time.time() 1176 | for i in t: 1177 | i.setDaemon(True) 1178 | i.start() 1179 | for i in t: 1180 | i.join() 1181 | order_result.append(i.get_result()) 1182 | end = time.time() 1183 | delay_ = float((end - begin) // 0.001) 1184 | self.log.debug("symbol_A发现逆循环信号!") 1185 | self.log.debug("预估交易数量: %f %f" % (size, size)) 1186 | self.log.debug("预估交易价格: %f %f" % (A_bestask_1, A_bestbid_2)) 1187 | self.log.debug('buy cost : %f sell cost : %f win : %f' % (size*A_bestask_1,size*A_bestbid_2,win)) 1188 | self.log.debug("价差比率:%f" % (Deficit_A)) 1189 | self.log.debug('询价延迟: %f ms' % delay ) 1190 | self.log.debug('下单延迟: %f ms' % delay_) 1191 | self.log.debug('下单参数:') 1192 | self.log.debug('A: %f %f %f %f' % (size, A_bestask_1, amt_1, price_1)) 1193 | self.log.debug('B: %f %f %f %f' % (size, A_bestbid_2, amt_2, price_2)) 1194 | self.log.debug('下单结果:') 1195 | for i in order_result: 1196 | if 'id' not in i: 1197 | # self.log.debug('下单出错!') 1198 | # self.open_fail += 1 1199 | signal = False 1200 | else: 1201 | self.log.debug(i) 1202 | self.CheckOpenBilateral(symbol_A,min_amt_A1,min_amt_A2) 1203 | if signal: 1204 | self.open_num += 1 1205 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1206 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1207 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1208 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1209 | self.log.debug('币量相当于%f个%s' % (total, X)) 1210 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 1211 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1212 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1213 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1214 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1215 | self.log.debug('币量相当于%f个%s' % (total_, X)) 1216 | self.win[X] += total_ - total 1217 | return 1218 | else: 1219 | self.log.debug('symbol_A有逆循环信号,但不符合条件!') 1220 | # self.log.debug('余钱:%f 余币:%f 买一量:%f 卖一量:%f' % (cur_size_11/A_bestask_1, cur_size_22, A_bestask_size_1, A_bestbid_size_2)) 1221 | hand = [cur_size_11/A_bestask_1, cur_size_22, A_bestask_size_1, A_bestbid_size_2] 1222 | n = hand.index(min(hand)) 1223 | if n == 0: 1224 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, X)) 1225 | self.signal_num += 1 1226 | elif n == 1: 1227 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Y)) 1228 | self.signal_num += 1 1229 | else: 1230 | self.log.debug('盘口深度不够') 1231 | self.log.debug('size: %f %f'%(size,size)) 1232 | self.log.debug('min_amt: %f %f'%(min_amt_A1,min_amt_A2)) 1233 | self.log.debug('amt: %f %f price: %f %f'%(amt_1,amt_2,price_1,price_2)) 1234 | if win <= 0: self.log.debug('预估盈利太低') 1235 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 1236 | return 1237 | if Surplus_B > 0 and Surplus_B < 0.01: # symbol B 1卖 2买 卖出主币 需要主币数量足够,买入主币需要计价货币足够,对于symbol_B主币是2,计价币是3 1238 | size = min(cur_size_12, cur_size_23/B_bestask_2, B_bestbid_size_1, B_bestask_size_2) * self.ratio 1239 | amt_1 = float(self.exchange_1.amount_to_precision(symbol_B,size)) 1240 | amt_2 = float(self.exchange_2.amount_to_precision(symbol_B,size)) 1241 | price_1 = float(self.exchange_1.price_to_precision(symbol_B, B_bestbid_1)) 1242 | price_2 = float(self.exchange_2.price_to_precision(symbol_B, B_bestask_2)) 1243 | win = size * Surplus_B 1244 | if size > min_amt_B1 and size > min_amt_B2 and amt_1>0 and amt_2>0 and price_1>0 and price_2>0 and win > 0 and delay <= 95: 1245 | t = [] 1246 | order_result = [] 1247 | t.append(MyThread(self.CreatOrder, args=(symbol_B,1,'limit','sell',size,B_bestbid_1,))) 1248 | t.append(MyThread(self.CreatOrder, args=(symbol_B,2,'limit','buy' ,size,B_bestask_2,))) 1249 | begin = time.time() 1250 | for i in t: 1251 | i.setDaemon(True) 1252 | i.start() 1253 | for i in t: 1254 | i.join() 1255 | order_result.append(i.get_result()) 1256 | end = time.time() 1257 | delay_ = float((end - begin) // 0.001) 1258 | self.log.debug("symbol_B发现正循环信号!") 1259 | self.log.debug("预估交易数量: %f %f" % (size,size)) 1260 | self.log.debug("预估交易价格: %f %f" % (B_bestbid_1,B_bestask_2)) 1261 | self.log.debug('sell cost : %f buy cost : %f win : %f' %(size*B_bestbid_1,size*B_bestask_2,win)) 1262 | self.log.debug("价差比率:%f" % (Surplus_B)) 1263 | self.log.debug('询价延迟: %f ms' % delay ) 1264 | self.log.debug('下单延迟: %f ms' % delay_) 1265 | self.log.debug('下单参数:') 1266 | self.log.debug('A: %f %f %f %f' % (size, B_bestbid_1, amt_1, price_1)) 1267 | self.log.debug('B: %f %f %f %f' % (size, B_bestask_2, amt_2, price_2)) 1268 | self.log.debug('下单结果:') 1269 | for i in order_result: 1270 | if 'id' not in i: 1271 | # self.log.debug('下单出错!') 1272 | # self.open_fail += 1 1273 | signal = False 1274 | else: 1275 | self.log.debug(i) 1276 | self.CheckOpenBilateral(symbol_B,min_amt_B1,min_amt_B2) 1277 | if signal: 1278 | self.open_num += 1 1279 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1280 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1281 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1282 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1283 | self.log.debug('币量相当于%f个%s' % (total, X)) 1284 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 1285 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1286 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1287 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1288 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1289 | self.log.debug('币量相当于%f个%s' % (total_, X)) 1290 | self.win[X] += total_ - total 1291 | return 1292 | else: 1293 | self.log.debug('symbol_B有正循环信号,但不符合条件!') 1294 | # self.log.debug('余币:%f 余钱:%f 卖一量:%f 买一量:%f'%(cur_size_12, cur_size_23/B_bestask_2, B_bestbid_size_1, B_bestask_size_2)) 1295 | hand = [cur_size_12, cur_size_23/B_bestask_2, B_bestbid_size_1, B_bestask_size_2] 1296 | n = hand.index(min(hand)) 1297 | if n == 0: 1298 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Y)) 1299 | self.signal_num += 1 1300 | elif n == 1: 1301 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Z)) 1302 | self.signal_num += 1 1303 | else: 1304 | self.log.debug('盘口深度不够') 1305 | self.log.debug('size: %f %f' % (size, size)) 1306 | self.log.debug('min_amt: %f %f' % (min_amt_B1, min_amt_B2)) 1307 | self.log.debug('amt: %f %f price: %f %f' % (amt_1, amt_2, price_1, price_2)) 1308 | if win <= 0: self.log.debug('预估盈利太低') 1309 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 1310 | return 1311 | if Deficit_B > 0 and Deficit_B < 0.01: #symbol B 1买 2卖 卖出主币 需要主币数量足够,买入主币需要计价货币足够,对于symbol_B主币是2,计价币是3 1312 | size = min(cur_size_13/B_bestask_1, cur_size_22, B_bestask_size_1, B_bestbid_size_2) * self.ratio 1313 | amt_1 = float(self.exchange_1.amount_to_precision(symbol_B,size)) 1314 | amt_2 = float(self.exchange_2.amount_to_precision(symbol_B,size)) 1315 | price_1 = float(self.exchange_1.price_to_precision(symbol_B,B_bestask_1)) 1316 | price_2 = float(self.exchange_2.price_to_precision(symbol_B,B_bestbid_2)) 1317 | win = size * Deficit_B 1318 | if size> min_amt_B1 and size > min_amt_B2 and amt_1 >0 and amt_2 >0 and price_1>0 and price_2>0 and win > 0 and delay <= 95: 1319 | t = [] 1320 | order_result = [] 1321 | t.append(MyThread(self.CreatOrder, args=(symbol_B,1,'limit','buy' ,size,B_bestask_1,))) 1322 | t.append(MyThread(self.CreatOrder, args=(symbol_B,2,'limit','sell',size,B_bestbid_2,))) 1323 | begin = time.time() 1324 | for i in t: 1325 | i.setDaemon(True) 1326 | i.start() 1327 | for i in t: 1328 | i.join() 1329 | order_result.append(i.get_result()) 1330 | end = time.time() 1331 | delay_ = float((end - begin) // 0.001) 1332 | self.log.debug("symbol_B发现逆循环信号!") 1333 | self.log.debug("预估交易数量: %f %f" % (size, size)) 1334 | self.log.debug("预估交易价格: %f %f" % (B_bestask_1, B_bestbid_2)) 1335 | self.log.debug('buy cost : %f sell cost : %f win : %f' % (size*B_bestask_1,size*B_bestbid_2,win)) 1336 | self.log.debug("价差比率:%f" % (Deficit_B)) 1337 | self.log.debug('询价延迟: %f ms' % delay ) 1338 | self.log.debug('下单延迟: %f ms' % delay_) 1339 | self.log.debug('下单参数:') 1340 | self.log.debug('A: %f %f %f %f' % (size, B_bestask_1, amt_1, price_1)) 1341 | self.log.debug('B: %f %f %f %f' % (size, B_bestbid_2, amt_2, price_2)) 1342 | self.log.debug('下单结果:') 1343 | for i in order_result: 1344 | if 'id' not in i: 1345 | # self.log.debug('下单出错!') 1346 | # self.open_fail += 1 1347 | signal = False 1348 | else: 1349 | self.log.debug(i) 1350 | self.CheckOpenBilateral(symbol_B,min_amt_B1,min_amt_B2) 1351 | if signal: 1352 | self.open_num += 1 1353 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1354 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1355 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1356 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1357 | self.log.debug('币量相当于%f个%s' % (total, X)) 1358 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 1359 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1360 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1361 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1362 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1363 | self.log.debug('币量相当于%f个%s' % (total_, X)) 1364 | self.win[X] += total_ - total 1365 | return 1366 | else: 1367 | self.log.debug('symbol_B有逆循环信号,但不符合条件!') 1368 | # self.log.debug('余钱:%f 余币:%f 买一量:%f 卖一量:%f' % (cur_size_13/B_bestask_1, cur_size_22, B_bestask_size_1, B_bestbid_size_2)) 1369 | hand = [cur_size_13/B_bestask_1, cur_size_22, B_bestask_size_1, B_bestbid_size_2] 1370 | n = hand.index(min(hand)) 1371 | if n == 0: 1372 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Z)) 1373 | self.signal_num += 1 1374 | elif n == 1: 1375 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Y)) 1376 | self.signal_num += 1 1377 | else: 1378 | self.log.debug('盘口深度不够') 1379 | self.log.debug('size: %f %f'%(size,size)) 1380 | self.log.debug('min_amt: %f %f'%(min_amt_B1,min_amt_B2)) 1381 | self.log.debug('amt: %f %f price: %f %f'%(amt_1,amt_2,price_1,price_2)) 1382 | if win <= 0: self.log.debug('预估盈利太低') 1383 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 1384 | return 1385 | if Surplus_C > 0 and Surplus_C < 0.01: # symbol_C 1卖 2买 卖出主币 需要主币数量足够,买入主币需要计价货币足够,对于symbol_C主币是3,计价币是1 1386 | size = min(cur_size_13, cur_size_21/C_bestask_2, C_bestbid_size_1, C_bestask_size_2) * self.ratio 1387 | amt_1 = float(self.exchange_1.amount_to_precision(symbol_C,size)) 1388 | amt_2 = float(self.exchange_2.amount_to_precision(symbol_C,size)) 1389 | price_1 = float(self.exchange_1.price_to_precision(symbol_C, C_bestbid_1)) 1390 | price_2 = float(self.exchange_2.price_to_precision(symbol_C, C_bestask_2)) 1391 | win = size * Surplus_C 1392 | if size > min_amt_C1 and size > min_amt_C2 and amt_1>0 and amt_2>0 and price_1>0 and price_2>0 and win > 0 and delay <= 95: 1393 | t = [] 1394 | order_result = [] 1395 | t.append(MyThread(self.CreatOrder, args=(symbol_C,1,'limit','sell',size,C_bestbid_1,))) 1396 | t.append(MyThread(self.CreatOrder, args=(symbol_C,2,'limit','buy' ,size,C_bestask_2,))) 1397 | begin = time.time() 1398 | for i in t: 1399 | i.setDaemon(True) 1400 | i.start() 1401 | for i in t: 1402 | i.join() 1403 | order_result.append(i.get_result()) 1404 | end = time.time() 1405 | delay_ = float((end - begin) // 0.001) 1406 | self.log.debug("symbol_C发现正循环信号!") 1407 | self.log.debug("预估交易数量: %f %f" % (size,size)) 1408 | self.log.debug("预估交易价格: %f %f" % (C_bestbid_1,C_bestask_2)) 1409 | self.log.debug('sell cost : %f buy cost : %f win : %f' %(size*C_bestbid_1,size*C_bestask_2,win)) 1410 | self.log.debug("价差比率:%f" % (Surplus_C)) 1411 | self.log.debug('询价延迟: %f ms' % delay ) 1412 | self.log.debug('下单延迟: %f ms' % delay_) 1413 | self.log.debug('下单参数:') 1414 | self.log.debug('A: %f %f %f %f' % (size, C_bestbid_1, amt_1, price_1)) 1415 | self.log.debug('B: %f %f %f %f' % (size, C_bestask_2, amt_2, price_2)) 1416 | self.log.debug('下单结果:') 1417 | for i in order_result: 1418 | if 'id' not in i: 1419 | # self.log.debug('下单出错!') 1420 | # self.open_fail += 1 1421 | signal = False 1422 | else: 1423 | self.log.debug(i) 1424 | self.CheckOpenBilateral(symbol_C,min_amt_C1,min_amt_C2) 1425 | if signal: 1426 | self.open_num += 1 1427 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1428 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1429 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1430 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1431 | self.log.debug('币量相当于%f个%s' % (total, X)) 1432 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 1433 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1434 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1435 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1436 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1437 | self.log.debug('币量相当于%f个%s' % (total_, X)) 1438 | self.win[X] += total_ - total 1439 | return 1440 | else: 1441 | self.log.debug('symbol_C有正循环信号,但不符合条件!') 1442 | # self.log.debug('余币:%f 余钱:%f 卖一量:%f 买一量:%f'%(cur_size_13, cur_size_21/C_bestask_2, C_bestbid_size_1, C_bestask_size_2)) 1443 | hand = [cur_size_13, cur_size_21/C_bestask_2, C_bestbid_size_1, C_bestask_size_2] 1444 | n = hand.index(min(hand)) 1445 | if n == 0: 1446 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, Z)) 1447 | self.signal_num += 1 1448 | elif n == 1: 1449 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, X)) 1450 | self.signal_num += 1 1451 | else: 1452 | self.log.debug('盘口深度不够') 1453 | self.log.debug('size: %f %f' % (size, size)) 1454 | self.log.debug('min_amt: %f %f' % (min_amt_C1, min_amt_C2)) 1455 | self.log.debug('amt: %f %f price: %f %f' % (amt_1, amt_2, price_1, price_2)) 1456 | if win <= 0: self.log.debug('预估盈利太低') 1457 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 1458 | return 1459 | if Deficit_C > 0 and Deficit_C < 0.01: # symbol_C 1买 2卖 卖出主币 需要主币数量足够,买入主币需要计价货币足够,对于symbol_C主币是3,计价币是1 1460 | size = min(cur_size_11/C_bestask_1, cur_size_23, C_bestask_size_1, C_bestbid_size_2) * self.ratio 1461 | amt_1 = float(self.exchange_1.amount_to_precision(symbol_C,size)) 1462 | amt_2 = float(self.exchange_2.amount_to_precision(symbol_C,size)) 1463 | price_1 = float(self.exchange_1.price_to_precision(symbol_C,C_bestask_1)) 1464 | price_2 = float(self.exchange_2.price_to_precision(symbol_C,C_bestbid_2)) 1465 | win = size * Deficit_C 1466 | if size> min_amt_C1 and size > min_amt_C2 and amt_1 >0 and amt_2 >0 and price_1>0 and price_2>0 and win > 0 and delay <= 95: 1467 | t = [] 1468 | order_result = [] 1469 | t.append(MyThread(self.CreatOrder, args=(symbol_C,1,'limit','buy' ,size,C_bestask_1,))) 1470 | t.append(MyThread(self.CreatOrder, args=(symbol_C,2,'limit','sell',size,C_bestbid_2,))) 1471 | begin = time.time() 1472 | for i in t: 1473 | i.setDaemon(True) 1474 | i.start() 1475 | for i in t: 1476 | i.join() 1477 | order_result.append(i.get_result()) 1478 | end = time.time() 1479 | delay_ = float((end - begin) // 0.001) 1480 | self.log.debug("symbol_C发现逆循环信号!") 1481 | self.log.debug("预估交易数量: %f %f" % (size, size)) 1482 | self.log.debug("预估交易价格: %f %f" % (C_bestask_1, C_bestbid_2)) 1483 | self.log.debug('buy cost : %f sell cost : %f win : %f' % (size*C_bestask_1,size*C_bestbid_2,win)) 1484 | self.log.debug("价差比率:%f" % (Deficit_C)) 1485 | self.log.debug('询价延迟: %f ms' % delay ) 1486 | self.log.debug('下单延迟: %f ms' % delay_) 1487 | self.log.debug('下单参数:') 1488 | self.log.debug('A: %f %f %f %f' % (size, C_bestask_1, amt_1, price_1)) 1489 | self.log.debug('B: %f %f %f %f' % (size, C_bestbid_2, amt_2, price_2)) 1490 | self.log.debug('下单结果:') 1491 | for i in order_result: 1492 | if 'id' not in i: 1493 | # self.log.debug('下单出错!') 1494 | # self.open_fail += 1 1495 | signal = False 1496 | else: 1497 | self.log.debug(i) 1498 | self.CheckOpenBilateral(symbol_C,min_amt_C1,min_amt_C2) 1499 | if signal: 1500 | self.open_num += 1 1501 | self.log.debug('套利前币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1502 | total = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1503 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1504 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1505 | self.log.debug('币量相当于%f个%s' % (total, X)) 1506 | cur_size_11, cur_size_12, cur_size_13, cur_size_21, cur_size_22, cur_size_23 = self.GetBalance(X, Y, Z) 1507 | self.log.debug('套利后币量之总和: %f %f %f' % (cur_size_11 + cur_size_21, cur_size_12 + cur_size_22, cur_size_13 + cur_size_23)) 1508 | total_ = (cur_size_11 + cur_size_21) + (cur_size_12 + cur_size_22) * ( 1509 | 0.5 * A_bestbid_1 + 0.5 * A_bestask_1) + (cur_size_13 + cur_size_23) * ( 1510 | 0.5 * C_bestask_1 + 0.5 * C_bestbid_1) 1511 | self.log.debug('币量相当于%f个%s' % (total_, X)) 1512 | self.win[X] += total_ - total 1513 | return 1514 | else: 1515 | self.log.debug('symbol_C有逆循环信号,但不符合条件!') 1516 | # self.log.debug('余钱:%f 余币:%f 买一量:%f 卖一量:%f' % (cur_size_11/C_bestask_1, cur_size_23, C_bestask_size_1, C_bestbid_size_2)) 1517 | hand = [cur_size_11/C_bestask_1, cur_size_23, C_bestask_size_1, C_bestbid_size_2] 1518 | n = hand.index(min(hand)) 1519 | if n == 0: 1520 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_1, X)) 1521 | self.signal_num += 1 1522 | elif n == 1: 1523 | self.log.info('提示:交易所%s缺少%s' % (self.exchange_name_2, Z)) 1524 | self.signal_num += 1 1525 | else: 1526 | self.log.debug('盘口深度不够') 1527 | self.log.debug('size: %f %f'%(size,size)) 1528 | self.log.debug('min_amt: %f %f'%(min_amt_C1,min_amt_C2)) 1529 | self.log.debug('amt: %f %f price: %f %f'%(amt_1,amt_2,price_1,price_2)) 1530 | if win <= 0: self.log.debug('预估盈利太低') 1531 | if delay > 95: self.log.debug('询价延迟过高! %f ms' % delay) 1532 | return 1533 | # self.log.debug('询价延迟: %f ms' % delay) 1534 | return 1535 | # self.CheckBalance() 1536 | 1537 | def HandleTick(self): 1538 | self.log.info('--------------------') 1539 | self.log.info('累计信号次数:%d' % self.signal_num) 1540 | self.log.info('累计开仓次数:%d' % self.open_num) 1541 | self.log.info('下单出错次数:%d' % self.open_fail) 1542 | self.log.info('累计补单次数:%d' % self.maker_fail) 1543 | self.log.info('累计出错次数:%d' % self.error_num) 1544 | self.log.info('当前盈利约为: %f CNY' %(self.win['USDT']*6.8+self.win['BTC']*80000)) 1545 | self.log.info('====================') 1546 | box = self.box 1547 | for i in box[0]: 1548 | self.CheckTraingle("USDT", i, "BTC") 1549 | for i in box[1]: 1550 | self.CheckTraingle("USDT", i, "ETH") 1551 | for i in box[2]: 1552 | self.CheckTraingle("BTC", i, "ETH") 1553 | # 采用多线程轮询无法发现交易机会,原因是线程过多导致卡顿,若开启此功能,需要服务器配置极其强悍 1554 | # t1 = [] 1555 | # t2 = [] 1556 | # t3 = [] 1557 | # result = [] 1558 | # box = self.box 1559 | # for i in box[0]: 1560 | # t1.append(MyThread(self.CheckTraingle, args=("USDT", i, "BTC",))) 1561 | # for i in box[1]: 1562 | # t2.append(MyThread(self.CheckTraingle, args=("USDT", i, "ETH",))) 1563 | # for i in box[2]: 1564 | # t3.append(MyThread(self.CheckTraingle, args=("BTC", i, "ETH",))) 1565 | # for t in [t1,t2,t3]: 1566 | # for i in t: 1567 | # i.setDaemon(True) 1568 | # i.start() 1569 | # for i in t: 1570 | # i.join() 1571 | # result.append(i.get_result()) 1572 | 1573 | def run(self): 1574 | self.InitLog() 1575 | while True: 1576 | try: 1577 | self.ChooseExchange() #实例化交易所,根据遍历次数自动选择每次 1578 | self.GetTotalBalance() 1579 | self.markets_1 = self.exchange_1.fetch_markets() #获取交易对信息 1580 | self.markets_2 = self.exchange_2.fetch_markets() #获取交易对信息 1581 | self.fee_1 = self.exchange_1.fees #获取手续费 1582 | self.fee_2 = self.exchange_2.fees #获取手续费 1583 | self.HandleTick() #主函数 1584 | self.num += 1 1585 | except Exception: 1586 | self.log.error("警告!!! 出现错误!", exc_info=True) 1587 | self.error_num += 1 1588 | time.sleep(10) 1589 | 1590 | 1591 | 1592 | 1593 | if __name__ == '__main__': 1594 | # 支持交易所列表: okex huobi binance fcoin gateio bitmex ...... 具体见https://github.com/ccxt/ccxt/wiki/Manual 1595 | # fcoin 1596 | exchange_name_1 = 'fcoin' #在这里填入第一个交易所的名称 1597 | api_key_1 = '' #填入交易所1的apikey 1598 | seceret_key_1 = '' #填入交易所1的seceretkey 1599 | fee_ratio_1 = 1 # 填入你的手续费比率,如果没有点卡就填1 ,如果有5折买的点卡,就填0.5,如果有3折买的点卡就填0.3 1600 | passphrase_1 = '' # password 大部分交易所不需要填这个,空着就行,okex必须填写 1601 | # okex v3 1602 | exchange_name_2 = 'okex3' 1603 | api_key_2='' 1604 | seceret_key_2='' 1605 | fee_ratio_2 = 1 1606 | passphrase_2 = '' 1607 | # gateio 1608 | exchange_name_3 = 'gateio' 1609 | api_key_3='' 1610 | seceret_key_3='' 1611 | fee_ratio_3 = 1 1612 | passphrase_3 = '' 1613 | ### 1614 | exchange_name = [exchange_name_1,exchange_name_2,exchange_name_3] 1615 | api_key = [api_key_1,api_key_2,api_key_3] 1616 | seceret_key = [seceret_key_1,seceret_key_2,seceret_key_3] 1617 | passphrase = [passphrase_1,passphrase_2,passphrase_3] 1618 | box1 = [['TRX','XLM','EOS','XRP','ETC','LTC'],['TRX','XLM','EOS','XRP','ETC','LTC'],['TRX','XLM','EOS','XRP','ETC','LTC']] #举例:此处填写 fcoin okex 监控币对 1619 | box2 = [['XLM','ETC','EOS'],['TRX','XLM','ETC','EOS'],['XLM','ETC','EOS']] # fcoin gateio 1620 | box3 = [['XLM','ETC','EOS'],['TRX','XLM','ETC','EOS'],['XLM','ETC','EOS']] # okex gateio 1621 | check_box = [box1,box2,box3] 1622 | fee_ratio_box = [fee_ratio_1,fee_ratio_2,fee_ratio_3] 1623 | eat_ratio = 0.8 # 吃单比率,指吃掉多少深度,一般0.5~0.8,如果太高,可能会导致较多的滑点,如果太低,可能导致较低的开仓率 1624 | ### 遍历顺序 1:交易所1+交易所2 2:交易所1+交易所3 3: 交易所2+交易所3 1625 | bz = BanZhuanKing(exchange_name,api_key,seceret_key,passphrase,check_box,ratio=eat_ratio,fee_ratio_box=fee_ratio_box) #实例化我们的策略 1626 | bz.run() #主线程开始运行策略 -------------------------------------------------------------------------------- /trend_strategy/strategy.py: -------------------------------------------------------------------------------- 1 | # 从二次封装的okex API接口导入相关类 2 | # 也可以替换成其他交易所的接口,比如:huobi、binance、bitmex等等 3 | import okex.spot_api as spot 4 | import okex.swap_api as swap 5 | import okex.futures_api as future 6 | import okex.account_api as account 7 | # 导入日志记录模块 8 | import logging 9 | # 导入时间记录模块 10 | import time 11 | # 导入数学计算模块 12 | import math 13 | # 导入科学计算模块 14 | import numpy 15 | # 导入json格式模块 16 | import json 17 | # 导入talib指标计算模块 18 | import talib 19 | # 导入pandas科学计算模块 20 | import pandas 21 | # 导入smtp邮箱协议模块 22 | import smtplib 23 | from email.mime.text import MIMEText 24 | from email.header import Header 25 | # 导入网络请求模块 钉钉报警 26 | import requests 27 | 28 | # 策略主类 29 | class strategy(): 30 | # 实例化类的时候 会执行以下代码 31 | def __init__(self, name,api_key,seceret_key,passphrase,instrument_id,mode,granularity,leverate): 32 | self.version = "version:1.1.3" 33 | self.name = name 34 | self.api_key = api_key 35 | self.seceret_key = seceret_key 36 | self.passphrase = passphrase 37 | self.instrument_id =instrument_id 38 | self.mode = mode 39 | self.total_coin = '' 40 | self.ding_time = 0 41 | self.long_rate_history = [] 42 | self.short_rate_history = [] 43 | self.take_limit = 10 44 | self.one_hand = 1 45 | self.win_cut = 0.2 46 | self.loss_cut = -0.1 47 | self.drawback_cut = 0.5 48 | self.kd, self.kk, self.pd, self.pk = 0, 0, 0, 0 49 | self.leverate = leverate 50 | self.granularity = granularity 51 | self.mail_time = 0 52 | self.jump_mode = 'None' 53 | self.jump_price = 0 54 | 55 | # 启动日志记录 56 | def InitLog(self): 57 | level = logging.INFO 58 | self.log = logging.getLogger(__name__) 59 | self.log.setLevel(level) 60 | handler = logging.FileHandler("运行日志%s.txt" %time.strftime("%Y-%m-%d %H-%M-%S")) 61 | handler.setLevel(level) 62 | formatter = logging.Formatter('[%(asctime)s] %(message)s') 63 | handler.setFormatter(formatter) 64 | console = logging.StreamHandler() 65 | console.setLevel(level) 66 | self.log.addHandler(handler) 67 | self.log.addHandler(console) 68 | self.PrintConfig() 69 | 70 | # 钉钉报警方法 71 | def dingmessage(self, msg, at_all): 72 | webhook = 'https://oapi.dingtalk.com/robot/send?access_token=9c1cf30275ac4fe57b41c05263a56c800aeec5ba4efe589737321a6af28c4f08' 73 | header = { 74 | "Content-Type": "application/json", 75 | "Charset": "UTF-8" 76 | } 77 | tex = '>' + msg 78 | message ={ 79 | 80 | "msgtype": "text", 81 | "text": { 82 | "content": tex 83 | }, 84 | "at": { 85 | 86 | "isAtAll": at_all 87 | } 88 | 89 | } 90 | message_json = json.dumps(message) 91 | info = requests.post(url=webhook,data=message_json,headers=header) 92 | print(info.text) 93 | 94 | # 打印当前策略参数 95 | def PrintConfig(self): 96 | self.dingmessage('启动程序:'+self.name, False) 97 | self.log.info('启动程序:'+self.name) 98 | self.log.info("版本:%s" % self.version) 99 | self.log.info("当前模式:%s" % self.mode) 100 | self.log.info("最大持仓量:%s" % self.take_limit) 101 | self.log.info("K线类别:%s" % self.granularity) 102 | self.log.info("单次开仓数量:%s" % self.one_hand) 103 | self.log.info("止盈比例:%s" % self.win_cut) 104 | self.log.info("止损比例:%s" % self.loss_cut) 105 | 106 | # 实例化交易所API接口 107 | def LogIn(self): 108 | # self.spot = spot.SpotAPI(self.api_key, self.seceret_key, self.passphrase, True) 109 | self.swap = swap.SwapAPI(self.api_key, self.seceret_key, self.passphrase, True) 110 | # self.future = future.FutureAPI(self.api_key, self.seceret_key, self.passphrase, True) 111 | 112 | # 盘前准备 113 | def BeforeTrade(self): 114 | pass 115 | 116 | # 计算指标 117 | def GetTaLib(self): 118 | # sar 119 | self.sar = talib.SAR(self.high, self.low, acceleration=0.05, maximum=0.2) 120 | # boll 121 | self.upper, self.middle, self.lower = talib.BBANDS(self.close, timeperiod=200, nbdevup=2, nbdevdn=2, matype=talib.MA_Type.SMA) 122 | # self.log.info([round(self.upper[-1],4), round(self.middle[-1],4), round(self.lower[-1],4)]) 123 | # macd 124 | self.macd, self.macd_signal, self.macd_hist = talib.MACD(self.close, fastperiod=12, slowperiod=26, signalperiod=9) 125 | # self.log.info([self.macd[-1], self.macd_signal[-1], self.macd_hist[-1]]) 126 | # rsi 127 | self.rsi6 = talib.RSI(self.close,6) 128 | self.rsi12 = talib.RSI(self.close,12) 129 | self.rsi24 = talib.RSI(self.close,24) 130 | # ema 131 | self.emafast = talib.EMA(self.close,12) 132 | self.emaslow = talib.EMA(self.close,24) 133 | # atr up-> vol high 134 | self.atr = talib.ATR(self.high,self.low,self.close, timeperiod=14) 135 | # DC up -> up 136 | N1 = 10 137 | N2 = 10 138 | # self.DC_kd = max(numpy.max(self.open[-N1:-2]), numpy.max(self.close[-N1:-2])) 139 | # self.DC_kk = min(numpy.min(self.open[-N1:-2]), numpy.min(self.close[-N1:-2])) 140 | # self.DC_pd = min(numpy.min(self.open[-N2:-2]), numpy.min(self.close[-N2:-2])) 141 | # self.DC_pk = max(numpy.max(self.open[-N2:-2]), numpy.max(self.close[-N2:-2])) 142 | 143 | self.DC_kd = numpy.max(self.high[-N1:-2]) 144 | self.DC_kk = numpy.min(self.low[-N1:-2]) 145 | self.DC_pd = numpy.min(self.low[-N2:-2]) 146 | self.DC_pk = numpy.max(self.high[-N2:-2]) 147 | # adx up -> trend high 148 | self.ADX = talib.ADX(self.high, self.low, self.close, timeperiod=14) 149 | # emv up->up low->low 150 | a = pandas.DataFrame((self.high + self.low) / 2) 151 | b = a.shift(1) 152 | c = pandas.DataFrame(self.high - self.low) 153 | vol = pandas.DataFrame(self.vol) 154 | em = (a - b) * c / vol * 1000000 155 | emv = em.rolling(14).sum() 156 | self.emv = emv._values 157 | self.maemv = emv.rolling(9).mean()._values 158 | # cci 159 | self.cci = talib.CCI(self.high, self.low, self.close, timeperiod=14) 160 | 161 | # 获取K线 162 | def GetKline(self): 163 | kline = self.swap.get_kline(self.instrument_id, granularity=self.granularity, start='', end='') 164 | # get close high low vol 165 | kline = numpy.array(kline) 166 | open = kline[:, -6] 167 | high = kline[:, -5] 168 | low = kline[:, -4] 169 | close = kline[:, -3] 170 | vol = kline[:, -2] 171 | # transpose 172 | open = open[::-1] 173 | high = high[::-1] 174 | low = low[::-1] 175 | close = close[::-1] 176 | vol = vol[::-1] 177 | self.open = open.astype(numpy.float64) 178 | self.high = high.astype(numpy.float64) 179 | self.low = low.astype(numpy.float64) 180 | self.close = close.astype(numpy.float64) 181 | self.vol = vol.astype(numpy.float64) 182 | self.close_price = self.close[-1] 183 | self.log.info("最新价格: %5.4f" % (self.close_price)) 184 | 185 | # 选择指定的策略执行 186 | def HandleBar(self, mode): 187 | if "boll" in mode:self.StrategyBoll() 188 | if "rsi" in mode: self.StrategyRsi() 189 | if "dc" in mode:self.StrategyDC() 190 | if "sar" in mode:self.StrategySar() 191 | if 'cci' in mode:self.StrategyCCI() 192 | if 'jump' in mode:self.StrategyJump() 193 | if 'boll_break' in mode:self.StrategyBollBreak() 194 | 195 | # 检查当前风控 196 | def CheckRisks(self): 197 | # get leverage 198 | leverage = float(self.position['holding'][0]['leverage']) 199 | win_cut = self.win_cut 200 | loss_cut = self.loss_cut 201 | drawback_cut = self.drawback_cut 202 | long_rate = 0 203 | short_rate = 0 204 | if self.long_avg_cost: 205 | long_rate = ((self.close_price - self.long_avg_cost) / self.long_avg_cost) * leverage 206 | self.log.info("多单盈利: %5.2f %%" % round(long_rate * 100, 2)) 207 | if self.short_avg_cost: 208 | short_rate = ((self.short_avg_cost - self.close_price) / self.short_avg_cost) * leverage 209 | self.log.info("空单盈利: %5.2f %%" % round(short_rate * 100, 2)) 210 | if long_rate > 0: 211 | self.long_rate_history.append(long_rate) 212 | long_drawback = (max(self.long_rate_history) - long_rate) / max(self.long_rate_history) 213 | if long_drawback > drawback_cut and max(self.long_rate_history) > win_cut / 4: 214 | msg = "回撤过大,平多" 215 | self.log.info(msg) 216 | self.pd += self.one_hand 217 | else: 218 | self.long_rate_history.clear() 219 | if short_rate > 0: 220 | self.short_rate_history.append(short_rate) 221 | short_drawback = (max(self.short_rate_history) - short_rate) / max(self.short_rate_history) 222 | if short_drawback > drawback_cut and max(self.short_rate_history) > win_cut / 4: 223 | msg = "回撤过大,平空" 224 | self.log.info(msg) 225 | self.pk += self.one_hand 226 | else: 227 | self.short_rate_history.clear() 228 | # handle risks 229 | if long_rate < loss_cut or long_rate > win_cut: 230 | msg = "警告: 马上平多" 231 | self.dingmessage(msg, True) 232 | self.log.info(msg) 233 | self.pd += self.buy_available 234 | if short_rate < loss_cut or short_rate > win_cut: 235 | msg = "警告: 马上平空" 236 | self.dingmessage(msg, True) 237 | self.log.info(msg) 238 | self.pk += self.sell_available 239 | 240 | # 获取当前持仓 241 | def GetPosition(self): 242 | self.position = self.swap.get_specific_position(self.instrument_id) 243 | self.buy_amount = 0 244 | self.sell_amount = 0 245 | self.buy_available = 0 246 | self.sell_available = 0 247 | self.long_avg_cost = 0 248 | self.short_avg_cost = 0 249 | for data in self.position['holding']: 250 | if data['side'] == "long": 251 | self.buy_amount = int(data['position']) 252 | self.buy_available = int(data['avail_position']) 253 | if float(data['avg_cost'])>0: 254 | self.long_avg_cost = float(data['avg_cost']) 255 | if data['side'] == "short": 256 | self.sell_amount = int(data['position']) 257 | self.sell_available = int(data['avail_position']) 258 | if float(data['avg_cost'])>0: 259 | self.short_avg_cost = float(data['avg_cost']) 260 | self.log.info("当前持仓: 多仓/可平 %d/%d 空仓/可平 %d/%d" \ 261 | % (self.buy_amount,self.buy_available,self.sell_amount,self.sell_available)) 262 | 263 | # 移动止盈 264 | def lottery(self): 265 | time.sleep(0.1) 266 | self.log.info('挂止盈单') 267 | self.GetPosition() 268 | if self.buy_available >= 1 * self.one_hand:self.TakeOrders("pd", self.close_price * 1.001, self.one_hand*1, "0") 269 | if self.buy_available >= 3 * self.one_hand:self.TakeOrders("pd", self.close_price * 1.002, self.one_hand*2, "0") 270 | if self.buy_available >= 6 * self.one_hand:self.TakeOrders("pd", self.close_price * 1.003, self.one_hand*3, "0") 271 | if self.buy_available >=10 * self.one_hand:self.TakeOrders("pd", self.close_price * 1.004, self.one_hand*4, "0") 272 | if self.buy_available >=15 * self.one_hand:self.TakeOrders("pd", self.close_price * 1.005, self.one_hand*5, "0") 273 | if self.sell_available >= 1 * self.one_hand:self.TakeOrders("pk", self.close_price * 0.999, self.one_hand*1, "0") 274 | if self.sell_available >= 3 * self.one_hand:self.TakeOrders("pk", self.close_price * 0.998, self.one_hand*2, "0") 275 | if self.sell_available >= 6 * self.one_hand:self.TakeOrders("pk", self.close_price * 0.997, self.one_hand*3, "0") 276 | if self.sell_available >=10 * self.one_hand:self.TakeOrders("pk", self.close_price * 0.996, self.one_hand*4, "0") 277 | if self.sell_available >=15 * self.one_hand:self.TakeOrders("pk", self.close_price * 0.995, self.one_hand*5, "0") 278 | 279 | # 检查当前订单情况 280 | def check_orders(self,status): 281 | # get orders list 282 | # status:-1:remove 0:wait 1:part 2:full 283 | # return:orders_id 284 | orders_id = [] 285 | result = self.swap.get_order_list(status, self.instrument_id, '', '', '') 286 | # remove orders 287 | if result['order_info']: 288 | for index in range(len(result['order_info'])): 289 | orders_id.append(result['order_info'][index]['order_id']) 290 | return orders_id 291 | 292 | # 撤销指定订单 293 | def remove_orders(self, orders_id): 294 | result = [] 295 | for id in orders_id: 296 | result.append(self.swap.revoke_order(instrument_id=self.instrument_id, order_id=id)) 297 | return result 298 | 299 | # 撤销所有订单 300 | def CleanOrders(self): 301 | orders_id = self.check_orders("1") 302 | self.remove_orders(orders_id) 303 | orders_id = self.check_orders("0") 304 | self.remove_orders(orders_id) 305 | 306 | # 处理下单信号 307 | def HandleOrders(self): 308 | self.log.info('处理下单信号:') 309 | kd, kk, pd, pk = self.kd, self.kk, self.pd, self.pk 310 | self.kd, self.kk, self.pd, self.pk = 0, 0, 0, 0 311 | if kd + kk + pd + pk > 0: 312 | self.log.info('提示: kd:%d kk:%d pd:%d pk:%d'%(kd, kk, pd, pk)) 313 | if pd > 0:kd = 0 314 | if pk > 0:kk = 0 315 | self.log.info('提示: kd:%d kk:%d pd:%d pk:%d'%(kd, kk, pd, pk)) 316 | if kd > 0: 317 | self.dingmessage('提示: 开仓请注意!', True) 318 | self.TakeOrders("kd", self.close_price, kd, "1") 319 | if kk > 0: 320 | self.dingmessage('提示: 开仓请注意!', True) 321 | self.TakeOrders("kk", self.close_price, kk, "1") 322 | if pd > 0: 323 | self.TakeOrders("pd", self.close_price, pd, "1") 324 | if pk > 0: 325 | self.TakeOrders("pk", self.close_price, pk, "1") 326 | 327 | # 下单函数 328 | def TakeOrders(self,signal,price,amount,match_price): 329 | result=[] 330 | amount = int(amount) 331 | try: 332 | if amount > 0: 333 | if signal == "sykd" and self.buy_amount < self.take_limit/2: 334 | result = self.swap.take_order(self.instrument_id, str(amount), '1', str(price), '',match_price) 335 | if signal == "sykk" and self.sell_amount < self.take_limit/2: 336 | result = self.swap.take_order(self.instrument_id, str(amount), '2', str(price), '',match_price) 337 | if signal == "kd" and self.buy_amount < self.take_limit: 338 | result = self.swap.take_order(self.instrument_id, str(amount), '1', str(price), '',match_price) 339 | if signal == "kk" and self.sell_amount < self.take_limit: 340 | result = self.swap.take_order(self.instrument_id, str(amount), '2', str(price), '',match_price) 341 | if signal == "pd" and self.buy_available > 0: 342 | if amount <= self.buy_available: 343 | result = self.swap.take_order(self.instrument_id, str(amount), '3', str(price), '',match_price) 344 | if amount > self.buy_available: 345 | result = self.swap.take_order(self.instrument_id, str(self.buy_available), '3', str(price), '',match_price) 346 | if signal == "pk" and self.sell_available > 0: 347 | if amount <= self.sell_available: 348 | result = self.swap.take_order(self.instrument_id, str(amount), '4', str(price), '',match_price) 349 | if amount > self.sell_available: 350 | result = self.swap.take_order(self.instrument_id, str(self.sell_available), '4', str(price), '',match_price) 351 | if signal == "sypd" and self.buy_available > self.take_limit/2: 352 | result = self.swap.take_order(self.instrument_id, str(amount), '3', str(price), '',match_price) 353 | if signal == "sypk" and self.sell_available > self.take_limit/2: 354 | result = self.swap.take_order(self.instrument_id, str(amount), '4', str(price), '',match_price) 355 | self.log.info("开始下单: %s %s张" % (signal, str(amount))) 356 | self.log.info(result) 357 | except Exception as e: 358 | self.log.info(e) 359 | 360 | # 检查K线形态 361 | def CheckKline(self): 362 | open = self.open[-2] 363 | close = self.close[-2] 364 | high = self.high[-2] 365 | low = self.low[-2] 366 | vol = self.vol[-2] 367 | vol_ma = self.vol[-10:-2].mean() 368 | amp = high - low 369 | amp_ma = (self.high[-10:-2] - self.low[-10:-2]).mean() 370 | if vol > 2 * vol_ma and amp/amp_ma > 1: 371 | if open > close: 372 | if (high - open) > (open - close) or (high - open) > 0.5: 373 | self.log.info('提示: 发现长上影线') 374 | self.pd += self.one_hand 375 | if (close - low) > (open - close) or (close - low) > 0.5: 376 | self.log.info('提示: 发现长下影线') 377 | self.pk += self.one_hand 378 | if close > open: 379 | if (high - close) > (close - open) or (high - close) > 0.5: 380 | self.log.info('提示: 发现长上影线') 381 | self.pd += self.one_hand 382 | if (open - low) > (close - open) or (open - low) > 0.5: 383 | self.log.info('提示: 发现长下影线') 384 | self.pk += self.one_hand 385 | 386 | def StrategyBollBreak(self): 387 | kd, kk, pd, pk = self.kd, self.kk, self.pd, self.pk 388 | upper = self.upper 389 | middle = self.middle 390 | lower = self.lower 391 | close = self.close 392 | if close[-1] > upper[-1] and close[-2] < upper[-2] and self.buy_amount == 0: 393 | self.kd += self.one_hand 394 | if close[-1] < middle[-1] and close[-2] > middle[-2] and self.buy_amount > 0: 395 | self.pd += self.one_hand 396 | if close[-1] < lower[-1] and close[-2] > lower[-2] and self.sell_amount == 0: 397 | self.kk += self.one_hand 398 | if close[-1] > middle[-1] and close[-2] < middle[-2] and self.sell_amount > 0: 399 | self.pk += self.one_hand 400 | self.log.info('策略: BOLL BREAK 信号: kd:%d kk:%d pd:%d pk:%d'%(self.kd - kd, self.kk- kk, self.pd - pd, self.pk - pk)) 401 | 402 | # BOLL策略 403 | def StrategyBoll(self): 404 | kd, kk, pd, pk = self.kd, self.kk, self.pd, self.pk 405 | upper = self.upper 406 | middle = self.middle 407 | lower = self.lower 408 | rsi = self.rsi6 409 | atr = self.atr 410 | trend_cur = upper[-2] - lower[-2] 411 | trend_pre = upper[-3] - lower[-3] 412 | if upper[-2] > upper[-3] and middle[-2] > middle[-3] and lower[-2] < lower[-3]\ 413 | and rsi[-2] < 70 and rsi[-2] > 50 and rsi[-2] > rsi[-3] and rsi[-1] < 80 and rsi[-1] > rsi[-2]\ 414 | and atr[-2] > atr[-3] and trend_cur > trend_pre: 415 | self.kd += self.one_hand 416 | self.pk += self.one_hand 417 | if atr[-1] > atr[-2] and rsi[-1] < 60 and rsi[-1] > 50: 418 | self.kd += self.one_hand 419 | if upper[-2] > upper[-3] and middle[-2] < middle[-3] and lower[-2] < lower[-3]\ 420 | and rsi[-2] > 30 and rsi[-2] < 50 and rsi[-2] < rsi[-3] and rsi[-1] > 20 and rsi[-1] < rsi[-2]\ 421 | and atr[-2] > atr[-3] and trend_cur > trend_pre: 422 | self.kk += self.one_hand 423 | self.pd += self.one_hand 424 | if atr[-1] > atr[-2] and rsi[-1] > 40 and rsi[-1] < 50: 425 | self.kk += self.one_hand 426 | if upper[-2] < upper[-3] or lower[-2] > lower[-3]: 427 | if trend_cur < trend_pre and middle[-2] > middle[-3]: 428 | self.pk += self.one_hand 429 | if trend_cur < trend_pre and middle[-2] < middle[-3]: 430 | self.pd += self.one_hand 431 | self.log.info('策略: BOLL 信号: kd:%d kk:%d pd:%d pk:%d'%(self.kd - kd, self.kk- kk, self.pd - pd, self.pk - pk)) 432 | 433 | # RSI策略 434 | def StrategyRsi(self): 435 | kd, kk, pd, pk = self.kd, self.kk, self.pd, self.pk 436 | rsi6 = self.rsi6 437 | rsi24 = self.rsi24 438 | if rsi6[-2] > 50 and rsi6[-2] < 70 and rsi6[-2] > rsi24[-2] and rsi6[-3] < rsi24[-3]: 439 | self.kd += self.one_hand 440 | if rsi6[-2] < 50 and rsi6[-2] > 30 and rsi6[-2] < rsi24[-3] and rsi6[-3] > rsi24[-3]: 441 | self.kk += self.one_hand 442 | if rsi6[-2] > 95: 443 | self.pd += self.one_hand 444 | if rsi6[-2] < 5: 445 | self.pk += self.one_hand 446 | if rsi6[-2] > rsi24[-2] and rsi6[-3] < rsi24[-3]: 447 | self.pk += self.one_hand 448 | if rsi6[-2] < rsi24[-2] and rsi6[-3] > rsi24[-3]: 449 | self.pd += self.one_hand 450 | self.log.info('策略: RSI 信号: kd:%d kk:%d pd:%d pk:%d'%(self.kd - kd, self.kk- kk, self.pd - pd, self.pk - pk)) 451 | 452 | # CCI策略 453 | def StrategyCCI(self): 454 | kd, kk, pd, pk = self.kd, self.kk, self.pd, self.pk 455 | cci = self.cci 456 | if cci[-2] > 100 and cci[-3] < 100: 457 | self.pd += self.one_hand 458 | if cci[-2] < -100 and cci[-3] > -100: 459 | self.pk += self.one_hand 460 | if cci[-2] < 100 and cci[-3] > 100: 461 | self.kk += self.one_hand 462 | if cci[-2] > -100 and cci[-3] < -100: 463 | self.kd += self.one_hand 464 | self.log.info('策略: CCI 信号: kd:%d kk:%d pd:%d pk:%d'%(self.kd - kd, self.kk- kk, self.pd - pd, self.pk - pk)) 465 | 466 | # JUMP策略 467 | def StrategyJump(self): 468 | kd, kk, pd, pk = self.kd, self.kk, self.pd, self.pk 469 | step = self.close_price * 0.003 470 | # 正向 471 | if self.jump_mode == 'None': 472 | if self.close_price > self.high[-2]: 473 | # self.kd += self.one_hand 474 | self.jump_mode = 'long' 475 | self.jump_price = self.close_price 476 | if self.close_price < self.low[-2]: 477 | # self.kk += self.one_hand 478 | self.jump_mode = 'short' 479 | self.jump_price = self.close_price 480 | if self.jump_mode == 'long': 481 | if self.sell_amount > 0:self.pk += self.one_hand 482 | if self.close_price >= self.jump_price + step: 483 | self.kd += self.one_hand 484 | self.jump_price = self.close_price 485 | if self.close_price < self.jump_price - step: 486 | self.kk += self.one_hand 487 | self.pd += self.buy_amount 488 | self.jump_price = self.close_price 489 | self.jump_mode = 'short' 490 | if self.jump_mode == 'short': 491 | if self.buy_amount > 0:self.pd += self.one_hand 492 | if self.close_price <= self.jump_price - step: 493 | self.kk += self.one_hand 494 | self.jump_price = self.close_price 495 | if self.close_price > self.jump_price + step: 496 | self.kd += self.one_hand 497 | self.pk += self.sell_amount 498 | self.jump_price = self.close_price 499 | self.jump_mode = 'long' 500 | self.log.info('策略: JUMP 信号: kd:%d kk:%d pd:%d pk:%d'%(self.kd - kd, self.kk- kk, self.pd - pd, self.pk - pk)) 501 | self.log.info('mode:%s price:%f'%(self.jump_mode, self.jump_price)) 502 | 503 | # DC通道策略 504 | def StrategyDC(self): 505 | kd, kk, pd, pk = self.kd, self.kk, self.pd, self.pk 506 | upp_kd = self.DC_kd 507 | upp_pk = self.DC_pk 508 | low_kk = self.DC_kk 509 | low_pd = self.DC_pd 510 | close = self.close[-1] 511 | # 512 | if close > upp_kd: 513 | self.kd += self.one_hand 514 | if close < low_kk : 515 | self.kk += self.one_hand 516 | if close < low_pd: 517 | self.pd += self.one_hand 518 | if close > upp_pk: 519 | self.pk += self.one_hand 520 | self.log.info('策略: DC 信号: kd:%d kk:%d pd:%d pk:%d'%(self.kd - kd, self.kk- kk, self.pd - pd, self.pk - pk)) 521 | 522 | # SAR策略 523 | def StrategySar(self): 524 | kd, kk, pd, pk = self.kd, self.kk, self.pd, self.pk 525 | last_close = self.close[-2] 526 | pre_last_close = self.close[-3] 527 | sar = self.sar 528 | if last_close > sar[-2] and pre_last_close < sar[-3]: 529 | self.pk += self.one_hand 530 | self.kd += self.one_hand 531 | if last_close < sar[-2] and pre_last_close > sar[-3]: 532 | self.pd += self.one_hand 533 | self.kk += self.one_hand 534 | self.log.info('策略: SAR 信号: kd:%d kk:%d pd:%d pk:%d'%(self.kd - kd, self.kk- kk, self.pd - pd, self.pk - pk)) 535 | 536 | # 获取账号信息 537 | def GetAccount(self): 538 | result = self.swap.get_coin_account(self.instrument_id) 539 | if result["info"]["equity"] == "": 540 | self.log.warning("Can not get MyWallet!") 541 | else: 542 | self.total_coin = result["info"]["equity"] 543 | self.log.info("%s %s" %(self.instrument_id, self.total_coin)) 544 | if time.time() - self.ding_time > 5 * 60: 545 | self.ding_time = time.time() 546 | self.dingmessage('%s %s'%(self.instrument_id, self.total_coin), False) 547 | 548 | # 策略运行主函数 549 | def Run(self): 550 | time.sleep(time.time()%int(self.granularity)) 551 | self.LogIn() 552 | self.InitLog() 553 | # result = self.swap.set_leverage(self.instrument_id, self.leverate, "3") 554 | # self.log.info(result) 555 | while True: 556 | try: 557 | # 记录本次循环开始时间 558 | start_time = time.time() 559 | # 记录当前时间 560 | self.log.info("---===当前时间:%s===---" % time.strftime("%Y-%m-%d %H:%M:%S")) 561 | # 撤销上一轮全部挂单 562 | self.CleanOrders() 563 | # 获取账户信息 564 | self.GetAccount() 565 | # 获取仓位信息 566 | self.GetPosition() 567 | # 获取k线信息 568 | self.GetKline() 569 | # 计算技术指标 570 | self.GetTaLib() 571 | # 产生择时信号 572 | self.HandleBar(self.mode) 573 | # 检查k线形态 574 | self.CheckKline() 575 | # 检查风控 576 | self.CheckRisks() 577 | # 处理下单信号 578 | self.HandleOrders() 579 | # 撤销全部订单 580 | self.CleanOrders() 581 | # 刮彩票 582 | self.lottery() 583 | # 日志空行 584 | self.log.info(" ") 585 | # 记录本次循环结束时间 586 | end_time = time.time() 587 | # 计算本次循环耗费的时间 588 | spend_time = end_time - start_time 589 | # 睡眠指定时间后进入下一次循环 590 | time.sleep(int(self.granularity) - spend_time) 591 | except Exception: 592 | # 将程序错误信息报警 593 | self.log.error("警告 趋势策略出现错误", exc_info=True) 594 | self.dingmessage('警告 趋势策略出现错误', True) 595 | time.sleep(int(self.granularity)) 596 | 597 | # 公众号: 千千的量化世界 598 | # 回复:目录 策略 趋势追踪 获取本代码 599 | # 感谢大家对千千量化的支持与厚爱 将持续做好开源 为大家带来更多的干货 600 | 601 | # 程序开始的地方 602 | if __name__ == '__main__': 603 | # 账号 604 | api_key = '' 605 | # 密码 606 | seceret_key = '' 607 | # 二级密码 608 | passphrase = 'qwer1234' 609 | # 选择策略 610 | mode = ['boll_break', 'jump', 'rsi'] 611 | # 时间粒度 s 612 | granularity = "3600" 613 | # 杠杆 614 | leverate = "5" 615 | # 交易对 616 | instrument_id = "ETH-USD-SWAP" 617 | # 策略名称 618 | name = "趋势追踪者" 619 | # 实例化类 620 | my_strategy = strategy(name, api_key, seceret_key, passphrase, instrument_id, mode, granularity, leverate) 621 | # 运行类的主逻辑函数 622 | my_strategy.Run() --------------------------------------------------------------------------------