Пример #1
0
    def __init__(self, config, debug):
        self.config = config
        self.debug = debug
        self.backtest = False
        self.pool = ThreadPoolExecutor(3)
        self.engine = MysqlEngine(config['db']['url'])

        self.max_miss_ms = 2000

        self.base_prices = []
        self.trade_prices = []
        self.base_price_mas = []
        self.trade_price_mas = []
        self.diff_mas = []

        self.diffs = []

        # --------- backtest vars --------------
        self.bt_status = 0
        self.bt_buy_price = 0
        self.bt_sell_price = 0
        self.bt_benefit = 0
        self.bt_tx_cnt = 0
        self.bt_record = None
        self.bt_buy_diff_ma = None
        self.bt_buy_record_id = None
        self.bt_buy_slope = 0
Пример #2
0
    def __init__(self, config, debug=True):
        key_config = config['apikey']
        self.debug = debug
        self.exchanges = {
            'zb': Zb(key_config['zb']['key'], key_config['zb']['secret']),
            'okex': Okex(key_config['okex']['key'], key_config['okex']['secret']),
        }

        self.engine = MysqlEngine(config['db']['url'])
        self.order_manager = OrderManager(self.engine)
        self.strategy_manager = StrategyManager(self.engine)

        self.min_a = 1.0055
        self.min_b = 1.0055

        self.cur_a = self.min_a
        self.cur_b = self.min_b
        self.miss_a = 0
        self.miss_b = 0

        self.has_init_strategy_threshold = False

        self.pool = ThreadPoolExecutor(3)

        self.accounts = {}
        self.balancer = None
        self.init_balancer()

        self.price_chooser = TakerPriceChooser()
        # self.price_chooser = MakerPriceChooser(0.0001)

        self.ts_got_a = 0
        self.ts_got_b = 0
Пример #3
0
    def __init__(self, config, debug=True):
        key_config = config['apikey']
        self.debug = debug
        self.exchanges = {
            'zb': Zb(key_config['zb']['key'], key_config['zb']['secret']),
            'okex': Okex(key_config['okex']['key'],
                         key_config['okex']['secret']),
            'weex': Weex(key_config['weex']['key'],
                         key_config['weex']['secret']),
            # 'huobipro': Huobipro(key_config['huobipro']['key'], key_config['huobipro']['secret']),
            'bithumb': ccxt.bithumb(),
            'binance': ccxt.binance(),
            'bitflyer': ccxt.bitflyer(),
            'hitbtc': ccxt.hitbtc(),
            'coincheck': ccxt.coincheck(),
            "quoinex": ccxt.quoinex(),
            "bitfinex": ccxt.bitfinex(),
            "hitbtc": ccxt.hitbtc(),
        }

        self.engine = MysqlEngine(config['db']['url'])
        self.pool = ThreadPoolExecutor(
            3)  # for many urls, this should probably be capped at some value.

        self. async = False
Пример #4
0
    def __init__(self, config, debug):
        self.debug = debug
        self.exchange = Okex(config['apikey']['okex']['key'],
                             config['apikey']['okex']['secret'])
        self.engine = MysqlEngine(config['db']['url'])
        self.init_db()

        self.symbols = self.refresh_db_config()

        self.pool = ThreadPoolExecutor(4)
        run_thread(self.sched_refresh_db_config)
        run_thread(self.reset_success_alarm)

        self.success_alarm = False
Пример #5
0
    def __init__(self, config, symbol, backtest=False, debug=True):
        key_config = config['apikey']
        self.okex_exchange = Okex(key_config['okex']['key'],
                                  key_config['okex']['secret'])
        self.symbol = symbol
        self.record = None
        self.in_backtest = backtest

        self.amount = 0.002
        self.debug = debug

        self.engine = MysqlEngine(config['db']['url'])
        self.order_manager = OrderManager(self.engine)

        self.buy_price = None
        self.buy_amount = None
        self.sell_price = None
        self.prod_status = BtStatus.INIT
        self.cmp_buy_price_cnt = [0, 0]

        BackTestMixin.__init__(self)
Пример #6
0
    def __init__(self, config, debug):
        self.debug = debug
        self.exchange = Okex(config['apikey']['okex']['key'], config['apikey']['okex']['secret'])
        self.engine = MysqlEngine(config['db']['url'])
        self.init_db()

        self.symbols = self.refresh_db_config()

        self.pool = ThreadPoolExecutor(4)
        run_thread(self.sched_refresh_db_config)
        run_thread(self.reset_success_alarm)

        self.success_alarm = False
Пример #7
0
 def __init__(self, debug=False, config=None):
     handlers = [
         ('/', IndexHandler),
         ('/abs_diff', AbsDiffHandler),
         ('/orders', OrderHandler),
         ('/st', StrategyHandler),
         ('/cancel_order', CancelOrderHandler),
     ]
     settings = dict(template_path=os.path.join(os.path.dirname(__file__),
                                                "./web/template"),
                     static_path=os.path.join(os.path.dirname(__file__),
                                              "./web/static"),
                     debug=debug,
                     cookie_secret="woshifyz",
                     autoescape=None)
     self.engine = MysqlEngine(config['db']['url'])
     self.order_manager = OrderManager(self.engine)
     super(ApiApplication, self).__init__(handlers, **settings)
Пример #8
0
    def __init__(self, config, symbol, backtest=False, debug=True):
        key_config = config['apikey']
        self.okex_exchange = Okex(key_config['okex']['key'], key_config['okex']['secret'])
        self.symbol = symbol
        self.record = None
        self.in_backtest = backtest

        self.amount = 0.002
        self.debug = debug

        self.engine = MysqlEngine(config['db']['url'])
        self.order_manager = OrderManager(self.engine)

        self.buy_price = None
        self.buy_amount = None
        self.sell_price = None
        self.prod_status = BtStatus.INIT
        self.cmp_buy_price_cnt = [0, 0]

        BackTestMixin.__init__(self)
Пример #9
0
    def __init__(self, config, debug=True):
        key_config = config['apikey']
        self.debug = debug
        self.exchanges = {
            'zb': Zb(key_config['zb']['key'], key_config['zb']['secret']),
            'okex': Okex(key_config['okex']['key'], key_config['okex']['secret']),
            'weex': Weex(key_config['weex']['key'], key_config['weex']['secret']),
            # 'huobipro': Huobipro(key_config['huobipro']['key'], key_config['huobipro']['secret']),
            'bithumb': ccxt.bithumb(),
            'binance': ccxt.binance(),
            'bitflyer': ccxt.bitflyer(),
            'hitbtc': ccxt.hitbtc(),
            'coincheck': ccxt.coincheck(),
            "quoinex": ccxt.quoinex(),
            "bitfinex": ccxt.bitfinex(),
            "hitbtc": ccxt.hitbtc(),
        }

        self.engine = MysqlEngine(config['db']['url'])
        self.pool = ThreadPoolExecutor(3)  # for many urls, this should probably be capped at some value.

        self.async = False
