Ejemplo n.º 1
0
    def get_order(self, order_id: Optional[str] = None) -> Union[SecurityOrder, Entity]:
        """
        获取用户委托单信息

        Args:
            order_id (str): [可选]单号, 不填单号则返回所有委托单

        Returns:
            :py:class:`~tqsdk.objs.SecurityOrder`: 当指定了 order_id 时, 返回一个委托单对象引用。 \
            其内容将在 :py:meth:`~tqsdk.api.TqApi.wait_update` 时更新。

            不填 order_id 参数调用本函数, 将返回包含用户所有委托单的一个 ``tqsdk.objs.Entity`` 对象引用, \
            使用方法与 dict 一致, 其中每个元素的 key 为委托单号, value为 :py:class:`~tqsdk.objs.SecurityOrder`

            注意: 在刚下单后, tqsdk 还没有收到回单信息时, 此对象中各项内容为空

        Example::

            from tqsdk import TqApi, TqAuth, TqKqStock
            tqkqstock = TqKqStock()
            api = TqApi(account=tqkqstock, auth=TqAuth("信易账户", "账户密码"))
            order = tqkqstock.get_order('委托单Id')
            print(f"委托股数 {order.volume_orign}, 剩余股数 {order.volume_left}")
            api.close()
        """
        api = _get_api_instance(self)
        if order_id:
            return _get_obj(api._data, ["trade", self._account_key, "orders", order_id], SecurityOrder(api))
        return _get_obj(api._data, ["trade", self._account_key, "orders"])
Ejemplo n.º 2
0
    def get_trade(self, trade_id: Optional[str] = None) -> Union[SecurityTrade, Entity]:
        """
        获取用户成交信息

        Args:
            trade_id (str): [可选]成交号, 不填成交号则返回所有委托单

        Returns:
            :py:class:`~tqsdk.objs.SecurityTrade`: 当指定了trade_id时, 返回一个成交对象引用. \
            其内容将在 :py:meth:`~tqsdk.api.TqApi.wait_update` 时更新.

            不填trade_id参数调用本函数, 将返回包含用户当前交易日所有成交记录的一个 ``tqsdk.objs.Entity`` 对象引用, 使用方法与dict一致, \
            其中每个元素的key为成交号, value为 :py:class:`~tqsdk.objs.SecurityTrade`

            推荐优先使用 :py:meth:`~tqsdk.objs.SecurityOrder.trade_records` 获取某个委托单的相应成交记录, 仅当确有需要时才使用本函数.

        Example::

            from tqsdk import TqApi, TqAuth, TqKqStock
            tqkqstock = TqKqStock()
            api = TqApi(account=tqkqstock, auth=TqAuth("信易账户", "账户密码"))
            trades = tqkqstock.get_trade('委托单Id')
            [print(trade.trade_id, f"成交股数 {trade.volume}, 成交价格 {trade.price}") for trade in trades]
            api.close()
        """
        api = _get_api_instance(self)
        if trade_id:
            return _get_obj(api._data, ["trade", self._account_key, "trades", trade_id], SecurityTrade(api))
        return _get_obj(api._data, ["trade", self._account_key, "trades"])
Ejemplo n.º 3
0
 def _is_all_received(self):
     set_chart_packs = {k: v for k, v in self._resend_request.items() if v.get("aid") == "set_chart"}
     # 处理 seriesl(k线/tick)
     if not all([v.items() <= _get_obj(self._data, ["charts", k, "state"]).items()
                 for k, v in set_chart_packs.items()]):
         return False  # 如果当前请求还没收齐回应, 不应继续处理
     # 在接收并处理完成指令后, 此时发送给客户端的数据包中的 left_id或right_id 至少有一个不是-1 , 并且 mdhis_more_data是False;否则客户端需要继续等待数据完全发送
     if not all([(_get_obj(self._data, ["charts", k]).get("left_id", -1) != -1
                  or _get_obj(self._data, ["charts", k]).get("right_id", -1) != -1)
                 and not self._data.get("mdhis_more_data", True)
                 for k in set_chart_packs.keys()]):
         return False  # 如果当前所有数据未接收完全(定位信息还没收到, 或数据序列还没收到), 不应继续处理
     all_received = True  # 订阅K线数据完全接收标志
     for k, v in set_chart_packs.items():  # 判断已订阅的数据是否接收完全
         for symbol in v["ins_list"].split(","):
             if symbol:
                 path = ["klines", symbol, str(v["duration"])] if v["duration"] != 0 else ["ticks", symbol]
                 serial = _get_obj(self._data, path)
                 if serial.get("last_id", -1) == -1:
                     all_received = False
                     break
         if not all_received:
             break
     if not all_received:
         return False
     # 处理实时行情quote
     if self._data.get("ins_list", "") != self._resend_request.get("subscribe_quote", {}).get("ins_list", ""):
         return False  # 如果实时行情quote未接收完全, 不应继续处理
     return True
