Пример #1
0
 def __lightning_fetch_balance(self):
     balance = Dotdict()
     if self.lightning_enabled:
         res = self.lightning.inventories()
         for k, v in res.items():
             balance[k] = Dotdict(v)
     return balance
Пример #2
0
 def __restapi_fetch_balance(self):
     balance = Dotdict()
     if self.private_api_enabled:
         res = self.exchange.private_get_getbalance()
         for v in res:
             balance[v['currency_code']] = Dotdict(v)
     return balance
Пример #3
0
 def create_rich_ohlcv(self, ohlcv):
     if self.settings.disable_rich_ohlcv:
         rich_ohlcv = Dotdict()
         for k in ohlcv[0].keys():
             rich_ohlcv[k] = [v[k] for v in ohlcv]
     else:
         rich_ohlcv = pd.DataFrame.from_records(ohlcv, index="created_at")
     return rich_ohlcv
Пример #4
0
 def __restapi_fetch_collateral(self):
     collateral = Dotdict()
     collateral.collateral = 0
     collateral.open_position_pnl = 0
     collateral.require_collateral = 0
     collateral.keep_rate = 0
     if self.private_api_enabled:
         collateral = Dotdict(self.exchange.private_get_getcollateral())
         # self.logger.info("COLLATERAL: {collateral} open {open_position_pnl} require {require_collateral:.2f} rate {keep_rate}".format(**collateral))
     return collateral
Пример #5
0
    def __init__(self, yourlogic):

        # トレーディングロジック設定
        self.yourlogic = yourlogic

        # ポジションサイズ
        self.position_size = 0.0

        # 取引所情報
        self.settings = Dotdict()
        self.settings.exchange = self.cfg.get_env("EXCHANGE", default='bitflyer')
        self.settings.symbol = self.cfg.get_env("SYMBOL", default='FX_BTC_JPY')
        self.settings.topics = ['ticker', 'executions']
        self.settings.apiKey = self.cfg.get_env("BITFLYER_KEY")
        self.settings.secret = self.cfg.get_env("BITFLYER_SECRET_KEY")

        # 取引所
        self.exchange = None

        # LightningAPI設定
        self.settings.use_lightning = self.cfg.get_env("BITFLER_LIGHTNING_API", default=False, type=bool)
        self.settings.lightning_userid = self.cfg.get_env("BITFLYER_LIGHTNING_USERID")
        self.settings.lightning_password = self.cfg.get_env("BITFLYER_LIGHTNING_PASSWORD")

        # 動作タイミング
        self.settings.interval = int(self.cfg.get_env("INTERVAL", default=60))
        self.settings.timeframe = self.cfg.get_env("TIMEFRAME", default=60)

        # OHLCV生成オプション
        self.settings.max_ohlcv_size = 1000
        self.settings.use_lazy_ohlcv = False
        self.settings.disable_create_ohlcv = False
        self.settings.disable_rich_ohlcv = False

        # その他
        self.hft = False
        self.settings.show_last_n_orders = 0
        self.settings.safe_order = True

        # リスク設定
        self.risk = Dotdict()
        self.risk.max_position_size = 1.0
        self.risk.max_num_of_orders = 1
Пример #6
0
 def get_open_order(self, myid):
     my_open_orders = self.get_open_orders()
     my_order = [v for v in my_open_orders.values() if v['myid'] == myid]
     if len(my_order) == 1:
         return Dotdict(my_order[0])
     elif len(my_order) == 0:
         raise OrderNotFoundException(
             "MyOrderID:%s is not open. MyOpenOrders:%s" %
             (myid, my_open_orders))
     else:
         raise OrderDuplicateFoundException("MyOrderID:%s is duplicated." %
                                            myid)