Пример #10
0
class TaStrategy(BackTestMixin):
    def __init__(self, config, symbol, backtest=False, debug=True):
        key_config = config['apikey']
        self.okex_exchange = Okex(key_config['okex']['key'], key_config['okex']['secret'])
        self.symbol = symbol
        self.record = None
        self.in_backtest = backtest

        self.amount = 0.002
        self.debug = debug

        self.engine = MysqlEngine(config['db']['url'])
        self.order_manager = OrderManager(self.engine)

        self.buy_price = None
        self.buy_amount = None
        self.sell_price = None
        self.prod_status = BtStatus.INIT
        self.cmp_buy_price_cnt = [0, 0]

        BackTestMixin.__init__(self)

    def recover_from_db(self):
        sql = "select * from `order` where status in (1, 100) order by id desc limit 1"
        od = self.engine.fetchone_row(sql, ())
        if od:
            if od['side'] == 'buy':
                self.buy_price = float(od['price'])
                self.buy_amount = float(od['amount'])
                if od['status'] == 1:
                    self.prod_status = BtStatus.PLACE_BUY_ORDER
                else:
                    self.prod_status = BtStatus.SUCCESS_BUY_ORDER
            else:
                self.sell_price = float(od['price'])
                if od['status'] == 1:
                    self.prod_status = BtStatus.PLACE_SELL_ORDER
                else:
                    self.prod_status = BtStatus.SUCCESS_SELL_ORDER

    def run(self):
        while True:
            try:
                if self.has_unfinish_order():
                    time.sleep(2)
                    continue
                self.recover_from_db()
                if arrow.now().to('local').second > 18:
                    self.record = self.okex_exchange.fetch_kline(self.symbol, type="1min", size=500)
                    self._run()
            except:
                logging.exception("")
            time.sleep(10)

    def back_test(self):
        self.in_backtest = True
        self.bt_min_round_benefit = -60
        data = self.okex_exchange.fetch_kline(self.symbol, type="3min", size=1000)
        data['MACD'], data['MACDsignal'], data['MACDhist'] = talib.MACD(data['close'].values,
                                                                        fastperiod=5, slowperiod=34, signalperiod=5)
        graph(data)
        return
        l = len(data)
        for i in range(400, l):
            self.record = data.iloc[0: i + 1, :]
            self._run()
        print self.bt_benefit - self.bt_tx_cnt * 10

    def has_unfinish_order(self):
        a = len(self.order_manager.list_by_status(ORDER_STATUS.PLACED)) >= 1
        if a:
            return a
        a = len(self.order_manager.list_by_status(ORDER_STATUS.INIT)) >= 1
        return a

    def _run(self):
        data = self.record
        if self.in_backtest:
            self.back_test_check_tx_success(data.iloc[-1]['high'], data.iloc[-1]['low'])
        # if self.bt_status == BtStatus.SUCCESS_BUY_ORDER:
        #         if float(data.iloc[-1]['high']) < (self.bt_buy_price + 20):
        #             self.cmp_buy_price_cnt[0] += 6
        #         else:
        #             self.cmp_buy_price_cnt[1] += 6
        #         if self.cmp_buy_price_cnt[0] - self.cmp_buy_price_cnt[1] > 30:
        #             logging.info("长时间不涨, 设定价格卖出")
        #             self.back_test_sell(price=self.bt_buy_price+20)
        #         if abs(self.bt_buy_price - 9381.4795) < 0.001:
        #             logging.info(self.cmp_buy_price_cnt)
        #     else:
        #         self.cmp_buy_price_cnt = [0, 0]
        # else:
        #     if self.prod_status == BtStatus.SUCCESS_BUY_ORDER:
        #         if float(data.iloc[-1]['high']) < (self.buy_price + 20):
        #             self.cmp_buy_price_cnt[0] += 1
        #         else:
        #             self.cmp_buy_price_cnt[1] += 1
        #         if self.cmp_buy_price_cnt[0] - self.cmp_buy_price_cnt[1] > 24:
        #             logging.info("长时间不涨, 设定价格卖出")
        #             self.sell(price=self.buy_price + 40, role='maker')
        #     else:
        #         self.cmp_buy_price_cnt = [0, 0]

        data['RSI6'] = talib.RSI(data['close'].values, timeperiod=6)
        data['RSI20'] = talib.RSI(data['close'].values, timeperiod=20)
        # data['EMA30'] = talib.EMA(data['close'].values, timeperiod=30)
        # data['MACD'], data['MACDsignal'], data['MACDhist'] = talib.MACD(data['close'].values)
        data['MACD'], data['MACDsignal'], data['MACDhist'] = talib.MACD(data['close'].values,
                                                                        fastperiod=5, slowperiod=34, signalperiod=5)
        data['MACDhist'] = data['MACDhist'] * 2
        zero = data.iloc[-4]['MACDhist']
        one = data.iloc[-3]['MACDhist']
        two = data.iloc[-2]['MACDhist']
        row = data.iloc[-1]['MACDhist']

        cur_row = data.iloc[-1]
        if zero * row > 0:  # 没有x
            return
        gold_cross, dead_cross = False, False
        steep = 5.4
        small = 1.8


        sl1 = one - zero
        sl2 = two - one
        sl3 = row - two
        steep = 11
        small = 5
        if row > 0:
            if sl3 > steep:
                gold_cross = True
            elif sl3 > small and sl2 > small and two > 0:
                gold_cross = True
        if row < 0:
            if sl3 < -steep:
                dead_cross = True
            if sl3 < -small and sl2 < -small and two < 0:
                dead_cross = True

        msg = (zero, one, two, row, sl1, sl2, sl3)
        if gold_cross:
            if not (cur_row['RSI6'] > 55 or cur_row['RSI20'] > 50):
                logging.info("find gold cross, but rsi not match %s, %s, %s, %s", data.index[-1], msg, cur_row['RSI6'], cur_row['RSI20'])
            else:
                logging.info("find gold cross, %s, %s", data.index[-1], msg)
                if self.in_backtest:
                    buy_price = cur_row['high'] + 10
                    self.back_test_buy(buy_price, msg=data.index[-1])
                else:
                    role = 'taker' if sl3 > steep else 'maker'
                    self.buy(self.amount, role)

        if dead_cross:
            if not (cur_row['RSI6'] < 40 or cur_row['RSI20'] < 40):
                logging.info("find gold cross, but rsi not match %s, %s, %s, %s", data.index[-1], msg, cur_row['RSI6'], cur_row['RSI20'])
            else:
                logging.info("find dead cross, %s, %s", data.index[-1], msg)
                if self.in_backtest:
                    sell_price = cur_row['low']
                    self.back_test_try_cancel_buy_order()
                    self.back_test_sell(sell_price, msg=data.index[-1])
                else:
                    self.try_cancel_buy_order()
                    role = 'taker' if sl3 < -steep else 'maker'
                    self.sell(role=role)

    def try_cancel_buy_order(self):
        if self.prod_status != BtStatus.PLACE_BUY_ORDER:  # 有未成交买单是处理
            return
        sql = "select * from `order` where status in (1, 100) order by id desc limit 1"
        od = self.engine.fetchone_row(sql, ())
        if not od:
            return
        if od['side'] != 'buy':
            return
        if self.okex_exchange.order_info(od['symbol'], od['ex_id'])['status'] == ORDER_STATUS.PLACED:
            self.okex_exchange.cancel_order(od['symbol'], od['ex_id'])
            self.order_manager.update_status(od['id'], ORDER_STATUS.CANCELLED)
            self.prod_status = BtStatus.INIT

    def buy(self, amount, role):
        if not (self.prod_status == BtStatus.INIT or self.prod_status == BtStatus.SUCCESS_SELL_ORDER):
            logging.info("不是初始状态或者卖单未完成, 不能买")
            return
        if role == 'maker':
            price = self.okex_exchange.fetch_depth(self.symbol)['bids'][0][0]
        else:
            price = self.okex_exchange.fetch_depth(self.symbol)['asks'][-1][0]
        logging.info("try buy, price %s, amount: %s" % (price, self.amount))
        if self.debug:
            order_id = cur_ms()
            self.prod_status = BtStatus.SUCCESS_BUY_ORDER
        else:
            buy_record_id = self.order_manager.init_order(self.okex_exchange.id, self.symbol, 'buy', self.amount, price)
            order_id = self.okex_exchange.buy_limit(self.symbol, price=price, amount=self.amount)
            self.order_manager.update_ex_id(buy_record_id, order_id)
            self.buy_price = price
            self.prod_status = BtStatus.PLACE_BUY_ORDER
        logging.info("发送买单成功 buy_order_id: %s" % order_id)
        slack("buy price %s" % price)

    def check_price_level(self, price):
        if price > 8900:
            return 'high'
        if price > 8500:
            return 'mid'
        return 'low'

    def _check_sell_price_is_ok(self, price):
        delta = price - self.buy_price
        if self.buy_price > 8900:
            return delta > -60
        if self.buy_price > 8500:
            return delta > -15
        if self.buy_price < 8200:
            return delta > 40
        return delta > 0

    def sell(self, price=None, role=None):
        if self.bt_force_buy_first and self.prod_status == BtStatus.INIT:
            logging.info("没有买单, 不能卖")
            return
        if not (self.prod_status == BtStatus.INIT or self.prod_status == BtStatus.SUCCESS_BUY_ORDER):
            logging.info("没有买单, 不能卖")
            return

        amount = self.buy_amount
        if not price:
            if role == 'maker':
                price = self.okex_exchange.fetch_depth(self.symbol)['asks'][-1][0]
            else:
                price = self.okex_exchange.fetch_depth(self.symbol)['bids'][0][0]
        logging.info("try sell, price %s, amount: %s" % (price, amount))
        if not self._check_sell_price_is_ok(price):
            logging.warn("卖价太低了, 等吧, buy: %s, sell: %s" % (self.buy_price, price))
            return
        if self.debug:
            order_id = cur_ms()
            self.prod_status = BtStatus.SUCCESS_SELL_ORDER
        else:
            record_id = self.order_manager.init_order(self.okex_exchange.id, self.symbol, 'sell', amount, price)
            order_id = self.okex_exchange.sell_limit(self.symbol, price=price, amount=amount)
            self.order_manager.update_ex_id(record_id, order_id)
            self.prod_status = BtStatus.PLACE_SELL_ORDER

        logging.info("发送卖单成功 sell_order_id: %s" % order_id)
        slack("sell price %s" % price)