Ejemplo n.º 4
0
    def get_position(self, symbol: Optional[str] = None) -> Union[SecurityPosition, Entity]:
        """
        获取用户持仓信息

        Args:
            symbol (str): [可选]合约代码, 不填则返回所有持仓

        Returns:
            :py:class:`~tqsdk.objs.SecurityPosition`: 当指定了 symbol 时, 返回一个持仓对象引用。
            其内容将在 :py:meth:`~tqsdk.api.TqApi.wait_update` 时更新。

            不填 symbol 参数调用本函数, 将返回包含用户所有持仓的一个 ``tqsdk.objs.Entity`` 对象引用, 使用方法与dict一致, \
            其中每个元素的 key 为合约代码, value 为 :py:class:`~tqsdk.objs.SecurityPosition`。


        Example::

            from tqsdk import TqApi, TqAuth, TqKqStock
            tqkqstock = TqKqStock()
            api = TqApi(account=tqkqstock, auth=TqAuth("信易账户", "账户密码"))
            position = tqkqstock.get_position('SSE.10003624')
            print(f"建仓日期 {position.create_date}, 持仓数量 {position.volume}")
            api.close()

        """
        api = _get_api_instance(self)
        if symbol:
            return _get_obj(api._data, ["trade", self._account_key, "positions", symbol], Position(api))
        return _get_obj(api._data, ["trade", self._account_key, "positions"])
Ejemplo n.º 5
0
 async def _update_dividend_factor(self, symbol):
     quote = self._api.get_quote(symbol)
     df = get_dividend_df(quote.stock_dividend_ratio,
                          quote.cash_dividend_ratio)
     between = df["datetime"].between(
         self._start_dt_nano, self._end_dt_nano)  # 只需要开始时间~结束时间之间的复权因子
     df["pre_close"] = float('nan')
     for i in df[between].index:
         chart_info = {
             "aid": "set_chart",
             "chart_id": _generate_uuid("PYSDK_data_factor"),
             "ins_list": symbol,
             "duration": 86400 * 1000000000,
             "view_width": 2,
             "focus_datetime": int(df.iloc[i].datetime),
             "focus_position": 1
         }
         await self._api._send_chan.send(chart_info)
         chart = _get_obj(self._api._data,
                          ["charts", chart_info["chart_id"]])
         serial = _get_obj(
             self._api._data,
             ["klines", symbol, str(86400000000000)])
         try:
             async with self._api.register_update_notify() as update_chan:
                 async for _ in update_chan:
                     if not (chart_info.items() <= _get_obj(
                             chart, ["state"]).items()):
                         continue  # 当前请求还没收齐回应, 不应继续处理
                     left_id = chart.get("left_id", -1)
                     right_id = chart.get("right_id", -1)
                     if (left_id == -1
                             and right_id == -1) or self._api._data.get(
                                 "mdhis_more_data", True) or serial.get(
                                     "last_id", -1) == -1:
                         continue  # 定位信息还没收到, 或数据序列还没收到, 合约的数据是否收到
                     last_item = serial["data"].get(str(left_id), {})
                     # 复权时间点的昨收盘
                     df.loc[
                         i,
                         'pre_close'] = last_item['close'] if last_item.get(
                             'close') else float('nan')
                     break
         finally:
             await self._api._send_chan.send({
                 "aid":
                 "set_chart",
                 "chart_id":
                 chart_info["chart_id"],
                 "ins_list":
                 "",
                 "duration":
                 86400000000000,
                 "view_width":
                 2
             })
     df["factor"] = (df["pre_close"] - df["cash_dividend"]
                     ) / df["pre_close"] / (1 + df["stock_dividend"])
     df["factor"].fillna(1, inplace=True)
     return df
async def download_symbol_dur(s, dur, api, server_type, chart_ids):
    chart_info = {
        "aid": "set_chart",
        "chart_id": chart_ids[dur]["chart_id"],
        "ins_list": s,
        "duration": int(dur * 1e9),
        "view_width": DATA_LENGTH
    }
    await api._send_chan.send(chart_info)
    chart = _get_obj(api._data, ["charts", chart_info["chart_id"]])
    path = ["klines", s, str(int(dur * 1e9))] if dur > 0 else ["ticks", s]
    serial = _get_obj(api._data, path)
    end_time = time() + 10
    async with api.register_update_notify() as chan:
        async for _ in chan:
            left_id = chart.get("left_id", -1)
            right_id = chart.get("right_id", -1)
            last_id = serial.get("last_id", -1)
            if (right_id > -1 and last_id > -1) and api._data.get(
                    "mdhis_more_data", True) is False:
                chart_ids[dur]["is_timeout"] = 0
                chart_ids[dur]["left_id"] = left_id
                chart_ids[dur]["right_id"] = right_id
                chart_ids[dur]["last_id"] = last_id
                break
    await api._send_chan.send({
        "aid": "set_chart",
        "chart_id": chart_ids[dur]["chart_id"],
        "ins_list": "",
        "duration": int(dur * 1e9),
        "view_width": DATA_LENGTH,
    })