Пример #7
0
    def __init__(self, yourlogic):

        # ログ設定
        self.logger, self.test_handler = SystemLogger(yourlogic.__name__).get_logger()
        self.logger.info("Initializing Strategy...")

        # トレーディングロジック設定
        self.yourlogic = yourlogic

        # 取引所情報
        self.settings = Dotdict()
        self.settings.exchange = self.cfg.get_env("EXCHANGE", default='bitmex')
        self.settings.symbol = self.cfg.get_env("SYMBOL", default='BTC/USD')
        self.settings.use_websocket = self.cfg.get_env("USE_WEB_SOCKET", type=bool, default=True)
        self.logger.info("USE_WEB_SOCKET: %s" % self.settings.use_websocket)
        if self.cfg.env.is_real():
            self.settings.apiKey = self.cfg.get_env("BITMEX_KEY")
            self.settings.secret = self.cfg.get_env("BITMEX_SECRET_KEY")
        else:
            self.settings.apiKey = self.cfg.get_env("TEST_BITMEX_KEY")
            self.settings.secret = self.cfg.get_env("TEST_BITMEX_SECRET_KEY")
        self.settings.close_position_at_start_stop = False

        # 動作タイミング
        self.settings.interval = int(self.cfg.get_env("INTERVAL", default=60))

        # ohlcv設定
        self.settings.timeframe = self.cfg.get_env("TIMEFRAME", default='1m')
        self.settings.partial = False
        self.hoge = None

        # リスク設定
        self.risk = Dotdict()
        self.risk.max_position_size = 1000
        self.risk.max_drawdown = 5000

        # ポジション情報
        self.position = Dotdict()
        self.position.currentQty = 0

        # 資金情報
        self.balance = None

        # 注文情報
        self.orders = Dotdict()

        # ティッカー情報
        self.ticker = Dotdict()

        # ohlcv情報
        self.ohlcv = None
        self.ohlcv_updated = False

        # 約定情報
        self.executions = Dotdict()

        # 取引所接続
        self.exchange = Exchange(self.settings, apiKey=self.settings.apiKey, secret=self.settings.secret)

        self.logger.info("Completed to initialize Strategy.")
Пример #8
0
 def __restapi_create_order(self, myid, side, qty, limit, stop,
                            time_in_force, minute_to_expire, symbol):
     # raise ccxt.ExchangeNotAvailable('sendchildorder {"status":-208,"error_message":"Order is not accepted"}')
     qty = round(qty, 8)  # 有効桁数8桁
     order_type = 'market'
     params = {}
     if limit is not None:
         order_type = 'limit'
         limit = float(limit)
     if time_in_force is not None:
         params['time_in_force'] = time_in_force
     if minute_to_expire is not None:
         params['minute_to_expire'] = minute_to_expire
     order = Dotdict(
         self.exchange.create_order(symbol, order_type, side, qty, limit,
                                    params))
     order.myid = myid
     order.accepted_at = datetime.utcnow()
     order = self.om.add_order(order)
     self.logger.info(
         "NEW: {myid} {status} {side} {price} {filled}/{amount} {id}".
         format(**order))
Пример #9
0
 def __restapi_fetch_position(self, symbol):
     #raise ccxt.ExchangeError("ConnectionResetError(104, 'Connection reset by peer')")
     position = Dotdict()
     position.currentQty = 0
     position.avgCostPrice = 0
     position.unrealisedPnl = 0
     position.all = []
     if self.private_api_enabled:
         res = self.exchange.private_get_getpositions(
             params={'product_code': self.exchange.market_id(symbol)})
         position.all = res
         for r in res:
             size = r['size'] if r['side'] == 'BUY' else r['size'] * -1
             cost = (position.avgCostPrice * abs(position.currentQty) +
                     r['price'] * abs(size))
             position.currentQty = round(position.currentQty + size, 8)
             position.avgCostPrice = int(cost / abs(position.currentQty))
             position.unrealisedPnl = position.unrealisedPnl + r['pnl']
             self.logger.info('{side} {price} {size} ({pnl})'.format(**r))
         self.logger.info(
             "POSITION: qty {currentQty} cost {avgCostPrice:.0f} pnl {unrealisedPnl}"
             .format(**position))
     return position