Пример #11
0
class Test(object):
    CHECK_COINS = ['BTC', 'ETH', 'LTC', 'ETC', 'XRP', 'EOS']

    def __init__(self, config, debug=True):
        key_config = config['apikey']
        self.debug = debug
        self.exchanges = {
            'zb': Zb(key_config['zb']['key'], key_config['zb']['secret']),
            'okex': Okex(key_config['okex']['key'], key_config['okex']['secret']),
            'weex': Weex(key_config['weex']['key'], key_config['weex']['secret']),
            # 'huobipro': Huobipro(key_config['huobipro']['key'], key_config['huobipro']['secret']),
            'bithumb': ccxt.bithumb(),
            'binance': ccxt.binance(),
            'bitflyer': ccxt.bitflyer(),
            'hitbtc': ccxt.hitbtc(),
            'coincheck': ccxt.coincheck(),
            "quoinex": ccxt.quoinex(),
            "bitfinex": ccxt.bitfinex(),
            "hitbtc": ccxt.hitbtc(),
        }

        self.engine = MysqlEngine(config['db']['url'])
        self.pool = ThreadPoolExecutor(3)  # for many urls, this should probably be capped at some value.

        self.async = False

    def _check_and_create_table(self, tablename):
        sql = '''
            CREATE TABLE if not EXISTS `%s` (
              `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
              `coin` varchar(8) DEFAULT NULL,
              `ab` decimal(8,4) DEFAULT NULL,
              `ba` decimal(8,4) DEFAULT NULL,
              `ts` bigint(20) DEFAULT NULL,
              PRIMARY KEY (`id`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8
        ''' % tablename
        self.engine.execute(sql)

    def insert(self, table, coin, a, b, ts):
        sql = "insert into " + table + " (coin, ab, ba, ts) values (?, ?, ?, ?)"
        self.engine.execute(sql, (coin, a, b, ts))

    def trade(self, first, second, coin):
        self.first_api = self.exchanges.get(first)
        self.second_api = self.exchanges.get(second)
        self.tablename = 'diff_%s_%s' % (first, second)
        self._check_and_create_table(self.tablename)
        while True:
            self._trade_async(coin)
            time.sleep(2)

    def get_right(self, exchange, coin, li, side='bid', amount=None):
        total = 0
        res = []
        if amount is None:
            amount = AMOUNT_THRESHOLD[coin]
        if exchange.id != 'huobipro':
            if side == 'ask':
                li.reverse()
        for x in li:
            total += x[1]
            if total >= amount:
                res.append(x[0])
                break
            else:
                res.append(x[0])
        return avg(res)

    def ccxt_get_bid_ask(self, exchange, coin, symbol):
        if exchange.id == 'bithumb':
            data = exchange.fetch_ticker(coin + '/KRW')
            return data['bid'] / 1068.6, data['ask'] / 1068.6
        elif exchange.id == 'binance':
            data = exchange.fetch_ticker(coin + "/USDT")
            return data['bid'], data['ask']
        elif exchange.id == 'bitflyer':
            data = exchange.fetch_ticker(coin + '/JPY')
            return data['bid'] / 108.84, data['ask'] / 108.84
        elif exchange.id == 'hitbtc':
            data = exchange.fetch_ticker(coin + '/USDT')
            return data['bid'], data['ask']
        elif exchange.id == 'coincheck':
            data = exchange.fetch_ticker(coin + '/JPY')
            return data['bid'] / 108.84, data['ask'] / 108.84
        elif exchange.id == 'coincheck':
            data = exchange.fetch_ticker(coin + '/JPY')
            return data['bid'] / 108.84, data['ask'] / 108.84
        elif exchange.id == 'quoinex':
            data = exchange.fetch_ticker(coin + '/JPY')
            return data['bid'] / 108.84, data['ask'] / 108.84
        elif exchange.id == 'bitfinex':
            data = exchange.fetch_ticker(coin + '/USD')
            return data['bid'], data['ask']
        elif exchange.id == 'hitbtc':
            data = exchange.fetch_ticker(coin + '/USDT')
            return data['bid'], data['ask']

    def get_bid_ask(self, exchange, coin, symbol):
        first_depth = exchange.fetch_depth(symbol)
        first_bid = self.get_right(exchange, coin, first_depth['bids'], 'bid')
        first_ask = self.get_right(exchange, coin, first_depth['asks'], 'ask')
        return first_bid, first_ask

    def _com_get_bid_ask(self, exchange, coin, symbol):
        try:
            first_bid, first_ask = self.get_bid_ask(exchange, coin, symbol)
        except:
            first_bid, first_ask = self.ccxt_get_bid_ask(exchange, coin, symbol)
        return first_bid, first_ask

    def _trade_async(self, coin):
        x = coin
        try:
            symbol = x + "_USDT"

            if self.async:
                first_future = self.pool.submit(self._com_get_bid_ask, self.first_api, coin, symbol)
                second_future = self.pool.submit(self._com_get_bid_ask, self.second_api, coin, symbol)

                first_bid, first_ask = first_future.result()
                second_bid, second_ask = second_future.result()
            else:
                first_bid, first_ask = self._com_get_bid_ask(self.first_api, coin, symbol)
                second_bid, second_ask = self._com_get_bid_ask(self.second_api, coin, symbol)

            a = fix_float_radix(first_bid / second_ask)  # 左卖右买
            b = fix_float_radix(second_bid / first_ask)  # 左买右卖
            logging.info("结果 %s\t%s\t%s\t%s\t%s\t%s" % (first_bid, first_ask, second_bid, second_ask, a, b))
            if not self.debug:
                self.insert(self.tablename, x, a, b, cur_ms())
        except Exception, e:
            logging.exception("")
