Beispiel #1
0
def transactions():
    eg = Engine(best_ip=True)
    eg.connect()
    m1 = eg.get_security_bars('000001', '1m')
    df = eg.time_and_price('000001')
    ohlcv = df.price.resample('1 Min', label='right', closed='left').ohlc()
    ohlcv['volume'] = df.vol.resample('1 Min', label='right',
                                      closed='left').sum()
Beispiel #2
0
class TdxBroker(Broker):
    def __init__(self, tdx_uri, account_id=None):

        self._orders = {}
        if tdx_uri.startswith('tcp'):
            self._client = zerorpc.Client()
            self._client.connect(tdx_uri)
        elif platform.architecture()[0] == '32bit':
            self._client = TdxClient(tdx_uri)
            self._client.login()
        else:
            raise Exception(
                "please use 32bit python to use local client directly, or use tcp client"
            )
        self.currency = 'RMB'
        self._subscribed_assets = []
        self._bars = {}
        self._bars_update_dt = None
        self._bars_update_interval = pd.tslib.Timedelta('5 S')
        self._mkt_client = Engine(auto_retry=True, best_ip=True)
        self._mkt_client.connect()

        super(TdxBroker, self).__init__()

    def subscribe_to_market_data(self, asset):
        # TODO fix me subcribe_to_market_data
        if asset not in self.subscribed_assets:
            # remove str() cast to have a fun debugging journey
            # self._client.subscribe_to_market_data(str(asset.symbol))
            self._subscribed_assets.append(asset)
            self._bars_update_dt = None

    def _update_bars(self):
        now = pd.to_datetime('now')
        if self._bars_update_dt and (now - self._bars_update_dt <
                                     self._bars_update_interval):
            return
        for code in self.subscribed_assets:
            bars = self._mkt_client.time_and_price(code.symbol)
            bars.index = bars.index.tz_localize('Asia/Shanghai').tz_convert(
                'UTC')
            self._bars[code.symbol] = bars

        self._bars_update_dt = now

    @property
    def subscribed_assets(self):
        return self._subscribed_assets

    @property
    def positions(self):
        now = datetime.datetime.now()
        z_positions = protocol.Positions()
        for pos in self._client.positions():
            if isinstance(pos, list):
                pos = TdxPosition(*pos)
            sid = pos.sid
            available = pos.available
            z_position = protocol.Position(symbol(sid))
            z_position.amount = pos.amount
            z_position.cost_basis = pos.cost_basis
            z_position.last_sale_price = pos.last_sale_price
            z_position.last_sale_date = now
            z_positions[symbol(sid)] = z_position

        return z_positions

    @property
    def portfolio(self):
        z_portfolio = protocol.Portfolio()
        pfo = self._client.portfolio()
        if isinstance(pfo, list):
            pfo = TdxPortfolio(*pfo)
        z_portfolio.capital_used = None  # TODO
        z_portfolio.starting_cash = None
        z_portfolio.portfolio_value = pfo.portfolio_value
        z_portfolio.pnl = None
        z_portfolio.returns = None
        z_portfolio.cash = pfo.cash
        z_portfolio.start_date = None
        z_portfolio.positions = self.positions
        z_portfolio.positions_value = pfo.positions_value
        z_portfolio.position_exposure = z_portfolio.positions_value / (
            z_portfolio.positions_value + z_portfolio.cash)

        return z_portfolio

    @property
    def account(self):
        z_account = protocol.Account()
        z_account.settled_cash = self.portfolio.cash
        z_account.accrued_interest = None
        z_account.buying_power = self.portfolio.portfolio_value
        z_account.equity_with_loan = self.portfolio.portfolio_value
        z_account.total_positions_value = self.portfolio.positions_value
        z_account.total_positions_exposure = z_account.total_positions_value / (
            z_account.total_positions_value + z_account.settled_cash)

        return z_account

    @property
    def time_skew(self):
        return pd.Timedelta('1 S')

    def order(self, asset, amount, style):
        code = asset.symbol

        if amount > 0:
            action = BUY
        else:
            action = SELL

        is_busy = (amount > 0)
        if isinstance(style, MarketOrder):
            order_type = FIVE_LEVEL_MARKET_ORDER
            price = 0.0
        elif isinstance(style, LimitOrder):
            order_type = LIMIT_CHARGE
            price = style.get_limit_price(is_busy)
        elif isinstance(style, StopOrder):
            raise Exception("stop order is not supported")
        elif isinstance(style, StopLimitOrder):
            raise Exception("stop limit order is not supported")

        data, err = self._client.order(code, abs(amount), price, action,
                                       order_type)
        if isinstance(data, list):
            data = OrderRt(*data)
        order_id = str(data.order_id)
        zp_order = self._get_or_create_zp_order(order_id)

        log.info("Placing order-{order_id}: "
                 "{action} {qty} {symbol} with {order_type}, price = {price}".
                 format(order_id=order_id,
                        action=action,
                        qty=amount,
                        symbol=code,
                        order_type=order_type,
                        price=price))

        return zp_order

    @property
    def orders(self):
        self._update_orders()
        return self._orders

    def _get_or_create_zp_order(self, order_id, order=None):
        zp_order_id = self._tdx_to_zp_order_id(order_id)
        if zp_order_id in self._orders:
            return self._orders[zp_order_id]

        if not order:
            order = self._client.orders()[order_id]

        if isinstance(order,
                      list):  # handle rpc response for namedtuple object
            order = TdxOrder(*order)
        self._orders[zp_order_id] = self.tdx_order_to_zipline_order(order)
        return self._orders[zp_order_id]

    # amount 可正数可负数
    def _create_zp_order(self, order_id, asset, price, amount, order_type):
        zp_order_id = self._tdx_to_zp_order_id(order_id)
        if zp_order_id in self._orders:
            return self._orders[zp_order_id]

        dt = pd.to_datetime("now", utc=True)
        self._orders[zp_order_id] = ZPOrder(
            dt=dt,
            asset=asset,
            amount=amount,
            stop=None,
            limit=price if order_type is LIMIT_CHARGE else None,
            id=zp_order_id,
            broker_order_id=order_id)

        return self._orders[zp_order_id]

    def _tdx_to_zp_order_id(self, order_id):
        return "TDX-{date}-{account_id}-{order_id}".format(
            date=str(pd.to_datetime('today').date()),
            account_id=self._client.account_id(),
            order_id=order_id)

    def tdx_order_to_zipline_order(self, order):
        if order.status == '已撤':
            zp_status = ZP_ORDER_STATUS.CANCELLED
        elif order.filled == 0:
            zp_status = ZP_ORDER_STATUS.OPEN
        else:
            zp_status = ZP_ORDER_STATUS.FILLED

        zp_order_id = self._tdx_to_zp_order_id(order.order_id)

        od = ZPOrder(
            dt=pd.to_datetime(order.dt),
            asset=symbol(order.symbol),
            amount=order.amount,
            filled=order.filled,
            stop=None,
            limit=order.price,  # TODO 市价单和限价单
            id=zp_order_id,
        )
        od.broker_order_id = order.order_id
        od.status = zp_status

        return od

    def _update_orders(self):
        ods = self._client.orders()
        for tdx_order_id, tdx_order in iteritems(ods):
            if isinstance(tdx_order,
                          list):  # handle rpc response for namedtuple object
                tdx_order = TdxOrder(*tdx_order)
            zp_order_id = self._tdx_to_zp_order_id(tdx_order_id)
            self._orders[zp_order_id] = self.tdx_order_to_zipline_order(
                tdx_order)

    def _tdx_transaction_to_zipline(self, transaction):
        return ZPTransaction(
            asset=symbol(transaction.asset),
            amount=transaction.amount,
            dt=pd.to_datetime(
                transaction.dt).tz_localize('Asia/Shanghai').tz_convert('UTC'),
            price=transaction.price,
            order_id=self._tdx_to_zp_order_id(transaction.order_id),
            commission=transaction.commission,
        )

    @property
    def transactions(self):
        t = self._client.transactions()
        rt = {}
        for exec_id, transaction in t.items():
            try:
                if isinstance(
                        transaction,
                        list):  # handle rpc response for namedtuple object
                    transaction = TdxTransaction(*transaction)
                rt[exec_id] = self._tdx_transaction_to_zipline(transaction)
            except SymbolNotFound as e:
                log.warning(e.message)

        return rt

    def cancel_order(self, order_id):
        if order_id not in self.orders:  # order become transaction, can't cancel
            return
        tdx_order_id = self.orders[order_id].broker_order_id
        broker_id = self._client.get_stock_type("{:6d}".format(
            self.orders[order_id].asset.sid))
        self._client.cancel_orders(broker_id, tdx_order_id)

    def get_last_traded_dt(self, asset):
        self.subscribe_to_market_data(asset)
        self._update_bars()

        return self._bars[str(asset.symbol)].index[-1]

    def get_spot_value(self, assets, field, dt, data_frequency):
        symbol = str(assets.symbol)
        self.subscribe_to_market_data(assets)
        self._update_bars()

        bars = self._bars[symbol]
        last_event_time = bars.index[-1]

        minute_start = (last_event_time - pd.Timedelta('1 min')) \
            .time()
        minute_end = last_event_time.time()

        if bars.empty:
            return pd.NaT if field == 'last_traded' else np.NaN
        else:
            if field == 'price':
                return bars.price.iloc[-1]
            elif field == 'last_traded':
                return last_event_time or pd.NaT

            minute_df = bars.between_time(minute_start,
                                          minute_end,
                                          include_start=True,
                                          include_end=True)

            if minute_df.empty:
                return np.NaN
            else:
                if field == 'open':
                    return minute_df.price.iloc[0]
                elif field == 'close':
                    return minute_df.price.iloc[-1]
                elif field == 'high':
                    return minute_df.price.max()
                elif field == 'low':
                    return minute_df.price.min()
                elif field == 'volume':
                    return minute_df.vol.sum()

    def get_realtime_bars(self, assets, frequency):
        if frequency == '1m':
            resample_freq = 'Min'
        elif frequency == '1d':
            resample_freq = '24 H'
        else:
            raise ValueError("Invalid frequency specified: %s" % frequency)

        df = pd.DataFrame()

        for asset in assets:
            symbol = str(asset.symbol)
            self.subscribe_to_market_data(asset)
            self._update_bars()

            trade_prices = self._bars[symbol]['price']
            trade_sizes = self._bars[symbol]['vol']
            ohlcv = trade_prices.resample(resample_freq,
                                          label='right',
                                          closed='left').ohlc()
            ohlcv['volume'] = trade_sizes.resample(resample_freq,
                                                   label='right',
                                                   closed='left').sum()

            ohlcv.columns = pd.MultiIndex.from_product([[
                asset,
            ], ohlcv.columns])
            df = pd.concat([df, ohlcv], axis=1)

        return df
