Пример #1
0
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)
Пример #2
0
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)
Пример #3
0
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)
Пример #4
0
Файл: main.py Проект: kz0/BITMEX
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)
Пример #5
0
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)
Пример #6
0
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)
Пример #7
0
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)
Пример #8
0
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)