Пример #12
0
class Test(object):
    CHECK_COINS = ['BTC', 'ETH', 'LTC', 'ETC', 'XRP', 'EOS']

    def __init__(self, config, debug=True):
        key_config = config['apikey']
        self.debug = debug
        self.exchanges = {
            'zb': Zb(key_config['zb']['key'], key_config['zb']['secret']),
            'okex': Okex(key_config['okex']['key'],
                         key_config['okex']['secret']),
            'weex': Weex(key_config['weex']['key'],
                         key_config['weex']['secret']),
            # 'huobipro': Huobipro(key_config['huobipro']['key'], key_config['huobipro']['secret']),
            'bithumb': ccxt.bithumb(),
            'binance': ccxt.binance(),
            'bitflyer': ccxt.bitflyer(),
            'hitbtc': ccxt.hitbtc(),
            'coincheck': ccxt.coincheck(),
            "quoinex": ccxt.quoinex(),
            "bitfinex": ccxt.bitfinex(),
            "hitbtc": ccxt.hitbtc(),
        }

        self.engine = MysqlEngine(config['db']['url'])
        self.pool = ThreadPoolExecutor(
            3)  # for many urls, this should probably be capped at some value.

        self. async = False

    def _check_and_create_table(self, tablename):
        sql = '''
            CREATE TABLE if not EXISTS `%s` (
              `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
              `coin` varchar(8) DEFAULT NULL,
              `ab` decimal(8,4) DEFAULT NULL,
              `ba` decimal(8,4) DEFAULT NULL,
              `ts` bigint(20) DEFAULT NULL,
              PRIMARY KEY (`id`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8
        ''' % tablename
        self.engine.execute(sql)

    def insert(self, table, coin, a, b, ts):
        sql = "insert into " + table + " (coin, ab, ba, ts) values (?, ?, ?, ?)"
        self.engine.execute(sql, (coin, a, b, ts))

    def trade(self, first, second, coin):
        self.first_api = self.exchanges.get(first)
        self.second_api = self.exchanges.get(second)
        self.tablename = 'diff_%s_%s' % (first, second)
        self._check_and_create_table(self.tablename)
        while True:
            self._trade_async(coin)
            time.sleep(2)

    def get_right(self, exchange, coin, li, side='bid', amount=None):
        total = 0
        res = []
        if amount is None:
            amount = AMOUNT_THRESHOLD[coin]
        if exchange.id != 'huobipro':
            if side == 'ask':
                li.reverse()
        for x in li:
            total += x[1]
            if total >= amount:
                res.append(x[0])
                break
            else:
                res.append(x[0])
        return avg(res)

    def ccxt_get_bid_ask(self, exchange, coin, symbol):
        if exchange.id == 'bithumb':
            data = exchange.fetch_ticker(coin + '/KRW')
            return data['bid'] / 1068.6, data['ask'] / 1068.6
        elif exchange.id == 'binance':
            data = exchange.fetch_ticker(coin + "/USDT")
            return data['bid'], data['ask']
        elif exchange.id == 'bitflyer':
            data = exchange.fetch_ticker(coin + '/JPY')
            return data['bid'] / 108.84, data['ask'] / 108.84
        elif exchange.id == 'hitbtc':
            data = exchange.fetch_ticker(coin + '/USDT')
            return data['bid'], data['ask']
        elif exchange.id == 'coincheck':
            data = exchange.fetch_ticker(coin + '/JPY')
            return data['bid'] / 108.84, data['ask'] / 108.84
        elif exchange.id == 'coincheck':
            data = exchange.fetch_ticker(coin + '/JPY')
            return data['bid'] / 108.84, data['ask'] / 108.84
        elif exchange.id == 'quoinex':
            data = exchange.fetch_ticker(coin + '/JPY')
            return data['bid'] / 108.84, data['ask'] / 108.84
        elif exchange.id == 'bitfinex':
            data = exchange.fetch_ticker(coin + '/USD')
            return data['bid'], data['ask']
        elif exchange.id == 'hitbtc':
            data = exchange.fetch_ticker(coin + '/USDT')
            return data['bid'], data['ask']

    def get_bid_ask(self, exchange, coin, symbol):
        first_depth = exchange.fetch_depth(symbol)
        first_bid = self.get_right(exchange, coin, first_depth['bids'], 'bid')
        first_ask = self.get_right(exchange, coin, first_depth['asks'], 'ask')
        return first_bid, first_ask

    def _com_get_bid_ask(self, exchange, coin, symbol):
        try:
            first_bid, first_ask = self.get_bid_ask(exchange, coin, symbol)
        except:
            first_bid, first_ask = self.ccxt_get_bid_ask(
                exchange, coin, symbol)
        return first_bid, first_ask

    def _trade_async(self, coin):
        x = coin
        try:
            symbol = x + "_USDT"

            if self. async:
                first_future = self.pool.submit(self._com_get_bid_ask,
                                                self.first_api, coin, symbol)
                second_future = self.pool.submit(self._com_get_bid_ask,
                                                 self.second_api, coin, symbol)

                first_bid, first_ask = first_future.result()
                second_bid, second_ask = second_future.result()
            else:
                first_bid, first_ask = self._com_get_bid_ask(
                    self.first_api, coin, symbol)
                second_bid, second_ask = self._com_get_bid_ask(
                    self.second_api, coin, symbol)

            a = fix_float_radix(first_bid / second_ask)  # 左卖右买
            b = fix_float_radix(second_bid / first_ask)  # 左买右卖
            logging.info("结果 %s\t%s\t%s\t%s\t%s\t%s" %
                         (first_bid, first_ask, second_bid, second_ask, a, b))
            if not self.debug:
                self.insert(self.tablename, x, a, b, cur_ms())
        except Exception, e:
            logging.exception("")