Ejemplo n.º 7
0
    def get_order(self, order_id: Optional[str] = None) -> Union[Order, Entity]:
        """
        获取用户委托单信息

        Args:
            order_id (str): [可选]单号, 不填单号则返回所有委托单

        Returns:
            :py:class:`~tqsdk.objs.Order`: 当指定了 order_id 时, 返回一个委托单对象引用。 \
            其内容将在 :py:meth:`~tqsdk.api.TqApi.wait_update` 时更新。

            不填 order_id 参数调用本函数, 将返回包含用户所有委托单的一个 ``tqsdk.objs.Entity`` 对象引用, \
            使用方法与dict一致, 其中每个元素的key为委托单号, value为 :py:class:`~tqsdk.objs.Order`

            注意: 在刚下单后, tqsdk 还没有收到回单信息时, 此对象中各项内容为空

        Example1::

            # 获取当前总挂单手数
            from tqsdk import TqApi, TqAuth

            tqacc = TqAccount("N南华期货", "123456", "123456")
            api = TqApi(account=tqacc, auth=TqAuth("信易账户", "账户密码"))
            orders = tqacc.get_order()
            while True:
                api.wait_update()
                print(sum(order.volume_left for oid, order in orders.items() if order.status == "ALIVE"))

            # 预计的输出是这样的:
            3
            3
            0
            ...

        Example2::

            # 多账户模式下, 分别获取各账户挂单手数
            from tqsdk import TqApi, TqAuth, TqMultiAccount, TqAccount, TqKq, TqSim

            account = TqAccount("N南华期货", "123456", "123456")
            tqkq = TqKq()
            tqsim = TqSim()
            api = TqApi(TqMultiAccount([account, tqkq, tqsim]), auth=TqAuth("信易账户", "账户密码"))
            orders1 = account.get_order()
            orders2 = tqkq.get_order()
            orders3 = tqsim.get_order()
            print(f"账户 1 挂单手数 {sum(order.volume_left for order in orders1.values() if order.status == "ALIVE")}, ",
                  f"账户 2 挂单手数 {sum(order.volume_left for order in orders2.values() if order.status == "ALIVE")}, ",
                  f"账户 3 挂单手数 {sum(order.volume_left for order in orders3.values() if order.status == "ALIVE")}")

            order = account.get_order(order_id="订单号")
            print(order)
            api.close()

        """
        api = _get_api_instance(self)
        if order_id:
            return _get_obj(api._data, ["trade", self._account_key, "orders", order_id], Order(api))
        return _get_obj(api._data, ["trade", self._account_key, "orders"])
Ejemplo n.º 8
0
    def get_position(self,
                     symbol: Optional[str] = None) -> Union[Position, Entity]:
        """
        获取用户持仓信息

        Args:
            symbol (str): [可选]合约代码, 不填则返回所有持仓

        Returns:
            :py:class:`~tqsdk.objs.Position`: 当指定了 symbol 时, 返回一个持仓对象引用。
            其内容将在 :py:meth:`~tqsdk.api.TqApi.wait_update` 时更新。

            不填 symbol 参数调用本函数, 将返回包含用户所有持仓的一个 ``tqsdk.objs.Entity`` 对象引用, 使用方法与dict一致, \
            其中每个元素的 key 为合约代码, value 为 :py:class:`~tqsdk.objs.Position`。

            注意: 为保留一些可供用户查询的历史信息, 如 volume_long_yd(本交易日开盘前的多头持仓手数) 等字段, 因此服务器会返回当天已平仓合约( pos_long 和 pos_short 等字段为0)的持仓信息

        Example1::

            # 获取 DCE.m2109 当前浮动盈亏
            from tqsdk import TqApi, TqAuth, TqAccount

            tqacc = TqAccount("N南华期货", "123456", "123456")
            api = TqApi(account=tqacc, auth=TqAuth("信易账户", "账户密码"))
            position = tqacc.get_position("DCE.m2109")
            print(position.float_profit_long + position.float_profit_short)
            while api.wait_update():
                print(position.float_profit_long + position.float_profit_short)

            # 预计的输出是这样的:
            300.0
            330.0
            ...

        Example2::

            # 多账户模式下, 分别获取各账户浮动盈亏
            from tqsdk import TqApi, TqAuth, TqMultiAccount, TqAccount, TqKq, TqSim

            account = TqAccount("N南华期货", "123456", "123456")
            tqkq = TqKq()
            tqsim = TqSim()
            api = TqApi(TqMultiAccount([account, tqkq, tqsim]), auth=TqAuth("信易账户", "账户密码"))
            position1 = account.get_position("DCE.m2101")
            position2 = tqkq.get_position("DCE.m2101")
            position3 = tqsim.get_position("DCE.m2101")
            print(f"账户 1 'DCE.m2101' 浮动盈亏 {position1.float_profit_long + position1.float_profit_short}, ",
                  f"账户 2 'DCE.m2101' 浮动盈亏 {position2.float_profit_long + position2.float_profit_short}, ",
                  f"账户 3 'DCE.m2101' 浮动盈亏 {position3.float_profit_long + position3.float_profit_short}")
            api.close()

        """
        api = _get_api_instance(self)
        if symbol:
            return _get_obj(api._data,
                            ["trade", self._account_key, "positions", symbol],
                            Position(api))
        return _get_obj(api._data, ["trade", self._account_key, "positions"])