Пример #10
0
 def edit_order(self, myid, side, qty, limit=None, stop=None, trailing_offset=None, symbol=None):
     type = 'market'
     params = {}
     if stop is not None and limit is not None:
         type = 'stopLimit'
         params['stopPx'] = stop
         # params['price'] = limit
     elif stop is not None:
         type = 'stop'
         params['stopPx'] = stop
     elif limit is not None:
         type = 'limit'
         # params['price'] = limit
     if trailing_offset is not None:
         params['pegOffsetValue'] = trailing_offset
     symbol = symbol or self.settings.symbol
     res = self.exchange.edit_order(myid, symbol, type, side, qty, limit, params)
     self.logger.info("EDIT: {id} {order_type} {amount} {rate}({stop_loss_rate})".format(**res['info']))
     return Dotdict(res)
Пример #11
0
 def create_order(self, myid, side, qty, limit, stop, trailing_offset, symbol):
     type = 'market'
     params = {}
     if stop is not None and limit is not None:
         type = 'stopLimit'
         params['stopPx'] = stop
         params['execInst'] = 'LastPrice'
         # params['price'] = limit
     elif stop is not None:
         type = 'stop'
         params['stopPx'] = stop
         params['execInst'] = 'LastPrice'
     elif limit is not None:
         type = 'limit'
         # params['price'] = limit
     if trailing_offset is not None:
         params['pegPriceType'] = 'TrailingStopPeg'
         params['pegOffsetValue'] = trailing_offset
     symbol = symbol or self.settings.symbol
     res = self.exchange.create_order(myid, symbol, type, side, qty, limit, params)
     self.logger.info("ORDER: {id} {order_type} {amount} {rate}({stop_loss_rate})".format(**res['info']))
     return Dotdict(res)
Пример #12
0
    def test_dotdict(self):
        d = Dotdict({"a": 1, 'b': 4})

        self.assertEqual({'a': 1, 'b': 4}, d)
        self.assertEqual(1, d.a)
        self.assertEqual(4, d.b)
Пример #13
0
 def __lightning_fetch_position_and_collateral(self, symbol):
     position = Dotdict()
     position.currentQty = 0
     position.avgCostPrice = 0
     position.unrealisedPnl = 0
     collateral = Dotdict()
     collateral.collateral = 0
     collateral.open_position_pnl = 0
     collateral.require_collateral = 0
     collateral.keep_rate = 0
     if self.lightning_enabled:
         res = self.lightning.getmyCollateral(
             product_code=self.exchange.market_id(symbol))
         collateral.collateral = res['collateral']
         collateral.open_position_pnl = res['open_position_pnl']
         collateral.require_collateral = res['require_collateral']
         collateral.keep_rate = res['keep_rate']
         position.all = res['positions']
         for r in position.all:
             size = r['size'] if r['side'] == 'BUY' else r['size'] * -1
             cost = (position.avgCostPrice * abs(position.currentQty) +
                     r['price'] * abs(size))
             position.currentQty = round(position.currentQty + size, 8)
             position.avgCostPrice = cost / abs(position.currentQty)
             position.unrealisedPnl = position.unrealisedPnl + r['pnl']
             self.logger.info('{side} {price} {size} ({pnl})'.format(**r))
         self.logger.info(
             "POSITION: qty {currentQty} cost {avgCostPrice:.0f} pnl {unrealisedPnl}"
             .format(**position))
         self.logger.info(
             "COLLATERAL: {collateral} open {open_position_pnl} require {require_collateral:.2f} rate {keep_rate}"
             .format(**collateral))
     return position, collateral