Пример #13
0
class TestStrategy(object):
    def __init__(self, config, debug=True):
        key_config = config['apikey']
        self.debug = debug
        self.exchanges = {
            'zb': Zb(key_config['zb']['key'], key_config['zb']['secret']),
            'okex': Okex(key_config['okex']['key'], key_config['okex']['secret']),
        }

        self.engine = MysqlEngine(config['db']['url'])
        self.order_manager = OrderManager(self.engine)
        self.strategy_manager = StrategyManager(self.engine)

        self.min_a = 1.0055
        self.min_b = 1.0055

        self.cur_a = self.min_a
        self.cur_b = self.min_b
        self.miss_a = 0
        self.miss_b = 0

        self.has_init_strategy_threshold = False

        self.pool = ThreadPoolExecutor(3)

        self.accounts = {}
        self.balancer = None
        self.init_balancer()

        self.price_chooser = TakerPriceChooser()
        # self.price_chooser = MakerPriceChooser(0.0001)

        self.ts_got_a = 0
        self.ts_got_b = 0

    def refresh_strategy_min_v(self):
        self.min_a, self.min_b = self.balancer.get_threshold()
        if not self.has_init_strategy_threshold:
            self.cur_a = self.min_a
            self.cur_b = self.min_b
        else:
            self.cur_a = max(self.cur_a, self.min_a)
            self.cur_b = max(self.cur_b, self.min_b)

        self.has_init_strategy_threshold = True

    def init_balancer(self):
        for k, v in self.exchanges.iteritems():
            a = v.account()
            logging.info("account %s: %s" % (k, a))
            self.accounts[k] = a

    def insert_diff_to_table(self, coin, a, b):
        sql = "insert into " + self.diff_tablename + " (coin, ab, ba, ts) values (?, ?, ?, ?)"
        self.engine.execute(sql, (coin, a, b, cur_ms()))

    def trade(self, first, second, coin="BTC"):
        self.first_api = self.exchanges.get(first)
        self.second_api = self.exchanges.get(second)
        first_account = self.accounts.get(first)
        second_account = self.accounts.get(second)
        self.diff_tablename = 'diff_%s_%s' % (first, second)
        self.balancer = BackSeeTwoSideBalancer(
            first_account.get_avail(coin), first_account.get_avail("usdt"),
            second_account.get_avail(coin), second_account.get_avail("usdt")
        ).init(self.engine, self.diff_tablename)
        self.strategy_a_key = '%s_%s_%s' % (first, second, 'a')
        self.strategy_b_key = '%s_%s_%s' % (first, second, 'b')
        self.refresh_strategy_min_v()
        while True:
            self._trade(coin)
            time.sleep(5)

    def get_right(self, exchange, coin, li, side='bid', amount=None):
        total = 0
        res = []
        if amount is None:
            amount = AMOUNT_THRESHOLD[coin]
        if side == 'ask':
            li.reverse()
        for x in li:
            total += x[1]
            if total >= amount:
                res.append(x[0])
                break
            else:
                res.append(x[0])
        return avg(res)

    def has_unfinish_order(self):
        a = len(self.order_manager.list_by_status(ORDER_STATUS.PLACED)) >= 6
        if a:
            return a
        a = len(self.order_manager.list_by_status(ORDER_STATUS.INIT)) > 2
        return a

    def analyze_price_from_depth(self, first_depth, second_depth, coin):
        first_bid = self.get_right(self.first_api, coin, first_depth['bids'], 'bid')
        first_ask = self.get_right(self.first_api, coin, first_depth['asks'], 'ask')
        second_bid = self.get_right(self.second_api, coin, second_depth['bids'], 'bid')
        second_ask = self.get_right(self.second_api, coin, second_depth['asks'], 'ask')

        return first_bid, first_ask, second_bid, second_ask

    def trade_from_left_to_right(self, coin, symbol, buy_price, sell_price, radio):
        avg_coin_price = (buy_price + sell_price) / 2
        self.execute_trade_in_exchange(coin, symbol, Balancer.TRADE_SIDE_LEFT_TO_RIGHT,
                                       self.second_api, self.first_api, buy_price, sell_price,
                                       avg_coin_price, radio)

    def trade_from_right_to_left(self, coin, symbol, buy_price, sell_price, radio):
        avg_coin_price = (buy_price + sell_price) / 2
        self.execute_trade_in_exchange(coin, symbol, Balancer.TRADE_SIDE_RIGHT_TO_LEFT,
                                       self.first_api, self.second_api, buy_price, sell_price,
                                       avg_coin_price, radio)

    def execute_trade_in_exchange(self, coin, symbol, trade_side,
                                  buy_exchange, sell_exchange, buy_price, sell_price,
                                  avg_price, radio):
        assert buy_price < sell_price
        logging.info("[%s]准备执行策略==========\t%s" % (trade_side, radio))

        # self.cur_b = (b + self.cur_b) / 2
        self.cur_b = radio
        coin_amount = self.balancer.get_trade_coin_amount(trade_side, radio)
        if not self.balancer.can_trade(coin_amount, coin_price=avg_price, side=trade_side):
            logging.info("执行策略失败, 余额不足")
            return

        # second_price = second_bid  + 0.0001
        assert trade_side in Balancer.TRADE_SIDES
        logging.info("真正执行策略, price is: buy: %s, sell: %s" % (buy_price, sell_price))
        buy_record_id = self.order_manager.init_order(buy_exchange.id, coin, 'buy', coin_amount,
                                                      buy_price)
        sell_record_id = self.order_manager.init_order(sell_exchange.id, coin, 'sell',
                                                       coin_amount,
                                                       sell_price)
        logging.info("创建订单记录 buy_record_id: %s , sell_record_id %s" % (
            buy_record_id, sell_record_id))

        buy_order_id_future = self.pool.submit(buy_exchange.buy_limit, symbol,
                                               price=buy_price, amount=coin_amount)
        sell_order_id_future = self.pool.submit(sell_exchange.sell_limit, symbol,
                                                price=sell_price,
                                                amount=coin_amount)

        sell_order_id = sell_order_id_future.result()
        buy_order_id = buy_order_id_future.result()

        logging.info("发送买单成功 buy_order_id: %s" % buy_order_id)
        logging.info("发送卖单成功 sell_order_id: %s" % sell_order_id)

        self.order_manager.update_ex_id(buy_record_id, buy_order_id)
        self.order_manager.update_ex_id(sell_record_id, sell_order_id)

        strategy_key = self.strategy_b_key
        if trade_side == Balancer.TRADE_SIDE_LEFT_TO_RIGHT:
            strategy_key = self.strategy_a_key
        self.strategy_manager.insert(strategy_key, buy_record_id, sell_record_id, radio,
                                     coin_amount)
        self.balancer.sync_by_trade(coin_amount, coin_price=avg_price, side=trade_side)
        logging.info("[%s]完成执行策略==========\t%s" % (trade_side, radio))

        slack("[%s] execute strategy success, radio is %s" % (trade_side, radio))

    def _trade(self, coin):
        try:
            symbol = (coin + "_USDT").upper()

            future_first = self.pool.submit(self.first_api.fetch_depth, symbol)
            future_second = self.pool.submit(self.second_api.fetch_depth, symbol)

            first_depth = future_first.result()
            second_depth = future_second.result()

            first_bid, first_ask, second_bid, second_ask = self.analyze_price_from_depth(first_depth, second_depth,
                                                                                         coin)

            left_buy_price, left_sell_price, right_buy_price, right_sell_price = \
                self.price_chooser.choose(first_bid, first_ask, second_bid, second_ask)

            a = fix_float_radix(left_sell_price / right_buy_price)  # 左卖右买
            b = fix_float_radix(right_sell_price / left_buy_price)  # 左买右卖

            logging.info("策略结果 %s\t%s, 阈值: %s\t%s" % (a, b, self.cur_a, self.cur_b))
            if self.debug:
                return

            self.insert_diff_to_table(coin, a, b)
            if max(a, b) < 1.01 and self.has_unfinish_order():
                logging.info("利润太小且有未完成订单")
            else:
                if a >= self.cur_a:
                    self.miss_a = 0
                    if self.ts_got_a > 0 and cur_ms() - self.ts_got_a < 60000:
                        self.trade_from_left_to_right(coin, symbol, right_buy_price, left_sell_price, a)
                    self.ts_got_a = cur_ms()
                else:
                    self.miss_a += 1
                    if self.miss_a > 9:
                        self.cur_a = max(a - 0.0001, self.min_a)
                if b >= self.cur_b:
                    self.miss_b = 0
                    if self.ts_got_b > 0 and cur_ms() - self.ts_got_b < 60000:
                        self.trade_from_right_to_left(coin, symbol, left_buy_price, right_sell_price, b)
                    self.ts_got_b = cur_ms()
                else:
                    self.miss_b += 1
                    if self.miss_b > 9:
                        self.cur_b = max(b - 0.0001, self.min_b)
                self.refresh_strategy_min_v()
        except Exception, e:
            logging.exception("")
Пример #14
0
class PriceAlarm(object):
    def __init__(self, config, debug):
        self.debug = debug
        self.exchange = Okex(config['apikey']['okex']['key'], config['apikey']['okex']['secret'])
        self.engine = MysqlEngine(config['db']['url'])
        self.init_db()

        self.symbols = self.refresh_db_config()

        self.pool = ThreadPoolExecutor(4)
        run_thread(self.sched_refresh_db_config)
        run_thread(self.reset_success_alarm)

        self.success_alarm = False

    def init_db(self):
        sql = """
        CREATE TABLE if not EXISTS `price_monitor_symbols` (
          `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
          `exchange` varchar(24) NOT NULL DEFAULT '',
          `symbol` varchar(24) NOT NULL DEFAULT '',
          `low` decimal(18,8) DEFAULT NULL,
          `high` decimal(18,8) DEFAULT NULL,
          `status` int(11) NOT NULL DEFAULT '1',
          `ts` bigint(20) DEFAULT NULL,
          PRIMARY KEY (`id`),
          UNIQUE KEY `ukey__exchange_symbol` (`exchange`,`symbol`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8
        """
        self.engine.execute(sql, ())

    def refresh_db_config(self):
        sql = "select * from price_monitor_symbols where status = 1"
        return self.engine.fetch_row(sql, ())

    def is_symbols_diff(self, a, b):
        if len(a) != len(b):
            return True
        a_map = {}
        for x in a:
            a_map[x.exchange + x.symbol] = [float(x.low), float(x.high)]
        for x in b:
            key = x.exchange + x.symbol
            if key not in a_map:
                return True
            a_v = a_map[key]
            if float(x.low) - a_v[0] > 1:
                return True
            if float(x.high) - a_v[1] > 1:
                return True
        return False

    def sched_refresh_db_config(self):
        while True:
            try:
                new_data = self.refresh_db_config()
                logging.info("refresh %s" % new_data)
                if self.is_symbols_diff(self.symbols, new_data):
                    self.success_alarm = False
                    logging.info("succ")
                self.symbols = new_data
            except:
                logging.exception("refresh error")
            time.sleep(2)

    def reset_success_alarm(self):
        while True:
            self.success_alarm = False
            time.sleep(3 * 60)

    def run(self):
        if not self.symbols:
            logging.error("no symbol to monitor")
            return
        while True:
            try:
                self._run()
            except:
                logging.exception("")
            time.sleep(5)

    def _run(self):
        for x in self.symbols:
            ticker = self.exchange.fetch_ticker(x.symbol)
            if x.low < ticker.price < x.high:
                self.notify("price reach %s" % ticker.price)
                return True
            return False

    def notify(self, msg):
        if not self.success_alarm:
            if self.debug:
                os.system('say "price monitor finished"')
            else:
                slack(msg)
            self.success_alarm = True