Ejemplo n.º 9
0
    def _gc_data(self):
        # api 应该删除的数据 diff
        need_rangeset = {}
        for ins, dur in self._serials:
            if dur == 0:  # tick 在发送数据过程中已经回收内存
                continue
            symbol_list = ins.split(',')
            for s in symbol_list:
                need_rangeset.setdefault((s, dur), [])
            main_serial = _get_obj(self._data, ["klines", symbol_list[0], str(dur)])
            main_serial_rangeset = self._sended_to_api.get((symbol_list[0], dur), [])  # 此 request 还没有给 api 发送过任何数据时为 []
            if not main_serial_rangeset:
                continue
            last_id = main_serial_rangeset[-1][-1] - 1
            assert last_id > -1
            need_rangeset[(symbol_list[0], dur)] = _rangeset_range_union(need_rangeset[(symbol_list[0], dur)],
                                                                         (last_id - 8963, last_id + 1))
            for symbol in symbol_list[1:]:
                symbol_need_rangeset = []
                symbol_binding = main_serial.get("binding", {}).get(symbol, {})
                if symbol_binding:
                    for i in range(last_id - 8963, last_id + 1):
                        other_id = symbol_binding.get(str(i))
                        if other_id:
                            symbol_need_rangeset = _rangeset_range_union(symbol_need_rangeset, (other_id, other_id + 1))
                if symbol_need_rangeset:
                    need_rangeset[(symbol, dur)] = _rangeset_union(need_rangeset[(symbol, dur)], symbol_need_rangeset)

        gc_rangeset = {}
        for key, rs in self._sended_to_api.items():
            gc_rangeset[key] = _rangeset_difference(rs, need_rangeset.get(key, []))

        # 更新 self._sended_to_api
        for key, rs in gc_rangeset.items():
            self._sended_to_api[key] = _rangeset_difference(self._sended_to_api[key], rs)

        gc_klines_diff = {}
        for (symbol, dur), rs in gc_rangeset.items():
            gc_klines_diff.setdefault(symbol, {})
            gc_klines_diff[symbol][str(dur)] = {"data": {}}
            serial = _get_obj(self._data, ["klines", symbol, str(dur)])
            serial_binding = serial.get("binding", None)
            if serial_binding:
                gc_klines_diff[symbol][str(dur)]["binding"] = {s: {} for s in serial_binding.keys()}
            for start_id, end_id in rs:
                for i in range(start_id, end_id):
                    gc_klines_diff[symbol][str(dur)]["data"][str(i)] = None
                    if serial_binding:
                        for s, s_binding in serial_binding.items():
                            gc_klines_diff[symbol][str(dur)]["binding"][s][str(i)] = None
        return {"klines": gc_klines_diff}
Ejemplo n.º 10
0
 def _generate_ext_diff(self):
     """"
     补充 quote, position 额外字段
     此函数在 send_diff() 才会调用, self._datetime_state.data_ready 一定为 True,
     调用 self._datetime_state.get_current_dt() 一定有正确的当前时间
     """
     for d in self._diffs:
         if d.get('quotes', None):
             self._update_quotes(d)
     pend_diff = {}
     _simple_merge_diff(pend_diff, self._get_positions_pend_diff())
     orders_set = set()  # 计算过委托单,is_dead、is_online、is_error
     orders_price_set = set()  # 根据成交计算哪些 order 需要重新计算平均成交价 trade_price
     for path in self._diffs_paths:
         if path[2] == 'orders':
             _, account_key, _, order_id, _ = path
             if (account_key, order_id) not in orders_set:
                 orders_set.add((account_key, order_id))
                 order = _get_obj(
                     self._data, ['trade', account_key, 'orders', order_id])
                 if order:
                     pend_order = pend_diff.setdefault(
                         'trade',
                         {}).setdefault(account_key, {}).setdefault(
                             'orders', {}).setdefault(order_id, {})
                     pend_order['is_dead'] = order['status'] == "FINISHED"
                     pend_order['is_online'] = order[
                         'exchange_order_id'] != "" and order[
                             'status'] == "ALIVE"
                     pend_order['is_error'] = order[
                         'exchange_order_id'] == "" and order[
                             'status'] == "FINISHED"
         elif path[2] == 'trades':
             _, account_key, _, trade_id = path
             trade = _get_obj(self._data, path)
             order_id = trade.get('order_id', '')
             if order_id:
                 orders_price_set.add(
                     ('trade', account_key, 'orders', order_id))
     for path in orders_price_set:
         _, account_key, _, order_id = path
         trade_price = self._get_trade_price(account_key, order_id)
         if trade_price == trade_price:
             pend_order = pend_diff.setdefault('trade', {}).setdefault(
                 account_key, {}).setdefault('orders',
                                             {}).setdefault(order_id, {})
             pend_order['trade_price'] = trade_price
     self._diffs_paths = set()
     return pend_diff
