diff --git a/prod/jobs/refill_future_renko.py b/prod/jobs/refill_future_renko.py index 17f1cf36..ace8b1b3 100644 --- a/prod/jobs/refill_future_renko.py +++ b/prod/jobs/refill_future_renko.py @@ -1,5 +1,6 @@ # flake8: noqa - +# 自动补全期货指数合约renko bar => Mongodb +# 下载的tick数据缓存 => tick_data/tdx/future import sys, os, copy, csv, signal vnpy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) @@ -23,7 +24,7 @@ if __name__ == "__main__": setting = { "host": host, "db_name": FUTURE_RENKO_DB_NAME, - "cache_folder": os.path.join(vnpy_root, 'ticks', 'tdx', 'future') + "cache_folder": os.path.join(vnpy_root, 'tick_data', 'tdx', 'future') } builder = FutureRenkoRebuilder(setting) diff --git a/requirements.txt b/requirements.txt index 2eccd11a..ee7b2c78 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,7 @@ ta-lib ibapi deap pyzmq -wmi QScintilla pytdx pykalman +cython diff --git a/vnpy/app/cta_crypto/back_testing.py b/vnpy/app/cta_crypto/back_testing.py index 6d79acae..84db0ee3 100644 --- a/vnpy/app/cta_crypto/back_testing.py +++ b/vnpy/app/cta_crypto/back_testing.py @@ -660,6 +660,9 @@ class BackTestingEngine(object): elif filename.endswith(".pyd"): strategy_module_name = ".".join( [module_name, filename.split(".")[0]]) + elif filename.endswith(".so"): + strategy_module_name = ".".join( + [module_name, filename.split(".")[0]]) else: continue self.load_strategy_class_from_module(strategy_module_name) diff --git a/vnpy/app/cta_crypto/engine.py b/vnpy/app/cta_crypto/engine.py index e61acd91..989a2a99 100644 --- a/vnpy/app/cta_crypto/engine.py +++ b/vnpy/app/cta_crypto/engine.py @@ -216,8 +216,9 @@ class CtaEngine(BaseEngine): # 主动获取所有策略得持仓信息 all_strategy_pos = self.get_all_strategy_pos() - # 比对仓位,使用上述获取得持仓信息,不用重复获取 - self.compare_pos(strategy_pos_list=copy(all_strategy_pos)) + if dt.minute % 5 == 0: + # 比对仓位,使用上述获取得持仓信息,不用重复获取 + self.compare_pos(strategy_pos_list=copy(all_strategy_pos)) # 推送到事件 self.put_all_strategy_pos_event(all_strategy_pos) @@ -1274,6 +1275,9 @@ class CtaEngine(BaseEngine): elif filename.endswith(".pyd"): strategy_module_name = ".".join( [module_name, filename.split(".")[0]]) + elif filename.endswith(".so"): + strategy_module_name = ".".join( + [module_name, filename.split(".")[0]]) else: continue self.load_strategy_class_from_module(strategy_module_name) diff --git a/vnpy/app/cta_strategy_pro/back_testing.py b/vnpy/app/cta_strategy_pro/back_testing.py index 7d580e05..d2baa03e 100644 --- a/vnpy/app/cta_strategy_pro/back_testing.py +++ b/vnpy/app/cta_strategy_pro/back_testing.py @@ -633,6 +633,9 @@ class BackTestingEngine(object): elif filename.endswith(".pyd"): strategy_module_name = ".".join( [module_name, filename.split(".")[0]]) + elif filename.endswith(".so"): + strategy_module_name = ".".join( + [module_name, filename.split(".")[0]]) else: continue self.load_strategy_class_from_module(strategy_module_name) diff --git a/vnpy/app/cta_strategy_pro/engine.py b/vnpy/app/cta_strategy_pro/engine.py index 5bc5aac3..2a447328 100644 --- a/vnpy/app/cta_strategy_pro/engine.py +++ b/vnpy/app/cta_strategy_pro/engine.py @@ -213,7 +213,7 @@ class CtaEngine(BaseEngine): all_trading = False dt = datetime.now() - + # 每分钟执行的逻辑 if self.last_minute != dt.minute: self.last_minute = dt.minute @@ -221,8 +221,10 @@ class CtaEngine(BaseEngine): # 主动获取所有策略得持仓信息 all_strategy_pos = self.get_all_strategy_pos() - # 比对仓位,使用上述获取得持仓信息,不用重复获取 - self.compare_pos(strategy_pos_list=copy(all_strategy_pos)) + # 每5分钟检查一次 + if dt.minute % 5 == 0: + # 比对仓位,使用上述获取得持仓信息,不用重复获取 + self.compare_pos(strategy_pos_list=copy(all_strategy_pos)) # 推送到事件 self.put_all_strategy_pos_event(all_strategy_pos) @@ -1244,6 +1246,9 @@ class CtaEngine(BaseEngine): elif filename.endswith(".pyd"): strategy_module_name = ".".join( [module_name, filename.split(".")[0]]) + elif filename.endswith(".so"): + strategy_module_name = ".".join( + [module_name, filename.split(".")[0]]) else: continue self.load_strategy_class_from_module(strategy_module_name) @@ -1313,7 +1318,7 @@ class CtaEngine(BaseEngine): # 兼容处理,如果strategy是None,通过name获取 if strategy is None: if name not in self.strategies: - self.write_log(u'getStategyPos 策略实例不存在:' + name) + self.write_log(u'get_strategy_pos 策略实例不存在:' + name) return [] # 获取策略实例 strategy = self.strategies[name] diff --git a/vnpy/app/cta_strategy_pro/portfolio_testing.py b/vnpy/app/cta_strategy_pro/portfolio_testing.py index 60e4d334..7cbc5b34 100644 --- a/vnpy/app/cta_strategy_pro/portfolio_testing.py +++ b/vnpy/app/cta_strategy_pro/portfolio_testing.py @@ -63,7 +63,7 @@ class PortfolioTestingEngine(BackTestingEngine): if vt_symbol in self.bar_df_dict: return True - if not os.path.exists(bar_file): + if bar_file is None or not os.path.exists(bar_file): self.write_error(u'回测时,{}对应的csv bar文件{}不存在'.format(vt_symbol, bar_file)) return False diff --git a/vnpy/component/cta_position.py b/vnpy/component/cta_position.py index 5e4b7011..8a735709 100644 --- a/vnpy/component/cta_position.py +++ b/vnpy/component/cta_position.py @@ -18,14 +18,14 @@ class CtaPosition(CtaComponent): self.short_pos = 0 # 空仓持仓(负数) self.pos = 0 # 持仓状态 0:空仓/对空平等; >=1 净多仓 ;<=-1 净空仓 self.maxPos = sys.maxsize # 最大持仓量(多仓+空仓总量) - + self.name = getattr(strategy, 'strategy_name', 'strategy') def open_pos(self, direction: Direction, volume: float): """开、加仓""" # volume: 正整数 if direction == Direction.LONG: # 加多仓 if (max(self.pos, self.long_pos) + volume) > self.maxPos: - self.write_error(content=f'开仓异常,净:{self.pos},多:{self.long_pos},加多:{volume},超过:{self.maxPos}') + self.write_error(content=f'{self.name} 开仓异常,净:{self.pos},多:{self.long_pos},加多:{volume},超过:{self.maxPos}') # 更新 pre_long_pos = self.long_pos @@ -34,20 +34,20 @@ class CtaPosition(CtaComponent): self.pos += volume self.long_pos = round(self.long_pos, 7) self.pos = round(self.pos, 7) - self.write_log(f'多仓:{pre_long_pos}->{self.long_pos}') - self.write_log(f'净:{pre_pos}->{self.pos}') + self.write_log(f'{self.name} 多仓:{pre_long_pos}->{self.long_pos}') + self.write_log(f'{self.name} 净:{pre_pos}->{self.pos}') if direction == Direction.SHORT: # 加空仓 if (min(self.pos, self.short_pos) - volume) < (0 - self.maxPos): - self.write_error(content=f'开仓异常,净:{self.pos},空:{self.short_pos},加空:{volume},超过:{self.maxPos}') + self.write_error(content=f'{self.name} 开仓异常,净:{self.pos},空:{self.short_pos},加空:{volume},超过:{self.maxPos}') pre_short_pos = self.short_pos pre_pos = self.pos self.short_pos -= volume self.pos -= volume self.short_pos = round(self.short_pos, 7) self.pos = round(self.pos, 7) - self.write_log(f'空仓:{pre_short_pos}->{self.short_pos}') - self.write_log(f'净:{pre_pos}->{self.pos}') + self.write_log(f'{self.name} 空仓:{pre_short_pos}->{self.short_pos}') + self.write_log(f'{self.name} 净:{pre_pos}->{self.pos}') return True def close_pos(self, direction: Direction, volume: float): @@ -56,7 +56,7 @@ class CtaPosition(CtaComponent): if direction == Direction.LONG: # 平空仓 Cover if self.short_pos + volume > 0: - self.write_error(u'平仓异常,超出仓位。净:{0},空:{1},平仓:{2}'.format(self.pos, self.short_pos, volume)) + self.write_error(f'{self.name} 平仓异常,超出仓位。净:{self.pos},空:{self.short_pos},平仓:{volume}') pre_short_pos = self.short_pos pre_pos = self.pos @@ -64,15 +64,15 @@ class CtaPosition(CtaComponent): self.pos += volume self.short_pos = round(self.short_pos, 7) self.pos = round(self.pos, 7) - self.write_log(f'空仓:{pre_short_pos}->{self.short_pos}') - self.write_log(f'净:{pre_pos}->{self.pos}') + self.write_log(f'{self.name} 空仓:{pre_short_pos}->{self.short_pos}') + self.write_log(f'{self.name} 净:{pre_pos}->{self.pos}') # 更新上层策略的pos。该方法不推荐使用 self.strategy.pos = self.pos if direction == Direction.SHORT: # 平多仓 if self.long_pos - volume < 0: - self.write_error(u'平仓异常,超出仓位。净:{0},多:{1},平仓:{2}'.format(self.pos, self.long_pos, volume)) + self.write_error(f'{self.name} 平仓异常,超出仓位。净:{self.pos},多:{self.long_pos},平仓:{volume}') pre_long_pos = self.long_pos pre_pos = self.pos @@ -81,14 +81,14 @@ class CtaPosition(CtaComponent): self.long_pos = round(self.long_pos, 7) self.pos = round(self.pos, 7) - self.write_log(f'多仓:{pre_long_pos}->{self.long_pos}') - self.write_log(f'净:{pre_pos}->{self.pos}') + self.write_log(f'{self.name} 多仓:{pre_long_pos}->{self.long_pos}') + self.write_log(f'{self.name} 净:{pre_pos}->{self.pos}') return True def clear(self): """清除状态""" - self.write_log(u'清除所有持仓状态') + self.write_log(f'{self.name} 清除所有持仓状态') self.pos = 0 self.long_pos = 0 self.short_pos = 0 diff --git a/vnpy/data/mongo/mongo_data.py b/vnpy/data/mongo/mongo_data.py index 5b640cd0..89e18290 100644 --- a/vnpy/data/mongo/mongo_data.py +++ b/vnpy/data/mongo/mongo_data.py @@ -41,6 +41,13 @@ class MongoData(object): def write_error(self, content): print(content, file=sys.stderr) + def get_collections(self, db_name): + """获取所有collection""" + if not self.db_client: + return [] + db = self.db_client[db_name] + return db.list_collection_names() + # ---------------------------------------------------------------------- def db_insert(self, db_name, col_name, d): """向MongoDB中插入数据,d是具体数据""" @@ -308,4 +315,4 @@ class MongoData(object): if __name__ == "__main__": m = MongoData(host='localhost', port=27017) - m.db_create_index('FutureRenko_Db', 'AU_5', 'datetime', 1) + m.db_create_index('FutureRenko', 'AU_5', 'datetime', 1) diff --git a/vnpy/data/stock/adjust_factor.py b/vnpy/data/stock/adjust_factor.py index fd98a526..f22b5d78 100644 --- a/vnpy/data/stock/adjust_factor.py +++ b/vnpy/data/stock/adjust_factor.py @@ -56,7 +56,7 @@ def get_adjust_factor(vt_symbol: str, stock_name: str = '', need_login: bool = T print(f'开始获取{stock_name} {bs_code}得复权因子') rs = bs.query_adjust_factor( code=bs_code, - start_date='2006-01-01' + start_date='2000-01-01' ) if rs.error_code != '0': print(f'证券宝获取沪深A股复权因子数据,错误代码:{rs.error_code}, 错误信息:{rs.error_msg}') diff --git a/vnpy/data/tdx/README.md b/vnpy/data/tdx/README.md index ac56cec0..987712d1 100644 --- a/vnpy/data/tdx/README.md +++ b/vnpy/data/tdx/README.md @@ -12,3 +12,146 @@ 1.tdx_stock_data, 股票数据接口 2.tdx_future_data, 期货数据接口 + + +上海交易所 + + 首位代码 产品定义 + 0 国债/指数 + 1 债券 + 2 回购 + 3 期货 + 4 备用 + 5 基金/权证 + 6 A股 + 7 非交易业务(发行、权益分配) + 8 备用 + 9 B股 + 第一位 第2-3位 业务定义 + 0 00 上证指数、沪深300指数、中证指数 + 09 国债(2000年前发行) + 10 国债(2000年-2009年发行) + 19 固定收益电子平台交易国债 + 20 记账式贴现国债 + 90 新国债质押式回购质押券出入库(对应010***国债) + 99 新国债质押式回购质押券出入库(对应009***国债) + 1 00 可转债(对应600*),其中1009用于转债回售 + 04 公司债及国家发改委等核准发行的、登记在证券账户的债券(对应122***)出入库 + 05 105000-105899用于分离债(对应126)出入库, 105900-105999用于企业债(120、129***)出入库 + 06 地方政府债出入库(对应130***) + 07 记账式贴现国债出入库(对应020***) + 10 可转债(对应600***) + 12 可转债(对应600***) + 13 可转债(对应601***) + 20 企业债 + 21 资产证券化 + 22 122000-122499用于公司债,122500-122999用于国家发改委等核准发行的、登记在证券账户的债券 + 26 分离交易的可转换公司债 + 28 可交换公司债 + 29 企业债 + 30 地方政府债 + 81 可转债转股(对应600***),已不再增用 + 90 可转债转股(对应600***) + 91 可转债转股(对应601***) + 92 可交换公司债转股(对应128***) + 2 01 国债回购(席位托管方式) + 02 企业债回购 + 03 国债买断式回购 + 04 债券质押式回购(账户托管方式) + 05 债券质押式报价回购 + 3 10 国债期货(暂停交易) + 5 00 契约型封闭式基金 + 10 交易型开放式指数证券投资基金 + 19 开放式基金申赎 + 21 开放式基金认购 + 22 开放式基金跨市场转托管 + 23 开放式基金分红 + 24 开放式基金基金转换 + 80 权证(含股改权证、公司权证) + 82 权证行权 + 6 00 A股证券 + 01 A股证券 + 7 00 配股(对应600***) + 02 职工股配股(对应600***) + 04 持股配债 + 05 基金扩募 + 06 要约收购 + 30 申购、增发(对应600***) + 31 持股增发(对应600***) + 33 可转债申购(对应600***) + 35 基金申购 + 38 网上投票(对应600***) + 40 申购款或增发款(对应600***) + 41 申购或增发配号(对应600***) + 43 可转债发债款(对应600***) + 44 可转债配号(对应600***) + 45 基金申购款 + 46 基金申购配号 + 51 751000-751199用于国债分销,751900-751969用于地方政府债(对应130)分销,751970-751999用于公司债及国家发改委等核准发行的、登记在证券账户的债券(对应122)分销 + 60 配股(对应601***) + 62 职工股配股(对应601***) + 80 申购、增发(对应601***) + 81 持股增发(对应601***) + 83 可转债申购(对应601***) + 88 网络投票(对应601***) + 90 申购款或增发款(对应601***) + 91 申购或增发配号(对应601***) + 93 可转债申购款(对应601***) + 94 可转债配号(对应601***) + 99 指定交易(含指定交易、撤销指定、回购指定撤销、A股密码服务等) + 9 00 B股证券 + 38 网上投票(B股) + 39 B股网络投票密码服务(现仅用939988) + + + + + + 深圳 + + 第一位 第二位 第三位 定义 + 0 0 0-1 主板 A 股 + 2-4 中小企业板股票 + 3 0-2 主板 A 股及中小企业板股票认购权证 + 6 创业板股权激励计划涉及的员工认股权 + 7 [037000,037499]主板 A 股股权激励计划涉及的员工认股权[037500,037999]中小企业板股权激励计划涉及的员工认股权 + 8-9 主板 A 股及中小企业板股票认沽权证 + 7 0-1 主板 A 股增发 主板可转换公司债券申购 + 2-4 中小企业板股票增发 中小企业板可转换公司债券申购 + 8 0-1 主板 A 股配股优先权 主板可转换公司债券的优先权认购 + 2-4 中小企业板配股优先权 中小企业板可转换公司债券的优先权认购 + 1 0 0-7 附息式国债 + [101650,101699]是债券分销代码区间,分销代码位于[101660, 101674]区间时实行投资者适当性管理 + 8 贴现式国债 + 9 地方政府债 + 1 1 企业债 + 2 公司债 + 5 可分离交易的可转换公司债券 + 7 [117000,117499]为中小企业可交换私募债 + [117500,117999]为证券公司短期债 + 8 [118900,118999]为证券公司次级债 + [118000,118899]为其他中小企业私募债 + 9 [119000,119499]为资产支持证券 ABS + 2 0-9 可转换公司债券(已发行的可转换公司债券继续保留原代码) + [123000,123999]是创业板可转换公司债券代码区间 [127000,127999]是主板可转换公司债券代码区间 [128000,128999]是中小企业板可转换公司债券代码区间 + 3 1 [131800,131899]为债券回购交易代码; + 131990 为债券回购的标准券代码; + 4 0 优先股 + 5 0-1 分级基金子基金 + 9 ETF + 6 0-9 开放式基金 + 8 4 封闭式证券投资基金 + 2 0 0-9 B股 + 3 8 B 股现金选择权 + 8 0-9 B 股配股优先权 + 3 0 0-9 创业板股票 + 6 0-1 主板股东大会网络投票 + 2-4 中小企业板股东大会网络投票 + 5-8 创业板股东大会网络投票证券 + 9 [369001,369499]为基金网络投票 + [369501,369899]为优先股、债券等网络投票(注 3) 369991 用于中国结算网络服务身份认证业务的密码激活/密码重 置 369999 用于深交所身份认证业务的密码激活/密码挂失 + 7 0-9 创业板股票增发 + 创业板可转换公司债券申购 + 8 0-9 创业板配股优先权 创业板可转换公司债券的优先权认购 + 9 5 成交量统计指标 + 9 指数 diff --git a/vnpy/data/tdx/future_contracts.json b/vnpy/data/tdx/future_contracts.json index f25bbc6a..c659519e 100644 --- a/vnpy/data/tdx/future_contracts.json +++ b/vnpy/data/tdx/future_contracts.json @@ -1,10 +1,10 @@ { "A": { "underlying_symbol": "A", - "mi_symbol": "a2005", - "full_symbol": "A2005", + "mi_symbol": "a2009", + "full_symbol": "A2009", "exchange": "DCE", - "margin_rate": 0.06, + "margin_rate": 0.08, "symbol_size": 10, "price_tick": 1.0 }, @@ -13,14 +13,14 @@ "mi_symbol": "ag2007", "full_symbol": "AG2007", "exchange": "SHFE", - "margin_rate": 0.09, + "margin_rate": 0.1, "symbol_size": 15, "price_tick": 1.0 }, "AL": { "underlying_symbol": "AL", - "mi_symbol": "al2004", - "full_symbol": "AL2004", + "mi_symbol": "al2006", + "full_symbol": "AL2006", "exchange": "SHFE", "margin_rate": 0.1, "symbol_size": 5, @@ -28,8 +28,8 @@ }, "AP": { "underlying_symbol": "AP", - "mi_symbol": "AP005", - "full_symbol": "AP2005", + "mi_symbol": "AP010", + "full_symbol": "AP2010", "exchange": "CZCE", "margin_rate": 0.08, "symbol_size": 10, @@ -46,10 +46,10 @@ }, "B": { "underlying_symbol": "B", - "mi_symbol": "b2003", - "full_symbol": "B2003", + "mi_symbol": "b2006", + "full_symbol": "B2006", "exchange": "DCE", - "margin_rate": 0.05, + "margin_rate": 0.08, "symbol_size": 10, "price_tick": 1.0 }, @@ -73,10 +73,10 @@ }, "C": { "underlying_symbol": "C", - "mi_symbol": "c2005", - "full_symbol": "C2005", + "mi_symbol": "c2009", + "full_symbol": "C2009", "exchange": "DCE", - "margin_rate": 0.05, + "margin_rate": 0.06, "symbol_size": 10, "price_tick": 1.0 }, @@ -91,8 +91,8 @@ }, "CJ": { "underlying_symbol": "CJ", - "mi_symbol": "CJ005", - "full_symbol": "CJ2005", + "mi_symbol": "CJ009", + "full_symbol": "CJ2009", "exchange": "CZCE", "margin_rate": 0.07, "symbol_size": 5, @@ -100,17 +100,17 @@ }, "CS": { "underlying_symbol": "CS", - "mi_symbol": "cs2005", - "full_symbol": "CS2005", + "mi_symbol": "cs2009", + "full_symbol": "CS2009", "exchange": "DCE", - "margin_rate": 0.05, + "margin_rate": 0.06, "symbol_size": 10, "price_tick": 1.0 }, "CU": { "underlying_symbol": "CU", - "mi_symbol": "cu2004", - "full_symbol": "CU2004", + "mi_symbol": "cu2006", + "full_symbol": "CU2006", "exchange": "SHFE", "margin_rate": 0.1, "symbol_size": 5, @@ -118,8 +118,8 @@ }, "CY": { "underlying_symbol": "CY", - "mi_symbol": "CY005", - "full_symbol": "CY2005", + "mi_symbol": "CY009", + "full_symbol": "CY2009", "exchange": "CZCE", "margin_rate": 0.07, "symbol_size": 5, @@ -127,8 +127,8 @@ }, "EB": { "underlying_symbol": "EB", - "mi_symbol": "eb2005", - "full_symbol": "EB2005", + "mi_symbol": "eb2009", + "full_symbol": "EB2009", "exchange": "DCE", "margin_rate": 0.11, "symbol_size": 5, @@ -136,8 +136,8 @@ }, "EG": { "underlying_symbol": "EG", - "mi_symbol": "eg2005", - "full_symbol": "EG2005", + "mi_symbol": "eg2009", + "full_symbol": "EG2009", "exchange": "DCE", "margin_rate": 0.11, "symbol_size": 10, @@ -154,8 +154,8 @@ }, "FG": { "underlying_symbol": "FG", - "mi_symbol": "FG005", - "full_symbol": "FG2005", + "mi_symbol": "FG009", + "full_symbol": "FG2009", "exchange": "CZCE", "margin_rate": 0.05, "symbol_size": 20, @@ -163,8 +163,8 @@ }, "FU": { "underlying_symbol": "FU", - "mi_symbol": "fu2005", - "full_symbol": "FU2005", + "mi_symbol": "fu2009", + "full_symbol": "FU2009", "exchange": "SHFE", "margin_rate": 0.11, "symbol_size": 10, @@ -172,8 +172,8 @@ }, "HC": { "underlying_symbol": "HC", - "mi_symbol": "hc2005", - "full_symbol": "HC2005", + "mi_symbol": "hc2010", + "full_symbol": "HC2010", "exchange": "SHFE", "margin_rate": 0.09, "symbol_size": 10, @@ -181,8 +181,8 @@ }, "I": { "underlying_symbol": "I", - "mi_symbol": "i2005", - "full_symbol": "I2005", + "mi_symbol": "i2009", + "full_symbol": "I2009", "exchange": "DCE", "margin_rate": 0.08, "symbol_size": 100, @@ -190,10 +190,10 @@ }, "IC": { "underlying_symbol": "IC", - "mi_symbol": "IC2003", - "full_symbol": "IC2003", + "mi_symbol": "IC2005", + "full_symbol": "IC2005", "exchange": "CFFEX", - "margin_rate": 0.1, + "margin_rate": 0.12, "symbol_size": 200, "price_tick": 0.2 }, @@ -217,8 +217,8 @@ }, "J": { "underlying_symbol": "J", - "mi_symbol": "j2005", - "full_symbol": "J2005", + "mi_symbol": "j2009", + "full_symbol": "J2009", "exchange": "DCE", "margin_rate": 0.08, "symbol_size": 100, @@ -226,17 +226,17 @@ }, "JD": { "underlying_symbol": "JD", - "mi_symbol": "jd2005", - "full_symbol": "JD2005", + "mi_symbol": "jd2006", + "full_symbol": "JD2006", "exchange": "DCE", - "margin_rate": 0.09, + "margin_rate": 0.07, "symbol_size": 10, "price_tick": 1.0 }, "JM": { "underlying_symbol": "JM", - "mi_symbol": "jm2005", - "full_symbol": "JM2005", + "mi_symbol": "jm2009", + "full_symbol": "JM2009", "exchange": "DCE", "margin_rate": 0.08, "symbol_size": 60, @@ -253,10 +253,10 @@ }, "L": { "underlying_symbol": "L", - "mi_symbol": "l2005", - "full_symbol": "L2005", + "mi_symbol": "l2009", + "full_symbol": "L2009", "exchange": "DCE", - "margin_rate": 0.07, + "margin_rate": 0.08, "symbol_size": 5, "price_tick": 5.0 }, @@ -271,17 +271,17 @@ }, "M": { "underlying_symbol": "M", - "mi_symbol": "m2005", - "full_symbol": "M2005", + "mi_symbol": "m2009", + "full_symbol": "M2009", "exchange": "DCE", - "margin_rate": 0.06, + "margin_rate": 0.08, "symbol_size": 10, "price_tick": 1.0 }, "MA": { "underlying_symbol": "MA", - "mi_symbol": "MA005", - "full_symbol": "MA2005", + "mi_symbol": "MA009", + "full_symbol": "MA2009", "exchange": "CZCE", "margin_rate": 0.07, "symbol_size": 10, @@ -289,8 +289,8 @@ }, "NI": { "underlying_symbol": "NI", - "mi_symbol": "ni2004", - "full_symbol": "NI2004", + "mi_symbol": "ni2007", + "full_symbol": "NI2007", "exchange": "SHFE", "margin_rate": 0.1, "symbol_size": 1, @@ -298,8 +298,8 @@ }, "NR": { "underlying_symbol": "NR", - "mi_symbol": "nr2004", - "full_symbol": "NR2004", + "mi_symbol": "nr2006", + "full_symbol": "NR2006", "exchange": "INE", "margin_rate": 0.11, "symbol_size": 10, @@ -307,19 +307,19 @@ }, "OI": { "underlying_symbol": "OI", - "mi_symbol": "OI005", - "full_symbol": "OI2005", + "mi_symbol": "OI007", + "full_symbol": "OI2007", "exchange": "CZCE", - "margin_rate": 0.05, + "margin_rate": 0.06, "symbol_size": 10, "price_tick": 1.0 }, "P": { "underlying_symbol": "P", - "mi_symbol": "p2005", - "full_symbol": "P2005", + "mi_symbol": "p2009", + "full_symbol": "P2009", "exchange": "DCE", - "margin_rate": 0.07, + "margin_rate": 0.08, "symbol_size": 10, "price_tick": 2.0 }, @@ -343,17 +343,17 @@ }, "PP": { "underlying_symbol": "PP", - "mi_symbol": "pp2005", - "full_symbol": "PP2005", + "mi_symbol": "pp2009", + "full_symbol": "PP2009", "exchange": "DCE", - "margin_rate": 0.07, + "margin_rate": 0.11, "symbol_size": 5, "price_tick": 1.0 }, "RB": { "underlying_symbol": "RB", - "mi_symbol": "rb2005", - "full_symbol": "RB2005", + "mi_symbol": "rb2010", + "full_symbol": "RB2010", "exchange": "SHFE", "margin_rate": 0.09, "symbol_size": 10, @@ -370,8 +370,8 @@ }, "RM": { "underlying_symbol": "RM", - "mi_symbol": "RM005", - "full_symbol": "RM2005", + "mi_symbol": "RM009", + "full_symbol": "RM2009", "exchange": "CZCE", "margin_rate": 0.06, "symbol_size": 10, @@ -379,10 +379,10 @@ }, "RR": { "underlying_symbol": "RR", - "mi_symbol": "rr2005", - "full_symbol": "RR2005", + "mi_symbol": "rr2009", + "full_symbol": "RR2009", "exchange": "DCE", - "margin_rate": 0.05, + "margin_rate": 0.06, "symbol_size": 10, "price_tick": 1.0 }, @@ -397,8 +397,8 @@ }, "RU": { "underlying_symbol": "RU", - "mi_symbol": "ru2005", - "full_symbol": "RU2005", + "mi_symbol": "ru2009", + "full_symbol": "RU2009", "exchange": "SHFE", "margin_rate": 0.11, "symbol_size": 10, @@ -406,8 +406,8 @@ }, "SA": { "underlying_symbol": "SA", - "mi_symbol": "SA005", - "full_symbol": "SA2005", + "mi_symbol": "SA009", + "full_symbol": "SA2009", "exchange": "CZCE", "margin_rate": 0.05, "symbol_size": 20, @@ -415,17 +415,17 @@ }, "SC": { "underlying_symbol": "SC", - "mi_symbol": "sc2004", - "full_symbol": "SC2004", + "mi_symbol": "sc2006", + "full_symbol": "SC2006", "exchange": "INE", - "margin_rate": 0.2, + "margin_rate": 0.11, "symbol_size": 1000, "price_tick": 0.1 }, "SF": { "underlying_symbol": "SF", - "mi_symbol": "SF005", - "full_symbol": "SF2005", + "mi_symbol": "SF009", + "full_symbol": "SF2009", "exchange": "CZCE", "margin_rate": 0.07, "symbol_size": 5, @@ -433,8 +433,8 @@ }, "SM": { "underlying_symbol": "SM", - "mi_symbol": "SM005", - "full_symbol": "SM2005", + "mi_symbol": "SM009", + "full_symbol": "SM2009", "exchange": "CZCE", "margin_rate": 0.07, "symbol_size": 5, @@ -451,8 +451,8 @@ }, "SP": { "underlying_symbol": "SP", - "mi_symbol": "sp2005", - "full_symbol": "SP2005", + "mi_symbol": "sp2009", + "full_symbol": "SP2009", "exchange": "SHFE", "margin_rate": 0.08, "symbol_size": 10, @@ -460,8 +460,8 @@ }, "SR": { "underlying_symbol": "SR", - "mi_symbol": "SR005", - "full_symbol": "SR2005", + "mi_symbol": "SR009", + "full_symbol": "SR2009", "exchange": "CZCE", "margin_rate": 0.05, "symbol_size": 10, @@ -487,8 +487,8 @@ }, "TA": { "underlying_symbol": "TA", - "mi_symbol": "TA005", - "full_symbol": "TA2005", + "mi_symbol": "TA009", + "full_symbol": "TA2009", "exchange": "CZCE", "margin_rate": 0.07, "symbol_size": 5, @@ -496,8 +496,8 @@ }, "TF": { "underlying_symbol": "TF", - "mi_symbol": "TF2004", - "full_symbol": "TF2004", + "mi_symbol": "TF2006", + "full_symbol": "TF2006", "exchange": "CFFEX", "margin_rate": 0.012, "symbol_size": 10000, @@ -514,8 +514,8 @@ }, "UR": { "underlying_symbol": "UR", - "mi_symbol": "UR005", - "full_symbol": "UR2005", + "mi_symbol": "UR009", + "full_symbol": "UR2009", "exchange": "CZCE", "margin_rate": 0.05, "symbol_size": 20, @@ -523,10 +523,10 @@ }, "V": { "underlying_symbol": "V", - "mi_symbol": "v2005", - "full_symbol": "V2005", + "mi_symbol": "v2009", + "full_symbol": "V2009", "exchange": "DCE", - "margin_rate": 0.1, + "margin_rate": 0.08, "symbol_size": 5, "price_tick": 5.0 }, @@ -550,17 +550,17 @@ }, "Y": { "underlying_symbol": "Y", - "mi_symbol": "y2005", - "full_symbol": "Y2005", + "mi_symbol": "y2009", + "full_symbol": "Y2009", "exchange": "DCE", - "margin_rate": 0.06, + "margin_rate": 0.08, "symbol_size": 10, "price_tick": 2.0 }, "ZC": { "underlying_symbol": "ZC", - "mi_symbol": "ZC005", - "full_symbol": "ZC2005", + "mi_symbol": "ZC009", + "full_symbol": "ZC2009", "exchange": "CZCE", "margin_rate": 0.06, "symbol_size": 100, @@ -568,11 +568,38 @@ }, "ZN": { "underlying_symbol": "ZN", - "mi_symbol": "zn2005", - "full_symbol": "ZN2005", + "mi_symbol": "zn2006", + "full_symbol": "ZN2006", "exchange": "SHFE", "margin_rate": 0.1, "symbol_size": 5, "price_tick": 5.0 + }, + "AF": { + "underlying_symbol": "AF", + "mi_symbol": "AF2009", + "full_symbol": "AF2009", + "exchange": "CFFEX" + }, + "EF": { + "underlying_symbol": "EF", + "mi_symbol": "EF2009", + "full_symbol": "EF2009", + "exchange": "CFFEX" + }, + "TL": { + "underlying_symbol": "TL", + "mi_symbol": "TL2009", + "full_symbol": "TL2009", + "exchange": "CFFEX" + }, + "PG": { + "underlying_symbol": "PG", + "mi_symbol": "pg2011", + "full_symbol": "PG2011", + "exchange": "DCE", + "margin_rate": 0.08, + "symbol_size": 20, + "price_tick": 1.0 } } \ No newline at end of file diff --git a/vnpy/data/tdx/tdx_stock_data.py b/vnpy/data/tdx/tdx_stock_data.py index 5d3c195e..685dc6a6 100644 --- a/vnpy/data/tdx/tdx_stock_data.py +++ b/vnpy/data/tdx/tdx_stock_data.py @@ -15,11 +15,12 @@ import os import pickle import bz2 import traceback +import pandas as pd + from datetime import datetime, timedelta from logging import ERROR from pytdx.hq import TdxHq_API from pytdx.params import TDXParams -from pandas import to_datetime from vnpy.trader.object import BarData from vnpy.trader.constant import Exchange @@ -268,7 +269,7 @@ class TdxStockData(object): current_datetime = datetime.now() data = self.api.to_df(_bars) - data = data.assign(datetime=to_datetime(data['datetime'])) + data = data.assign(datetime=pd.to_datetime(data['datetime'])) data = data.assign(ticker=symbol) data['symbol'] = symbol data = data.drop( @@ -506,3 +507,63 @@ class TdxStockData(object): self.write_error( 'exception in get_transaction_data:{},{},{}'.format(symbol, str(ex), traceback.format_exc())) return False, ret_datas + + def get_stock_list(self, types=["stock_cn", "etf_cn", "bond_cn", "cb_cn"]): + """股票所有的code&name列表""" + if self.api is None: + self.connect() + + data = pd.concat( + [pd.concat([self.api.to_df(self.api.get_security_list(j, i * 1000)).assign(sse='sz' if j == 0 else 'sh').set_index( + ['code', 'sse'], drop=False) for i in range(int(self.api.get_security_count(j) / 1000) + 1)], axis=0) for j + in range(2)], axis=0) + sz = data.query('sse=="sz"') + sh = data.query('sse=="sh"') + sz = sz.assign(sec=sz.code.apply(get_stock_type)) + sh = sh.assign(sec=sh.code.apply(get_stock_type)) + + temp_df = pd.concat([sz, sh]).query('sec in ["{}"]'.format(types)).sort_index().assign( + name=data['name'].apply(lambda x: str(x)[0:6])) + + hq_codelist = [] + + for i in range(0, len(temp_df)): + row = temp_df.iloc[i] + hq_codelist.append( + { + "code": row['code'], + "exchange": Exchange.SSE.value if row['sse'] == 'sh' else Exchange.SZSE.value, + "market_id": 1 if row['sse'] == 'sh' else 0, + "name": row['name'] + + } + ) + + return hq_codelist + + def get_security_quotes(self, all_stock, code=None): + """ + 支持三种形式的参数 + get_security_quotes(market, code ) + get_security_quotes((market, code)) + get_security_quotes([(market1, code1), (market2, code2)] ) + :param all_stock (market, code) 的数组 + :param code{optional} code to query + :return: + """ + if self.api is None: + self.connect() + + return self.api.get_security_quotes(all_stock, code) + + def get_stock_quotes_by_type(self, stock_type): + """根据股票代码类型,获取其最新行情""" + stock_list = [(stock.get('market_id'), stock.get('code')) for stock in self.symbol_dict.values() if stock.get('stock_type') == stock_type] + + num_per_count = 60 + results = [] + for i in range(0, len(stock_list)+1, num_per_count): + cur_results = self.get_security_quotes(stock_list[i:i+num_per_count]) + results.extend(cur_results) + + return results diff --git a/vnpy/gateway/ctp/ctp_gateway.py b/vnpy/gateway/ctp/ctp_gateway.py index 67f46ad6..a441df29 100644 --- a/vnpy/gateway/ctp/ctp_gateway.py +++ b/vnpy/gateway/ctp/ctp_gateway.py @@ -708,6 +708,7 @@ class CtpTdApi(TdApi): order = OrderData( symbol=symbol, exchange=exchange, + accountid=self.accountid, orderid=orderid, type=order_type, direction=DIRECTION_CTP2VT[data["Direction"]], diff --git a/vnpy/gateway/xtp/xtp_gateway.py b/vnpy/gateway/xtp/xtp_gateway.py index af2ab2a5..05175787 100644 --- a/vnpy/gateway/xtp/xtp_gateway.py +++ b/vnpy/gateway/xtp/xtp_gateway.py @@ -26,35 +26,39 @@ from vnpy.trader.object import ( ) from vnpy.trader.utility import get_folder_path - +# 市场id <=> Exchange MARKET_XTP2VT: Dict[int, Exchange] = { 1: Exchange.SZSE, 2: Exchange.SSE } MARKET_VT2XTP: Dict[Exchange, int] = {v: k for k, v in MARKET_XTP2VT.items()} +# 交易所id <=> Exchange EXCHANGE_XTP2VT: Dict[int, Exchange] = { 1: Exchange.SSE, 2: Exchange.SZSE, } EXCHANGE_VT2XTP: Dict[Exchange, int] = {v: k for k, v in EXCHANGE_XTP2VT.items()} +# 方向 <=> Direction, Offset DIRECTION_STOCK_XTP2VT: Dict[int, Any] = { - 1: (Direction.LONG, Offset.NONE), - 2: (Direction.SHORT, Offset.NONE), - 21: (Direction.LONG, Offset.OPEN), - 22: (Direction.SHORT, Offset.OPEN), - 24: (Direction.LONG, Offset.CLOSE), - 23: (Direction.SHORT, Offset.CLOSE) + 1: (Direction.LONG, Offset.NONE), # 买 + 2: (Direction.SHORT, Offset.NONE), # 卖 + 21: (Direction.LONG, Offset.OPEN), # 多,开 + 22: (Direction.SHORT, Offset.OPEN), # 空,开 + 24: (Direction.LONG, Offset.CLOSE), # 多,平 + 23: (Direction.SHORT, Offset.CLOSE) # 空, 平 } DIRECTION_STOCK_VT2XTP: Dict[Any, int] = {v: k for k, v in DIRECTION_STOCK_XTP2VT.items()} +# 期权方向 <=> Direction DIRECTION_OPTION_XTP2VT: Dict[int, Direction] = { 1: Direction.LONG, 2: Direction.SHORT } DIRECTION_OPTION_VT2XTP: Dict[Direction, int] = {v: k for k, v in DIRECTION_OPTION_XTP2VT.items()} +# 持仓方向 <=> Direction POSITION_DIRECTION_XTP2VT = { 0: Direction.NET, 1: Direction.LONG, @@ -62,17 +66,20 @@ POSITION_DIRECTION_XTP2VT = { 3: Direction.SHORT } +# 委托单类型 ORDERTYPE_XTP2VT: Dict[int, OrderType] = { 1: OrderType.LIMIT, 2: OrderType.MARKET } ORDERTYPE_VT2XTP: Dict[OrderType, int] = {v: k for k, v in ORDERTYPE_XTP2VT.items()} +# 协议类型 PROTOCOL_VT2XTP: Dict[str, int] = { "TCP": 1, "UDP": 2 } +# 状态 <=> Status STATUS_XTP2VT: Dict[int, Status] = { 0: Status.SUBMITTING, 1: Status.ALLTRADED, @@ -84,6 +91,7 @@ STATUS_XTP2VT: Dict[int, Status] = { 7: Status.SUBMITTING } +# 合约类型 <=> Product PRODUCT_XTP2VT: Dict[int, Product] = { 0: Product.EQUITY, 1: Product.INDEX, @@ -94,6 +102,7 @@ PRODUCT_XTP2VT: Dict[int, Product] = { 6: Product.OPTION } +# 开平仓 <=> Offset OFFSET_VT2XTP: Dict[Offset, int] = { Offset.NONE: 0, Offset.OPEN: 1, @@ -103,6 +112,7 @@ OFFSET_VT2XTP: Dict[Offset, int] = { } OFFSET_XTP2VT: Dict[int, Offset] = {v: k for k, v in OFFSET_VT2XTP.items()} +# 业务类型 <=> xtp BUSINESS_VT2XTP: Dict[Any, int] = { "CASH": 0, Offset.NONE: 0, @@ -112,7 +122,9 @@ BUSINESS_VT2XTP: Dict[Any, int] = { "OPTION": 10, } +# 代码 <=> 中文名称 symbol_name_map: Dict[str, str] = {} +# 代码 <=> 交易所 symbol_exchange_map: Dict[str, Exchange] = {} @@ -130,11 +142,12 @@ class XtpGateway(BaseGateway): "授权码": "" } + # 接口支持得交易所清单 exchanges: List[Exchange] = list(EXCHANGE_VT2XTP.keys()) - def __init__(self, event_engine: EventEngine): + def __init__(self, event_engine: EventEngine, gateway_name='XTP'): """""" - super().__init__(event_engine, "XTP") + super().__init__(event_engine, gateway_name=gateway_name) self.md_api = XtpMdApi(self) self.td_api = XtpTdApi(self) @@ -258,7 +271,7 @@ class XtpMdApi(MdApi): pass def onDepthMarketData(self, data: dict) -> None: - """""" + """深度行情回报""" timestamp = str(data["data_time"]) dt = datetime.strptime(timestamp, "%Y%m%d%H%M%S%f") @@ -266,6 +279,9 @@ class XtpMdApi(MdApi): symbol=data["ticker"], exchange=EXCHANGE_XTP2VT[data["exchange_id"]], datetime=dt, + date=dt.strftime('%Y-%m-%d'), + time=dt.strftime('%H:%M:%S.%f'), + trading_day=dt.strftime('%Y-%m-%d'), volume=data["qty"], last_price=data["last_price"], limit_up=data["upper_limit_price"], @@ -334,7 +350,7 @@ class XtpMdApi(MdApi): pass def onQueryAllTickers(self, data: dict, error: dict, last: bool) -> None: - """""" + """合约信息回报""" contract = ContractData( symbol=data["ticker"], exchange=EXCHANGE_XTP2VT[data["exchange_id"]], @@ -347,8 +363,10 @@ class XtpMdApi(MdApi): ) self.gateway.on_contract(contract) + # 更新 symbol <=> 中文名称映射 symbol_name_map[contract.vt_symbol] = contract.name + # 更新 股票代码 <=> 交易所 if contract.product != Product.INDEX: symbol_exchange_map[contract.symbol] = contract.exchange @@ -440,7 +458,7 @@ class XtpMdApi(MdApi): self.subscribeMarketData(req.symbol, 1, xtp_exchange) def query_contract(self) -> None: - """""" + """查询合约明细""" for exchange_id in EXCHANGE_XTP2VT.keys(): self.queryAllTickers(exchange_id) @@ -487,21 +505,24 @@ class XtpTdApi(TdApi): self.gateway.write_error("交易接口报错", error) def onOrderEvent(self, data: dict, error: dict, session: int) -> None: - """""" + """委托回报""" if error["error_id"]: self.gateway.write_error("交易委托失败", error) symbol = data["ticker"] if len(symbol) == 8: + # 期权 direction = DIRECTION_OPTION_XTP2VT[data["side"]] offset = OFFSET_XTP2VT[data["position_effect"]] else: + # 股票 direction, offset = DIRECTION_STOCK_XTP2VT[data["side"]] order = OrderData( symbol=symbol, exchange=MARKET_XTP2VT[data["market"]], orderid=str(data["order_xtp_id"]), + sys_orderid=str(data["order_xtp_id"]), type=ORDERTYPE_XTP2VT[data["price_type"]], direction=direction, offset=offset, @@ -528,6 +549,7 @@ class XtpTdApi(TdApi): symbol=symbol, exchange=MARKET_XTP2VT[data["market"]], orderid=str(data["order_xtp_id"]), + sys_orderid=str(data["order_xtp_id"]), tradeid=str(data["exec_id"]), direction=direction, offset=offset, @@ -750,7 +772,7 @@ class XtpTdApi(TdApi): "market": MARKET_VT2XTP[req.exchange], "price": req.price, "quantity": int(req.volume), - "side": DIRECTION_STOCK_VT2XTP.get((req.direction, req.offset), ""), + "side": DIRECTION_STOCK_VT2XTP.get((req.direction, Offset.NONE), ""), "price_type": ORDERTYPE_VT2XTP[req.type], "business_type": BUSINESS_VT2XTP[req.offset] } @@ -765,6 +787,7 @@ class XtpTdApi(TdApi): def cancel_order(self, req: CancelRequest) -> None: """""" self.cancelOrder(int(req.orderid), self.session_id) + return True def query_account(self) -> None: """""" diff --git a/vnpy/trader/ui/kline/kline.py b/vnpy/trader/ui/kline/kline.py index 92e68030..e75cef42 100644 --- a/vnpy/trader/ui/kline/kline.py +++ b/vnpy/trader/ui/kline/kline.py @@ -1163,12 +1163,12 @@ class KLineWidget(KeyWraper): price = df_trades['price'].loc[idx] direction = df_trades['direction'].loc[idx] - if direction.lower() in ['long', 'direction.long']: + if direction.lower() in ['long', 'direction.long', '多']: direction = Direction.LONG else: direction = Direction.SHORT offset = df_trades['offset'].loc[idx] - if offset.lower() in ['open', 'offset.open']: + if offset.lower() in ['open', 'offset.open', '开']: offset = Offset.OPEN else: offset = Offset.CLOSE