Пример #15
0
class AbsDiffStrategy(object):
    def __init__(self, config, debug):
        self.config = config
        self.debug = debug
        self.backtest = False
        self.pool = ThreadPoolExecutor(3)
        self.engine = MysqlEngine(config['db']['url'])

        self.max_miss_ms = 2000

        self.base_prices = []
        self.trade_prices = []
        self.base_price_mas = []
        self.trade_price_mas = []
        self.diff_mas = []

        self.diffs = []

        # --------- backtest vars --------------
        self.bt_status = 0
        self.bt_buy_price = 0
        self.bt_sell_price = 0
        self.bt_benefit = 0
        self.bt_tx_cnt = 0
        self.bt_record = None
        self.bt_buy_diff_ma = None
        self.bt_buy_record_id = None
        self.bt_buy_slope = 0
        # --------- backtest vars --------------

    def _check_table_exist(self, tablename):
        sql = '''
        CREATE TABLE if not EXISTS `%s` (
          `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
          `symbol` varchar(24) NOT NULL DEFAULT '',
          `base_bid` decimal(14,4) NOT NULL DEFAULT '0.0000',
          `base_ask` decimal(14,4) NOT NULL DEFAULT '0.0000',
          `base_price` decimal(14,4) NOT NULL DEFAULT '0.0000',
          `trade_bid` decimal(14,4) NOT NULL DEFAULT '0.0000',
          `trade_ask` decimal(14,4) NOT NULL DEFAULT '0.0000',
          `trade_price` decimal(14,4) NOT NULL DEFAULT '0.0000',
          `ts` bigint(20) NOT NULL DEFAULT '0',
          PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8
        ''' % tablename
        self.engine.execute(sql)

    def run(self, base_exchange, trade_exchange, symbol):
        self.diff_tablename = "abs_diff_%s_%s" % (trade_exchange.id,
                                                  base_exchange.id)
        self._check_table_exist(self.diff_tablename)
        while True:
            try:
                future_base_ticker = self.pool.submit(
                    base_exchange.fetch_ticker, symbol)
                future_trade_ticker = self.pool.submit(
                    trade_exchange.fetch_ticker, symbol)
                base_ticker = future_base_ticker.result()
                trade_ticker = future_trade_ticker.result()

                self.tick(base_ticker, trade_ticker, symbol)
            except:
                logging.exception("")
            time.sleep(2)

    def back_test(self,
                  base_exchange,
                  trade_exchange,
                  symbol,
                  begin_time,
                  end_time=None):
        self.backtest = True
        self.diff_tablename = "abs_diff_%s_%s" % (trade_exchange.id,
                                                  base_exchange.id)
        sql = "select * from " + self.diff_tablename + " where symbol = ? and ts > ? and ts < ?"
        if not end_time:
            end_time = cur_ms()
        data = self.engine.fetch_row(sql, (symbol, begin_time, end_time))
        print begin_time, end_time
        for x in data:
            x.ar = ms_to_str(x.ts)
            self.bt_record = x
            bt = Ticker(x['base_bid'],
                        x['base_ask'],
                        x['base_price'],
                        ms=x['ts'])
            tt = Ticker(x['trade_bid'],
                        x['trade_ask'],
                        x['trade_price'],
                        ms=x['ts'])
            self.back_test_tick(bt, tt, symbol)
        print self.bt_benefit * 0.01

    def back_test_tick(self, base_ticker, trade_ticker, symbol):
        diff_price = trade_ticker.price - base_ticker.price
        self.diffs.append(diff_price)
        self.base_prices.append(base_ticker.price)
        self.trade_prices.append(trade_ticker.price)

        if self.in_warming():
            return
        window = 10
        base_ma = avg(self.base_prices[-window:])
        trade_ma = avg(self.trade_prices[-window:])
        self.base_price_mas.append(base_ma)
        self.trade_price_mas.append(trade_ma)
        self.diff_mas.append(trade_ma - base_ma)

        if len(self.diff_mas) < 10:
            return

        if self.bt_status == BtStatus.PLACE_BUY_ORDER:
            if trade_ticker.price < self.bt_buy_price:
                print 'buy success %s, id: %s, ts: %s' % (
                    trade_ticker.price, self.bt_record.id, self.bt_record.ar)
                self.bt_status = BtStatus.SUCCESS_BUY_ORDER
                self.bt_tx_cnt += 1
                if self.bt_tx_cnt % 2 == 0:
                    self.bt_benefit += self.bt_sell_price - self.bt_buy_price
        elif self.bt_status == BtStatus.PLACE_SELL_ORDER:
            if trade_ticker.price > self.bt_sell_price:
                print 'sell success %s, id: %s, ts: %s' % (
                    trade_ticker.price, self.bt_record.id, self.bt_record.ar)
                self.bt_status = BtStatus.SUCCESS_SELL_ORDER
                self.bt_tx_cnt += 1
                if self.bt_tx_cnt % 2 == 0:
                    self.bt_benefit += self.bt_sell_price - self.bt_buy_price
        elif self.bt_status == BtStatus.PLACE_BUY_ORDER and self.bt_record.id > self.bt_buy_record_id + 5:
            self.bt_cancel_buy()
        else:
            can_buy = self.ana_buy_status()
            can_sell = self.ana_sell_status()
            add_price = -0.0001
            if can_buy:
                buy_price = trade_ticker.ask + add_price
                self.back_test_buy(buy_price, 0.001)
            if can_sell:
                sell_price = trade_ticker.bid - add_price
                if sell_price > self.bt_buy_price + 10:
                    self.back_test_sell(sell_price, 0.001)

    def ana_sell_status(self):
        if self.bt_status != BtStatus.SUCCESS_BUY_ORDER:  # 必须先买后卖
            return False
        window = 3
        base_slope = self.cal_slope(self.base_prices, window)
        trade_slope = self.cal_slope(self.trade_prices, window)
        if base_slope < -1 and trade_slope - base_slope > 1.5:
            return True
        return False

    def cal_slope(self, li, window):
        slope = (li[-1] - li[-window]) / window
        return slope

    def ana_buy_status(self):
        window = 4
        up_cnt = 0
        down_cnt = 0
        for i in range(window, 1, -1):
            delta = self.base_price_mas[-i + 1] - self.base_price_mas[-i]
            if delta > 0.01:
                up_cnt += 1
            elif delta < -0.01:
                down_cnt += 1
        if up_cnt < window - 1:
            return False
        base_slope = self.cal_slope(self.base_prices, window)
        trade_slope = self.cal_slope(self.trade_prices, window)
        if base_slope >= 3 and base_slope - trade_slope > 2.2:
            self.bt_buy_slope = base_slope
            return True
        return False

    def bt_cancel_buy(self):
        if self.bt_status != BtStatus.PLACE_BUY_ORDER:
            return
        self.bt_buy_price = 0
        self.bt_status = BtStatus.INIT
        self.bt_buy_record_id = None
        print 'cancel buy %s, id: %s, ts: %s' % (
            self.bt_buy_price, self.bt_record.id, self.bt_record.ar)

    def back_test_buy(self, price, amount):
        if not (self.bt_status == BtStatus.INIT
                or self.bt_status == BtStatus.SUCCESS_SELL_ORDER):
            return
        self.bt_buy_price = price
        self.bt_status = BtStatus.PLACE_BUY_ORDER
        self.bt_buy_record_id = self.bt_record.id
        print 'place buy %s, id: %s, ts: %s' % (
            self.bt_buy_price, self.bt_record.id, self.bt_record.ar)

    def back_test_sell(self, price, amount):
        if not (self.bt_status == BtStatus.INIT
                or self.bt_status == BtStatus.SUCCESS_BUY_ORDER):
            return
        self.bt_sell_price = price
        self.bt_status = BtStatus.PLACE_SELL_ORDER
        print 'place sell %s, id: %s, ts: %s' % (
            self.bt_sell_price, self.bt_record.id, self.bt_record.ar)

    def in_warming(self):
        return len(self.base_prices) < 50

    def tick(self, base_ticker, trade_ticker, symbol):

        # now = cur_ms()
        # if abs(now - trade_ticker.ms) > self.max_miss_ms:
        #     logging.warn("%s ticker 过期, %s" % (base_exchange.id, now - trade_ticker.ms))
        #     return
        # if abs(now - base_ticker.ms) > self.max_miss_ms:
        #     logging.warn("%s ticker 过期, %s" % (base_exchange.id, now - base_ticker.ms))
        #     return

        # diff_price, diff_bid, diff_ask = trade_ticker.price - base_ticker.price, \
        #                                  trade_ticker.bid - base_ticker.bid, \
        #                                  trade_ticker.ask - base_ticker.ask
        # logging.info("diff is : %s\t%s\t%s", diff_price, diff_bid, diff_ask)
        if self.debug:
            return
        if not self.backtest:
            self.insert_diff_to_table(symbol, trade_ticker, base_ticker)

    def insert_diff_to_table(self, symbol, trade_ticker, base_ticker):
        sql = "insert into " + self.diff_tablename + \
              " (symbol, base_bid, base_ask, base_price, trade_bid, trade_ask, trade_price, ts) values (?, ?, ?, ?, ?, ?, ?, ?)"
        self.engine.execute(
            sql,
            (symbol, base_ticker.bid, base_ticker.ask, base_ticker.price,
             trade_ticker.bid, trade_ticker.ask, trade_ticker.price, cur_ms()))