Ejemplo n.º 11
0
    def __init__(self, api: TqApi) -> None:
        """
        创建 TqNotify 实例

        Args:
            api (tqsdk.api.TqApi): TqApi 实例

        Example::

            from tqsdk import TqApi, TqAuth, TqKq, TqNotify

            api = TqApi(account=TqKq(), auth=TqAuth("信易账户", "账户密码"))
            tqNotify = TqNotify(api)  # 构造实例类
            while True:
                api.wait_update()
                # 每次调用返回距离上一次调用 tqNotify.get_notifies() 之后产生的通知列表,没有的话返回 []
                notify_list = tqNotify.get_notifies()
                for notify in notify_list:
                    print(notify)  # 打印出通知内容
                    # send_message(notify['content'])  可以发送通知到其他工具

        """
        self._api = api
        self._notify = _get_obj(self._api._data, ["notify"])
        # 用户未读取过的通知,用 list 类型尽量保证用户读到通知的顺序和进程收到的顺序一致,但是不能完全保证
        self._unread_notifies_list = [
            k for k in self._notify if not k.startswith("_")
        ]
        # 已经添加到 _unread_notifies 的通知
        self._processed_notifies_set = {
            k
            for k in self._notify if not k.startswith("_")
        }
        self._task = self._api.create_task(self._run())
Ejemplo n.º 12
0
    def set_commission(self, symbol: str, commission: float=float('nan')):
        """
        设置指定合约模拟交易的每手手续费。

        Args:
            symbol (str): 合约代码

            commission (float): 每手手续费

        Returns:
            float: 设置的每手手续费

        Example::

            from tqsdk import TqSim, TqApi, TqAuth

            sim = TqSim()
            api = TqApi(sim, auth=TqAuth("信易账户", "账户密码"))

            sim.set_commission("SHFE.cu2112", 50)

            print(sim.get_commission("SHFE.cu2112"))
        """
        if commission != commission:
            raise Exception("合约手续费不可以设置为 float('nan')")
        quote = _get_obj(self._data, ["quotes", symbol], Quote(self._api if hasattr(self, "_api") else None))
        quote["user_commission"] = commission
        if self._quote_tasks.get(symbol):
            self._quote_tasks[symbol]["quote_chan"].send_nowait({
                "quotes": {symbol: {"user_commission": commission}}
            })
        return commission
Ejemplo n.º 13
0
 async def async_update(self):
     await self.__dict__["_api"]._ensure_symbol_async(
         self.__dict__["_symbol"])
     ranking_id = _generate_uuid("PYSDK_rank")
     self.__dict__["_api"].create_task(self._get_ranking_data(ranking_id),
                                       _caller_api=True)  # 错误会抛给 api 处理
     symbol_rankings = _get_obj(self.__dict__["_api"]._data,
                                ["_symbol_rankings"])
     async with self.__dict__["_api"].register_update_notify(
             symbol_rankings) as update_chan:
         async for _ in update_chan:
             content = symbol_rankings.get(ranking_id, None)
             if content is None:
                 continue
             data = self._content_to_list(content)
             for i, d in enumerate(data):
                 self.loc[i] = d
             self.dropna(subset=[self.__dict__["_ranking_type"]],
                         inplace=True)
             self.sort_values(
                 by=['datetime', self.__dict__["_ranking_type"]],
                 inplace=True,
                 ignore_index=True)
             # 读完数据,清空数据
             await self.__dict__["_api"]._ws_md_recv_chan.send({
                 "aid":
                 "rtn_data",
                 "data": [{
                     "_symbol_rankings": {
                         ranking_id: None
                     }
                 }]
             })
             return self
Ejemplo n.º 14
0
 async def _ensure_quotes(self):
     await self._ensure_symbols()
     self._api._auth._has_md_grants([q._path[-1] for q in self])  # 权限检查
     # 发送的请求会请求到所有字段,如果是期权也会请求标的的合约信息
     underlying_symbols = set(
         [q.underlying_symbol for q in self if q.underlying_symbol])
     need_quotes = set([q._path[-1]
                        for q in self]).union(underlying_symbols)
     if need_quotes - self._api._requests["quotes"] != set():
         self._api._requests["quotes"] = self._api._requests[
             "quotes"].union(need_quotes)
         self._api._send_pack({
             "aid":
             "subscribe_quote",
             "ins_list":
             ",".join(self._api._requests["quotes"]),
         })
     if all([q.datetime != "" for q in self]):
         return self
     all_quotes = self + [
         _get_obj(self._api._data, ["quotes", s],
                  self._api._prototype["quotes"]["#"])
         for s in underlying_symbols
     ]
     async with self._api.register_update_notify(self) as update_chan:
         async for _ in update_chan:
             if all([q.datetime != "" for q in all_quotes]):
                 return self
Ejemplo n.º 15
0
async def _query_graphql_async(api, query_id, query):
    api._send_pack({"aid": "ins_query", "query_id": query_id, "query": query})
    symbols = _get_obj(api._data, ["symbols"])
    async with api.register_update_notify(symbols) as update_chan:
        async for _ in update_chan:
            s = symbols.get(query_id, {})
            if s.get("query") == query:
                break
Ejemplo n.º 16
0
 async def _ensure_quote(self, symbol, quote_chan):
     """quote收到行情后返回"""
     quote = _get_obj(self._data, ["quotes", symbol], Quote(self._api))
     _register_update_chan(quote, quote_chan)
     if quote.get("datetime", ""):
         return quote.copy()
     async for _ in quote_chan:
         quote_chan.task_done()
         if quote.get("datetime", ""):
             return quote.copy()