Пример #14
0
 def __lightning_create_order(self, myid, side, qty, limit, stop,
                              time_in_force, minute_to_expire, symbol):
     # raise LightningError({'status':-208})
     qty = round(qty, 8)  # 有効桁数8桁
     ord_type = 'MARKET'
     if limit is not None:
         ord_type = 'LIMIT'
         limit = int(limit)
     res = self.lightning.sendorder(self.exchange.market_id(symbol),
                                    ord_type, side.upper(), limit, qty,
                                    minute_to_expire, time_in_force)
     order = Dotdict()
     order.myid = myid
     order.accepted_at = datetime.utcnow()
     order.id = res['order_ref_id']
     order.status = 'accepted'
     order.symbol = symbol
     order.type = ord_type.lower()
     order.side = side
     order.price = limit if limit is not None else 0
     order.average_price = 0
     order.cost = 0
     order.amount = qty
     order.filled = 0
     order.remaining = 0
     order.fee = 0
     order = self.om.add_order(order)
     self.logger.info(
         "NEW: {myid} {status} {side} {price} {filled}/{amount} {id}".
         format(**order))
Пример #15
0
 def __restapi_fetch_board_state(self, symbol):
     res = Dotdict(
         self.exchange.public_get_getboardstate(
             params={'product_code': self.exchange.market_id(symbol)}))
     self.logger.info("health {health} state {state}".format(**res))
     return res
Пример #16
0
 def loop(self, ohlcv, ticker, board_state, strategy, **other):
     out = Dotdict()
     out.health = board_state.health
     out.state = board_state.state
     out.datetime = datetime.utcnow()
     out.open = ohlcv.open[-1]
     out.high = ohlcv.high[-1]
     out.low = ohlcv.low[-1]
     out.close = ohlcv.close[-1]
     out.volume = ohlcv.volume[-1]
     out.average = ohlcv.average[-1]
     out.stdev = ohlcv.stdev[-1]
     out.trades = ohlcv.trades[-1]
     out.imbalance = ohlcv.imbalance[-1]
     out.volume_imbalance = ohlcv.volume_imbalance[-1]
     # out.opened_at = ohlcv.opened_at[-1]
     # out.closed_at = ohlcv.closed_at[-1]
     out.delay_seconds = ohlcv.delay_seconds[-1]
     if self.once:
         logger.info(','.join(str(v) for v in out.keys()))
         self.once = False
     logger.info(','.join(str(v) for v in out.values()))