Пример #16
0
class TaStrategy(BackTestMixin):
    def __init__(self, config, symbol, backtest=False, debug=True):
        key_config = config['apikey']
        self.okex_exchange = Okex(key_config['okex']['key'],
                                  key_config['okex']['secret'])
        self.symbol = symbol
        self.record = None
        self.in_backtest = backtest

        self.amount = 0.002
        self.debug = debug

        self.engine = MysqlEngine(config['db']['url'])
        self.order_manager = OrderManager(self.engine)

        self.buy_price = None
        self.buy_amount = None
        self.sell_price = None
        self.prod_status = BtStatus.INIT
        self.cmp_buy_price_cnt = [0, 0]

        BackTestMixin.__init__(self)

    def recover_from_db(self):
        sql = "select * from `order` where status in (1, 100) order by id desc limit 1"
        od = self.engine.fetchone_row(sql, ())
        if od:
            if od['side'] == 'buy':
                self.buy_price = float(od['price'])
                self.buy_amount = float(od['amount'])
                if od['status'] == 1:
                    self.prod_status = BtStatus.PLACE_BUY_ORDER
                else:
                    self.prod_status = BtStatus.SUCCESS_BUY_ORDER
            else:
                self.sell_price = float(od['price'])
                if od['status'] == 1:
                    self.prod_status = BtStatus.PLACE_SELL_ORDER
                else:
                    self.prod_status = BtStatus.SUCCESS_SELL_ORDER

    def run(self):
        while True:
            try:
                if self.has_unfinish_order():
                    time.sleep(2)
                    continue
                self.recover_from_db()
                if arrow.now().to('local').second > 18:
                    self.record = self.okex_exchange.fetch_kline(self.symbol,
                                                                 type="1min",
                                                                 size=500)
                    self._run()
            except:
                logging.exception("")
            time.sleep(10)

    def back_test(self):
        self.in_backtest = True
        self.bt_min_round_benefit = -60
        data = self.okex_exchange.fetch_kline(self.symbol,
                                              type="3min",
                                              size=1000)
        data['MACD'], data['MACDsignal'], data['MACDhist'] = talib.MACD(
            data['close'].values, fastperiod=5, slowperiod=34, signalperiod=5)
        graph(data)
        return
        l = len(data)
        for i in range(400, l):
            self.record = data.iloc[0:i + 1, :]
            self._run()
        print self.bt_benefit - self.bt_tx_cnt * 10

    def has_unfinish_order(self):
        a = len(self.order_manager.list_by_status(ORDER_STATUS.PLACED)) >= 1
        if a:
            return a
        a = len(self.order_manager.list_by_status(ORDER_STATUS.INIT)) >= 1
        return a

    def _run(self):
        data = self.record
        if self.in_backtest:
            self.back_test_check_tx_success(data.iloc[-1]['high'],
                                            data.iloc[-1]['low'])
        # if self.bt_status == BtStatus.SUCCESS_BUY_ORDER:
        #         if float(data.iloc[-1]['high']) < (self.bt_buy_price + 20):
        #             self.cmp_buy_price_cnt[0] += 6
        #         else:
        #             self.cmp_buy_price_cnt[1] += 6
        #         if self.cmp_buy_price_cnt[0] - self.cmp_buy_price_cnt[1] > 30:
        #             logging.info("长时间不涨, 设定价格卖出")
        #             self.back_test_sell(price=self.bt_buy_price+20)
        #         if abs(self.bt_buy_price - 9381.4795) < 0.001:
        #             logging.info(self.cmp_buy_price_cnt)
        #     else:
        #         self.cmp_buy_price_cnt = [0, 0]
        # else:
        #     if self.prod_status == BtStatus.SUCCESS_BUY_ORDER:
        #         if float(data.iloc[-1]['high']) < (self.buy_price + 20):
        #             self.cmp_buy_price_cnt[0] += 1
        #         else:
        #             self.cmp_buy_price_cnt[1] += 1
        #         if self.cmp_buy_price_cnt[0] - self.cmp_buy_price_cnt[1] > 24:
        #             logging.info("长时间不涨, 设定价格卖出")
        #             self.sell(price=self.buy_price + 40, role='maker')
        #     else:
        #         self.cmp_buy_price_cnt = [0, 0]

        data['RSI6'] = talib.RSI(data['close'].values, timeperiod=6)
        data['RSI20'] = talib.RSI(data['close'].values, timeperiod=20)
        # data['EMA30'] = talib.EMA(data['close'].values, timeperiod=30)
        # data['MACD'], data['MACDsignal'], data['MACDhist'] = talib.MACD(data['close'].values)
        data['MACD'], data['MACDsignal'], data['MACDhist'] = talib.MACD(
            data['close'].values, fastperiod=5, slowperiod=34, signalperiod=5)
        data['MACDhist'] = data['MACDhist'] * 2
        zero = data.iloc[-4]['MACDhist']
        one = data.iloc[-3]['MACDhist']
        two = data.iloc[-2]['MACDhist']
        row = data.iloc[-1]['MACDhist']

        cur_row = data.iloc[-1]
        if zero * row > 0:  # 没有x
            return
        gold_cross, dead_cross = False, False
        steep = 5.4
        small = 1.8

        sl1 = one - zero
        sl2 = two - one
        sl3 = row - two
        steep = 11
        small = 5
        if row > 0:
            if sl3 > steep:
                gold_cross = True
            elif sl3 > small and sl2 > small and two > 0:
                gold_cross = True
        if row < 0:
            if sl3 < -steep:
                dead_cross = True
            if sl3 < -small and sl2 < -small and two < 0:
                dead_cross = True

        msg = (zero, one, two, row, sl1, sl2, sl3)
        if gold_cross:
            if not (cur_row['RSI6'] > 55 or cur_row['RSI20'] > 50):
                logging.info(
                    "find gold cross, but rsi not match %s, %s, %s, %s",
                    data.index[-1], msg, cur_row['RSI6'], cur_row['RSI20'])
            else:
                logging.info("find gold cross, %s, %s", data.index[-1], msg)
                if self.in_backtest:
                    buy_price = cur_row['high'] + 10
                    self.back_test_buy(buy_price, msg=data.index[-1])
                else:
                    role = 'taker' if sl3 > steep else 'maker'
                    self.buy(self.amount, role)

        if dead_cross:
            if not (cur_row['RSI6'] < 40 or cur_row['RSI20'] < 40):
                logging.info(
                    "find gold cross, but rsi not match %s, %s, %s, %s",
                    data.index[-1], msg, cur_row['RSI6'], cur_row['RSI20'])
            else:
                logging.info("find dead cross, %s, %s", data.index[-1], msg)
                if self.in_backtest:
                    sell_price = cur_row['low']
                    self.back_test_try_cancel_buy_order()
                    self.back_test_sell(sell_price, msg=data.index[-1])
                else:
                    self.try_cancel_buy_order()
                    role = 'taker' if sl3 < -steep else 'maker'
                    self.sell(role=role)

    def try_cancel_buy_order(self):
        if self.prod_status != BtStatus.PLACE_BUY_ORDER:  # 有未成交买单是处理
            return
        sql = "select * from `order` where status in (1, 100) order by id desc limit 1"
        od = self.engine.fetchone_row(sql, ())
        if not od:
            return
        if od['side'] != 'buy':
            return
        if self.okex_exchange.order_info(
                od['symbol'], od['ex_id'])['status'] == ORDER_STATUS.PLACED:
            self.okex_exchange.cancel_order(od['symbol'], od['ex_id'])
            self.order_manager.update_status(od['id'], ORDER_STATUS.CANCELLED)
            self.prod_status = BtStatus.INIT

    def buy(self, amount, role):
        if not (self.prod_status == BtStatus.INIT
                or self.prod_status == BtStatus.SUCCESS_SELL_ORDER):
            logging.info("不是初始状态或者卖单未完成, 不能买")
            return
        if role == 'maker':
            price = self.okex_exchange.fetch_depth(self.symbol)['bids'][0][0]
        else:
            price = self.okex_exchange.fetch_depth(self.symbol)['asks'][-1][0]
        logging.info("try buy, price %s, amount: %s" % (price, self.amount))
        if self.debug:
            order_id = cur_ms()
            self.prod_status = BtStatus.SUCCESS_BUY_ORDER
        else:
            buy_record_id = self.order_manager.init_order(
                self.okex_exchange.id, self.symbol, 'buy', self.amount, price)
            order_id = self.okex_exchange.buy_limit(self.symbol,
                                                    price=price,
                                                    amount=self.amount)
            self.order_manager.update_ex_id(buy_record_id, order_id)
            self.buy_price = price
            self.prod_status = BtStatus.PLACE_BUY_ORDER
        logging.info("发送买单成功 buy_order_id: %s" % order_id)
        slack("buy price %s" % price)

    def check_price_level(self, price):
        if price > 8900:
            return 'high'
        if price > 8500:
            return 'mid'
        return 'low'

    def _check_sell_price_is_ok(self, price):
        delta = price - self.buy_price
        if self.buy_price > 8900:
            return delta > -60
        if self.buy_price > 8500:
            return delta > -15
        if self.buy_price < 8200:
            return delta > 40
        return delta > 0

    def sell(self, price=None, role=None):
        if self.bt_force_buy_first and self.prod_status == BtStatus.INIT:
            logging.info("没有买单, 不能卖")
            return
        if not (self.prod_status == BtStatus.INIT
                or self.prod_status == BtStatus.SUCCESS_BUY_ORDER):
            logging.info("没有买单, 不能卖")
            return

        amount = self.buy_amount
        if not price:
            if role == 'maker':
                price = self.okex_exchange.fetch_depth(
                    self.symbol)['asks'][-1][0]
            else:
                price = self.okex_exchange.fetch_depth(
                    self.symbol)['bids'][0][0]
        logging.info("try sell, price %s, amount: %s" % (price, amount))
        if not self._check_sell_price_is_ok(price):
            logging.warn("卖价太低了, 等吧, buy: %s, sell: %s" %
                         (self.buy_price, price))
            return
        if self.debug:
            order_id = cur_ms()
            self.prod_status = BtStatus.SUCCESS_SELL_ORDER
        else:
            record_id = self.order_manager.init_order(self.okex_exchange.id,
                                                      self.symbol, 'sell',
                                                      amount, price)
            order_id = self.okex_exchange.sell_limit(self.symbol,
                                                     price=price,
                                                     amount=amount)
            self.order_manager.update_ex_id(record_id, order_id)
            self.prod_status = BtStatus.PLACE_SELL_ORDER

        logging.info("发送卖单成功 sell_order_id: %s" % order_id)
        slack("sell price %s" % price)