Ejemplo n.º 17
0
 def orders(self):
     tdict = _get_obj(self._api._data, ["trade", self._path[1], "orders"])
     fts = {
         order_id: order
         for order_id, order in tdict.items()
         if (not order_id.startswith("_")) and order.instrument_id ==
         self.instrument_id and order.exchange_id == self.exchange_id
         and order.status == "ALIVE"
     }
     return fts
Ejemplo n.º 18
0
    def orders(self):
        """
        与此持仓相关的开仓/平仓挂单

        :return: dict, 其中每个元素的key为委托单ID, value为 :py:class:`~tqsdk.objs.Order`
        """
        tdict = _get_obj(self._api._data, ["trade", self._api._account._account_id, "orders"])
        fts = {order_id: order for order_id, order in tdict.items() if (not order_id.startswith(
            "_")) and order.instrument_id == self.instrument_id and order.exchange_id == self.exchange_id and order.status == "ALIVE"}
        return fts
Ejemplo n.º 19
0
    def trade_records(self):
        """
        成交记录

        :return: dict, 其中每个元素的key为成交ID, value为 :py:class:`~tqsdk.objs.Trade`
        """
        tdict = _get_obj(self._api._data, ["trade", self._api._account._account_id, "trades"])
        fts = {trade_id: trade for trade_id, trade in tdict.items() if
               (not trade_id.startswith("_")) and trade.order_id == self.order_id}
        return fts
def download_symbol_dur(s, dur, api, file_name):
    csv_file = open(file_name, 'w', newline='')
    csv_writer = csv.writer(csv_file, dialect='excel')
    data_cols = KLINES_COLS if dur > 0 else TICKS_COLS
    csv_writer.writerow(["id", "datetime_nano", "datetime"] + data_cols)
    chart_info = {
        "aid": "set_chart",
        "chart_id": _generate_uuid("PYSDK_downloader"),
        "ins_list": s,
        "duration": int(dur*1e9),
        "view_width": DATA_LENGTH
    }
    api._send_chan.send_nowait(chart_info)
    chart = _get_obj(api._data, ["charts", chart_info["chart_id"]])
    path = ["klines", s, str(int(dur*1e9))] if dur > 0 else ["ticks", s]
    serial = _get_obj(api._data, path)
    end_time = time() + 10
    while True:
        api.wait_update(end_time)
        left_id = chart.get("left_id", -1)
        right_id = chart.get("right_id", -1)
        last_id = serial.get("last_id", -1)
        if (right_id > -1 and last_id > -1) and api._data.get("mdhis_more_data", True) is False:
            for current_id in range(max(left_id, 0), right_id + 1):
                item = serial["data"].get(str(current_id), {})
                row = [str(current_id), item["datetime"], _nano_to_str(item["datetime"])]
                for col in data_cols:
                    row.append(item.get(col, "#N/A"))
                csv_writer.writerow(row)
            break
        elif time() > end_time:
            print(f"request timeout {s} {dur} {file_name}")
            timeout_writer.writerow([s, dur, file_name])
            break
    csv_file.close()
    api._send_chan.send_nowait({
        "aid": "set_chart",
        "chart_id": chart_info["chart_id"],
        "ins_list": "",
        "duration": int(dur*1e9),
        "view_width": DATA_LENGTH,
    })
Ejemplo n.º 21
0
 async def _ensure_quote_info(self, symbol, quote_chan):
     """quote收到合约信息后返回"""
     quote = _get_obj(self._data, ["quotes", symbol], Quote(self._api))
     if quote.get("price_tick") == quote.get("price_tick"):
         return quote.copy()
     if quote.get("price_tick") != quote.get("price_tick"):
         await self._md_send_chan.send(_query_for_quote(symbol))
     async for _ in quote_chan:
         quote_chan.task_done()
         if quote.get("price_tick") == quote.get("price_tick"):
             return quote.copy()
Ejemplo n.º 22
0
 async def _ensure_quote(self, ins):
     # 在接新版合约服务器后,合约信息程序运行过程中查询得到的,这里不再能保证合约一定存在,需要添加 quote 默认值
     quote = _get_obj(self._data, ["quotes", ins], BtQuote(self._api))
     if math.isnan(quote.get("price_tick")):
         query_pack = _query_for_quote(ins)
         await self._md_send_chan.send(query_pack)
         async with TqChan(self._api, last_only=True) as update_chan:
             quote["_listener"].add(update_chan)
             while math.isnan(quote.get("price_tick")):
                 await update_chan.recv()
     if ins not in self._quotes or self._quotes[ins]["min_duration"] > 60000000000:
         await self._ensure_serial(ins, 60000000000)
