class GridStrategy: # 开仓价格 open_price = 100000 # 价格间距 price_dist = 2 # 利润间距 profit_dist = 2 # 初始仓位 init_position = 47 # 最终仓位 final_position = 94 # 单位数量,每一个fragment不一样 unit_amount = 1 contract_name = 'XBTUSD' redis_fragment_list = 'redis_fragment_list_0' filled_order_set = 'filled_order_set' setting_ht = 'grid_setting_hash' def __init__(self): self.logger = setup_logger() test = False api_key = 'kVfKITnQdJEzEC2sKYlVr9mM' api_secret = 'joccPUd5_DwOd3CDL1lSq_prKDxxM6oRQCmu7aALcw_6KWCi' test_url = 'https://testnet.bitmex.com/api/v1' product_url = 'https://www.bitmex.com/api/v1' if test: url = test_url else: url = product_url self.cli = bitmex(test=test, api_key=api_key, api_secret=api_secret) self.ws = BitMEXWebsocket(endpoint=url, symbols=[self.contract_name], api_key=api_key, api_secret=api_secret) # init redis client self.redis_cli = redis.Redis(host='localhost', port=6379, decode_responses=True) # threading lock self._value_lock = threading.Lock() self.unfilled_sell_list = '' self.unfilled_buy_list = '' self.logger.info('从redis同步参数') if self.redis_cli.llen(self.redis_fragment_list) > 0: fm = json.loads(self.redis_cli.lindex(self.redis_fragment_list, -1)) self.logger.info(fm) self.open_price = fm['open_price'] self.price_dist = fm['price_dist'] self.profit_dist = fm['profit_dist'] self.init_position = fm['init_position'] self.final_position = fm['final_position'] self.unit_amount = fm['unit_amount'] self.unfilled_buy_list = fm['buy_list_name'] self.unfilled_sell_list = fm['sell_list_name'] else: self.logger.info('当前redis为空') def get_filled_order(self, symbol): first_buy_order = None first_sell_order = None for order in self.ws.open_orders(): if order['ordStatus'] == 'Filled' and order[ 'symbol'] == symbol and (not self.redis_cli.sismember( self.filled_order_set, order['orderID'])): if order['side'] == 'Buy': if not first_buy_order: first_buy_order = order else: if order['price'] > first_buy_order['price']: first_buy_order = order else: if not first_sell_order: first_sell_order = order else: if order['price'] < first_sell_order['price']: first_sell_order = order if first_buy_order and first_sell_order: if first_buy_order['timestamp'] < first_sell_order['timestamp']: result_order = first_buy_order else: result_order = first_sell_order elif first_buy_order: result_order = first_buy_order elif first_sell_order: result_order = first_sell_order else: result_order = None return result_order def close_order(self, symbol, price): try: order = self.cli.Order.Order_new(symbol=symbol, price=price, execInst='Close').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) def send_order(self, symbol, side, qty, price): times = 0 result = None while times < 500: self.logger.info('第%s次发起委托 side: %s, price: %s' % (times + 1, side, price)) try: order = self.cli.Order.Order_new( symbol=symbol, side=side, orderQty=qty, price=price, ordType='Limit', execInst='ParticipateDoNotInitiate').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] if result['ordStatus'] == 'Canceled': if side == 'Buy': return self.send_order(symbol, side, qty, price - self.price_dist) else: return self.send_order(symbol, side, qty, price + self.price_dist) self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) redis_item = { 'orderID': result['orderID'], 'side': result['side'], 'price': result['price'], 'orderQty': result['orderQty'] } if side == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) break times += 1 return result def redis_rem(self, name, order_id): for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['orderID'] == order_id: return self.redis_cli.lrem(name, 1, redis_order) return 0 def redis_insert_sell(self, name, item): flag = False for i in range(self.redis_cli.llen(name), 0, -1): redis_order = self.redis_cli.lindex(name, i - 1) json_redis_order = json.loads(redis_order) if json_redis_order['price'] <= item['price']: self.redis_cli.linsert(name, 'after', redis_order, json.dumps(item)) flag = True break if not flag: self.redis_cli.lpush(name, json.dumps(item)) def redis_insert_buy(self, name, item): flag = False for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['price'] >= item['price']: self.redis_cli.linsert(name, 'before', redis_order, json.dumps(item)) flag = True break if not flag: self.redis_cli.rpush(name, json.dumps(item)) def cancel_order(self, orderid): times = 0 result = False while times < 500: self.logger.info('第%s次发起撤销委托, orderId: %s' % (times + 1, orderid)) try: self.cli.Order.Order_cancel(orderID=orderid).result() except Exception as e: self.logger.error('撤销错误: %s, 1秒后重试' % e) time.sleep(1) else: result = True break times += 1 return result def cancel_all(self, symbol=None, filter=None): times = 0 result = False while times < 200: self.logger.info('第 %s 次Cancle All' % (times + 1)) try: result = self.cli.Order.Order_cancelAll( symbol=symbol, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('cancel_all error: %s' % e) else: print(result) print(len(result)) result = True break times += 1 return result def new_bulk_orders(self, orders): result = None times = 0 while times < 200: self.logger.info('第%s次newBulk' % (times + 1)) try: order = self.cli.Order.Order_newBulk( orders=json.dumps(orders)).result() except Exception as e: self.logger.error('newBulk error: %s' % e) time.sleep(1) else: result = order[0] # print(result) for o in order[0]: self.logger.info('委托成功: side: %s, price: %s, orderid: %s' % (o['side'], o['price'], o['orderID'])) redis_item = { 'orderID': o['orderID'], 'side': o['side'], 'price': o['price'], 'orderQty': o['orderQty'] } if o['side'] == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) break times += 1 return result def run(self): self.logger.info('start') buy_amount = 0 sell_amount = 0 last_buy_qty = 0 while True: filled_order = self.get_filled_order(self.contract_name) if filled_order: order_id = filled_order['orderID'] cum_qty = filled_order['cumQty'] order_px = filled_order['price'] side = filled_order['side'] ord_type = filled_order['ordType'] symbol = filled_order['symbol'] self.logger.info( '--------------------------------------------------------------------------------' ) self.logger.info( 'side: %s, type: %s, symbol: %s, cum_qty: %s, order_px: %s, orderID: %s' % (side, ord_type, symbol, cum_qty, order_px, order_id)) # init_position最好是素数,默认11 if cum_qty % self.init_position == 0: if order_px < self.open_price: self.redis_cli.rpop(self.redis_fragment_list) self.logger.info( '清空redis: %s, %s' % (self.unfilled_buy_list, self.unfilled_sell_list)) self.redis_cli.ltrim(self.unfilled_buy_list, 1, 0) self.redis_cli.ltrim(self.unfilled_sell_list, 1, 0) self.logger.info('取消委托') self.cancel_all(symbol, {'orderQty': self.unit_amount}) self.logger.info('开仓...') self.init_position = int( self.redis_cli.hget(self.setting_ht, 'init_position')) self.final_position = int( self.redis_cli.hget(self.setting_ht, 'final_position')) self.price_dist = float( self.redis_cli.hget(self.setting_ht, 'price_dist')) self.profit_dist = float( self.redis_cli.hget(self.setting_ht, 'profit_dist')) # fragment_amount = self.redis_cli.llen(self.redis_fragment_list) redis_item = { 'open_price': order_px, 'unit_amount': int(cum_qty / self.init_position), 'init_position': self.init_position, 'final_position': self.final_position, 'price_dist': self.price_dist, 'profit_dist': self.profit_dist, 'sell_list_name': 'unfilled_sell_list_0', 'buy_list_name': 'unfilled_buy_list_0', } self.redis_cli.rpush(self.redis_fragment_list, json.dumps(redis_item)) self.open_price = redis_item['open_price'] self.unit_amount = redis_item['unit_amount'] self.unfilled_sell_list = redis_item['sell_list_name'] self.unfilled_buy_list = redis_item['buy_list_name'] self.logger.info(redis_item) self.logger.info( '清空redis: %s, %s' % (self.unfilled_buy_list, self.unfilled_sell_list)) self.redis_cli.ltrim(self.unfilled_sell_list, 1, 0) self.redis_cli.ltrim(self.unfilled_buy_list, 1, 0) new_orders = [] # Buy Order for i in range(self.init_position): new_orders.append({ 'symbol': symbol, 'side': 'Buy', 'orderQty': self.unit_amount, 'ordType': 'Limit', 'price': order_px - self.price_dist * i - self.profit_dist }) # Sell Order for i in range(self.final_position - self.init_position): new_orders.append({ 'symbol': symbol, 'side': 'Sell', 'orderQty': self.unit_amount, 'ordType': 'Limit', 'price': order_px + self.price_dist * (i + 1) }) self.new_bulk_orders(new_orders) else: if side == 'Sell': self.redis_rem(self.unfilled_sell_list, order_id) price = order_px - self.profit_dist self.send_order(symbol, 'Buy', self.unit_amount, price) sell_amount += 1 # 上涨止损 if self.redis_cli.llen(self.unfilled_sell_list) == 0: self.cancel_all() self.close_order(symbol, price + 100) else: self.redis_rem(self.unfilled_buy_list, order_id) price = order_px + self.profit_dist self.send_order(symbol, 'Sell', self.unit_amount, price) buy_amount += 1 self.logger.info( 'TOTAL: %d\tBUY: %d\tSELL: %d' % (sell_amount + buy_amount, buy_amount, sell_amount)) self.redis_cli.sadd(self.filled_order_set, filled_order['orderID']) time.sleep(0.2)
class GridStrategy: # 开仓价格 open_price = 100000 # 价格间距 price_dist = 2 # 利润间距 profit_dist = 2 # 初始仓位 init_position = 47 # 最终仓位 final_position = 94 contract_names = ['XBTUSD', 'XBTZ19'] filled_order_set = 'filled_order_set' setting_ht = 'grid_setting_hash' def __init__(self): self.logger = setup_logger() test = False self.api_key = 'kVfKITnQdJEzEC2sKYlVr9mM' self.api_secret = 'joccPUd5_DwOd3CDL1lSq_prKDxxM6oRQCmu7aALcw_6KWCi' test_url = 'https://testnet.bitmex.com/api/v1' product_url = 'https://www.bitmex.com/api/v1' if test: url = test_url self.filled_order_set = 'filled_order_set2' self.setting_ht = 'grid_setting_hash2' self.api_key = 'hDZPEs8ECXv9A1OfBysNIySo' self.api_secret = '_KkD8sZiG8T1rhNRqN2EvnGu9C4lJXoQHi6v4lj6eVyNxAM4' else: url = product_url self.cli = bitmex(test=test, api_key=self.api_key, api_secret=self.api_secret) self.ws = BitMEXWebsocket(endpoint=url, symbols=self.contract_names, api_key=self.api_key, api_secret=self.api_secret) # init redis client self.redis_cli = redis.Redis(host='localhost', port=6379, decode_responses=True) # # threading lock # self._value_lock = threading.Lock() self.logger.info('从redis同步参数') self.price_dist = int(self.redis_cli.hget(self.setting_ht, 'price_dist')) self.profit_dist = int(self.redis_cli.hget(self.setting_ht, 'profit_dist')) self.init_position = int(self.redis_cli.hget(self.setting_ht, 'init_position')) self.final_position = int(self.redis_cli.hget(self.setting_ht, 'final_position')) self.unit_amount = int(self.redis_cli.hget(self.setting_ht, 'unit_amount')) self.unfilled_buy_list = 'unfilled_buy_list' self.unfilled_sell_list = 'unfilled_sell_list' self.logger.info('同步委托列表') self.redis_cli.ltrim(self.unfilled_buy_list, 1, 0) self.redis_cli.ltrim(self.unfilled_sell_list, 1, 0) for o in self.get_unfilled_orders({'orderQty': self.unit_amount, 'ordStatus': 'New'}): redis_item = {'orderID': o['orderID'], 'side': o['side'], 'price': o['price'], 'orderQty': o['orderQty'] } if o['side'] == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) self.logger.info('同步完毕') def get_filled_order(self): filled_orders = [] for order in self.ws.open_orders(): if order['ordStatus'] == 'Filled' and not self.redis_cli.sismember(self.filled_order_set, order['orderID']): filled_orders.append(order) return filled_orders def get_unfilled_orders(self, filter=None): times = 0 result = [] while times < 200: self.logger.info('第%s次获取未成交委托' % (times + 1)) try: orders = self.cli.Order.Order_getOrders(reverse=True, count=500, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('get orders error: %s' % e) time.sleep(1) else: for o in orders[0]: result.append(o) break times += 1 return result def close_order(self, symbol, side, price): try: order = self.cli.Order.Order_new(symbol=symbol, side=side, price=price, execInst='Close').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) def send_market_order(self, symbol, side, qty): times = 0 result = None while times < 500: self.logger.info('第%s次发起市价委托 side: %s' % (times + 1, side)) try: order = self.cli.Order.Order_new(symbol=symbol, side=side, orderQty=qty, ordType='Market').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) break times += 1 return result def send_order(self, symbol, side, qty, price): times = 0 result = None while times < 500: self.logger.info('第%s次发起委托 side: %s, price: %s' % (times + 1, side, price)) try: order = self.cli.Order.Order_new(symbol=symbol, side=side, orderQty=qty, price=price, ordType='Limit', execInst='ParticipateDoNotInitiate').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] if result['ordStatus'] == 'Canceled': if side == 'Buy': return self.send_order(symbol, side, qty, price - self.price_dist) else: return self.send_order(symbol, side, qty, price + self.price_dist) self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) redis_item = {'orderID': result['orderID'], 'side': result['side'], 'price': result['price'], 'orderQty': result['orderQty'] } if side == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) break times += 1 return result def redis_rem(self, name, order_id): for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['orderID'] == order_id: return self.redis_cli.lrem(name, 1, redis_order) return 0 def redis_insert_sell(self, name, item): flag = False for i in range(self.redis_cli.llen(name), 0, -1): redis_order = self.redis_cli.lindex(name, i - 1) json_redis_order = json.loads(redis_order) if json_redis_order['price'] <= item['price']: self.redis_cli.linsert(name, 'after', redis_order, json.dumps(item)) flag = True break if not flag: self.redis_cli.lpush(name, json.dumps(item)) def redis_insert_buy(self, name, item): flag = False for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['price'] >= item['price']: self.redis_cli.linsert(name, 'before', redis_order, json.dumps(item)) flag = True break if not flag: self.redis_cli.rpush(name, json.dumps(item)) def cancel_order(self, orderid): times = 0 result = False while times < 500: self.logger.info('第%s次发起撤销委托, orderId: %s' % (times + 1, orderid)) try: self.cli.Order.Order_cancel(orderID=orderid).result() except Exception as e: self.logger.error('撤销错误: %s, 1秒后重试' % e) time.sleep(1) else: result = True break times += 1 return result def cancel_all(self, symbol=None, filter=None): times = 0 result = False while times < 200: self.logger.info('第 %s 次Cancle All' % (times + 1)) try: result = self.cli.Order.Order_cancelAll(symbol=symbol, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('cancel_all error: %s' % e) else: print(result) print(len(result)) result = True break times += 1 return result def new_bulk_orders(self, orders): result = None times = 0 while times < 200: self.logger.info('第%s次newBulk' % (times + 1)) try: order = self.cli.Order.Order_newBulk(orders=json.dumps(orders)).result() except Exception as e: self.logger.error('newBulk error: %s' % e) time.sleep(1) else: result = order[0] # print(result) for o in order[0]: self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (o['side'], o['price'], o['orderID'])) redis_item = {'orderID': o['orderID'], 'side': o['side'], 'price': o['price'], 'orderQty': o['orderQty'] } if o['side'] == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) break times += 1 return result def run(self): self.logger.info('start') buy_amount = 0 sell_amount = 0 while True: filled_orders = self.get_filled_order() for filled_order in filled_orders: order_id = filled_order['orderID'] cum_qty = filled_order['cumQty'] order_px = filled_order['price'] side = filled_order['side'] ord_type = filled_order['ordType'] symbol = filled_order['symbol'] self.logger.info('--------------------------------------------------------------------------------') self.logger.info('side: %s, type: %s, symbol: %s, cum_qty: %s, order_px: %s, orderID: %s' % (side, ord_type, symbol, cum_qty, order_px, order_id)) # init_position最好是素数 if cum_qty % self.init_position == 0: self.logger.info('开仓...') if side == 'Sell': self.redis_cli.hset(self.setting_ht, 'open_price_sell', order_px) self.redis_cli.ltrim(self.unfilled_sell_list, 1, 0) else: self.redis_cli.hset(self.setting_ht, 'open_price_buy', order_px) self.redis_cli.ltrim(self.unfilled_buy_list, 1, 0) new_orders = [] # Sell Order for i in range(self.init_position): new_orders.append({ 'symbol': symbol, 'side': 'Sell', 'orderQty': self.unit_amount, 'ordType': 'Limit', 'price': order_px + self.price_dist * i + self.profit_dist }) self.new_bulk_orders(new_orders) new_orders = [] # Buy Order for i in range(self.final_position - self.init_position): new_orders.append({ 'symbol': symbol, 'side': 'Buy', 'orderQty': self.unit_amount, 'ordType': 'Limit', 'price': order_px - self.price_dist * (i + 1) }) self.new_bulk_orders(new_orders) elif cum_qty == self.unit_amount: if side == 'Sell': self.redis_rem(self.unfilled_sell_list, order_id) price = order_px - self.profit_dist self.send_order(symbol, 'Buy', self.unit_amount, price) sell_amount += 1 # 上涨止损 if self.redis_cli.llen(self.unfilled_sell_list) == 0: # qty = self.redis_cli.llen(self.unfilled_buy_list) * self.unit_amount / 2 self.cancel_all() self.close_order(self.contract_names[0], 'Buy', price + 500) # self.send_market_order(symbol, 'Buy', qty) else: self.redis_rem(self.unfilled_buy_list, order_id) price = order_px + self.profit_dist self.send_order(symbol, 'Sell', self.unit_amount, price) buy_amount += 1 # 下跌止损 if self.redis_cli.llen(self.unfilled_buy_list) == 0: # qty = self.redis_cli.llen(self.unfilled_sell_list) * self.unit_amount / 2 self.cancel_all() self.close_order(self.contract_names[1], 'Sell', price - 500) # self.send_market_order(symbol, 'Sell', qty) self.logger.info('TOTAL: %d\tBUY: %d\tSELL: %d' % (sell_amount + buy_amount, buy_amount, sell_amount)) self.redis_cli.sadd(self.filled_order_set, filled_order['orderID']) time.sleep(0.2)
class GridStrategy: contract_names = ['XBTU21'] filled_order_set = 'filled_order_set' setting_ht = 'grid_setting_hash' def __init__(self): self.logger = setup_logger() # init redis client self.redis_cli = redis.Redis(host='localhost', port=6379, decode_responses=True) self.logger.info('从redis同步参数') self.price_dist = int( self.redis_cli.hget(self.setting_ht, 'price_dist')) self.profit_dist = int( self.redis_cli.hget(self.setting_ht, 'profit_dist')) self.init_position = int( self.redis_cli.hget(self.setting_ht, 'init_position')) self.final_position = int( self.redis_cli.hget(self.setting_ht, 'final_position')) self.unit_amount = int( self.redis_cli.hget(self.setting_ht, 'unit_amount')) self.if_test = int(self.redis_cli.hget(self.setting_ht, 'if_test')) self.api_key = self.redis_cli.hget(self.setting_ht, 'api_key') self.api_secret = self.redis_cli.hget(self.setting_ht, 'api_secret') #test = False #self.api_key = '-ycA8-LJUWi58YNRiqTnBTjn' #self.api_secret = '4BYMXW9vTv97Fx6W2j9zSw3atTE-GVxiEsobFaZZlqJtHLH8' test_url = 'https://testnet.bitmex.com/api/v1' product_url = 'https://www.bitmex.com/api/v1' print(self.if_test) if self.if_test: print('TEST.') url = test_url self.filled_order_set = 'filled_order_set_test' self.setting_ht = 'grid_setting_hash_test' self.api_key = 'YaZ6c81UNsKVCW2eh87a7OeL' self.api_secret = '4lursf1Lk5DBrl7M28hJTBsxMiVeBIhnNyciL_glYQDPCJdy' else: url = product_url self.cli = bitmex(test=self.if_test, api_key=self.api_key, api_secret=self.api_secret) self.ws = BitMEXWebsocket(endpoint=url, symbols=self.contract_names, api_key=self.api_key, api_secret=self.api_secret) # # threading lock # self._value_lock = threading.Lock() self.logger.info('同步委托列表') self.unfilled_buy_list = 'unfilled_buy_list' self.unfilled_sell_list = 'unfilled_sell_list' self.redis_cli.ltrim(self.unfilled_buy_list, 1, 0) self.redis_cli.ltrim(self.unfilled_sell_list, 1, 0) for o in self.get_unfilled_orders({ 'orderQty': self.unit_amount, 'ordStatus': 'New' }): redis_item = { 'orderID': o['orderID'], 'side': o['side'], 'price': o['price'], 'orderQty': o['orderQty'] } if o['side'] == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) self.logger.info('同步完毕') def get_filled_order(self): filled_orders = [] for order in self.ws.open_orders(): if order['ordStatus'] == 'Filled' and not self.redis_cli.sismember( self.filled_order_set, order['orderID']): filled_orders.append(order) return filled_orders def get_unfilled_orders(self, filter=None): times = 0 result = [] while times < 200: self.logger.info('第%s次获取未成交委托' % (times + 1)) try: orders = self.cli.Order.Order_getOrders( reverse=True, count=500, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('get orders error: %s' % e) time.sleep(1) else: for o in orders[0]: result.append(o) break times += 1 return result def close_order(self, symbol, side, price): try: order = self.cli.Order.Order_new(symbol=symbol, side=side, price=price, execInst='Close').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) def send_market_order(self, symbol, side, qty): times = 0 result = None while times < 500: self.logger.info('第%s次发起市价委托 side: %s' % (times + 1, side)) try: order = self.cli.Order.Order_new(symbol=symbol, side=side, orderQty=qty, ordType='Market').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) break times += 1 return result def send_order(self, symbol, side, qty, price): times = 0 result = None while times < 500: self.logger.info('第%s次发起委托 side: %s, price: %s' % (times + 1, side, price)) try: order = self.cli.Order.Order_new( symbol=symbol, side=side, orderQty=qty, price=price, ordType='Limit', execInst='ParticipateDoNotInitiate').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] if result['ordStatus'] == 'Canceled': if side == 'Buy': return self.send_order(symbol, side, qty, price - self.price_dist) else: return self.send_order(symbol, side, qty, price + self.price_dist) self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) redis_item = { 'orderID': result['orderID'], 'side': result['side'], 'price': result['price'], 'orderQty': result['orderQty'] } if side == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) break times += 1 return result def redis_rem(self, name, order_id): for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['orderID'] == order_id: return self.redis_cli.lrem(name, 1, redis_order) return 0 def redis_insert_sell(self, name, item): flag = False for i in range(self.redis_cli.llen(name), 0, -1): redis_order = self.redis_cli.lindex(name, i - 1) json_redis_order = json.loads(redis_order) if json_redis_order['price'] <= item['price']: self.redis_cli.linsert(name, 'after', redis_order, json.dumps(item)) flag = True break if not flag: self.redis_cli.lpush(name, json.dumps(item)) def redis_insert_buy(self, name, item): flag = False for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['price'] >= item['price']: self.redis_cli.linsert(name, 'before', redis_order, json.dumps(item)) flag = True break if not flag: self.redis_cli.rpush(name, json.dumps(item)) def cancel_order(self, orderid): times = 0 result = False while times < 500: self.logger.info('第%s次发起撤销委托, orderId: %s' % (times + 1, orderid)) try: self.cli.Order.Order_cancel(orderID=orderid).result() except Exception as e: self.logger.error('撤销错误: %s, 1秒后重试' % e) time.sleep(1) else: result = True break times += 1 return result def cancel_all(self, symbol=None, filter=None): times = 0 result = False while times < 200: self.logger.info('第 %s 次Cancle All' % (times + 1)) try: result = self.cli.Order.Order_cancelAll( symbol=symbol, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('cancel_all error: %s' % e) else: print(result) print(len(result)) result = True break times += 1 return result def new_bulk_orders(self, orders): result = None times = 0 while times < 200: self.logger.info('第%s次newBulk' % (times + 1)) try: order = self.cli.Order.Order_newBulk( orders=json.dumps(orders)).result() except Exception as e: self.logger.error('newBulk error: %s' % e) time.sleep(1) else: result = order[0] # print(result) for o in order[0]: self.logger.info('委托成功: side: %s, price: %s, orderid: %s' % (o['side'], o['price'], o['orderID'])) redis_item = { 'orderID': o['orderID'], 'side': o['side'], 'price': o['price'], 'orderQty': o['orderQty'] } if o['side'] == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) break times += 1 return result def run(self): self.logger.info('start') buy_amount = 0 sell_amount = 0 last_buy = [] while True: filled_orders = self.get_filled_order() for filled_order in filled_orders: order_id = filled_order['orderID'] cum_qty = filled_order['cumQty'] order_px = filled_order['price'] side = filled_order['side'] ord_type = filled_order['ordType'] symbol = filled_order['symbol'] self.logger.info( '--------------------------------------------------------------------------------' ) self.logger.info( 'side: %s, type: %s, symbol: %s, cum_qty: %s, order_px: %s, orderID: %s' % (side, ord_type, symbol, cum_qty, order_px, order_id)) # init_position最好是素数 if cum_qty % self.init_position == 0: self.logger.info('开仓...') if side == 'Sell': self.redis_cli.hset(self.setting_ht, 'open_price_sell', order_px) self.redis_cli.ltrim(self.unfilled_sell_list, 1, 0) else: self.redis_cli.hset(self.setting_ht, 'open_price_buy', order_px) self.redis_cli.ltrim(self.unfilled_buy_list, 1, 0) new_orders = [] # Sell Order for i in range(self.init_position): new_orders.append({ 'symbol': symbol, 'side': 'Sell', 'orderQty': self.unit_amount, 'ordType': 'Limit', 'price': order_px + self.price_dist * i + self.profit_dist }) self.new_bulk_orders(new_orders) new_orders = [] # Buy Order for i in range(self.final_position - self.init_position): new_orders.append({ 'symbol': symbol, 'side': 'Buy', 'orderQty': self.unit_amount, 'ordType': 'Limit', 'price': order_px - self.price_dist * (i + 1) }) self.new_bulk_orders(new_orders) elif cum_qty == self.unit_amount: if side == 'Sell': self.redis_rem(self.unfilled_sell_list, order_id) price = order_px - self.profit_dist self.send_order(symbol, 'Buy', self.unit_amount, price) sell_amount += 1 if last_buy: self.logger.info('orderID\tSell:%s-Buy:%s', order_id, last_buy[-1]) last_buy.pop() else: self.logger.info('orderID\tSell:%s-Buy:%s', order_id, '') # 上涨止损 # if self.redis_cli.llen(self.unfilled_sell_list) == 0: # # qty = self.redis_cli.llen(self.unfilled_buy_list) * self.unit_amount / 2 # self.cancel_all() # self.close_order(self.contract_names[0], 'Buy', price + 500) # # self.send_market_order(symbol, 'Buy', qty) else: self.redis_rem(self.unfilled_buy_list, order_id) price = order_px + self.profit_dist self.send_order(symbol, 'Sell', self.unit_amount, price) buy_amount += 1 last_buy.append(order_id) # 下跌止损 # if self.redis_cli.llen(self.unfilled_buy_list) == 0: # # qty = self.redis_cli.llen(self.unfilled_sell_list) * self.unit_amount / 2 # self.cancel_all() # self.close_order(self.contract_names[1], 'Sell', price - 500) # # self.send_market_order(symbol, 'Sell', qty) self.logger.info( 'TOTAL: %d\tBUY: %d\tSELL: %d' % (sell_amount + buy_amount, buy_amount, sell_amount)) self.redis_cli.sadd(self.filled_order_set, filled_order['orderID']) time.sleep(0.2)
class MyRobot: lever = 5 contract_name = 'XBTZ18' new_position_thd = 350 re_position_thd = 30 price_table = { '8': [4, 10, 21, 43], '12': [6, 15, 31, 64], '16': [8, 20, 42, 85], '24': [12, 30, 63, 127], '32': [16, 40, 84, 170] } open_price_list = 'open_price_list' base_price_list = 'base_price_list' base_price = 'base_price' filled_order_set = 'filled_order_set' unit_amount_list = 'unit_amount_list' def __init__(self): self.logger = setup_logger() test = False api_key = os.getenv('API_KEY') api_secret = os.getenv('API_SECRET') test_url = 'https://testnet.bitmex.com/api/v1' product_url = 'https://www.bitmex.com/api/v1' self.logger.info('APIKEY: %s' % api_key) if test: url = test_url else: url = product_url self.cli = bitmex(test=test, api_key=api_key, api_secret=api_secret) self.ws = BitMEXWebsocket(endpoint=url, symbols=["XBTUSD", self.contract_name], api_key=api_key, api_secret=api_secret) # init redis client self.redis_cli = redis.Redis(host='35.230.143.112', password='******', port=6379, decode_responses=True) self.last_sms_time = 0 """ 2018/6/14 更新 每次选取最邻近的订单 2018/7/23 更新 解决当价格变动很大,订单没有按照顺序成交,导致重复订单 """ def get_filled_order(self, last_trans_qty=0, last_trans_side='', last_trans_type=''): recent_order = None for order in self.ws.open_orders(): if order['ordStatus'] == 'Filled' and ( not self.redis_cli.sismember('filled_order_set', order['orderID'])): # 目前仅考虑买单 if last_trans_side == 'Sell' and order['ordType'] == 'Limit': if order[ 'side'] == 'Buy' and last_trans_type == 'Limit' and order[ 'cumQty'] != last_trans_qty: continue elif last_trans_side == 'Buy' and order['ordType'] == 'Limit': if order[ 'side'] == 'Buy' and last_trans_type == 'Limit' and order[ 'cumQty'] != last_trans_qty * 2: continue if not recent_order: recent_order = order else: if order['timestamp'] > recent_order['timestamp']: recent_order = order return recent_order # 2018/7/26 添加 def get_unfilled_order(self): unfilled_orders = [] for o in self.ws.open_orders(): if o['ordStatus'] == 'New' or o['ordStatus'] == 'PartiallyFilled': unfilled_orders.append(o) return unfilled_orders """ 2018/7/23 更新 增加异常多次请求 2018/7/25 修改过滤条件, 增加PartiallyFilled 2018/7/26 重写函数,并命名为get_unfilled_order """ def get_delegated_orders(self): times = 0 result = [] while times < 200: self.logger.info('第%s次获取未成交委托' % (times + 1)) try: orders = self.cli.Order.Order_getOrders(reverse=True).result() except Exception as e: self.logger.error('get orders error: %s' % e) time.sleep(1) else: for o in orders[0]: if o['ordStatus'] == 'New' or o[ 'ordStatus'] == 'PartiallyFilled': result.append(o) break times += 1 return result def get_ticker(self, symbol): # tickers = self.ws.get_ticker() while True: tickers = self.ws.get_ticker() if len(tickers) > 0: for ticker in tickers[::-1]: if ticker['symbol'] == symbol: return ticker time.sleep(0.5) def send_order(self, symbol, side, qty, price, ordtype='Limit'): times = 0 result = 0 for o in self.get_delegated_orders(): if o['side'] == side and o['price'] == price: self.logger.info('委托已存在, orderid: %s' % o['orderID']) return 1 while times < 500: self.logger.info('第%s次发起订单委托' % (times + 1)) if ordtype == 'Limit': try: order = self.cli.Order.Order_new(symbol=symbol, side=side, orderQty=qty, price=price, ordType=ordtype).result() except Exception as e: self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: self.logger.info('委托成功') result = order[0]['orderID'] break else: try: order = self.cli.Order.Order_new(symbol=symbol, side=side, orderQty=qty, ordType=ordtype).result() except Exception as e: self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0]['orderID'] break times += 1 return result def cancel_order(self, orderid): times = 0 result = False while times < 500: self.logger.info('第%s次发起撤销委托, orderId: %s' % (times + 1, orderid)) try: self.cli.Order.Order_cancel(orderID=orderid).result() except Exception as e: self.logger.error('撤销错误: %s, 1秒后重试' % e) time.sleep(1) else: result = True break times += 1 return result def amend_order(self, orderid, qty): times = 0 while times < 500: self.logger.info('第%s次修改订单信息, orderID: %s' % (times + 1, orderid)) try: self.cli.Order.Order_amend(orderID=orderid, orderQty=qty).result() except Exception as e: logging.error('修改订单错误: %s' % e) time.sleep(1) else: self.logger.info('修改成功') break times += 1 def sms_notify(self, msg): if int(time.time() - self.last_sms_time > 900): self.logger.info('短信通知: %s' % msg) url = 'http://221.228.17.88:8080/sendmsg/send' params = {'phonenum': '18118999630', 'msg': msg} # requests.get(url, params=params) self.last_sms_time = int(time.time()) """ 2018/6/28 修改使支持len>3的情形 """ def get_current_index(self, price): key = 'open_price_list' index = 0 for i in range(10): if i < self.redis_cli.llen(key) and price < float( self.redis_cli.lindex(key, i)): index = i return index def run(self): self.logger.info('start') last_trans_qty = 0 last_trans_side = '' last_trans_type = '' last_unit_amount = 0 while True: filled_order = self.get_filled_order(last_trans_qty, last_trans_side, last_trans_type) if filled_order: cum_qty = filled_order['cumQty'] order_px = filled_order['price'] avg_px = adjust_price(filled_order['avgPx']) side = filled_order['side'] ord_type = filled_order['ordType'] self.logger.info( '--------------------------------------------------------------------------------' ) self.logger.info( 'side: %s, type: %s, cum_qty: %s, order_px: %s, avg_px: %s, orderID: %s' % (side, ord_type, cum_qty, order_px, avg_px, filled_order['orderID'])) index = self.get_current_index(order_px) price_base = 8 if self.redis_cli.llen('open_price_list') > 0: price_base = int( self.redis_cli.lindex('base_price_list', index)) self.logger.info('index: %s, price_base: %s' % (index, price_base)) price_table = self.price_table[str(price_base)] if ord_type == 'Market': if side == 'Buy': self.logger.info('建仓 仓位: %s, 价格: %a' % (cum_qty, avg_px)) self.logger.info('rpush') self.redis_cli.rpush('open_price_list', avg_px) self.redis_cli.rpush('unit_amount_list', cum_qty) if self.redis_cli.get('base_price'): self.redis_cli.rpush( 'base_price_list', self.redis_cli.get('base_price')) else: self.logger.info('base_price未赋值') time.sleep(300) price_base = float(self.redis_cli.get('base_price')) self.logger.info('买入: %s,价格: %s' % (cum_qty, avg_px - price_base)) orderid = self.send_order(self.contract_name, 'Buy', cum_qty, avg_px - price_base) if orderid == 0: self.logger.info('委托失败,程序终止') break else: self.logger.info('平仓 仓位: %s, 价格: %s' % (cum_qty, avg_px)) self.logger.info('市价开启新的仓位 仓位: %s' % last_unit_amount) orderid = self.send_order(self.contract_name, 'Buy', last_unit_amount, 0, 'Market') if orderid == 0: self.logger.info('委托失败,程序终止') break else: if side == 'Buy': if cum_qty % 16 == 0: self.logger.info( '卖出: %s,价格: %s' % (cum_qty * 2, order_px + price_table[3])) orderid = self.send_order( self.contract_name, 'Sell', cum_qty * 2, order_px + price_table[3]) if orderid == 0: self.logger.info('委托失败,程序终止') break elif cum_qty % 2 == 0: if cum_qty % 8 == 0: price_buy = order_px - price_base * 8 price_sell = order_px + price_table[2] elif cum_qty % 4 == 0: price_buy = order_px - price_base * 4 price_sell = order_px + price_table[1] else: price_buy = order_px - price_base * 2 price_sell = order_px + price_table[0] self.logger.info('卖出: %s,价格: %s' % (cum_qty, price_sell)) orderid = self.send_order(self.contract_name, 'Sell', cum_qty, price_sell) if orderid == 0: self.logger.info('委托失败,程序终止') break self.logger.info('买入: %s,价格: %s' % (cum_qty * 2, price_buy)) orderid = self.send_order(self.contract_name, 'Buy', cum_qty * 2, price_buy) if orderid == 0: self.logger.info('委托失败,程序终止') break else: if cum_qty % 32 == 0: self.logger.info('撤销多余Buy委托') open_price = float( self.redis_cli.lindex('open_price_list', index)) unfilled_orders = self.get_delegated_orders() if open_price < order_px: self.logger.info('open price: %s' % open_price) for o in unfilled_orders: if o['side'] == 'Buy' and o[ 'price'] < open_price: self.logger.info( 'cancel order orderID: %s, price: %s' % (o['orderID'], o['price'])) self.cancel_order(o['orderID']) self.logger.info('rpop') self.redis_cli.rpop('open_price_list') self.redis_cli.rpop('base_price_list') self.redis_cli.rpop('unit_amount_list') open_price = float( self.redis_cli.lindex( 'open_price_list', index)) else: self.logger.info('没有多余的Buy委托') self.logger.info('撤销多余Sell委托') self.logger.info('open price: %s' % open_price) for o in unfilled_orders: if o['side'] == 'Sell' and order_px < o[ 'price'] < open_price: self.logger.info( 'cancel order orderID: %s, price: %s' % (o['orderID'], o['price'])) self.cancel_order(o['orderID']) # self.logger.info('rpop') self.redis_cli.rpop('open_price_list') self.redis_cli.rpop('base_price_list') self.redis_cli.rpop('unit_amount_list') self.logger.info('已全部平仓,待重建仓位') elif cum_qty % 2 == 0: if cum_qty % 16 == 0: buy_price = order_px - price_table[3] elif cum_qty % 8 == 0: buy_price = order_px - price_table[2] elif cum_qty % 4 == 0: buy_price = order_px - price_table[1] else: buy_price = order_px - price_table[0] self.logger.info('买入: %s,价格: %s' % (cum_qty, buy_price)) orderid = self.send_order(self.contract_name, 'Buy', cum_qty, buy_price) if orderid == 0: self.logger.info('委托失败,程序终止') break # self.redis_cli.sadd('filled_order_set', filled_order['orderID']) last_trans_side = side last_trans_qty = cum_qty last_trans_type = ord_type if self.redis_cli.llen('open_price_list') > 0: ticker = self.get_ticker(self.contract_name) bid_price = ticker['bidPrice'] last_open_price = float( self.redis_cli.lindex('open_price_list', -1)) unit_amount = int(self.redis_cli.lindex( 'unit_amount_list', -1)) if bid_price - last_open_price < -1 * self.new_position_thd: self.sms_notify( '开启新的仓位 bid_price: %s, last_open_price: %s' % (bid_price, self.redis_cli.lindex( 'open_price_list', -1))) # if bid_price - last_open_price > self.re_position_thd: min_sell_price = 100000 for o in self.get_delegated_orders(): if o['side'] == 'Sell' and o['price'] < min_sell_price: min_sell_price = o['price'] if min_sell_price - bid_price > 100: self.logger.info('rpop') open_price = float( self.redis_cli.rpop('open_price_list')) self.redis_cli.rpop('base_price_list') self.redis_cli.rpop('unit_amount_list') self.logger.info('撤销多余委托') # PartiallyFilled 需要特别处理 unfilled_amount = 0 for o in self.get_delegated_orders(): if o['price'] < open_price and o['side'] == 'Buy': if o['ordStatus'] == 'PartiallyFilled': self.logger.info('已部分成交: %s' % o['cumQty']) unfilled_amount += o['cumQty'] self.logger.info( 'cancel order, orderID: %s, price: %s' % (o['orderID'], o['price'])) self.cancel_order(o['orderID']) # self.sms_notify('重建仓位, bid_price: %s, last_open_price: %s' % ( # bid_price, self.redis_cli.lindex('open_price_list', -1))) orderid = self.send_order( self.contract_name, 'Sell', unit_amount + unfilled_amount, 0, 'Market') if orderid == 0: self.logger.info('委托失败,程序终止') break last_unit_amount = unit_amount time.sleep(0.2)
class GridStrategy: # 开仓价格 open_price = 11000 # 价格间距 price_dist = 100 # 利润间距 profit_dist = 50 contract_name = 'XBTZ19' filled_order_set = 'filled_order_set' def __init__(self): self.logger = setup_logger() test = False api_key = 'dbS7FklMUz4A0Ftf_0eb-khj' api_secret = 'UGbHj7ucCrz1xz5slMhPPAV72wemdXxxMk4J2OS_73foWObM' test_url = 'https://testnet.bitmex.com/api/v1' product_url = 'https://www.bitmex.com/api/v1' if test: url = test_url else: url = product_url self.cli = bitmex(test=test, api_key=api_key, api_secret=api_secret) self.ws = BitMEXWebsocket(endpoint=url, symbols=[self.contract_name], api_key=api_key, api_secret=api_secret) #init redis client self.redis_cli = redis.Redis(host='localhost', port=6379, decode_responses=True) # test reids self.redis_cli.sadd(self.filled_order_set, 'test orderid') # threading lock self._value_lock = threading.Lock() self.unfilled_sell_list = '' self.unfilled_buy_list = '' def get_filled_order(self, symbol): first_buy_order = None first_sell_order = None for order in self.ws.open_orders(): if order['ordStatus'] == 'Filled' and order['symbol'] == symbol and ( not self.redis_cli.sismember(self.filled_order_set, order['orderID'])): if order['side'] == 'Buy': if not first_buy_order: first_buy_order = order else: if order['price'] > first_buy_order['price']: first_buy_order = order else: if not first_sell_order: first_sell_order = order else: if order['price'] < first_sell_order['price']: first_sell_order = order if first_buy_order and first_sell_order: if first_buy_order['timestamp'] < first_sell_order['timestamp']: result_order = first_buy_order else: result_order = first_sell_order elif first_buy_order: result_order = first_buy_order elif first_sell_order: result_order = first_sell_order else: result_order = None return result_order def send_order(self, symbol, side, qty, price): times = 0 result = None while times < 500: self.logger.info('第%s次发起委托 side: %s, price: %s' % (times + 1, side, price)) try: order = self.cli.Order.Order_new(symbol=symbol, side=side, orderQty=qty, price=price, ordType='Limit', execInst='ParticipateDoNotInitiate').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] if result['ordStatus'] == 'Canceled': if side == 'Buy': return self.send_order(symbol, side, qty, price - self.price_dist) else: return self.send_order(symbol, side, qty, price + self.price_dist) self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) break times += 1 return result def run(self): self.logger.info('start') while True: filled_order = self.get_filled_order(self.contract_name) if filled_order: order_id = filled_order['orderID'] cum_qty = filled_order['cumQty'] order_px = filled_order['price'] side = filled_order['side'] ord_type = filled_order['ordType'] symbol = filled_order['symbol'] self.logger.info('--------------------------------------------------------------------------------') self.logger.info('side: %s, type: %s, symbol: %s, cum_qty: %s, order_px: %s, orderID: %s' % (side, ord_type, symbol, cum_qty, order_px, order_id)) if side == 'Sell': price = order_px - self.profit_dist self.send_order(symbol, 'Buy', cum_qty, price) else: price = order_px + self.profit_dist self.send_order(symbol, 'Sell', cum_qty, price) self.redis_cli.sadd(self.filled_order_set, filled_order['orderID']) time.sleep(0.2)
class hedgingStrategy: contract_1 = { 'name': 'XBTUSD', 'name2': 'XBTZ18', 'side': 'Buy', 'unfilled_buy_list': 'unfilled_buy_list_1', 'unfilled_sell_list': 'unfilled_sell_list_1' } contract_2 = { 'name': 'XBTZ18', 'name2': 'XBTUSD', 'side': 'Sell', 'unfilled_buy_list': 'unfilled_buy_list_2', 'unfilled_sell_list': 'unfilled_sell_list_2' } unit_amount = 25 unit_price_dist = 1 total_price_dist = 20 base_position = unit_amount * total_price_dist profit_dist = 0.5 filled_order_set = 'filled_order_set2' def __init__(self): self.logger = setup_logger() test = False api_key = 'vj708HQhWkv1JbTM9y_LI-Xn' api_secret = 'lWPOhvhY-yn-HAIo7k3mnjR7pijJJJQAKjTKtioQ_K1Wq3vf' test_url = 'https://testnet.bitmex.com/api/v1' product_url = 'https://www.bitmex.com/api/v1' if test: url = test_url else: url = product_url self.cli = bitmex(test=test, api_key=api_key, api_secret=api_secret) self.ws = BitMEXWebsocket( endpoint=url, symbols=[self.contract_1['name'], self.contract_2['name']], api_key=api_key, api_secret=api_secret) # init redis client self.redis_cli = redis.Redis(host='localhost', port=6379, decode_responses=True) # threading lock self._value_lock = threading.Lock() def get_filled_order(self, symbol): first_buy_order = None first_sell_order = None with self._value_lock: for order in self.ws.open_orders(): if order['ordStatus'] == 'Filled' and order[ 'symbol'] == symbol and (not self.redis_cli.sismember( 'filled_order_set2', order['orderID'])): if order['side'] == 'Buy': if not first_buy_order: first_buy_order = order else: if order['price'] > first_buy_order['price']: first_buy_order = order else: if not first_sell_order: first_sell_order = order else: if order['price'] < first_sell_order['price']: first_sell_order = order if first_buy_order and first_sell_order: if first_buy_order['timestamp'] < first_sell_order['timestamp']: result_order = first_buy_order else: result_order = first_sell_order elif first_buy_order: result_order = first_buy_order elif first_sell_order: result_order = first_sell_order else: result_order = None return result_order def send_order(self, contract, side, qty, price): times = 0 result = None while times < 500: self.logger.info('第%s次发起委托 side: %s, price: %s' % (times + 1, side, price)) try: order = self.cli.Order.Order_new( symbol=contract['name'], side=side, orderQty=qty, price=price, ordType='Limit', execInst='ParticipateDoNotInitiate').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] if result['ordStatus'] == 'Canceled': if side == 'Buy': return self.send_order(contract, side, qty, price - self.unit_price_dist) else: return self.send_order(contract, side, qty, price + self.unit_price_dist) self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) redis_item = { 'orderID': result['orderID'], 'side': result['side'], 'price': result['price'], 'orderQty': result['orderQty'] } if side == 'Buy': self.redis_insert_buy(contract['unfilled_buy_list'], redis_item) else: self.redis_insert_sell(contract['unfilled_sell_list'], redis_item) break times += 1 return result def redis_rem(self, name, order_id): for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['orderID'] == order_id: return self.redis_cli.lrem(name, redis_order, 1) return 0 def redis_insert_sell(self, name, item): flag = False for i in range(self.redis_cli.llen(name), 0, -1): redis_order = self.redis_cli.lindex(name, i - 1) json_redis_order = json.loads(redis_order) if json_redis_order['price'] <= item['price']: self.redis_cli.linsert(name, 'after', redis_order, json.dumps(item)) flag = True break if not flag: self.redis_cli.rpush(name, json.dumps(item)) def redis_insert_buy(self, name, item): flag = False for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['price'] >= item['price']: self.redis_cli.linsert(name, 'before', redis_order, json.dumps(item)) flag = True break if not flag: self.redis_cli.lpush(name, json.dumps(item)) def cancel_order(self, orderid): times = 0 result = False while times < 500: self.logger.info('第%s次发起撤销委托, orderId: %s' % (times + 1, orderid)) try: self.cli.Order.Order_cancel(orderID=orderid).result() except Exception as e: self.logger.error('撤销错误: %s, 1秒后重试' % e) time.sleep(1) else: result = True break times += 1 return result def cancel_all(self, symbol, filter=None): times = 0 result = False while times < 200: self.logger.info('第 %s 次Cancle All' % (times + 1)) try: result = self.cli.Order.Order_cancelAll( symbol=symbol, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('cancel_all error: %s' % e) else: print(result) result = True break times += 1 return result def close_position(self, symbol): times = 0 result = False while times < 200: self.logger.info('第 %s 次Close Position' % (times + 1)) try: result = self.cli.Order.Order_closePosition( symbol=symbol).result() except Exception as e: self.logger.error('close_position error: %s' % e) else: print(result[0]) result = True break times += 1 return result def start_strategy(self): self.logger.info('start') t1 = threading.Thread(target=self.run, name=self.contract_1['name'], args=(self.contract_1, )) t1.start() t2 = threading.Thread(target=self.run, name=self.contract_2['name'], args=(self.contract_2, )) t2.start() def run(self, contract): self.logger.info('run %s', contract['name']) order_amount = int(self.total_price_dist / self.unit_price_dist) while True: filled_order = self.get_filled_order(contract['name']) if filled_order: order_id = filled_order['orderID'] cum_qty = filled_order['cumQty'] order_px = filled_order['price'] avg_px = adjust_price(filled_order['avgPx']) side = filled_order['side'] ord_type = filled_order['ordType'] symbol = filled_order['symbol'] self.logger.info( '--------------------------------------------------------------------------------' ) self.logger.info( 'side: %s, type: %s, symbol: %s, cum_qty: %s, order_px: %s, avg_px: %s, orderID: %s' % (side, ord_type, symbol, cum_qty, order_px, avg_px, order_id)) if cum_qty == self.base_position: self.logger.info('清空redis数据') self.redis_cli.ltrim(contract['unfilled_sell_list'], 1, 0) self.redis_cli.ltrim(contract['unfilled_buy_list'], 1, 0) if side == 'Buy': # Buy Order price = avg_px - self.unit_price_dist self.send_order(contract, 'Buy', self.unit_amount, price) # Sell order for i in range(order_amount): price = avg_px + self.unit_price_dist * i + self.profit_dist self.send_order(contract, 'Sell', self.unit_amount, price) else: # Buy order for i in range(order_amount): price = avg_px - self.unit_price_dist * i - self.profit_dist self.send_order(contract, 'Buy', self.unit_amount, price) # Sell Order price = avg_px + self.unit_price_dist self.send_order(contract, 'Sell', self.unit_amount, price) elif cum_qty > self.unit_amount: self.logger.info('%s 已平仓,撤销其余委托' % contract['name']) self.cancel_all(contract['name']) self.close_position(contract['name']) self.cancel_all(contract['name2'], {'side': side}) else: if contract['side'] == 'Buy': if side == 'Sell': self.redis_rem(contract['unfilled_sell_list'], order_id) price = order_px - self.profit_dist self.send_order(contract, 'Buy', self.unit_amount, price) buy_order_amount = self.redis_cli.llen( contract['unfilled_buy_list']) order_thd = int(0.3 * order_amount) if buy_order_amount > order_thd: for i in range(int(order_thd / 2)): order = json.loads( self.redis_cli.lpop( contract['unfilled_buy_list'])) self.logger.info('cancel order: %s' % order['orderID']) self.cancel_order(order['orderID']) sell_order_amount = self.redis_cli.llen( contract['unfilled_sell_list']) if sell_order_amount == 0: self.logger.info('撤销所有委托并平仓') self.cancel_all(contract['name']) self.cancel_all(contract['name2']) self.close_position(contract['name2']) else: self.redis_rem(contract['unfilled_buy_list'], order_id) sell_order_amount = self.redis_cli.llen( contract['unfilled_sell_list']) price = order_px + self.profit_dist if sell_order_amount > int(1.8 * order_amount): qty = self.unit_amount * sell_order_amount else: qty = self.unit_amount self.send_order(contract, 'Sell', qty, price) buy_order_amount = self.redis_cli.llen( contract['unfilled_buy_list']) if buy_order_amount == 0: price = order_px - self.unit_price_dist self.send_order(contract, 'Buy', self.unit_amount, price) else: if side == 'Sell': self.redis_rem(contract['unfilled_sell_list'], order_id) buy_order_amount = self.redis_cli.llen( contract['unfilled_buy_list']) price = order_px - self.profit_dist if buy_order_amount > int(1.8 * order_amount): qty = self.unit_amount * buy_order_amount else: qty = self.unit_amount self.send_order(contract, 'Buy', qty, price) sell_order_amount = self.redis_cli.llen( contract['unfilled_sell_list']) if sell_order_amount == 0: price = order_px + self.unit_price_dist self.send_order(contract, 'Sell', self.unit_amount, price) else: self.redis_rem(contract['unfilled_buy_list'], order_id) price = order_px + self.profit_dist self.send_order(contract, 'Sell', self.unit_amount, price) sell_order_amount = self.redis_cli.llen( contract['unfilled_sell_list']) order_thd = int(0.3 * order_amount) if sell_order_amount > order_thd: for i in range(int(order_thd / 2)): order = json.loads( self.redis_cli.rpop( contract['unfilled_sell_list'])) self.logger.info('cancel order: %s' % order['orderID']) self.cancel_order(order['orderID']) buy_order_amount = self.redis_cli.llen( contract['unfilled_buy_list']) if buy_order_amount == 0: self.logger.info('撤销所有委托并平仓') self.cancel_all(contract['name']) self.cancel_all(contract['name2']) self.close_position(contract['name2']) self.redis_cli.sadd('filled_order_set2', filled_order['orderID']) time.sleep(0.2)
class GridStrategy: # 开仓价格 open_price = 100000 # 价格间距 price_dist = 2 # 利润间距 profit_dist = 2 # 初始仓位 init_position = 47 # 最终仓位 final_position = 94 contract_names = ['XBTUSD', 'XBTZ19'] filled_order_set = 'filled_order_set' setting_ht = 'grid_setting_hash' backup_order_list = 'backup_order_list' def __init__(self): self.logger = setup_logger() test = True self.api_key = 'kVfKITnQdJEzEC2sKYlVr9mM' self.api_secret = 'joccPUd5_DwOd3CDL1lSq_prKDxxM6oRQCmu7aALcw_6KWCi' test_url = 'https://testnet.bitmex.com/api/v1' product_url = 'https://www.bitmex.com/api/v1' if test: url = test_url self.filled_order_set = 'filled_order_set2' self.setting_ht = 'grid_setting_hash2' self.api_key = 'W6sK1OHR6eiS60ri4ITwH3Aq' self.api_secret = 'ipr3Vkq5800x3yrIImocfzqVJhDHsfgGXSoN0-ZaivbIuIw-' else: url = product_url self.cli = bitmex(test=test, api_key=self.api_key, api_secret=self.api_secret) self.ws = BitMEXWebsocket(endpoint=url, symbols=self.contract_names, api_key=self.api_key, api_secret=self.api_secret) # init redis client self.redis_cli = redis.Redis(host='localhost', port=6379, decode_responses=True) # threading lock # self._value_lock = threading.Lock() # 同步redis数据 self.logger.info('从redis同步参数') # self.price_dist = int( self.redis_cli.hget(self.setting_ht, 'price_dist')) self.profit_dist = int( self.redis_cli.hget(self.setting_ht, 'profit_dist')) self.init_position = int( self.redis_cli.hget(self.setting_ht, 'init_position')) self.final_position = int( self.redis_cli.hget(self.setting_ht, 'final_position')) self.unit_amount = int( self.redis_cli.hget(self.setting_ht, 'unit_amount')) self.unfilled_buy_list = [] self.unfilled_sell_list = [] self.backup_buy_order_0 = [] self.backup_buy_order_1 = [] self.backup_sell_order_0 = [] self.backup_sell_order_1 = [] # for o in self.get_unfilled_orders({'ordStatus': 'New'}): item = { 'orderID': o['orderID'], 'side': o['side'], 'symbol': o['symbol'] } if o['orderQty'] != self.unit_amount: if o['side'] == 'Buy' and o['symbol'] == self.contract_names[0]: self.backup_buy_order_0.append(item) elif o['side'] == 'Buy' and o['symbol'] == self.contract_names[ 1]: self.backup_buy_order_1.append(item) elif o['side'] == 'Sell' and o[ 'symbol'] == self.contract_names[0]: self.backup_sell_order_0.append(item) else: self.backup_sell_order_1.append(item) else: if o['side'] == 'Buy': self.unfilled_buy_list.append(o['orderID']) else: self.unfilled_sell_list.append(o['orderID']) print(len(self.unfilled_buy_list)) print(self.unfilled_buy_list) print(len(self.unfilled_sell_list)) print(self.unfilled_sell_list) self.logger.info('同步完毕') t = threading.Thread(target=self.monitor_backup_order) t.daemon = True t.start() self.logger.debug("Started thread") def monitor_backup_order(self): while True: info = [ [self.contract_names[0], 'Buy', 10, 3000], [self.contract_names[1], 'Buy', 10, 3000], [self.contract_names[0], 'Sell', 40, 14000], [self.contract_names[1], 'Sell', 40, 14000], ] for idx, order_list in enumerate([ self.backup_buy_order_0, self.backup_buy_order_1, self.backup_sell_order_0, self.backup_sell_order_1 ]): amount = len(order_list) new_orders = [] if amount < 10: for i in range(20 - amount): new_orders.append({ 'symbol': info[idx][0], 'side': info[idx][1], 'orderQty': info[idx][2], 'price': info[idx][3], 'ordType': 'Limit' }) times = 0 while times < 200: self.logger.info('第%s次newBulk' % (times + 1)) try: order = self.cli.Order.Order_newBulk( orders=json.dumps(new_orders)).result() except Exception as e: self.logger.error('newBulk error: %s' % e) time.sleep(1) else: for o in order[0]: self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (o['side'], o['price'], o['orderID'])) item = { 'orderID': o['orderID'], 'side': o['side'], 'symbol': o['symbol'] } order_list.append(item) break times += 1 time.sleep(5) def get_filled_order(self): filled_orders = [] for order in self.ws.open_orders(): if order['ordStatus'] == 'Filled' and not self.redis_cli.sismember( self.filled_order_set, order['orderID']): filled_orders.append(order) return filled_orders def get_unfilled_orders(self, filter=None): times = 0 result = [] while times < 200: self.logger.info('第%s次获取未成交委托' % (times + 1)) try: orders = self.cli.Order.Order_getOrders( reverse=True, count=500, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('get orders error: %s' % e) time.sleep(1) else: for o in orders[0]: result.append(o) break times += 1 return result def close_order(self, symbol, side, price): try: order = self.cli.Order.Order_new(symbol=symbol, side=side, price=price, execInst='Close').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) def send_market_order(self, symbol, side, qty): times = 0 result = None while times < 500: self.logger.info('第%s次发起市价委托 side: %s' % (times + 1, side)) try: order = self.cli.Order.Order_new(symbol=symbol, side=side, orderQty=qty, ordType='Market').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) break times += 1 return result def send_order(self, symbol, side, qty, price): self.logger.info('发起委托修改 symbol: %s, side: %s, price: %s' % (symbol, side, price)) # redis_order = self.redis_cli.lpop(self.backup_order_list) if side == 'Buy' and symbol == self.contract_names[0]: backup_order = self.backup_buy_order_0.pop(0) elif side == 'Buy' and symbol == self.contract_names[1]: backup_order = self.backup_buy_order_1.pop(0) elif side == 'Sell' and symbol == self.contract_names[0]: backup_order = self.backup_sell_order_0.pop(0) else: backup_order = self.backup_sell_order_1.pop(0) if backup_order: order = self.cli.Order.Order_amend(orderID=backup_order['orderID'], orderQty=qty, price=price).result() self.logger.info('委托修改成功: orderID: %s' % (order[0]['orderID'])) # redis_item = {'orderID': order[0]['orderID'], # 'side': order[0]['side'], # 'price': order[0]['price'], # 'orderQty': order[0]['orderQty']} if side == 'Buy': self.unfilled_buy_list.append(order[0]['orderID']) else: self.unfilled_sell_list.append(order[0]['orderID']) return order[0] else: times = 0 result = None while times < 500: self.logger.info('第%s次发起委托 side: %s, price: %s' % (times + 1, side, price)) try: order = self.cli.Order.Order_new( symbol=symbol, side=side, orderQty=qty, price=price, ordType='Limit', execInst='ParticipateDoNotInitiate').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] if result['ordStatus'] == 'Canceled': if side == 'Buy': return self.send_order(symbol, side, qty, price - self.price_dist) else: return self.send_order(symbol, side, qty, price + self.price_dist) self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) # redis_item = {'orderID': result['orderID'], # 'side': result['side'], # 'price': result['price'], # 'orderQty': result['orderQty'] # } # if side == 'Buy': # self.redis_insert_buy(self.unfilled_buy_list, redis_item) # else: # self.redis_insert_sell(self.unfilled_sell_list, redis_item) if side == 'Buy': self.unfilled_buy_list.append(result['orderID']) else: self.unfilled_sell_list.append(result['orderID']) break times += 1 return result def redis_rem(self, name, order_id): for i in range(self.redis_cli.llen(name)): redis_order = self.redis_cli.lindex(name, i) json_redis_order = json.loads(redis_order) if json_redis_order['orderID'] == order_id: return self.redis_cli.lrem(name, 1, redis_order) return 0 # def redis_insert_sell(self, name, item): # flag = False # for i in range(self.redis_cli.llen(name), 0, -1): # redis_order = self.redis_cli.lindex(name, i - 1) # json_redis_order = json.loads(redis_order) # if json_redis_order['price'] <= item['price']: # self.redis_cli.linsert(name, 'after', redis_order, json.dumps(item)) # flag = True # break # if not flag: # self.redis_cli.lpush(name, json.dumps(item)) # # def redis_insert_buy(self, name, item): # flag = False # for i in range(self.redis_cli.llen(name)): # redis_order = self.redis_cli.lindex(name, i) # json_redis_order = json.loads(redis_order) # if json_redis_order['price'] >= item['price']: # self.redis_cli.linsert(name, 'before', redis_order, json.dumps(item)) # flag = True # break # if not flag: # self.redis_cli.rpush(name, json.dumps(item)) def cancel_order(self, orderid): times = 0 result = False while times < 500: self.logger.info('第%s次发起撤销委托, orderId: %s' % (times + 1, orderid)) try: self.cli.Order.Order_cancel(orderID=orderid).result() except Exception as e: self.logger.error('撤销错误: %s, 1秒后重试' % e) time.sleep(1) else: result = True break times += 1 return result def cancel_all(self, symbol=None, filter=None): times = 0 result = False while times < 200: self.logger.info('第 %s 次Cancle All' % (times + 1)) try: result = self.cli.Order.Order_cancelAll( symbol=symbol, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('cancel_all error: %s' % e) else: print(result) print(len(result)) result = True break times += 1 return result def new_bulk_orders(self, orders): result = None times = 0 while times < 200: self.logger.info('第%s次newBulk' % (times + 1)) try: order = self.cli.Order.Order_newBulk( orders=json.dumps(orders)).result() except Exception as e: self.logger.error('newBulk error: %s' % e) time.sleep(1) else: result = order[0] # print(result) for o in order[0]: self.logger.info('委托成功: side: %s, price: %s, orderid: %s' % (o['side'], o['price'], o['orderID'])) # redis_item = {'orderID': o['orderID'], # 'side': o['side'], # 'price': o['price'], # 'orderQty': o['orderQty'] # } # if o['side'] == 'Buy': # self.redis_insert_buy(self.unfilled_buy_list, redis_item) # else: # self.redis_insert_sell(self.unfilled_sell_list, redis_item) if o['side'] == 'Buy': self.unfilled_buy_list.append(o['orderID']) else: self.unfilled_sell_list.append(o['orderID']) break times += 1 return result def run(self): self.logger.info('start') buy_amount = 0 sell_amount = 0 while True: filled_orders = self.get_filled_order() for filled_order in filled_orders: order_id = filled_order['orderID'] cum_qty = filled_order['cumQty'] order_px = filled_order['price'] side = filled_order['side'] ord_type = filled_order['ordType'] symbol = filled_order['symbol'] self.logger.info( '--------------------------------------------------------------------------------' ) self.logger.info( 'side: %s, type: %s, symbol: %s, cum_qty: %s, order_px: %s, orderID: %s' % (side, ord_type, symbol, cum_qty, order_px, order_id)) # init_position最好是素数 if cum_qty % self.init_position == 0: self.logger.info('开仓...') if side == 'Sell': self.redis_cli.hset(self.setting_ht, 'open_price_sell', order_px) # self.redis_cli.ltrim(self.unfilled_sell_list, 1, 0) else: self.redis_cli.hset(self.setting_ht, 'open_price_buy', order_px) # self.redis_cli.ltrim(self.unfilled_buy_list, 1, 0) new_orders = [] # Sell Order for i in range(self.init_position): new_orders.append({ 'symbol': symbol, 'side': 'Sell', 'orderQty': self.unit_amount, 'ordType': 'Limit', 'price': order_px + self.price_dist * i + self.profit_dist }) self.new_bulk_orders(new_orders) new_orders = [] # Buy Order for i in range(self.final_position - self.init_position): new_orders.append({ 'symbol': symbol, 'side': 'Buy', 'orderQty': self.unit_amount, 'ordType': 'Limit', 'price': order_px - self.price_dist * (i + 1) }) self.new_bulk_orders(new_orders) elif cum_qty == self.unit_amount: if side == 'Sell': # self.redis_rem(self.unfilled_sell_list, order_id) self.unfilled_sell_list.remove(order_id) #print(self.unfilled_sell_list) price = order_px - self.profit_dist self.send_order(symbol, 'Buy', self.unit_amount, price) sell_amount += 1 # 上涨止损 if len(self.unfilled_sell_list) == 0: # qty = self.redis_cli.llen(self.unfilled_buy_list) * self.unit_amount / 2 self.cancel_all() self.close_order(self.contract_names[0], 'Buy', price + 500) # self.send_market_order(symbol, 'Buy', qty) else: # self.redis_rem(self.unfilled_buy_list, order_id) self.unfilled_buy_list.remove(order_id) #print(self.unfilled_buy_list) price = order_px + self.profit_dist self.send_order(symbol, 'Sell', self.unit_amount, price) buy_amount += 1 # 下跌止损 if len(self.unfilled_buy_list) == 0: # qty = self.redis_cli.llen(self.unfilled_sell_list) * self.unit_amount / 2 self.cancel_all() self.close_order(self.contract_names[1], 'Sell', price - 500) # self.send_market_order(symbol, 'Sell', qty) self.logger.info( 'TOTAL: %d\tBUY: %d\tSELL: %d' % (sell_amount + buy_amount, buy_amount, sell_amount)) self.logger.info( 'total: %d\tunfilled_sell: %d\tunfilled_buy: %d' % (len(self.unfilled_sell_list) + len(self.unfilled_buy_list), len(self.unfilled_sell_list), len(self.unfilled_buy_list))) self.redis_cli.sadd(self.filled_order_set, filled_order['orderID']) time.sleep(0.2)
class MarketMaker: contract_names = ['XBTUSD'] if_test = True def __init__(self): self.logger = setup_logger() # init redis client test_url = 'https://testnet.bitmex.com/api/v1' product_url = 'https://www.bitmex.com/api/v1' print(self.if_test) if self.if_test: print('TEST.') url = test_url self.api_key = 'YaZ6c81UNsKVCW2eh87a7OeL' self.api_secret = '4lursf1Lk5DBrl7M28hJTBsxMiVeBIhnNyciL_glYQDPCJdy' else: url = product_url self.cli = bitmex(test=self.if_test, api_key=self.api_key, api_secret=self.api_secret) self.ws = BitMEXWebsocket(endpoint=url, symbols=self.contract_names, api_key=self.api_key, api_secret=self.api_secret) def get_filled_order(self): filled_orders = [] for order in self.ws.open_orders(): if order['ordStatus'] == 'Filled' and not self.redis_cli.sismember( self.filled_order_set, order['orderID']): filled_orders.append(order) return filled_orders def get_unfilled_orders(self, filter=None): times = 0 result = [] while times < 200: self.logger.info('第%s次获取未成交委托' % (times + 1)) try: orders = self.cli.Order.Order_getOrders( reverse=True, count=500, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('get orders error: %s' % e) time.sleep(1) else: for o in orders[0]: result.append(o) break times += 1 return result def close_order(self, symbol, side, price): try: order = self.cli.Order.Order_new(symbol=symbol, side=side, price=price, execInst='Close').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) def send_market_order(self, symbol, side, qty): times = 0 result = None while times < 500: self.logger.info('第%s次发起市价委托 side: %s' % (times + 1, side)) try: order = self.cli.Order.Order_new(symbol=symbol, side=side, orderQty=qty, ordType='Market').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) break times += 1 return result def send_order(self, symbol, side, qty, price): times = 0 result = None while times < 500: self.logger.info('第%s次发起委托 side: %s, price: %s' % (times + 1, side, price)) try: order = self.cli.Order.Order_new( symbol=symbol, side=side, orderQty=qty, price=price, ordType='Limit', execInst='ParticipateDoNotInitiate').result() except Exception as e: if 'insufficient Available Balance' in str(e): self.logger.info('余额不足,委托取消 %s' % e) break elif '403 Forbidden' in str(e): self.logger.info('403错误,委托取消 %s' % e) break self.logger.error('订单error: %s,1秒后重试' % e) time.sleep(1) else: result = order[0] if result['ordStatus'] == 'Canceled': if side == 'Buy': return self.send_order(symbol, side, qty, price - self.price_dist) else: return self.send_order(symbol, side, qty, price + self.price_dist) self.logger.info( '委托成功: side: %s, price: %s, orderid: %s' % (result['side'], result['price'], result['orderID'])) redis_item = { 'orderID': result['orderID'], 'side': result['side'], 'price': result['price'], 'orderQty': result['orderQty'] } if side == 'Buy': self.redis_insert_buy(self.unfilled_buy_list, redis_item) else: self.redis_insert_sell(self.unfilled_sell_list, redis_item) break times += 1 return result def cancel_order(self, orderid): times = 0 result = False while times < 500: self.logger.info('第%s次发起撤销委托, orderId: %s' % (times + 1, orderid)) try: self.cli.Order.Order_cancel(orderID=orderid).result() except Exception as e: self.logger.error('撤销错误: %s, 1秒后重试' % e) time.sleep(1) else: result = True break times += 1 return result def cancel_all(self, symbol=None, filter=None): times = 0 result = False while times < 200: self.logger.info('第 %s 次Cancle All' % (times + 1)) try: result = self.cli.Order.Order_cancelAll( symbol=symbol, filter=json.dumps(filter)).result() except Exception as e: self.logger.error('cancel_all error: %s' % e) else: print(result) print(len(result)) result = True break times += 1 return result def run(self): self.logger.info('start') buy_amount = 0 sell_amount = 0 last_buy = [] while True: filled_orders = self.get_filled_order() for filled_order in filled_orders: order_id = filled_order['orderID'] cum_qty = filled_order['cumQty'] order_px = filled_order['price'] side = filled_order['side'] ord_type = filled_order['ordType'] symbol = filled_order['symbol'] self.logger.info( '--------------------------------------------------------------------------------' ) self.logger.info( 'side: %s, type: %s, symbol: %s, cum_qty: %s, order_px: %s, orderID: %s' % (side, ord_type, symbol, cum_qty, order_px, order_id)) # init_position最好是素数 if cum_qty == self.open_amount: self.logger.info('开仓...') if side == 'Sell': self.redis_cli.hset(self.setting_ht, 'open_price_sell', order_px) self.redis_cli.ltrim(self.unfilled_sell_list, 1, 0) else: self.redis_cli.hset(self.setting_ht, 'open_price_buy', order_px) self.redis_cli.ltrim(self.unfilled_buy_list, 1, 0) new_orders = [] # Sell Order for i in range(self.init_sell_cnt): price = order_px + self.price_dist * i + self.profit_dist qty = int(price * self.unit_value) new_orders.append({ 'symbol': symbol, 'side': 'Sell', 'orderQty': qty, 'ordType': 'Limit', 'price': price }) self.new_bulk_orders(new_orders) new_orders = [] # Buy Order for i in range(self.init_buy_cnt): price = order_px - self.price_dist * (i + 1) qty = int(price * self.unit_value) new_orders.append({ 'symbol': symbol, 'side': 'Buy', 'orderQty': qty, 'ordType': 'Limit', 'price': price }) self.new_bulk_orders(new_orders) else: if side == 'Sell': self.redis_rem(self.unfilled_sell_list, order_id) price = order_px - self.profit_dist self.send_order(symbol, 'Buy', cum_qty, price) sell_amount += 1 if last_buy: self.logger.info('orderID\tSell:%s-Buy:%s', order_id, last_buy[-1]) last_buy.pop() else: self.logger.info('orderID\tSell:%s-Buy:%s', order_id, '') else: self.redis_rem(self.unfilled_buy_list, order_id) price = order_px + self.profit_dist self.send_order(symbol, 'Sell', cum_qty, price) buy_amount += 1 last_buy.append(order_id) self.logger.info( 'TOTAL: %d\tBUY: %d\tSELL: %d' % (sell_amount + buy_amount, buy_amount, sell_amount)) self.redis_cli.sadd(self.filled_order_set, filled_order['orderID']) time.sleep(0.2)