Пример #17
0
class OrderManager(metaclass=Singleton):
    logger, test_handler = SystemLogger(__name__).get_logger()

    INVALID_ORDER = Dotdict({
        'No': 0,
        'myid': '__INVALID_ORDER__',
        'id': '__INVALID_ORDER__',
        'accepted_at': '1989-10-28T0:00:00.000',
        'status': 'closed',
        'symbol': 'FX_BTC_JPY',
        'type': 'market',
        'side': 'none',
        'price': 0,
        'average_price': 0,
        'amount': 0,
        'filled': 0,
        'remaining': 0,
        'fee': 0,
    })

    lock = threading.Lock()
    number_of_orders = 0
    orders = OrderedDict()
    positions = deque()

    def clear_for_test(self):
        self.number_of_orders = 0
        self.orders.clear()

    def add_order(self, new_order):
        with self.lock:
            self.number_of_orders += 1
            new_order['No'] = self.number_of_orders
            self.orders[new_order['myid']] = new_order
        return new_order

    def add_position(self, p):
        # 建玉追加
        self.positions.append(p)
        while len(self.positions) >= 2:
            r = self.positions.pop()
            l = self.positions.popleft()
            if r['side'] == l['side']:
                # 売買方向が同じなら取り出したポジションを戻す
                self.positions.append(r)
                self.positions.appendleft(l)
                break
            else:
                if l['size'] >= r['size']:
                    # 決済
                    l['size'] = round(l['size'] - r['size'], 8)
                    if l['size'] > 0:
                        # サイズが残っている場合、ポジションを戻す
                        self.positions.appendleft(l)
                else:
                    # 決済
                    r['size'] = round(r['size'] - l['size'], 8)
                    if r['size'] > 0:
                        # サイズが残っている場合、ポジションを戻す
                        self.positions.append(r)

    def execute(self, o, e):
        updated = False
        with self.lock:
            if o['filled'] < o['amount']:
                # ポジション追加
                self.add_position({
                    'side': o['side'],
                    'size': e['size'],
                    'price': e['price']
                })
                # 注文情報更新
                last = o['filled'] * o['average_price']
                curr = e['size'] * e['price']
                filled = round(o['filled'] + e['size'], 8)
                average_price = (last + curr) / filled
                o['filled'] = filled
                o['average_price'] = average_price
                o['remaining'] = round(o['amount'] - filled, 8)
                o['status'] = o['status']
                if o['remaining'] <= 0:
                    o['status'] = 'closed'
                else:
                    if o['status'] == 'accepted':
                        o['status'] = 'open'
                updated = True
        return updated

    def open_or_cancel(self, o, size):
        updated = False
        with self.lock:
            if o['status'] == 'cancel':
                # 板サイズが注文サイズ未満ならキャンセル完了
                if size < o['amount']:
                    o['status'] = 'canceled'
                    updated = True
            elif o['status'] == 'accepted':
                # 板サイズが注文サイズ以上ならオープン(他のユーザの注文と被る可能性があるが許容する)
                if size >= o['amount']:
                    o['status'] = 'open'
                    updated = True
        return updated

    def expire(self, o):
        with self.lock:
            if o['status'] in ['cancel', 'open']:
                o['status'] = 'canceled'

    def overwrite(self, o, latest):
        with self.lock:
            # ローカルで更新した状態は残しておく
            if latest['status'] == 'open':
                if o['status'] in ['cancel', 'canceled', 'closed']:
                    latest['status'] = o['status']
            if latest['filled'] < o['filled']:
                latest['filled'] = o['filled']
            for k in [
                    'id', 'accepted_at', 'status', 'average_price', 'filled',
                    'remaining', 'fee'
            ]:
                o[k] = latest[k]

    def cancel_order(self, myid):
        cancelable = ['open', 'accepted']
        with self.lock:
            my_orders = [
                v for v in self.orders.values()
                if (v['type'] != 'market') and (v['myid'] == myid) and (
                    v['status'] in cancelable)
            ]
            for o in my_orders:
                o['status'] = 'cancel'
        return my_orders

    def cancel_order_all(self):
        cancelable = ['open', 'accepted']
        with self.lock:
            my_orders = [
                v for v in self.orders.values()
                if (v['type'] != 'market') and (v['status'] in cancelable)
            ]
            for o in my_orders:
                o['status'] = 'cancel'
        return my_orders

    def get_order(self, myid):
        with self.lock:
            my_orders = [v for v in self.orders.values() if v['myid'] == myid]
        if len(my_orders):
            return my_orders[-1]
        raise OrderNotFoundException("MyOrderID:%s is not found. MyOrders:%s" %
                                     (myid, my_orders))

    def get_open_order(self, myid):
        my_open_orders = self.get_open_orders()
        my_order = [v for v in my_open_orders.values() if v['myid'] == myid]
        if len(my_order) == 1:
            return Dotdict(my_order[0])
        elif len(my_order) == 0:
            raise OrderNotFoundException(
                "MyOrderID:%s is not open. MyOpenOrders:%s" %
                (myid, my_open_orders))
        else:
            raise OrderDuplicateFoundException("MyOrderID:%s is duplicated." %
                                               myid)

    def get_open_orders(self):
        return self.get_orders(status_filter=['open', 'accepted', 'cancel'])

    def get_orders(self, status_filter=None):
        with self.lock:
            if status_filter is None:
                my_orders = self.orders.copy()
            else:
                my_orders = {
                    k: v
                    for k, v in self.orders.items()
                    if (v['status'] in status_filter)
                }
        return my_orders

    def is_active(self, myid):
        try:
            self.get_open_order(myid)
        except OrderNotFoundException as e:
            return False
        except Exception as e:
            return False
        return True

    def update_order(self, o):
        self.get_order(o['myid']).update(o)
        return o

    def cleaning_if_needed(self, limit_orders=200, remaining_orders=20):
        """注文情報整理"""
        open_status = ['open', 'accepted', 'cancel']
        with self.lock:
            if len(self.orders) > limit_orders:
                all_orders = list(self.orders.items())
                # open/accepted状態の注文は残す
                orders = [(k, v) for k, v in all_orders[:-remaining_orders]
                          if v['status'] in open_status]
                # 最新n件の注文は残す
                orders.extend(all_orders[-remaining_orders:])
                self.orders = OrderedDict(orders)

    def printall(self):
        print('\n' + '\t'.join(self.INVALID_ORDER.keys()))
        for v in self.orders.values():
            print('\t'.join([str(v) for v in v.values()]))