Ejemplo n.º 23
0
    def get_trade(self,
                  trade_id: Optional[str] = None) -> Union[Trade, Entity]:
        """
        获取用户成交信息

        Args:
            trade_id (str): [可选]成交号, 不填成交号则返回所有委托单

        Returns:
            :py:class:`~tqsdk.objs.Trade`: 当指定了trade_id时, 返回一个成交对象引用. \
            其内容将在 :py:meth:`~tqsdk.api.TqApi.wait_update` 时更新.

            不填trade_id参数调用本函数, 将返回包含用户当前交易日所有成交记录的一个tqsdk.objs.Entity对象引用, 使用方法与dict一致, \
            其中每个元素的key为成交号, value为 :py:class:`~tqsdk.objs.Trade`

            推荐优先使用 :py:meth:`~tqsdk.objs.Order.trade_records` 获取某个委托单的相应成交记录, 仅当确有需要时才使用本函数.

        Example::

            # 多账户模式下, 分别获取各账户的成交记录
            from tqsdk import TqApi, TqAuth, TqMultiAccount

            account = TqAccount("N南华期货", "123456", "123456")
            tqkq = TqKq()
            tqsim = TqSim()
            api = TqApi(TqMultiAccount([account, tqkq, tqsim]), auth=TqAuth("信易账户", "账户密码"))
            trades1 = account.get_trade()
            trades2 = tqkq.get_trade()
            trades3 = tqsim.get_trade()
            print(trades1)
            print(trades2)
            print(trades3)
            api.close()
        """
        api = _get_api_instance(self)
        if trade_id:
            return _get_obj(api._data,
                            ["trade", self._account_key, "trades", trade_id],
                            Trade(api))
        return _get_obj(api._data, ["trade", self._account_key, "trades"])
def download_symbol_dur(s, dur, api, file_name, download_finished):
    chart_info = {
        "aid": "set_chart",
        "chart_id": _generate_uuid("PYSDK_downloader"),
        "ins_list": s,
        "duration": int(dur*1e9),
        "view_width": DATA_LENGTH
    }
    await api._send_chan.send(chart_info)
    chart = _get_obj(api._data, ["charts", chart_info["chart_id"]])
    path = ["klines", s, str(int(dur*1e9))] if dur > 0 else ["ticks", s]
    serial = _get_obj(api._data, path)
    async with api.register_update_notify() as chan:
        async for _ in chan:
            right_id = chart.get("right_id", -1)
            last_id = serial.get("last_id", -1)
            if (right_id > -1 and last_id > -1) and api._data.get("mdhis_more_data", True) is False:
                break   # 数据收到
    csv_file = open(file_name, 'w', newline='')
    csv_writer = csv.writer(csv_file, dialect='excel')
    data_cols = KLINES_COLS if dur > 0 else TICKS_COLS
    csv_writer.writerow(["id", "datetime_nano", "datetime"] + data_cols)
    left_id = chart.get("left_id", -1)
    right_id = chart.get("right_id", -1)
    for current_id in range(max(left_id, 0), right_id + 1):
        item = serial["data"].get(str(current_id), {})
        row = [str(current_id), item["datetime"], _nano_to_str(item["datetime"])]
        for col in data_cols:
            row.append(item.get(col, "#N/A"))
        csv_writer.writerow(row)
    csv_file.close()
    await api._send_chan.send({
        "aid": "set_chart",
        "chart_id": chart_info["chart_id"],
        "ins_list": "",
        "duration": int(dur * 1e9),
        "view_width": DATA_LENGTH,
    })
    download_finished[dur] = True
Ejemplo n.º 25
0
 async def _ensure_quote(self, symbol, quote_chan):
     """quote收到行情以及合约信息后返回"""
     quote = _get_obj(self._data, ["quotes", symbol], Quote(self._api))
     _register_update_chan(quote, quote_chan)
     if quote.get("datetime", "") and quote.get("price_tick") == quote.get("price_tick"):
         return quote.copy()
     if quote.get("price_tick") != quote.get("price_tick"):
         # 对于没有合约信息的 quote,发送查询合约信息的请求
         await self._md_send_chan.send(_query_for_quote(symbol))
     async for _ in quote_chan:
         quote_chan.task_done()
         if quote.get("datetime", "") and quote.get("price_tick") == quote.get("price_tick"):
             return quote.copy()
Ejemplo n.º 26
0
    def trade_price(self):
        """
        平均成交价

        :return: 当委托单部分成交或全部成交时, 返回成交部分的平均成交价. 无任何成交时, 返回 nan
        """
        tdict = _get_obj(self._api._data, ["trade", self._api._account._account_id, "trades"])
        sum_volume = sum([trade.volume for trade_id, trade in tdict.items() if
                          (not trade_id.startswith("_")) and trade.order_id == self.order_id])
        if sum_volume == 0:
            return float('nan')
        sum_amount = sum([trade.volume * trade.price for trade_id, trade in tdict.items() if
                          (not trade_id.startswith("_")) and trade.order_id == self.order_id])
        return sum_amount / sum_volume
