diff --git a/PKG-INFO b/PKG-INFO index 25fe2c4d..935ea73e 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: tqsdk -Version: 3.5.1 +Version: 3.5.2 Summary: TianQin SDK Home-page: https://www.shinnytech.com/tqsdk Author: TianQin diff --git a/doc/conf.py b/doc/conf.py index 4523b683..be4fea02 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -48,9 +48,9 @@ # built documents. # # The short X.Y version. -version = u'3.5.1' +version = u'3.5.2' # The full version, including alpha/beta/rc tags. -release = u'3.5.1' +release = u'3.5.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/version.rst b/doc/version.rst index 4e7ee7ad..19014aa5 100644 --- a/doc/version.rst +++ b/doc/version.rst @@ -2,6 +2,14 @@ 版本变更 ============================= +3.5.2 (2024/02/07) + +* 新增::py:class:`~tqsdk.objs.Quote` 增加以下属性 + :py:meth:`~tqsdk.objs.Quote.open_max_market_order_volume`、:py:meth:`~tqsdk.objs.Quote.open_max_limit_order_volume`、 + :py:meth:`~tqsdk.objs.Quote.open_min_market_order_volume`、:py:meth:`~tqsdk.objs.Quote.open_min_limit_order_volume`、 + :py:meth:`~tqsdk.objs.Quote.categories` + + 3.5.1 (2024/01/24) * 修复::py:meth:`~tqsdk.TqApi.query_his_cont_quotes` 接口在 3.4.11、3.5.0 版本上报错的问题 diff --git a/setup.py b/setup.py index 6d6221f7..6edd8ea0 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name='tqsdk', - version="3.5.1", + version="3.5.2", description='TianQin SDK', author='TianQin', author_email='tianqincn@gmail.com', diff --git a/tqsdk/__version__.py b/tqsdk/__version__.py index bf5afe7f..0bc4055f 100644 --- a/tqsdk/__version__.py +++ b/tqsdk/__version__.py @@ -1 +1 @@ -__version__ = '3.5.1' +__version__ = '3.5.2' diff --git a/tqsdk/api.py b/tqsdk/api.py index a31b3d5c..7bcbe909 100644 --- a/tqsdk/api.py +++ b/tqsdk/api.py @@ -3341,7 +3341,12 @@ def _init_serial(self, root_list, width, default, adj_type): values = serial["array"].T block = FloatBlock(values=values, ndim=2, placement=BlockPlacement(slice(0, len(columns)))) bm = BlockManagerUnconsolidated(blocks=[block], axes=[columns, index]) - serial["df"] = TqDataFrame(self, bm, copy=False) + # DeprecationWarning: + # Passing a BlockManagerUnconsolidated to TqDataFrame is deprecated and will raise in a future version. + # Use an empty dataframe instead. + temp_df = pd.DataFrame() + temp_df._mgr = bm + serial["df"] = TqDataFrame(self, temp_df, copy=False) serial["df"]["symbol"] = root_list[0]["_path"][1] for i in range(1, len(root_list)): serial["df"]["symbol" + str(i)] = root_list[i]["_path"][1] diff --git a/tqsdk/calendar.py b/tqsdk/calendar.py index 912a5e3d..d4a5a7b9 100644 --- a/tqsdk/calendar.py +++ b/tqsdk/calendar.py @@ -47,10 +47,7 @@ def _get_trading_calendar(start_dt: date, end_dt: date, headers=None): _init_chinese_rest_days(headers=headers) df = pd.DataFrame() df['date'] = pd.Series(pd.date_range(start=start_dt, end=end_dt, freq="D")) - df['trading'] = df['date'].dt.dayofweek.lt(5) - result = pd.merge(rest_days_df, df, sort=True, how="right", on="date") - result.fillna(True, inplace=True) - df['trading'] = result['trading'] & result['trading_restdays'] + df['trading'] = df['date'].dt.dayofweek.lt(5) & ~df['date'].isin(rest_days_df['date']) return df diff --git a/tqsdk/ins_schema.py b/tqsdk/ins_schema.py index 925b5930..6c8948d5 100644 --- a/tqsdk/ins_schema.py +++ b/tqsdk/ins_schema.py @@ -14,6 +14,12 @@ ######################################################################## Boolean = sgqlc.types.Boolean + +class Category(sgqlc.types.Enum): + __schema__ = ins_schema + __choices__ = ('AGRICULTURAL', 'CHEMICAL', 'COAL', 'EQUITY_INDEX', 'FERROUS', 'GRAIN', 'GREASE', 'LIGHT_INDUSTRY', 'NONFERROUS_METALS', 'OIL', 'PRECIOUS_METALS', 'SOFT_COMMODITY', 'TREASURY_BOND') + + class Class(sgqlc.types.Enum): __schema__ = ins_schema __choices__ = ('BOND', 'COMBINE', 'CONT', 'FUND', 'FUTURE', 'INDEX', 'OPTION', 'SPOT', 'STOCK') @@ -39,11 +45,12 @@ class Int64(sgqlc.types.Scalar): ######################################################################## class basic(sgqlc.types.Interface): __schema__ = ins_schema - __field_names__ = ('price_tick', 'derivatives', 'trading_time', 'trading_day', 'instrument_name', 'english_name', 'price_decs', 'class_', 'instrument_id', 'exchange_id', 'derivative') + __field_names__ = ('trading_time', 'instrument_name', 'instrument_id', 'derivative', 'ins_id', 'derivatives', 'exchange_id', 'instrument_name_wh', 'trading_day', 'english_name', 'price_decs', 'class_', 'py_wh', 'price_tick') price_tick = sgqlc.types.Field(Float, graphql_name='price_tick') derivatives = sgqlc.types.Field('derivativeConnection', graphql_name='derivatives', args=sgqlc.types.ArgDict(( ('class_', sgqlc.types.Arg(sgqlc.types.list_of(Class), graphql_name='class', default=None)), ('exchange_id', sgqlc.types.Arg(sgqlc.types.list_of(String), graphql_name='exchange_id', default=None)), + ('expired', sgqlc.types.Arg(Boolean, graphql_name='expired', default=None)), ('timestamp', sgqlc.types.Arg(Int64, graphql_name='timestamp', default=None)), )) ) @@ -55,13 +62,17 @@ class basic(sgqlc.types.Interface): class_ = sgqlc.types.Field(String, graphql_name='class') instrument_id = sgqlc.types.Field(String, graphql_name='instrument_id') exchange_id = sgqlc.types.Field(String, graphql_name='exchange_id') + ins_id = sgqlc.types.Field(String, graphql_name='ins_id') + instrument_name_wh = sgqlc.types.Field(String, graphql_name='instrument_name_wh') + py_wh = sgqlc.types.Field(String, graphql_name='py_wh') + price_tick = sgqlc.types.Field(Float, graphql_name='price_tick') derivative = sgqlc.types.Field('derivativeConnection', graphql_name='derivative', args=sgqlc.types.ArgDict(( ('class_', sgqlc.types.Arg(Class, graphql_name='class', default=None)), ('exchange_id', sgqlc.types.Arg(String, graphql_name='exchange_id', default=None)), + ('expired', sgqlc.types.Arg(Boolean, graphql_name='expired', default=None)), )) ) - class derivative(sgqlc.types.Interface): __schema__ = ins_schema __field_names__ = ('underlying',) @@ -94,6 +105,7 @@ class rootQuery(sgqlc.types.Type): ('expired', sgqlc.types.Arg(Boolean, graphql_name='expired', default=None)), ('has_night', sgqlc.types.Arg(Boolean, graphql_name='has_night', default=None)), ('has_derivatives', sgqlc.types.Arg(Boolean, graphql_name='has_derivatives', default=None)), + ('categories', sgqlc.types.Arg(sgqlc.types.list_of(Category), graphql_name='categories', default=None)), )) ) symbol_info = sgqlc.types.Field(sgqlc.types.list_of('allClassUnion'), graphql_name='symbol_info', args=sgqlc.types.ArgDict(( @@ -110,7 +122,7 @@ class rootQuery(sgqlc.types.Type): class securities(sgqlc.types.Interface): __schema__ = ins_schema - __field_names__ = ('status', 'public_float_share_quantity', 'currency', 'face_value', 'first_trading_day', 'first_trading_datetime', 'buy_volume_unit', 'sell_volume_unit') + __field_names__ = ('currency', 'face_value', 'first_trading_day', 'first_trading_datetime', 'buy_volume_unit', 'sell_volume_unit', 'status', 'public_float_share_quantity') status = sgqlc.types.Field(String, graphql_name='status') public_float_share_quantity = sgqlc.types.Field(Int64, graphql_name='public_float_share_quantity') currency = sgqlc.types.Field(String, graphql_name='currency') @@ -123,7 +135,7 @@ class securities(sgqlc.types.Interface): class tradeable(sgqlc.types.Interface): __schema__ = ins_schema - __field_names__ = ('quote_multiple', 'pre_close', 'upper_limit', 'lower_limit', 'volume_multiple') + __field_names__ = ('volume_multiple', 'quote_multiple', 'pre_close', 'upper_limit', 'lower_limit') quote_multiple = sgqlc.types.Field(Float, graphql_name='quote_multiple') pre_close = sgqlc.types.Field(Float, graphql_name='pre_close') upper_limit = sgqlc.types.Field(Float, graphql_name='upper_limit') @@ -131,6 +143,13 @@ class tradeable(sgqlc.types.Interface): volume_multiple = sgqlc.types.Field(Float, graphql_name='volume_multiple') +class categoryInfo(sgqlc.types.Type): + __schema__ = ins_schema + __field_names__ = ('id', 'name') + id = sgqlc.types.Field(String, graphql_name='id') + name = sgqlc.types.Field(String, graphql_name='name') + + class tradingTime(sgqlc.types.Type): __schema__ = ins_schema __field_names__ = ('day', 'night') @@ -147,13 +166,23 @@ class bond(sgqlc.types.Type, basic, tradeable, securities): class combine(sgqlc.types.Type, basic): __schema__ = ins_schema - __field_names__ = ('expire_datetime', 'expired', 'leg1', 'leg2', 'max_limit_order_volume', 'max_market_order_volume', 'product_id') + __field_names__ = ('close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'expire_datetime', 'expired', 'leg1', 'leg2', 'max_limit_order_volume', 'max_market_order_volume', 'min_limit_order_volume', 'min_market_order_volume', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'product_id') + close_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_limit_order_volume') + close_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_market_order_volume') + close_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_limit_order_volume') + close_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_market_order_volume') expire_datetime = sgqlc.types.Field(Int64, graphql_name='expire_datetime') expired = sgqlc.types.Field(Boolean, graphql_name='expired') leg1 = sgqlc.types.Field('allClassUnion', graphql_name='leg1') leg2 = sgqlc.types.Field('allClassUnion', graphql_name='leg2') max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='max_limit_order_volume') max_market_order_volume = sgqlc.types.Field(Int, graphql_name='max_market_order_volume') + min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='min_limit_order_volume') + min_market_order_volume = sgqlc.types.Field(Int, graphql_name='min_market_order_volume') + open_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_limit_order_volume') + open_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_market_order_volume') + open_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_limit_order_volume') + open_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_market_order_volume') product_id = sgqlc.types.Field(String, graphql_name='product_id') @@ -170,7 +199,12 @@ class fund(sgqlc.types.Type, basic, tradeable, securities): class future(sgqlc.types.Type, basic, tradeable): __schema__ = ins_schema - __field_names__ = ('commission', 'delivery_month', 'delivery_year', 'expire_datetime', 'expired', 'margin', 'max_limit_order_volume', 'max_market_order_volume', 'mmsa', 'pre_open_interest', 'product_id', 'product_short_name', 'settlement_price') + __field_names__ = ('categories', 'close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'commission', 'delivery_month', 'delivery_year', 'expire_datetime', 'expired', 'margin', 'max_limit_order_volume', 'max_market_order_volume', 'min_limit_order_volume', 'min_market_order_volume', 'mmsa', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'pre_open_interest', 'product_id', 'product_short_name', 'product_short_name_wh', 'settlement_price') + categories = sgqlc.types.Field(sgqlc.types.list_of(categoryInfo), graphql_name='categories') + close_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_limit_order_volume') + close_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_market_order_volume') + close_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_limit_order_volume') + close_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_market_order_volume') commission = sgqlc.types.Field(Float, graphql_name='commission') delivery_month = sgqlc.types.Field(Int, graphql_name='delivery_month') delivery_year = sgqlc.types.Field(Int, graphql_name='delivery_year') @@ -179,10 +213,17 @@ class future(sgqlc.types.Type, basic, tradeable): margin = sgqlc.types.Field(Float, graphql_name='margin') max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='max_limit_order_volume') max_market_order_volume = sgqlc.types.Field(Int, graphql_name='max_market_order_volume') + min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='min_limit_order_volume') + min_market_order_volume = sgqlc.types.Field(Int, graphql_name='min_market_order_volume') mmsa = sgqlc.types.Field(Boolean, graphql_name='mmsa') + open_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_limit_order_volume') + open_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_market_order_volume') + open_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_limit_order_volume') + open_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_market_order_volume') pre_open_interest = sgqlc.types.Field(Int64, graphql_name='pre_open_interest') product_id = sgqlc.types.Field(String, graphql_name='product_id') product_short_name = sgqlc.types.Field(String, graphql_name='product_short_name') + product_short_name_wh = sgqlc.types.Field(String, graphql_name='product_short_name_wh') settlement_price = sgqlc.types.Field(Float, graphql_name='settlement_price') @@ -194,8 +235,12 @@ class index(sgqlc.types.Type, basic): class option(sgqlc.types.Type, basic, tradeable, derivative): __schema__ = ins_schema - __field_names__ = ('call_or_put', 'exercise_type', 'expire_datetime', 'expired', 'last_exercise_datetime', 'last_exercise_day', 'max_limit_order_volume', 'max_market_order_volume', 'pre_open_interest', 'product_short_name', 'settlement_price', 'strike_price') + __field_names__ = ('call_or_put', 'close_max_limit_order_volume', 'close_max_market_order_volume', 'close_min_limit_order_volume', 'close_min_market_order_volume', 'exercise_type', 'expire_datetime', 'expired', 'last_exercise_datetime', 'last_exercise_day', 'max_limit_order_volume', 'max_market_order_volume', 'min_limit_order_volume', 'min_market_order_volume', 'open_max_limit_order_volume', 'open_max_market_order_volume', 'open_min_limit_order_volume', 'open_min_market_order_volume', 'pre_open_interest', 'product_short_name', 'settlement_price', 'strike_price') call_or_put = sgqlc.types.Field(String, graphql_name='call_or_put') + close_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_limit_order_volume') + close_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_max_market_order_volume') + close_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_limit_order_volume') + close_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='close_min_market_order_volume') exercise_type = sgqlc.types.Field(String, graphql_name='exercise_type') expire_datetime = sgqlc.types.Field(Int64, graphql_name='expire_datetime') expired = sgqlc.types.Field(Boolean, graphql_name='expired') @@ -203,6 +248,12 @@ class option(sgqlc.types.Type, basic, tradeable, derivative): last_exercise_day = sgqlc.types.Field(Int64, graphql_name='last_exercise_day') max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='max_limit_order_volume') max_market_order_volume = sgqlc.types.Field(Int, graphql_name='max_market_order_volume') + min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='min_limit_order_volume') + min_market_order_volume = sgqlc.types.Field(Int, graphql_name='min_market_order_volume') + open_max_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_limit_order_volume') + open_max_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_max_market_order_volume') + open_min_limit_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_limit_order_volume') + open_min_market_order_volume = sgqlc.types.Field(Int, graphql_name='open_min_market_order_volume') pre_open_interest = sgqlc.types.Field(Int64, graphql_name='pre_open_interest') product_short_name = sgqlc.types.Field(String, graphql_name='product_short_name') settlement_price = sgqlc.types.Field(Float, graphql_name='settlement_price') @@ -294,9 +345,16 @@ class allClassUnion(sgqlc.types.Union): future_frag.settlement_price() future_frag.max_market_order_volume() future_frag.max_limit_order_volume() +future_frag.min_market_order_volume() +future_frag.min_limit_order_volume() +future_frag.open_max_market_order_volume() +future_frag.open_max_limit_order_volume() +future_frag.open_min_market_order_volume() +future_frag.open_min_limit_order_volume() future_frag.margin() future_frag.commission() future_frag.mmsa() +future_frag.categories() option_frag = Fragment(option, 'option') option_frag.pre_open_interest() @@ -307,6 +365,12 @@ class allClassUnion(sgqlc.types.Union): option_frag.settlement_price() option_frag.max_market_order_volume() option_frag.max_limit_order_volume() +option_frag.min_market_order_volume() +option_frag.min_limit_order_volume() +option_frag.open_max_market_order_volume() +option_frag.open_max_limit_order_volume() +option_frag.open_min_market_order_volume() +option_frag.open_min_limit_order_volume() option_frag.strike_price() option_frag.call_or_put() option_frag.exercise_type() @@ -317,6 +381,12 @@ class allClassUnion(sgqlc.types.Union): combine_frag.expire_datetime() combine_frag.max_market_order_volume() combine_frag.max_limit_order_volume() +combine_frag.min_market_order_volume() +combine_frag.min_limit_order_volume() +combine_frag.open_max_market_order_volume() +combine_frag.open_max_limit_order_volume() +combine_frag.open_min_market_order_volume() +combine_frag.open_min_limit_order_volume() combine_frag.leg1().__as__(basic).instrument_id() combine_frag.leg2().__as__(basic).instrument_id() diff --git a/tqsdk/objs.py b/tqsdk/objs.py index 524a68d1..11297021 100644 --- a/tqsdk/objs.py +++ b/tqsdk/objs.py @@ -5,6 +5,7 @@ import copy import json import warnings +from typing import List from tqsdk.diff import _get_obj from tqsdk.entity import Entity @@ -128,6 +129,14 @@ def __init__(self, api): self.min_limit_order_volume: int = 0 #: 最小市价单手数 self.min_market_order_volume: int = 0 + #: 最大市价开仓手数 + self.open_max_market_order_volume: int = 0 + #: 最大限价开仓手数 + self.open_max_limit_order_volume: int = 0 + #: 最小市价开仓手数 + self.open_min_market_order_volume: int = 0 + #: 最小限价开仓手数 + self.open_min_limit_order_volume: int = 0 #: 标的合约 self.underlying_symbol: str = "" #: 行权价 @@ -172,6 +181,8 @@ def __init__(self, api): self.cash_dividend_ratio: list = [] #: 距离到期日的剩余天数(自然日天数),正数表示距离到期日的剩余天数,0表示到期日当天,负数表示距离到期日已经过去的天数 self.expire_rest_days: int = float('nan') + #: 板块信息 + self.categories: List[CategoryInfo] = [] def _instance_entity(self, path): super(Quote, self)._instance_entity(path) @@ -194,6 +205,16 @@ def __await__(self): return self._task.__await__() +class CategoryInfo(Entity): + """CategoryInfo 是一个板块信息对象""" + + def __init__(self): + #: 板块代码 + self.id: str = "" + #: 板块名称 + self.name: str = "" + + class TradingTime(Entity): """ TradingTime 是一个交易时间对象 它不是一个可单独使用的类,而是用于定义 Quote 的 trading_time 字段的类型 diff --git a/tqsdk/objs_not_entity.py b/tqsdk/objs_not_entity.py index 9722bcfd..7f4e9437 100644 --- a/tqsdk/objs_not_entity.py +++ b/tqsdk/objs_not_entity.py @@ -6,6 +6,7 @@ from typing import Callable, Tuple import aiohttp +import numpy from pandas import DataFrame, Series from sgqlc.operation import Operation from tqsdk.backtest import TqBacktest @@ -196,6 +197,18 @@ def __await__(self): return self.__dict__["_task"].__await__() +def _get_col_dtype(col): + if col == "expired": + return bool + if col in [ + "price_tick", "volume_multiple", "strike_price", "upper_limit", "lower_limit", "pre_settlement", "pre_close", + "pre_open_interest", "max_limit_order_volume", "max_market_order_volume", "expire_datetime", "expire_rest_days", + "delivery_year", "delivery_month", "last_exercise_datetime", "exercise_year", "exercise_month", + ]: + return float + return object + + class TqSymbolDataFrame(DataFrame): def __init__(self, api, symbol_list, backtest_timestamp, *args, **kwargs): @@ -260,7 +273,7 @@ async def async_update(self): self._quotes_to_dataframe(quotes) if self.__dict__["_backtest_timestamp"]: # 回测时这些字段应该为 nan - self.loc[:, ["upper_limit", "lower_limit", "pre_settlement", "pre_open_interest", "pre_close"]] = float('nan') + self.loc[:, ["upper_limit", "lower_limit", "pre_settlement", "pre_open_interest", "pre_close"]] = numpy.nan # 回测时清空请求,不缓存请求内容 self.__dict__["_api"]._send_pack({ "aid": "ins_query", @@ -283,9 +296,15 @@ def _quotes_to_dataframe(self, quotes): for s in self.__dict__["_symbol_list"]] elif col == "trading_time_day" or col == "trading_time_night": k = 'day' if col == "trading_time_day" else 'night' - self[col] = Series([self._get_trading_time(quotes, s, k) for s in self.__dict__["_symbol_list"]]) + self[col] = Series( + [self._get_trading_time(quotes, s, k) for s in self.__dict__["_symbol_list"]], + dtype=_get_col_dtype(col) + ) else: - self[col] = Series([quotes[s].get(col, default_quote[col]) for s in self.__dict__["_symbol_list"]]) + self[col] = Series( + [quotes[s].get(col, default_quote[col]) for s in self.__dict__["_symbol_list"]], + dtype=_get_col_dtype(col) + ) def __await__(self): return self.__dict__["_task"].__await__()