Пример #18
0
    def start(self):
        self.logger.info("Start Trading")
        self.setup()

        def async_inverval(func, interval, parallels):
            next_exec_time = 0
            @wraps(func)
            def wrapper(*args, **kargs):
                nonlocal next_exec_time
                f_result = None
                t = time()
                if t > next_exec_time:
                    next_exec_time = ((t//interval)+1)*interval
                    f_result = func(*args,**kargs)
                    if parallels is not None:
                        parallels.append(f_result)
                return f_result
            return wrapper

        def async_result(f_result, last):
            if f_result is not None and f_result.done():
                try:
                    return None, f_result.result()
                except Exception as e:
                    self.logger.warning(type(e).__name__ + ": {0}".format(e))
                    f_result = None
            return f_result, last

        async_requests = []
        fetch_position = async_inverval(self.exchange.fetch_position, 30, async_requests)
        check_order_status = async_inverval(self.exchange.check_order_status, 5, async_requests)
        errorWait = 0
        f_position = position = f_check = None
        once = True

        while True:
            self.interval = self.settings.interval

            try:
                # 注文処理の完了待ち
                self.exchange.wait_for_completion()

                # 待ち時間
                self.monitoring_ep.suspend(False)
                if self.interval:
                    if not self.hft:
                        self.logger.info("Waiting...")
                    wait_sec = (-time() % self.interval) or self.interval
                    sleep(wait_sec)
                self.monitoring_ep.suspend(True)

                # 例外発生時の待ち
                no_needs_err_wait = (errorWait == 0) or (errorWait < time())

                # ポジション等の情報取得
                if no_needs_err_wait:
                    f_position = f_position or fetch_position(self.settings.symbol)
                    f_check = f_check or check_order_status(show_last_n_orders=self.settings.show_last_n_orders)

                    # リクエスト完了を待つ
                    if not self.hft or once:
                        for f in concurrent.futures.as_completed(async_requests):
                            pass
                        once = False
                    async_requests.clear()

                    # 建玉取得
                    if self.settings.use_lightning:
                        f_position, res = async_result(f_position, (position, None))
                        position, _ = res
                    else:
                        f_position, position = async_result(f_position, position)

                    # 内部管理のポジション数をAPIで取得した値に更新
                    if 'checked' not in position:
                        self.exchange.restore_position(position.all)
                        position['checked'] = True

                    # 内部管理のポジション数取得
                    self.position_size, self.position_avg_price, self.openprofit, self.positions = self.exchange.get_position()

                    # 注文情報取得
                    f_check, _ = async_result(f_check, None)

                    # REST API状態取得
                    self.api_state, self.api_avg_responce_time = self.exchange.api_state()
                    if self.api_state is not 'normal':
                        self.logger.info("REST API: {0} ({1:.1f}ms)".format(self.api_state, self.api_avg_responce_time*1000))

                # 価格データ取得
                ticker, executions, ohlcv = Dotdict(self.ep.get_ticker()), None, None

                # インターバルが0の場合、約定履歴の到着を待つ
                if self.settings.interval==0:
                    self.ep.wait_any(['executions'], timeout=0.5)

                # OHLCVを作成しない場合、約定履歴を渡す
                if self.settings.disable_create_ohlcv:
                    executions = self.ep.get_executions()
                else:
                    if self.settings.use_lazy_ohlcv:
                        ohlcv = self.create_rich_ohlcv(self.ep.get_lazy_ohlcv())
                    else:
                        ohlcv = self.create_rich_ohlcv(self.ep.get_boundary_ohlcv())

                # 資金情報取得
                balance = self.fetch_balance()

                # 売買ロジック呼び出し
                args = {
                    'strategy': self,
                    'ticker': ticker,
                    'ohlcv': ohlcv,
                    'position': position,
                    'balance': balance,
                    'executions': executions
                }
                if no_needs_err_wait:
                    self.yourlogic.bizlogic(self.yourlogic, **args)
                    errorWait = 0
                else:
                    self.logger.info("Waiting for Error...")

            except ccxt.DDoSProtection as e:
                self.logger.warning(type(e).__name__ + ": {0}".format(e))
                errorWait = time() + 60
            except ccxt.RequestTimeout as e:
                self.logger.warning(type(e).__name__ + ": {0}".format(e))
                errorWait = time() + 30
            except ccxt.ExchangeNotAvailable as e:
                self.logger.warning(type(e).__name__ + ": {0}".format(e))
                errorWait = time() + 5
            except ccxt.AuthenticationError as e:
                self.logger.warning(type(e).__name__ + ": {0}".format(e))
                self.private_api_enabled = False
                errorWait = time() + 5
            except ccxt.ExchangeError as e:
                self.logger.warning(type(e).__name__ + ": {0}".format(e))
                errorWait = time() + 5
            except (KeyboardInterrupt, SystemExit):
                self.logger.info('Shutdown!')
                break
            except Exception as e:
                self.logger.exception(e)
                errorWait = time() + 1

        self.logger.info("Stop Trading")
        # 停止
        self.running = False
        # ストリーミング停止
        self.streaming.stop()
        # 取引所停止
        self.exchange.stop()
Пример #19
0
 def fetch_order_book(self, symbol):
     """板情報取得"""
     return Dotdict(
         self.exchange.public_get_getboard(
             params={'product_code': self.exchange.market_id(symbol)}))
Пример #20
0
 def make_ohlcv(self, executions):
     price = [e['price'] for e in executions]
     buy = [e for e in executions if e['side'] == 'BUY']
     sell = [e for e in executions if e['side'] == 'SELL']
     ohlcv = Dotdict()
     ohlcv.open = price[0]
     ohlcv.high = max(price)
     ohlcv.low = min(price)
     ohlcv.close = price[-1]
     ohlcv.volume = sum(e['size'] for e in executions)
     ohlcv.buy_volume = sum(e['size'] for e in buy)
     ohlcv.sell_volume = sum(e['size'] for e in sell)
     ohlcv.volume_imbalance = ohlcv.buy_volume - ohlcv.sell_volume
     ohlcv.buy_count = len(buy)
     ohlcv.sell_count = len(sell)
     ohlcv.trades = ohlcv.buy_count + ohlcv.sell_count
     ohlcv.imbalance = ohlcv.buy_count - ohlcv.sell_count
     ohlcv.average = sum(price) / len(price)
     ohlcv.average_sq = sum(p**2 for p in price) / len(price)
     ohlcv.variance = ohlcv.average_sq - (ohlcv.average * ohlcv.average)
     ohlcv.stdev = math.sqrt(ohlcv.variance)
     ohlcv.vwap = sum(e['price']*e['size'] for e in executions) / ohlcv.volume if ohlcv.volume > 0 else price[-1]
     ohlcv.created_at = datetime.utcnow()
     ohlcv.closed_at = self.parse_exec_date(executions[-1]['exec_date'])
     e = executions[-1]
     if e['side']=='SELL':
         ohlcv.market_order_delay = (ohlcv.closed_at-self.parse_order_ref_id(e['sell_child_order_acceptance_id'])).total_seconds()
     elif e['side']=='BUY':
         ohlcv.market_order_delay = (ohlcv.closed_at-self.parse_order_ref_id(e['buy_child_order_acceptance_id'])).total_seconds()
     else:
         ohlcv.market_order_delay = 0
     ohlcv.distribution_delay = (ohlcv.created_at - ohlcv.closed_at).total_seconds()
     return ohlcv