Ejemplo n.º 27
0
    def set_margin(self, symbol: str, margin: float = float('nan')):
        """
        设置指定合约模拟交易的每手保证金。

        Args:
            symbol (str): 合约代码 (只支持期货合约)

            margin (float): 每手保证金

        Returns:
            float: 设置的每手保证金

        Example::

            from tqsdk import TqSim, TqApi, TqAuth

            sim = TqSim()
            api = TqApi(sim, auth=TqAuth("信易账户", "账户密码"))

            sim.set_margin("SHFE.cu2112", 26000)

            print(sim.get_margin("SHFE.cu2112"))
        """
        if margin != margin:
            raise Exception("合约手续费不可以设置为 float('nan')")
        quote = _get_obj(self._data, ["quotes", symbol],
                         Quote(self._api if hasattr(self, "_api") else None))
        quote["user_margin"] = margin
        if self._quote_tasks.get(symbol):
            self._quote_tasks[symbol]["quote_chan"].send_nowait(
                {"quotes": {
                    symbol: {
                        "user_margin": margin
                    }
                }})
            # 当用户设置保证金时,用户应该得到的效果是:
            # 在调用 sim.set_margin() 之后,立即调用 api.get_position(symbol),得到的 margin 字段应该按照新设置的保证金调整过,而且中间没有收到过行情更新包
            # 以下代码可以保证这个效果,说明:
            # 1. 持仓已经调整过:
            #   sim_trade 中持仓的 future_margin 字段更新,margin 会同时调整,那么 api 中持仓的 future_margin 更新时,margin 一定也已经更新
            # 2. 中间没有收到过行情更新包:
            #   前提1:根据 diff 协议,sim 收到 peek_message 时,会将缓存的 diffs 发给用户,当缓存的 diffs 为空,会转发 peek_message;
            #   前提2:api.wait_update() 会等到所有 task 都执行到 pending 状态,然后发送 peek_message 给 sim
            #   当用户代码执行到 sim.set_margin(),立即向 quote_chan 中发送一个数据包,quote_task 就会到 ready 状态,此时调用 wait_update(),
            #   到所有 task 执行到 pending 状态时,sim 的 diffs 中有数据了,此时收到 api 发来 peek_message 不会转发给上游,用户会先收到 sim 本身的账户数据,
            #   在下一次 wait_update,sim 的 diffs 为空,才会收到行情数据
            # 在回测时,以下代码应该只经历一次 wait_update
            while margin != self.get_position(symbol).get("future_margin"):
                self._api.wait_update()
        return margin
Ejemplo n.º 28
0
 async def _update_time_from_md(self):
     """监听行情更新并记录当时本地时间的task"""
     try:
         chan = TqChan(self._api, last_only=True)
         self._api.register_update_notify(self._quote,
                                          chan)  # quote有更新时: 更新记录的时间
         if isinstance(self._api._backtest, TqBacktest):
             # 回测情况下,在收到回测时间有更新的时候,也需要更新记录的时间
             self._api.register_update_notify(
                 _get_obj(self._api._data, ["_tqsdk_backtest"]), chan)
         async for _ in chan:
             self._local_time_record = time.time() - 0.005  # 更新最新行情时间时的本地时间
             self._local_time_record_update_chan.send_nowait(
                 True)  # 通知记录的时间有更新
     finally:
         await chan.close()
Ejemplo n.º 29
0
 async def _query_graphql(self):
     pack = {"query": self._query}
     symbols = _get_obj(self._api._data, ["symbols"])
     query_result = None
     for symbol in symbols.values():
         if symbol.items() >= pack.items():  # 检查是否发送过相同的请求
             query_result = symbol
     if query_result is None:
         await _query_graphql_async(self._api, self._query_id, self._query)
         query_result = symbols.get(self._query_id)
     self += self._filter(query_result)
     if isinstance(self._api._backtest, TqBacktest):  # 回测时,清空缓存的请求
         self._api._send_pack({
             "aid": "ins_query",
             "query_id": self._query_id,
             "query": ""
         })
     return self
Ejemplo n.º 30
0
    def get_account(self) -> SecurityAccount:
        """
        获取用户账户资金信息

        Returns:
            :py:class:`~tqsdk.objs.SecurityAccount`: 返回一个账户对象引用. 其内容将在 :py:meth:`~tqsdk.api.TqApi.wait_update` 时更新

        Example1::

            # 获取当前浮动盈亏
            from tqsdk import TqApi, TqAuth

            tqacc = TqAccount("N南华期货", "123456", "123456")
            api = TqApi(account=tqacc, auth=TqAuth("信易账户", "账户密码"))
            account = tqacc.get_account()
            print(account.float_profit)

            # 预计的输出是这样的:
            2180.0
            ...

        Example2::

            # 多账户模式下, 分别获取各账户浮动盈亏
            from tqsdk import TqApi, TqAuth, TqMultiAccount, TqAccount, TqKq, TqSim

            account = TqAccount("N南华期货", "123456", "123456")
            tqkq = TqKq()
            tqsim = TqSim()
            api = TqApi(TqMultiAccount([account, tqkq, tqsim]), auth=TqAuth("信易账户", "账户密码"))
            account1 = account.get_account()
            account2 = tqkq.get_account()
            account3 = tqsim.get_account()
            print(f"账户 1 浮动盈亏 {account1.float_profit}, 账户 2 浮动盈亏 {account2.float_profit}, 账户 3 浮动盈亏 {account3.float_profit}")
            api.close()

        """
        api = _get_api_instance(self)
        return _get_obj(api._data,
                        ["trade", self._account_key, "accounts", "CNY"],
                        SecurityAccount(api))