Пример #17
0
class PriceAlarm(object):
    def __init__(self, config, debug):
        self.debug = debug
        self.exchange = Okex(config['apikey']['okex']['key'],
                             config['apikey']['okex']['secret'])
        self.engine = MysqlEngine(config['db']['url'])
        self.init_db()

        self.symbols = self.refresh_db_config()

        self.pool = ThreadPoolExecutor(4)
        run_thread(self.sched_refresh_db_config)
        run_thread(self.reset_success_alarm)

        self.success_alarm = False

    def init_db(self):
        sql = """
        CREATE TABLE if not EXISTS `price_monitor_symbols` (
          `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
          `exchange` varchar(24) NOT NULL DEFAULT '',
          `symbol` varchar(24) NOT NULL DEFAULT '',
          `low` decimal(18,8) DEFAULT NULL,
          `high` decimal(18,8) DEFAULT NULL,
          `status` int(11) NOT NULL DEFAULT '1',
          `ts` bigint(20) DEFAULT NULL,
          PRIMARY KEY (`id`),
          UNIQUE KEY `ukey__exchange_symbol` (`exchange`,`symbol`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8
        """
        self.engine.execute(sql, ())

    def refresh_db_config(self):
        sql = "select * from price_monitor_symbols where status = 1"
        return self.engine.fetch_row(sql, ())

    def is_symbols_diff(self, a, b):
        if len(a) != len(b):
            return True
        a_map = {}
        for x in a:
            a_map[x.exchange + x.symbol] = [float(x.low), float(x.high)]
        for x in b:
            key = x.exchange + x.symbol
            if key not in a_map:
                return True
            a_v = a_map[key]
            if float(x.low) - a_v[0] > 1:
                return True
            if float(x.high) - a_v[1] > 1:
                return True
        return False

    def sched_refresh_db_config(self):
        while True:
            try:
                new_data = self.refresh_db_config()
                logging.info("refresh %s" % new_data)
                if self.is_symbols_diff(self.symbols, new_data):
                    self.success_alarm = False
                    logging.info("succ")
                self.symbols = new_data
            except:
                logging.exception("refresh error")
            time.sleep(2)

    def reset_success_alarm(self):
        while True:
            self.success_alarm = False
            time.sleep(3 * 60)

    def run(self):
        if not self.symbols:
            logging.error("no symbol to monitor")
            return
        while True:
            try:
                self._run()
            except:
                logging.exception("")
            time.sleep(5)

    def _run(self):
        for x in self.symbols:
            ticker = self.exchange.fetch_ticker(x.symbol)
            if x.low < ticker.price < x.high:
                self.notify("price reach %s" % ticker.price)
                return True
            return False

    def notify(self, msg):
        if not self.success_alarm:
            if self.debug:
                os.system('say "price monitor finished"')
            else:
                slack(msg)
            self.success_alarm = True