Beispiel #3
0
class TdxBroker(Broker):
    def __init__(self, tdx_uri, account_id=None):

        self._orders = {}
        if tdx_uri.startswith('tcp'):
            self._client = zerorpc.Client()
            self._client.connect(tdx_uri)
        elif platform.architecture()[0] == '32bit':
            self._client = TdxClient(tdx_uri)
            self._client.login()
        else:
            raise Exception("please use 32bit python to use local client directly, or use tcp client")
        self.currency = 'RMB'
        self._subscribed_assets = []
        self._bars = {}
        self._bars_update_dt = None
        self._bars_update_interval = pd.tslib.Timedelta('5 S')
        self._mkt_client = Engine(auto_retry=True, best_ip=True)
        self._mkt_client.connect()

        super(TdxBroker, self).__init__()

    def subscribe_to_market_data(self, asset):
        # TODO fix me subcribe_to_market_data
        if asset not in self.subscribed_assets:
            # remove str() cast to have a fun debugging journey
            # self._client.subscribe_to_market_data(str(asset.symbol))
            self._subscribed_assets.append(asset)
            self._bars_update_dt = None

    def _update_bars(self):
        now = pd.to_datetime('now')
        if self._bars_update_dt and (now - self._bars_update_dt < self._bars_update_interval):
            return
        for code in self.subscribed_assets:
            bars = self._mkt_client.time_and_price(code.symbol)
            if bars.empty:
                return
            bars.index = bars.index.tz_localize('Asia/Shanghai').tz_convert('UTC')
            self._bars[code.symbol] = bars

        self._bars_update_dt = now

    @property
    def subscribed_assets(self):
        return self._subscribed_assets

    def is_alive(self):
        return True

    @property
    def positions(self):
        now = datetime.datetime.now()
        z_positions = protocol.Positions()
        for pos in self._client.positions():
            if isinstance(pos, list):
                pos = TdxPosition(*pos)
            sid = pos.sid
            available = pos.available
            z_position = protocol.Position(symbol(sid))
            z_position.amount = pos.amount
            z_position.cost_basis = pos.cost_basis
            z_position.last_sale_price = pos.last_sale_price
            z_position.last_sale_date = now
            z_positions[symbol(sid)] = z_position

        return z_positions

    @property
    def portfolio(self):
        z_portfolio = protocol.Portfolio()
        pfo = self._client.portfolio()
        if isinstance(pfo, list):
            pfo = TdxPortfolio(*pfo)
        z_portfolio.capital_used = None  # TODO
        z_portfolio.starting_cash = None
        z_portfolio.portfolio_value = pfo.portfolio_value
        z_portfolio.pnl = None
        z_portfolio.returns = None
        z_portfolio.cash = pfo.cash
        z_portfolio.start_date = None
        z_portfolio.positions = self.positions
        z_portfolio.positions_value = pfo.positions_value
        z_portfolio.position_exposure = z_portfolio.positions_value / (z_portfolio.positions_value + z_portfolio.cash)

        return z_portfolio

    @property
    def account(self):
        z_account = protocol.Account()
        z_account.settled_cash = self.portfolio.cash
        z_account.accrued_interest = None
        z_account.buying_power = self.portfolio.portfolio_value
        z_account.equity_with_loan = self.portfolio.portfolio_value
        z_account.total_positions_value = self.portfolio.positions_value
        z_account.total_positions_exposure = z_account.total_positions_value / (
            z_account.total_positions_value + z_account.settled_cash)

        return z_account

    @property
    def time_skew(self):
        return pd.Timedelta('1 S')

    def order(self, asset, amount, style):
        code = asset.symbol

        if amount > 0:
            action = BUY
        else:
            action = SELL

        is_busy = (amount > 0)
        if isinstance(style, MarketOrder):
            order_type = FIVE_LEVEL_MARKET_ORDER
            price = 0.0
        elif isinstance(style, LimitOrder):
            order_type = LIMIT_CHARGE
            price = style.get_limit_price(is_busy)
        elif isinstance(style, StopOrder):
            raise Exception("stop order is not supported")
        elif isinstance(style, StopLimitOrder):
            raise Exception("stop limit order is not supported")

        data, err = self._client.order(code, abs(amount), price, action, order_type)
        if isinstance(data,list):
            data = OrderRt(*data)
        order_id = str(data.order_id)
        zp_order = self._get_or_create_zp_order(order_id)

        log.info("Placing order-{order_id}: "
                 "{action} {qty} {symbol} with {order_type}, price = {price}".format(
            order_id=order_id,
            action=action,
            qty=amount,
            symbol=code,
            order_type=order_type,
            price=price
        ))

        return zp_order

    @property
    def orders(self):
        self._update_orders()
        return self._orders

    def _get_or_create_zp_order(self, order_id, order=None):
        zp_order_id = self._tdx_to_zp_order_id(order_id)
        if zp_order_id in self._orders:
            return self._orders[zp_order_id]

        if not order:
            order = self._client.orders()[order_id]

        if isinstance(order, list):  # handle rpc response for namedtuple object
            order = TdxOrder(*order)
        self._orders[zp_order_id] = self.tdx_order_to_zipline_order(order)
        return self._orders[zp_order_id]

    # amount 可正数可负数
    def _create_zp_order(self, order_id, asset, price, amount, order_type):
        zp_order_id = self._tdx_to_zp_order_id(order_id)
        if zp_order_id in self._orders:
            return self._orders[zp_order_id]

        dt = pd.to_datetime("now", utc=True)
        self._orders[zp_order_id] = ZPOrder(
            dt=dt,
            asset=asset,
            amount=amount,
            stop=None,
            limit=price if order_type is LIMIT_CHARGE else None,
            id=zp_order_id,
            broker_order_id=order_id
        )

        return self._orders[zp_order_id]

    def _tdx_to_zp_order_id(self, order_id):
        return "TDX-{date}-{account_id}-{order_id}".format(
            date=str(pd.to_datetime('today').date()),
            account_id=self._client.account_id(),
            order_id=order_id
        )

    def tdx_order_to_zipline_order(self, order):
        if order.status == '已撤':
            zp_status = ZP_ORDER_STATUS.CANCELLED
        elif order.filled == 0:
            zp_status = ZP_ORDER_STATUS.OPEN
        else:
            zp_status = ZP_ORDER_STATUS.FILLED

        zp_order_id = self._tdx_to_zp_order_id(order.order_id)

        od = ZPOrder(
            dt=pd.to_datetime(order.dt),
            asset=symbol(order.symbol),
            amount=order.amount,
            filled=order.filled,
            stop=None,
            limit=order.price,  # TODO 市价单和限价单
            id=zp_order_id,
        )
        od.broker_order_id = order.order_id
        od.status = zp_status

        return od

    def _update_orders(self):
        ods = self._client.orders()
        for tdx_order_id, tdx_order in iteritems(ods):
            if isinstance(tdx_order, list):  # handle rpc response for namedtuple object
                tdx_order = TdxOrder(*tdx_order)
            zp_order_id = self._tdx_to_zp_order_id(tdx_order_id)
            self._orders[zp_order_id] = self.tdx_order_to_zipline_order(tdx_order)

    def _tdx_transaction_to_zipline(self, transaction):
        return ZPTransaction(
            asset=symbol(transaction.asset),
            amount=transaction.amount,
            dt=pd.to_datetime(transaction.dt).tz_localize('Asia/Shanghai').tz_convert('UTC'),
            price=transaction.price,
            order_id=self._tdx_to_zp_order_id(transaction.order_id),
            commission=transaction.commission,
        )

    @property
    def transactions(self):
        t = self._client.transactions()
        rt = {}
        for exec_id, transaction in t.items():
            try:
                if isinstance(transaction, list):  # handle rpc response for namedtuple object
                    transaction = TdxTransaction(*transaction)
                rt[exec_id] = self._tdx_transaction_to_zipline(transaction)
            except SymbolNotFound as e:
                log.warning(e.message)

        return rt

    def cancel_order(self, order_id):
        if order_id not in self.orders:  # order become transaction, can't cancel
            return
        tdx_order_id = self.orders[order_id].broker_order_id
        broker_id = self._client.get_stock_type("{:6d}".format(self.orders[order_id].asset.sid))
        self._client.cancel_orders(broker_id, tdx_order_id)

    def get_last_traded_dt(self, asset):
        self.subscribe_to_market_data(asset)
        self._update_bars()

        return self._bars[str(asset.symbol)].index[-1]

    def get_spot_value(self, assets, field, dt, data_frequency):
        symbol = str(assets.symbol)
        self.subscribe_to_market_data(assets)
        self._update_bars()
        if symbol not in self._bars:
            return pd.NaT if field == 'last_traded' else np.NaN
        bars = self._bars[symbol]
        last_event_time = bars.index[-1]

        minute_start = (last_event_time - pd.Timedelta('1 min')) \
            .time()
        minute_end = last_event_time.time()

        if bars.empty:
            return pd.NaT if field == 'last_traded' else np.NaN
        else:
            if field == 'price':
                return bars.price.iloc[-1]
            elif field == 'last_traded':
                return last_event_time or pd.NaT

            minute_df = bars.between_time(minute_start, minute_end,
                                          include_start=True, include_end=True)

            if minute_df.empty:
                return np.NaN
            else:
                if field == 'open':
                    return minute_df.price.iloc[0]
                elif field == 'close':
                    return minute_df.price.iloc[-1]
                elif field == 'high':
                    return minute_df.price.max()
                elif field == 'low':
                    return minute_df.price.min()
                elif field == 'volume':
                    return minute_df.vol.sum()

    def get_realtime_bars(self, assets, frequency):
        if frequency == '1m':
            resample_freq = 'Min'
        elif frequency == '1d':
            resample_freq = 'd'
        else:
            raise ValueError("Invalid frequency specified: %s" % frequency)

        df = pd.DataFrame()

        for asset in assets:
            symbol = str(asset.symbol)
            self.subscribe_to_market_data(asset)
            self._update_bars()

            trade_prices = self._bars[symbol]['price']
            trade_sizes = self._bars[symbol]['vol']
            ohlcv = trade_prices.resample(resample_freq,
                                          label='left',
                                          closed='left').ohlc()
            ohlcv['volume'] = trade_sizes.resample(resample_freq,
                                                   label='left',
                                                   closed='left').sum()

            ohlcv.columns = pd.MultiIndex.from_product([[asset, ],
                                                        ohlcv.columns])
            df = pd.concat([df, ohlcv], axis=1)

        return df