diff --git a/src/xtquant/__init__.py b/src/xtquant/__init__.py index afd593c..c8554d3 100644 --- a/src/xtquant/__init__.py +++ b/src/xtquant/__init__.py @@ -3,7 +3,6 @@ __version__ = "xtquant" - def check_for_update(package_name): import requests from pkg_resources import get_distribution diff --git a/src/xtquant/config/downloadSchedule.json b/src/xtquant/config/downloadSchedule.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/src/xtquant/config/downloadSchedule.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/xtquant/config/user/root2/lua/FunStatistic.lua b/src/xtquant/config/user/root2/lua/FunStatistic.lua index ead335c..60c1a5a 100644 --- a/src/xtquant/config/user/root2/lua/FunStatistic.lua +++ b/src/xtquant/config/user/root2/lua/FunStatistic.lua @@ -328,12 +328,19 @@ function c_relate() end function c_std() - local cache = FormulaDataCacheDouble(cacheDoubleNum) - function std_func(value, N, timetag, __formula, type) - local ret = std(value, cache, N, timetag, __formula, type) - return ret + local container = FormulaCacheContainer() + function wrapper(X, N, timetag, formula) + return std(container, X, N, timetag, formula) end - return std_func + return wrapper +end + +function c_stdp() + local container = FormulaCacheContainer() + function wrapper(X, N, timetag, formula) + return stdp(container, X, N, timetag, formula) + end + return wrapper end function c_var() @@ -345,15 +352,6 @@ function c_var() return var_func end -function c_stdp() - local cache = FormulaDataCacheDouble(cacheDoubleNum) - function stdp_func(value, N, timetag, __formula) - local ret = stdp(value, cache, N, timetag, __formula) - return ret - end - return stdp_func -end - function c_varp() local cache = FormulaDataCacheDouble(cacheDoubleNum) function varp_func(value, N, timetag, __formula) diff --git a/src/xtquant/config/user/root3/config/config_cmd b/src/xtquant/config/user/root3/config/config_cmd new file mode 100644 index 0000000..18866fc --- /dev/null +++ b/src/xtquant/config/user/root3/config/config_cmd @@ -0,0 +1 @@ +Ѫg幃bhV(E)5a - - - - - - + + + + - - - - - - + + + + diff --git a/src/xtquant/config/xtstocktype.lua b/src/xtquant/config/xtstocktype.lua index 739b140..01ad137 100644 --- a/src/xtquant/config/xtstocktype.lua +++ b/src/xtquant/config/xtstocktype.lua @@ -25,7 +25,7 @@ g_stocktype_info = { XT_GE_SH_B = "90****,SH,102",--沪市B股 XT_GE_SH_FUND = "50****,SH,103",--沪市封基 XT_GE_SH_INDEX = "000***,SH,104", --沪市指数 - XT_GE_SH_ETF = "510***|511***|512***|513***|515***|516***|517***|518***|560***|561***|562***|563***|588***,SH,105", --沪市ETF + XT_GE_SH_ETF = "510***|511***|512***|513***|515***|516***|517***|518***|520***|530***|560***|561***|562***|563***|588***,SH,105", --沪市ETF XT_GE_SH_WARRANT = "000000,SH,106", --沪市权证 XT_GE_SH_SUBSCRIBE = "73****|78****|712***|715***|795***,SH,107", --沪市申购 XT_GE_SH_EXCHANGEABLE_LOAN = "132***|1370**|1371**|1372**|1373**|1374**,SH,108", --沪市可交换公司债券 @@ -35,7 +35,7 @@ g_stocktype_info = { XT_GE_SH_SHORTTERM_CORPORATE_LOAN_TRANSFER = "1350**|1351**|1352**|1353**|1354**|1175**|1176**|1177**|1178**|1179**,SH,112", --沪市证券公司短期债券挂牌转让 XT_GE_SH_ABS = "128***,SH,113", --信贷资产支持证券 XT_GE_SH_CORPORATE_LOAN_PLEDGE = "102***|134***|154***|164***,SH,114", --沪市公司债券质押券入库 - XT_GE_SH_CORPORATE_BOND = "1230**|1231**|1232**|1233**|1234**|136***|143***|1220**|1221**|1222**|1223**|1224**|155***|163***|175***|185***|188***|1375**|1376**|1377**|1378**|1379**|1385**|1386**|1387**|1388**|1389**|115***|240***|241***,SH,115", --沪市公司债 + XT_GE_SH_CORPORATE_BOND = "1230**|1231**|1232**|1233**|1234**|136***|143***|1220**|1221**|1222**|1223**|1224**|155***|163***|175***|185***|188***|1375**|1376**|1377**|1378**|1379**|1385**|1386**|1387**|1388**|1389**|115***|240***|241***|242***|243***|244***,SH,115", --沪市公司债 XT_GE_SH_PUBLIC_PREFERED_SHARES = "330***,SH,116", --沪市公开发行优先股交易 XT_GE_SH_NON_PUBLIC_PREFERED_SHARES_TRANSFER = "360***,SH,117",--沪市非公开发行优先股转让 XT_GE_SH_PUBLIC_PREFERED_SHARES_SUBSCRIBE = "770***,SH,118", --沪市公开发行优先股申购 @@ -54,10 +54,10 @@ g_stocktype_info = { XT_GE_SH_SEPERATION_BOND = "126***,SH,131", --沪市分离债 XT_GE_SH_ASSET_SECURITIZATION = "121***,SH,132", --沪市资产证券化 XT_GE_SH_CREDIT_ASSET_SUPPORTED = "128***,SH,133", --信贷资产支持证券 - XT_GE_SH_ENTERPRISE_BOND = "120***|124***|1270**|1271**|1272**|1273**|1274**|1275**|1276**|1277**|1278**|129***|139***|1225**|1226**|1227**|1228**|1229**|152***|1840**|1841**|1842**|1843**|1844**|1845**|1846**|1847**|270***|271***|272***,SH,134", --沪市企业债(席位托管方式) + XT_GE_SH_ENTERPRISE_BOND = "120***|124***|127***|129***|139***|1225**|1226**|1227**|1228**|1229**|152***|184***|270***|271***|272***,SH,134", --沪市企业债(席位托管方式) XT_GE_SH_CONVERTIBALE_BOND = "1000**|1001**|1002**|1003**|1004**|1005**|1006**|1007**|1008**|110***|112***|113***|1110**|1111**|1112**|1113**|1114**|1180**|1181**|1182**|1183**|1184**,SH,135", --沪市可转债 - XT_GE_SH_LOCAL_GOVERNMENT_LOAN = "130***|140***|147***|157***|160***|173***|171***|186***|101***|109***|198***|230***|231***,SH,136", --沪市地方债 - XT_GE_SH_GOVERNMENT_LOAN = "010***|019***|020***|130***|160***|171***|009***|140***|147***|157***|173***|186***|101***|109***|198***|230***|231***,SH,137", --沪市政府债(国债+地方债) + XT_GE_SH_LOCAL_GOVERNMENT_LOAN = "130***|140***|147***|157***|160***|173***|171***|186***|101***|109***|198***|230***|231***|232***|233***,SH,136", --沪市地方债 + XT_GE_SH_GOVERNMENT_LOAN = "010***|019***|020***|130***|160***|171***|009***|140***|147***|157***|173***|186***|101***|109***|198***|230***|231***|232***|233***,SH,137", --沪市政府债(国债+地方债) XT_GE_SH_CPB = "1370**|1371**|1372**|1373**|1374**,SH,138",--上海可交换私募债 XT_GE_SH_STANDARD_BOND = "888880|SHRQ88,SH,139", --沪市标准券 XT_GE_SH_CLOSED_ENDED_FUNDS = "500***|5058**,SH,140", --沪市封闭式基金 @@ -72,11 +72,11 @@ g_stocktype_info = { XT_GE_SH_SEPERATION_BOND_REPURCHASE = "1050**|1051**|1052**|1053**|1054**|1055**|1056**|1057*|1058**,SH,149", --分离债质押式回购标准券入库 XT_GE_SH_BOND_OFFER_REPURCHASE = "205***,SH,150", --债券质押式报价回购 XT_GE_SH_MS_PRIVATE_PLACEMENT_BOND = "125***|145***|150***|151***,SH,151", --中小企业私募债券在固定收益平台转让 - XT_GE_SH_CROSS_BORDER_ETF = "513**0|5109*0,SH,152", --跨境ETF + XT_GE_SH_CROSS_BORDER_ETF = "513**0|510900|5205**|5206**|5207**|5208**|5209**,SH,152", --跨境ETF XT_GE_SH_CROSS_BORDER_LOF = "501018|501021|501023|501025|50130*|501310|501311|501313,SH,153", --跨境LOF XT_GE_SH_INNOVATION_CLOSED_ENDED_FUNDS = "5058**,SH,154", --上海创新型封闭式基金 XT_GE_SF_FIXED_INCOME_ETF = "511***,SH,155",--上海的固定收益类 - XT_GE_SH_GOLD = "518**0,SH,156",--上海黄金 + XT_GE_SH_GOLD = "518**0,SH,156",--上海黄金ETF XT_GE_SH_RTMF = "5198**,SH,157",--上海实时申赎货币基金 XT_GE_SH_TMF = "5116**|5117**|5118**|5119**,SH,158",--上海交易型货币基金 XT_GE_SH_STOCK_IPO = "730***|732***|780***|712***|795***|787***|707***,SH,159",--上海股票申购代码 @@ -106,7 +106,7 @@ g_stocktype_info = { XT_GE_SH_LOAN_REPURCHASE_DAY_28 = "204028,SH,183", --沪市28天回购 XT_GE_SH_LOAN_REPURCHASE_DAY_28_UPPER = "204091|204182,SH,184", --沪市28天以上回购 XT_GE_SH_GSF = "502**1|502**2|502**4|502**5|502**7|502008|502018|502028|502038|502058|502049|502050,SH,185", --上海分级基金子基金 - XT_GE_SH_ASS = "121***|1235**|1236**|1237**|1238**|1239**|128***|131***|142***|146***|149***|156***|159***|165***|168***|169***|179***|180***|183***|189***|1931**|1932**|1933**|1934**|1935**|1936**|1937**|1938**|1939**|112***|199***|260***|261***,SH,186",--上海资产支持证券 + XT_GE_SH_ASS = "121***|1235**|1236**|1237**|1238**|1239**|128***|131***|142***|146***|149***|156***|159***|165***|168***|169***|179***|180***|183***|189***|1931**|1932**|1933**|1934**|1935**|1936**|1937**|1938**|1939**|112***|199***|260***|261***|262***|263***|264***|265***|266***,SH,186",--上海资产支持证券 XT_GE_SH_LOAN_CBB_SCB_NEW = "733***|783***|754***|7590**|713***|718***,SH,187",--上海可转债可交换债新债申购代码 --XT_GE_SH_EXCHANGEABLE_BOND = "759***,SH,188",--上海可交换债券 XT_GE_SH_OPEN_END_FUND = "5190**|5191**|5192**|5193**|5194**|5195**|5196**|5197**|5199**,SH,189",--上海开放式基金申赎代码 @@ -179,11 +179,11 @@ g_stocktype_info = { XT_GE_SH_SUBSCRIPTION_ETF_CROSS_BORDER = "5109*3|513**3,SH,256", --上海跨境ETF认购 XT_GE_SH_SUBSCRIPTION_REPAYMENT_ETF_CROSS_BORDER = "5109*4|513**4,SH,257", --上海跨境ETF认购扣款还款 XT_GE_SH_NON_FUND_ETF_CROSS_BORDER = "5109*5|513**5,SH,258", --上海跨境ETF非沪市资金 - XT_GE_SH_TRANSACTION_ETF_LOAN = "5110*0|5112*0,SH,259", --上海债券ETF交易 + XT_GE_SH_TRANSACTION_ETF_LOAN = "5110*0|5111*0|5112*0,SH,259", --上海实物债券ETF XT_GE_SH_SUBSCRIPTION_ETF_LOAN = "5110*3|5112*3,SH,260", --上海债券ETF认购 XT_GE_SH_SUBSCRIPTION_REPAYMENT_ETF_LOAN = "5110*4|5112*4,SH,261", --上海债券ETF认购扣款还款 XT_GE_SH_NON_FUND_ETF_LOAN = "5110*5|5112*5,SH,262", --上海债券ETF非沪市资金 - XT_GE_SH_TRANSACTION_ETF_CR_LOAN = "5113*0|5114*0|5115*0,SH,263", --上海现金申赎债券ETF交易 + XT_GE_SH_TRANSACTION_ETF_CR_LOAN = "5113*0|5114*0|5115*0,SH,263", --上海现金债券ETF XT_GE_SH_FUND_ETF_CR_LOAN = "5113*2|5114*2|5115*2,SH,264", --上海现金申赎债券ETF沪市资金 XT_GE_SH_SUBSCRIPTION_ETF_CR_LOAN = "5113*3|5114*3|5115*3,SH,265", --上海现金申赎债券ETF认购 XT_GE_SH_SUBSCRIPTION_REPAYMENT_ETF_CR_LOAN = "5113*4|5114*4|5115*4,SH,266", --上海现金申赎债券ETF认购扣款还款 @@ -218,15 +218,15 @@ g_stocktype_info = { XT_GE_SH_QUOTATION_REPURCHASE_DAY_245 = "205245,SH,295", --沪市245天报价回购 XT_GE_SH_QUOTATION_REPURCHASE_DAY_301 = "205301,SH,296", --沪市301天报价回购 XT_GE_SH_QUOTATION_REPURCHASE_DAY_357 = "205357,SH,297", --沪市357天报价回购 - XT_GE_SH_NON_PUBLIC_CORPORATE_LOAN = "125***|135***|145***|150***|151***|162***|166***|167***|177***|178***|194***|196***|197***|1823**|1824**|1825**|1826**|1827**|1828**|1829**|114***|250***|251***|252***|253***|254***,SH,298", --上海非公开发行公司债券 + XT_GE_SH_NON_PUBLIC_CORPORATE_LOAN = "125***|135***|145***|150***|151***|162***|166***|167***|177***|178***|194***|196***|197***|1823**|1824**|1825**|1826**|1827**|1828**|1829**|114***|250***|251***|252***|253***|254***|255***|256***|257***,SH,298", --上海非公开发行公司债券 XT_GE_SH_ENTERPROSE_SUPPORT_AUCTION_BOND = "142***|131***,SH,299",--企业支持债券(竞价系统可交易) XT_GE_SH_ABS_TRANSFER = "149***,SH,300", --沪市资产支持证券挂牌转让 XT_GE_SH_TMFR = "5116*1|5117*1|5118*1|5119*1|5195*1|5199*1,SH,301",--上海交易型货币及其它货币基金申赎 XT_GE_SH_PUBLIC_INFRASTRUCTURE_FUND = "5080**,SH,302",--上海公募基础设施基金 - XT_GE_SH_DIRECTIONAL_CONVERTIBALE_BOND = "1108**|1109**,SH,303", --沪市定向可转债 + XT_GE_SH_DIRECTIONAL_CONVERTIBALE_BOND = "1108**|1109**|1185**|1186**,SH,303", --沪市定向可转债 XT_GE_SH_50_ETF = "510050,SH,350", XT_GE_SH_300_ETF = "510300,SH,351", - XT_GE_SH_PUBLIC_CORPORATE_TRADE_LOAN = "115***|136***|143***|163***|175***|185***|188***|240***|241***,SH,352", --上海公开发行公司债现券交易 + XT_GE_SH_PUBLIC_CORPORATE_TRADE_LOAN = "115***|136***|143***|163***|175***|185***|188***|240***|241***|242***|243***|244***,SH,352", --上海公开发行公司债现券交易 XT_GE_SH_TECH_BOARD_ETF = "5880*1|5881*1|5882*1|5883*1|5884*1,SH,353", -- 上海科创板etf申赎 XT_GE_SH_NON_PUBLIC_CONVERTIBLE_CORPORATE_LOAN = "1108**|1109**,SH,354", -- 上海非公开发行可转换公司债券 XT_GE_SH_TECH_BOARD_CONVERTIBLE_BOND = "1180**|1181**|1182**|1183**|1184**,SH,355", -- 上海科创板可转债 @@ -238,12 +238,13 @@ g_stocktype_info = { XT_GE_SH_GOVERNMENT_BANK_FINANCE_LOAN_DISTRIBUTE_SALE = "7512**|7513**,SH,361", --政策性银行金融债券分销 XT_GE_SH_LOCAL_GOVERNMENT_LOAN_ONLINE_DISTRIBUTE_SALE = "75190*|75191*|75192*|75193*|75194*|75195*|75196*,SH,362", --地方政府债券网上分销 XT_GE_SH_PLACING = "703***,SH,363", -- 上海配售 - XT_GE_SH_TECH_BOARD_ETF_ETFCODE = "5880*0|5881*0|5882*0|5883*0|5884*0,SH,364", -- 上海科创板etf + XT_GE_SH_TECH_BOARD_ETF_ETFCODE = "588***,SH,364", -- 上海科创板etf XT_GE_SH_MAIN_BOARD = "60****,SH,365", -- 沪市主板 XT_GE_SH_500_ETF = "510500,SH,366", -- 上海500etf XT_GE_SH_TECH_BOARD_50_ETF = "588080,SH,367", --科创板50ETF XT_GE_SH_TECH_50_ETF = "588000,SH,368", --科创50ETF XT_GE_SH_GOV_ALLOW = "1279**|1848**|1849**,SH,369",--上海政府支持债券 + XT_GE_SH_TECH_DIRECTIONAL_CONVERTIBALE_BOND = "1185**|1186**,SH,370", --沪市科创板定向可转债 XT_GE_SZ_A = "00****|30****,SZ,10001",--深市A股 XT_GE_SZ_B = "20****,SZ,10002",--深市B股 @@ -257,13 +258,13 @@ g_stocktype_info = { XT_GE_SZ_GLR = "131990,SZ,10010",--深市国债回购(131990不是的,需要业务支持) XT_GE_SZ_GLIB = "100***|101***|102***|103***|104***|105***|106***|107***,SZ,10011",--深市附息国债 XT_GE_SZ_GLD = "108***|110***,SZ,10012",--深市贴现国债 - XT_GE_SZ_CB = "112***,SZ,10013",--深市公司债 + XT_GE_SZ_CB = "112***|524***|525***|526***|527***|528***|529***,SZ,10013",--深市公司债 XT_GE_SZ_EB = "111***,SZ,10014",--深市企业债 XT_GE_SZ_SB = "115***,SZ,10015",--深市分离债 - XT_GE_SZ_MSP_PB = "118***|114***|133***|134***,SZ,10016",--深市私募债 + XT_GE_SZ_MSP_PB = "118***|114***|133***|134***|520***|521***|522***|523***,SZ,10016",--深市非公开发行公司债券 XT_GE_SZ_SFMP = "119***,SZ,10017",--深市专项资金管理规划 - XT_GE_SZ_LGL = "109***|104***|105***|19****|173***,SZ,10018",--深市地方政府债 - XT_GE_SZ_CBB = "121***|122***|123***|124***|125***|126***|127***|128***|129***|10165*|10166*|10167*|10168*|10169*,SZ,10019",--深市可转债 + XT_GE_SZ_LGL = "109***|104***|105***|106***|107***|19****|173***|56****|57****|58****|59****,SZ,10018",--深市地方政府债 + XT_GE_SZ_CBB = "1210**|1211**|1212**|1213**|1214**|122***|123***|124***|125***|126***|127***|128***|129***,SZ,10019",--深市可转债 XT_GE_SZ_STANDAR_B = "131990|131991|SZRQ88,SZ,10020",--深市标准券 XT_GE_SZ_CEF = "184***,SZ,10021",--深市封闭式基金 XT_GE_SZ_LOF = "16****,SZ,10022",--深市LOF @@ -271,21 +272,21 @@ g_stocktype_info = { XT_GE_SZ_SCB_PB = "117***|1156**|1157**|1158**|1159**,SZ,10024",--深市 中小企业可交换私募债 XT_GE_SZ_SC_SB = "1189**|1151**|1152**|1153**|1154**|1155**,SZ,10025",--深市证券公司次级债 XT_GE_SZ_SPB = "1180**|1181**|1182**|1183**|1184**|1185**|1186**|1187**|1188**,SZ,10026",--深市其他中小企业私募债 - XT_GE_SZ_ASS = "1161**|1162**|1163**|1164**|1191**|1192**|1193**|1194**|138***|139***|135***|136***|137***|143***|144***|146***,SZ,10027",--深市企业资产支持证券 + XT_GE_SZ_ASS = "116***|1191**|1192**|1193**|1194**|138***|139***|135***|136***|137***|143***|144***|146***|50****|51****,SZ,10027",--深市企业资产支持证券 XT_GE_SZ_GSF = "150***|151***,SZ,10028",--深市分级基金子基金 - XT_GE_SZ_CB_ETF = "159920|159941|159954|159960|159963|159605|159607|159612|159615|159632|159636|159655|159711|159712|159718|159726|159735|159740|159741|159742|159747|159750|159751|159776|159788|159792|159822|159823|159850|159866|159892|159519|159696|159699|159509|159513|159506|159501|159659,SZ,10029",--深市跨境ETF - XT_GE_SZ_CB_LOF = "160125|160416|160717|160719|161116|161210|161714|161815|162411|164701|164705|164815|164824|165510|165513|164906|163208|162719|162416|162415|161831|161229|161130|161129|161128|161127|161126|161125|161124|160924|160923|160922|160723|160644|160322|160216|160140|160138|159691|159660|159688|159687,SZ,10030",--深市跨境LOF + XT_GE_SZ_CB_ETF = "159920|159941|159954|159960|159605|159607|159612|159615|159632|159636|159655|159711|159712|159718|159726|159735|159740|159741|159742|159747|159750|159751|159776|159788|159792|159822|159823|159850|159866|159892|159519|159696|159699|159509|159513|159506|159501|159659|159568|159577|159529|159570|159567|159502|159518|159691|159660|159688|159687|159318|159303|159329|159331|159569|159302|159333|159312,SZ,10029",--深市跨境ETF + XT_GE_SZ_CB_LOF = "160125|160416|160717|160719|161116|161210|161714|161815|162411|164701|164705|164815|164824|165510|165513|164906|163208|162719|162416|162415|161831|161229|161130|161129|161128|161127|161126|161125|161124|160924|160923|160922|160723|160644|160322|160216|160140|160138,SZ,10030",--深市跨境LOF XT_GE_SZ_ICEF = "150***,SZ,10031",--深市创新型封闭式基金 XT_GE_SZ_ZB_CCB = "127***,SZ,10032",--深市主板可转换公司债券 XT_GE_SZ_CYB_CCB = "123***,SZ,10033",--深市创业板可转换公司债券 XT_GE_SZ_ZXB_CCB = "128***,SZ,10034",--深市中小板可转换公司债券 XT_GE_SZ_GLRA = "131***,SZ,10035",--深市国债回购(131900不是的,需要业务支持) - XT_GE_SZ_GOLD = "159934|159937|159812|159830|159831|159832|159833|159834,SZ,10036",--深市黄金 + XT_GE_SZ_GOLD = "159934|159937|159812|159830|159831|159834,SZ,10036",--深市黄金ETF XT_GE_SZ_RTMF = "1590**,SZ,10037",--深市实时申赎货币基金 XT_GE_SZ_XGED = "SZXGED,SZ,10038",--深新股额 XT_GE_SZ_SEO = "07****|37****,SZ,10039",--深增发股 XT_GE_SZ_SA = "08****|380***,SZ,10040",--深圳配股 - XT_GE_SZ_LOAN_ETF = "159926|159972|159988|159816|159649|159650|159651,SZ,10041",--深圳债券ETF + XT_GE_SZ_LOAN_ETF = "159972|159816|159649|159650|159651,SZ,10041",--深圳债券ETF XT_GE_SZ_LOAN_REPURCHASE_DAY_1 = "131810,SZ,10042", --深市1天回购 XT_GE_SZ_LOAN_REPURCHASE_DAY_2 = "131811,SZ,10043", --深市2天回购 XT_GE_SZ_LOAN_REPURCHASE_DAY_3 = "131800,SZ,10044", --深市3天回购 @@ -322,15 +323,22 @@ g_stocktype_info = { XT_GE_SZ_PUBLIC_INFRASTRUCTURE_FUND = "180***,SZ,10076",--深市公募基础设施基金 XT_GE_SZ_DIRECTIONAL_CONVERTIBALE_BOND = "124***,SZ,10077", --深市定向可转债 XT_GE_SZ_EXCHANGEABLE_LOAN = "120***|117***|1156**|1157**|1158**|1159**,SZ,10078",--深圳可交换公司债 - XT_GE_SZ_ETF_CROSS_MARKET = "159602|159603|159606|159608|159609|159610|159611|159613|159616|159617|159618|159619|159620|159621|159623|159625|159628|159629|159630|159631|159633|159635|159637|159638|159639|159640|159641|159642|159643|159645|159646|159647|159658|159663|159667|159701|159702|159703|159707|159710|159713|159715|159717|159719|159720|159723|159725|159728|159729|159730|159731|159732|159733|159736|159738|159739|159743|159745|159748|159752|159755|159757|159758|159760|159761|159763|159766|159767|159768|159769|159770|159775|159778|159779|159780|159781|159782|159786|159787|159789|159791|159793|159795|159796|159797|159798|159813|159815|159819|159820|159824|159825|159827|159828|159835|159837|159838|159839|159840|159841|159842|159843|159845|159847|159848|159849|159851|159852|159853|159855|159856|159857|159858|159859|159861|159862|159863|159864|159865|159867|159870|159871|159872|159873|159875|159876|159877|159880|159881|159883|159885|159886|159887|159888|159889|159890|159891|159895|159896|159898|159899|159999|159980|159981|159985|159649|159650|159801|159805|159806|159807|159811|159919|159922|159923|159925|159928|159929|159930|159931|159933|159935|159936|159938|159939|159940|159944|159945|159951|159953|159959|159962|159965|159968|159973|159974|159982|159986|159987|159990|159992|159993|159994|159995|159996|159997|159998|159809|159983|159978|159979|159976|159984|159869|159790|159783|159601|159672|159676|159685|159653|159657|159689|159671|159678|159679|159666|159652|159656|159669|159683|159665|159677|159675|159662|159627|159680|159907|159515|159517|159698|159510|159511|159516|159512|159503|159686|159673|159508|159690|159507|159692|159695|159622|159670|159697,SZ,10079",--深圳跨市etf + XT_GE_SZ_ETF_CROSS_MARKET = "159602|159603|159606|159608|159609|159610|159611|159613|159616|159617|159618|159619|159620|159621|159623|159625|159628|159629|159630|159631|159633|159635|159637|159638|159639|159640|159641|159642|159643|159645|159646|159647|159658|159663|159667|159701|159703|159707|159713|159715|159717|159719|159720|159723|159725|159728|159729|159730|159731|159732|159736|159738|159739|159743|159745|159748|159752|159755|159757|159758|159760|159761|159763|159766|159767|159768|159769|159770|159775|159778|159779|159780|159781|159782|159786|159787|159791|159793|159795|159796|159797|159798|159813|159819|159820|159824|159825|159827|159828|159835|159837|159838|159839|159840|159841|159842|159843|159845|159847|159848|159849|159851|159852|159855|159856|159857|159858|159859|159861|159862|159863|159864|159865|159867|159870|159871|159872|159873|159875|159876|159877|159880|159881|159883|159885|159886|159887|159888|159889|159890|159891|159895|159896|159898|159899|159801|159805|159806|159807|159811|159919|159922|159923|159925|159928|159929|159930|159931|159933|159935|159936|159938|159939|159940|159944|159945|159959|159965|159968|159973|159974|159982|159987|159990|159992|159993|159994|159995|159996|159997|159998|159976|159869|159790|159783|159601|159672|159676|159685|159653|159657|159689|159671|159678|159679|159666|159652|159656|159669|159683|159665|159677|159675|159662|159627|159680|159907|159515|159517|159698|159510|159511|159516|159512|159503|159686|159673|159508|159690|159507|159692|159695|159622|159670|159697|159505|159520|159521|159522|159523|159531|159532|159535|159536|159537|159538|159539|159540|159543|159546|159549|159551|159555|159560|159661|159693|159565|159566|159547|159527|159562|159530|159556|159559|159593|159589|159591|159592|159595|159596|159581|159586|159300|159542|159533|159322|159315|159558|159309|159552|159583|159800|159301|159332|159327|159330|159587|159335|159326|159351|159339|159338|159352|159353|159305|159337|159590|159325|159328|159361,SZ,10079",--深圳跨市etf XT_GE_SZ_100_ETF = "159901,SZ,10080",--深证100ETF股票期权 XT_GE_SZ_500_ETF = "159922,SZ,10081",--深圳500ETF XT_GE_SZ_CYB_ETF = "159915,SZ,10082",--创业板ETF + XT_GE_SZ_BEARER_LOAN_ETF = "159972|159816,SZ,10083",--深市实物债券ETF + XT_GE_SZ_CR_LOAN_ETF = "159651|159649|159650,SZ,10084",--深市现金债券ETF + XT_GE_SZ_COMMODITY_FUTURES_ETF = "159980|159981|159985,SZ,10085",--深市商品期货ETF XT_GE_MARKET_NEW3BOARD_DELISTED = "400***|420***,NEEQ,20000", --两网及退市公司股票 新三板 XT_GE_NEW3BOARD_PREFERED_SHARES_TRANSFER = "820***,NEEQ,20001", --全国股转非公开优先股转让 - XT_GE_BJ = "43****|83****|87****,BJ,20002",--北交 - XT_GE_BJ_SUBSCRIBE = "889***,BJ,20003",--北交所申购 + XT_GE_BJ = "43****|83****|87****|920***,BJ,20002",--北交 + XT_GE_BJ_SUBSCRIBE = "889***|920***,BJ,20003",--北交所申购 + XT_GE_BJ_CENTRAL_GOVERNMENT_LOAN = "802***|812***,BJ,20004",--京市国债 + XT_GE_BJ_LOCAL_GOVERNMENT_LOAN = "801***|809***,BJ,20005",--京市地方债 + XT_GE_BJ_GOVERNMENT_LOAN = "802***|812***|801***|809***,BJ,20006",--京市政府债(国债+地方债) + XT_GE_BJ_CORPORATE_LOAN = "821***,BJ,20007",--京市公司债 }, --存放扩展类型,能用基础类型描述的,尽量用基础类型,基础类型执行效率高于扩展类型 --扩展类型可以是基础类型,也可以由基础类型通过简单的&(且)|(或)运算得出,允许用小括号调整运算优先级 @@ -347,12 +355,12 @@ g_stocktype_info = { XT_GE_EXTRA_MARKET_ST = "XT_GE_MARKET_SH|XT_GE_MARKET_SZ,100008",--股票 XT_GE_EXTRA_SZ_CGL = "XT_GE_SZ_GLIB|XT_GE_SZ_GLD,100009",--深市中央政府债(国债) XT_GE_EXTRA_SZ_GL = "XT_GE_EXTRA_SZ_CGL|XT_GE_SZ_LGL,100010",--深市政府债 - XT_GE_EXTRA_SZ_LOAN = "XT_GE_SZ_GLIB|XT_GE_SZ_GLD|XT_GE_SZ_CB|XT_GE_SZ_CBB|XT_GE_SZ_EB|XT_GE_SZ_SB|XT_GE_SZ_MSP_PB|XT_GE_SZ_SFMP|XT_GE_SZ_LGL|XT_GE_SZ_POB|XT_GE_SZ_SCB_PB|XT_GE_SZ_ZB_CCB|XT_GE_SZ_CYB_CCB|XT_GE_SZ_ZXB_CCB|XT_GE_SZ_LOAN_REITS|XT_GE_SZ_LOAN_DIRECTIONAL|XT_GE_SZ_EXCHANGEABLE_LOAN|XT_GE_SZ_ENTERPROSE_SUPPORT_BOND|XT_GE_SZ_GOV_ALLOW,100011",--深市所有债券 + XT_GE_EXTRA_SZ_LOAN = "XT_GE_SZ_GLIB|XT_GE_SZ_GLD|XT_GE_SZ_CB|XT_GE_SZ_CBB|XT_GE_SZ_EB|XT_GE_SZ_SB|XT_GE_SZ_MSP_PB|XT_GE_SZ_SFMP|XT_GE_SZ_LGL|XT_GE_SZ_POB|XT_GE_SZ_SCB_PB|XT_GE_SZ_ZB_CCB|XT_GE_SZ_CYB_CCB|XT_GE_SZ_ZXB_CCB|XT_GE_SZ_LOAN_REITS|XT_GE_SZ_LOAN_DIRECTIONAL|XT_GE_SZ_EXCHANGEABLE_LOAN|XT_GE_SZ_ENTERPROSE_SUPPORT_BOND|XT_GE_SZ_GOV_ALLOW|XT_GE_SZ_LOAN_IPO|XT_GE_SZ_ASS,100011",--深市所有债券 XT_GE_EXTRA_STOCK_EX = "!XT_GE_EXTRA_STOCK_INDEX,100012",--广义的股票 XT_GE_EXTRA_ETF = "XT_GE_SH_ETF|XT_GE_SZ_ETF,100013",--ETF XT_GE_EXTRA_CLOSED_ENDED_FUNDS = "XT_GE_SH_CLOSED_ENDED_FUNDS|XT_GE_SZ_CEF,100014",--封闭式基金 XT_GE_EXTRA_WARRANT = "XT_GE_SH_WARRANT|XT_GE_SZ_WARRANT,100015",--权证 - XT_GE_EXTRA_LOAN = "XT_GE_EXTRA_SH_LOAN|XT_GE_EXTRA_SZ_LOAN,100016",--债券 + XT_GE_EXTRA_LOAN = "XT_GE_EXTRA_SH_LOAN|XT_GE_EXTRA_SZ_LOAN|XT_GE_EXTRA_BJ_LOAN,100016",--债券 XT_GE_EXTRA_SZ_GLR = "XT_GE_SZ_GLRA&(!XT_GE_SZ_GLR),100017",--深市国债回购 XT_GE_EXTRA_STANDARD_BOND = "XT_GE_SH_STANDARD_BOND|XT_GE_SZ_STANDAR_B,100018",--标准券 XT_GE_EXTRA_POLICY_JRZ = "XT_GE_SH_POLICY_JRZ,100019", @@ -364,7 +372,7 @@ g_stocktype_info = { XT_GE_EXTRA_SH_IPO = "XT_GE_SH_STOCK_IPO|XT_GE_SH_LOAN_IPO|XT_GE_SH_FUND_IPO,100025",--上海申购代码 XT_GE_EXTRA_CB_ETF = "XT_GE_SZ_CB_ETF|XT_GE_SH_CROSS_BORDER_ETF,100026",--跨境ETF XT_GE_EXTRA_CB_LOF = "XT_GE_SH_CROSS_BORDER_LOF|XT_GE_SZ_CB_LOF,100027",--跨境LOF - XT_GE_EXTRA_STOCK_TRANABLE = "XT_GE_EXTRA_STOCK|XT_GE_EXTRA_FUND|XT_GE_EXTRA_ETF|XT_GE_EXTRA_WARRANT|XT_GE_SH_SUBSCRIBE|XT_GE_SZ_GEM_BORAD|XT_GE_EXTRA_GLR|XT_GE_EXTRA_LOAN|XT_GE_SF_FIXED_INCOME_ETF|XT_GE_EXTRA_GOLD|XT_GE_EXTRA_MONETARY_FUND|XT_GE_EXTRA_SZ_CGL|XT_GE_SH_CENTRAL_GOVERNMENT_LOAN|XT_GE_SH_LOCAL_GOVERNMENT_LOAN|XT_GE_SZ_LGL|XT_GE_EXTRA_SH_IPO|XT_GE_SH_PLEDGE|XT_GE_EXTRA_CB_ETF|XT_GE_EXTRA_CB_LOF|XT_GE_SH_SHARES_ALLOTMEN|XT_GE_SH_SHARES_CONVERTIBLE_BOND|XT_GE_SZ_CBB|XT_GE_SH_CONVERTIBALE_BOND|XT_GE_SH_SEO|XT_GE_SZ_SEO|XT_GE_SH_LOAN_CBB_SCB_NEW|XT_GE_SZ_LOAN_IPO|XT_GE_SZ_CDR_ALLOTMEN|XT_GE_SH_TECH_BOARD|XT_GE_SH_BOND_OFFER_REPURCHASE|XT_GE_SH_SUBSCRIPTION_TECH_BOARD|XT_GE_SH_TRANSACTION_ETF_CROSS_MARKET|XT_GE_BOND_DISTRIBUTION|XT_GE_SH_PUBLIC_PREFERED_SHARES|XT_GE_SH_NON_PUBLIC_PREFERED_SHARES_TRANSFER|XT_GE_SH_BOND_RESALE|XT_GE_SH_CONVERTIBALE_BOND_RESALE|XT_GE_SH_CONVERTIBLE_BOND_STOCK|XT_GE_SZ_NON_PUBLIC_PREFERED_SHARES_TRANSFER|XT_GE_SZ_SA|XT_GE_SZ_OLDSHARES_PREFERRED_CONVERTIBLE_BOND|XT_GE_SH_ENTERPROSE_SUPPORT_AUCTION_BOND|XT_GE_EXTRA_PUBLIC_INFRASTRUCTURE_FUND|XT_GE_BJ_SUBSCRIBE,100028",--可交易的 + XT_GE_EXTRA_STOCK_TRANABLE = "XT_GE_EXTRA_STOCK|XT_GE_EXTRA_FUND|XT_GE_EXTRA_ETF|XT_GE_EXTRA_WARRANT|XT_GE_SH_SUBSCRIBE|XT_GE_SZ_GEM_BORAD|XT_GE_EXTRA_GLR|XT_GE_EXTRA_LOAN|XT_GE_SF_FIXED_INCOME_ETF|XT_GE_EXTRA_GOLD|XT_GE_EXTRA_MONETARY_FUND|XT_GE_EXTRA_SZ_CGL|XT_GE_SH_CENTRAL_GOVERNMENT_LOAN|XT_GE_SH_LOCAL_GOVERNMENT_LOAN|XT_GE_SZ_LGL|XT_GE_EXTRA_SH_IPO|XT_GE_SH_PLEDGE|XT_GE_EXTRA_CB_ETF|XT_GE_EXTRA_CB_LOF|XT_GE_SH_SHARES_ALLOTMEN|XT_GE_SH_SHARES_CONVERTIBLE_BOND|XT_GE_SZ_CBB|XT_GE_SH_CONVERTIBALE_BOND|XT_GE_SH_SEO|XT_GE_SZ_SEO|XT_GE_SH_LOAN_CBB_SCB_NEW|XT_GE_SZ_LOAN_IPO|XT_GE_SZ_CDR_ALLOTMEN|XT_GE_SH_TECH_BOARD|XT_GE_SH_BOND_OFFER_REPURCHASE|XT_GE_SH_SUBSCRIPTION_TECH_BOARD|XT_GE_SH_TRANSACTION_ETF_CROSS_MARKET|XT_GE_BOND_DISTRIBUTION|XT_GE_SH_PUBLIC_PREFERED_SHARES|XT_GE_SH_NON_PUBLIC_PREFERED_SHARES_TRANSFER|XT_GE_SH_BOND_RESALE|XT_GE_SH_CONVERTIBALE_BOND_RESALE|XT_GE_SH_CONVERTIBLE_BOND_STOCK|XT_GE_SZ_NON_PUBLIC_PREFERED_SHARES_TRANSFER|XT_GE_SZ_SA|XT_GE_SZ_OLDSHARES_PREFERRED_CONVERTIBLE_BOND|XT_GE_SH_ENTERPROSE_SUPPORT_AUCTION_BOND|XT_GE_EXTRA_PUBLIC_INFRASTRUCTURE_FUND|XT_GE_BJ_SUBSCRIBE|XT_GE_BJ_GOVERNMENT_LOAN|XT_GE_BJ_CORPORATE_LOAN,100028",--可交易的 XT_GE_EXTRA_MAIN_BOARD = "XT_GE_SH_MAIN_BOARD|XT_GE_SZ_MAIN_BOARD,100029", --主板 XT_GE_EXTRA_INTRA_DAY = "XT_GE_EXTRA_LOAN|XT_GE_EXTRA_GOLD|XT_GE_SF_FIXED_INCOME_ETF|XT_GE_EXTRA_WARRANT|XT_GE_EXTRA_CB_ETF|XT_GE_EXTRA_CB_LOF|XT_GE_SH_TMF|XT_GE_SZ_RTMF|XT_GE_EXTRA_LOAN_ETF|XT_GE_EXTRA_MARKET_FU|XT_GE_MARKET_OP,100030", --回转交易 XT_GE_EXTRA_SH_DISTRIBUTION = "XT_GE_SH_NEW_SHARES_DISTRIBUTION|XT_GE_SH_PLACING_FIRST_DISTRIBUTION|XT_GE_SH_CONVERTIBLE_BOUND_DISTRIBUTION,100031", --上海配号 @@ -375,7 +383,7 @@ g_stocktype_info = { XT_GE_EXTRA_GF = "XT_GE_SH_GF|XT_GE_SZ_GF,100036", --分级基金 XT_GE_EXTRA_LOF = "XT_GE_SH_LOF|XT_GE_SZ_LOF,100037", --LOF XT_GE_EXTRA_LOAN_ETF = "XT_GE_SH_LOAN_ETF|XT_GE_SZ_LOAN_ETF,100038", --债券ETF - XT_GE_EXTRA_SH_LOAN = "XT_GE_SH_GOVERNMENT_LOAN_INTEREST_BEARING|XT_GE_SH_GOVERNMENT_LOAN_DISCOUNT|XT_GE_SH_LOCAL_GOVERNMENT_LOAN|XT_GE_SH_CONVERTIBALE_BOND|XT_GE_SH_CORPORATE_BOND|XT_GE_SH_ENTERPRISE_BOND|XT_GE_SH_ASSET_SECURITIZATION|XT_GE_SH_SEPERATION_BOND_REPURCHASE|XT_GE_SH_FINANCIAL_BONDS|XT_GE_SH_CREDIT_ASSET_SUPPORTED|XT_GE_SH_EXCHANGEABLE_LOAN|XT_GE_SH_PRIVATELY_LOAN_TRANSFER|XT_GE_SH_SHORTTERM_CORPORATE_LOAN_TRANSFER|XT_GE_SH_EPB_TRANSFER|XT_GE_SH_CPB|XT_GE_SH_CPB_LOAN|XT_GE_SH_GOVERNMENT_LOAN|XT_GE_SH_SEPERATION_BOND|XT_GE_SH_LOAN_CBB_SCB_NEW|XT_GE_SH_MS_PRIVATE_PLACEMENT_BOND|XT_GE_SH_ENTERPROSE_SUPPORT_BOND|XT_GE_SH_PUBLIC_CORPORATE_TRADE_LOAN|XT_GE_SH_NON_PUBLIC_CORPORATE_LOAN|XT_GE_SH_ASS|XT_GE_SH_GOV_ALLOW,100039", --上海债券 + XT_GE_EXTRA_SH_LOAN = "XT_GE_SH_GOVERNMENT_LOAN_INTEREST_BEARING|XT_GE_SH_GOVERNMENT_LOAN_DISCOUNT|XT_GE_SH_LOCAL_GOVERNMENT_LOAN|XT_GE_SH_CONVERTIBALE_BOND|XT_GE_SH_CORPORATE_BOND|XT_GE_SH_ENTERPRISE_BOND|XT_GE_SH_ASSET_SECURITIZATION|XT_GE_SH_SEPERATION_BOND_REPURCHASE|XT_GE_SH_FINANCIAL_BONDS|XT_GE_SH_CREDIT_ASSET_SUPPORTED|XT_GE_SH_EXCHANGEABLE_LOAN|XT_GE_SH_PRIVATELY_LOAN_TRANSFER|XT_GE_SH_SHORTTERM_CORPORATE_LOAN_TRANSFER|XT_GE_SH_EPB_TRANSFER|XT_GE_SH_CPB|XT_GE_SH_CPB_LOAN|XT_GE_SH_GOVERNMENT_LOAN|XT_GE_SH_SEPERATION_BOND|XT_GE_SH_LOAN_CBB_SCB_NEW|XT_GE_SH_MS_PRIVATE_PLACEMENT_BOND|XT_GE_SH_ENTERPROSE_SUPPORT_BOND|XT_GE_SH_PUBLIC_CORPORATE_TRADE_LOAN|XT_GE_SH_NON_PUBLIC_CORPORATE_LOAN|XT_GE_SH_ASS|XT_GE_SH_GOV_ALLOW|XT_GE_SH_LOAN_IPO,100039", --上海债券 XT_GE_EXTRA_REPURCHASE_DAY_1 = "XT_GE_SH_LOAN_REPURCHASE_DAY_1|XT_GE_SZ_LOAN_REPURCHASE_DAY_1,100040", --1天逆回购 XT_GE_EXTRA_REPURCHASE_DAY_2 = "XT_GE_SH_LOAN_REPURCHASE_DAY_2|XT_GE_SZ_LOAN_REPURCHASE_DAY_2,100041", --2天逆回购 XT_GE_EXTRA_REPURCHASE_DAY_3 = "XT_GE_SH_LOAN_REPURCHASE_DAY_3|XT_GE_SZ_LOAN_REPURCHASE_DAY_3,100042", --3天逆回购 @@ -385,8 +393,8 @@ g_stocktype_info = { XT_GE_EXTRA_REPURCHASE_DAY_28 = "XT_GE_SH_LOAN_REPURCHASE_DAY_28|XT_GE_SZ_LOAN_REPURCHASE_DAY_28,100046", --28天逆回购 XT_GE_EXTRA_REPURCHASE_DAY_28_UPPER = "XT_GE_SH_LOAN_REPURCHASE_DAY_28_UPPER|XT_GE_SZ_LOAN_REPURCHASE_DAY_28_UPPER,100047", --28天以上逆回购 XT_GE_EXTRA_NOT_CLOSING_AUCTION_MATCH = "XT_GE_EXTRA_SH_LOAN|XT_GE_SH_FUND|XT_GE_SH_ETF|XT_GE_SH_BOND_OFFER_REPURCHASE|XT_GE_SH_GOVERNMENT_LOAN_REPURCHASE|XT_GE_SH_PLEDGE,100070", --上交所不执行收盘集合竞价的品种 - XT_GE_EXTRA_RATE_BOND = "XT_GE_SH_GOVERNMENT_LOAN|XT_GE_EXTRA_SZ_GL|XT_GE_SH_POLICY_JRZ|XT_GE_BANK_LOAN,100080", --利率类债券 - XT_GE_EXTRA_FICC = "XT_GE_SH_CORPORATE_BOND|XT_GE_SH_OLD_GOVERNMENT_LOAN|XT_GE_SH_CENTRAL_GOVERNMENT_LOAN|XT_GE_SH_GOVERNMENT_LOAN_INTEREST_BEARING|XT_GE_SH_CONVERTIBALE_BOND|XT_GE_SH_ENTERPRISE_BOND|XT_GE_SH_MS_PRIVATE_PLACEMENT_BOND|XT_GE_SH_SEPERATION_BOND|XT_GE_SH_CREDIT_ASSET_SUPPORTED|XT_GE_SH_GOVERNMENT_LOAN|XT_GE_SH_ENTERPROSE_SUPPORT_BOND|XT_GE_SH_EXCHANGEABLE_LOAN|XT_GE_SH_PRIVATELY_LOAN_TRANSFER|XT_GE_SH_SHORTTERM_CORPORATE_LOAN_TRANSFER|XT_GE_SH_CPB_LOAN|XT_GE_SH_NON_PUBLIC_CONVERTIBLE_BOND_STOCK|XT_GE_SH_BOND_TRIPARTITE_REPURCHASE|XT_GE_SH_LOW_CORPORATE_BOND|XT_GE_SH_ASSET_BACKED_SECURITIES|XT_GE_SH_LOCAL_GOVERNMENT_LOAN|XT_GE_SH_NON_PUBLIC_CORPORATE_LOAN|XT_GE_SH_ASS|XT_GE_SH_FINANCIAL_BONDS|XT_GE_SH_BOND_PROTOCOL_REPURCHASE|XT_GE_SH_BOND_TRIPARTITE_REPURCHASE|XT_GE_SZ_LOAN_REITS|XT_GE_SZ_LOAN_DIRECTIONAL|XT_GE_SH_PUBLIC_CORPORATE_TRADE_LOAN|XT_GE_SH_PUBLIC_INFRASTRUCTURE_FUND|XT_GE_SH_GOV_ALLOW,100090", --固收 + XT_GE_EXTRA_RATE_BOND = "XT_GE_SH_GOVERNMENT_LOAN|XT_GE_EXTRA_SZ_GL|XT_GE_SH_POLICY_JRZ|XT_GE_BANK_LOAN|XT_GE_BJ_GOVERNMENT_LOAN ,100080", --利率类债券 + XT_GE_EXTRA_FICC = "XT_GE_SH_CORPORATE_BOND|XT_GE_SH_OLD_GOVERNMENT_LOAN|XT_GE_SH_CENTRAL_GOVERNMENT_LOAN|XT_GE_SH_GOVERNMENT_LOAN_INTEREST_BEARING|XT_GE_SH_CONVERTIBALE_BOND|XT_GE_SH_ENTERPRISE_BOND|XT_GE_SH_MS_PRIVATE_PLACEMENT_BOND|XT_GE_SH_SEPERATION_BOND|XT_GE_SH_CREDIT_ASSET_SUPPORTED|XT_GE_SH_GOVERNMENT_LOAN|XT_GE_SH_ENTERPROSE_SUPPORT_BOND|XT_GE_SH_EXCHANGEABLE_LOAN|XT_GE_SH_PRIVATELY_LOAN_TRANSFER|XT_GE_SH_SHORTTERM_CORPORATE_LOAN_TRANSFER|XT_GE_SH_CPB_LOAN|XT_GE_SH_NON_PUBLIC_CONVERTIBLE_BOND_STOCK|XT_GE_SH_BOND_TRIPARTITE_REPURCHASE|XT_GE_SH_LOW_CORPORATE_BOND|XT_GE_SH_LOCAL_GOVERNMENT_LOAN|XT_GE_SH_NON_PUBLIC_CORPORATE_LOAN|XT_GE_SH_ASS|XT_GE_SH_FINANCIAL_BONDS|XT_GE_SH_BOND_PROTOCOL_REPURCHASE|XT_GE_SH_BOND_TRIPARTITE_REPURCHASE|XT_GE_SZ_LOAN_REITS|XT_GE_SZ_LOAN_DIRECTIONAL|XT_GE_SH_PUBLIC_CORPORATE_TRADE_LOAN|XT_GE_SH_PUBLIC_INFRASTRUCTURE_FUND|XT_GE_SH_GOV_ALLOW|XT_GE_BJ_GOVERNMENT_LOAN|XT_GE_BJ_CORPORATE_LOAN|XT_GE_SZ_ASS,100090", --固收 XT_GE_BOND_DISTRIBUTION = "XT_GE_SH_GOVERNMENT_LOAN_DISTRIBUTE_SALE|XT_GE_SH_LOCAL_GOVERNMENT_LOAN_DISTRIBUTE_SALE|XT_GE_SH_PUBLIC_LOAN_DISTRIBUTE_SALE|XT_GE_SH_LOAN_ISSUANCE_DISTRIBUTE_SALE|XT_GE_SZ_LOAN_ISSUANCE_DISTRIBUTE_SALE|XT_GE_SH_GOVERNMENT_BANK_FINANCE_LOAN_DISTRIBUTE_SALE|XT_GE_SH_LOCAL_GOVERNMENT_LOAN_ONLINE_DISTRIBUTE_SALE,100200", --债券分销 XT_GE_EXTRA_50_ETF = "XT_GE_SH_50_ETF,100100", XT_GE_EXTRA_300_ETF = "XT_GE_SH_300_ETF|XT_GE_SZ_300_ETF,100101", @@ -399,12 +407,13 @@ g_stocktype_info = { XT_GE_EXTRA_100_ETF = "XT_GE_SZ_100_ETF,100108",--100ETF股票期权 XT_GE_EXTRA_500_ETF = "XT_GE_SH_500_ETF|XT_GE_SZ_500_ETF,100109",--500ETF XT_GE_EXTRA_CYB_ETF = "XT_GE_SZ_CYB_ETF,100110",--创业板ETF + XT_GE_EXTRA_BJ_LOAN = "XT_GE_BJ_CENTRAL_GOVERNMENT_LOAN|XT_GE_BJ_LOCAL_GOVERNMENT_LOAN|XT_GE_BJ_GOVERNMENT_LOAN|XT_GE_BJ_CORPORATE_LOAN,100111",--北京债券 }, optionTypes = { - XT_GE_SF_FTOPTION = "au*****?|cu*****?|al*****?|ru*****?|zn*****?|ag*****?|rb*****?|br*****?,SFO,100050", --上期所期权 四位到期数字,一位C/P - XT_GE_ZF_FTOPTION = "SR****?|CF****?|TA****?|MA****?|RM****?|ZC****?|OI****?|PK****?|PX****?|SH****?,ZFO,100051", --郑商所期权 三位到期数字,一位C/P - XT_GE_DF_FTOPTION = "m****-*-?|c****-*-?|i****-*-?|y****-*-?|p****-*-?|j****-*-?|jm****-*-?|pg****-*-?|v****-*-?|l****-*-?|pp****-*-?|a****-*-?|b****-*-?|eg****-*-?|eb****-*-?,DFO,100052", --大商所期权 四位到期数字,一位C/P + XT_GE_SF_FTOPTION = "au*****?|cu*****?|al*****?|ru*****?|zn*****?|ag*****?|rb*****?|br*****?|pb*****?|ni*****?|sn*****?|ao*****?,SFO,100050", --上期所期权 四位到期数字,一位C/P + XT_GE_ZF_FTOPTION = "SR****?|CF****?|TA****?|MA****?|RM****?|ZC****?|OI****?|PK****?|PX****?|SH****?|PF****?|SA****?|SM****?|SF****?|UR****?|AP****?,ZFO,100051", --郑商所期权 三位到期数字,一位C/P + XT_GE_DF_FTOPTION = "m****-*-?|c****-*-?|i****-*-?|y****-*-?|p****-*-?|j****-*-?|jm****-*-?|pg****-*-?|v****-*-?|l****-*-?|pp****-*-?|a****-*-?|b****-*-?|eg****-*-?|eb****-*-?|jd****-*-?|cs****-*-?|lh****-*-?|lg****-*-?,DFO,100052", --大商所期权 四位到期数字,一位C/P XT_GE_IF_FTOPTION = "HO?|IO?|MO?|ZO?|IF?^&&IO?,IFO,100053", --中金所期权,HO\IO期权专用,有IF套利期权合约 XT_GE_SF_ARBITAGE_FTOPTION = ",SFO,100054",--上期所套利期权 XT_GE_ZF_ARBITAGE_FTOPTION = ",ZFO,100055",--郑商所套利期权 diff --git a/src/xtquant/datacenter.cp310-win_amd64.pyd b/src/xtquant/datacenter.cp310-win_amd64.pyd index ed78fa6..1311b0a 100644 Binary files a/src/xtquant/datacenter.cp310-win_amd64.pyd and b/src/xtquant/datacenter.cp310-win_amd64.pyd differ diff --git a/src/xtquant/datacenter.cp311-win_amd64.pyd b/src/xtquant/datacenter.cp311-win_amd64.pyd index c0a7d49..2edbfb3 100644 Binary files a/src/xtquant/datacenter.cp311-win_amd64.pyd and b/src/xtquant/datacenter.cp311-win_amd64.pyd differ diff --git a/src/xtquant/datacenter.cp312-win_amd64.pyd b/src/xtquant/datacenter.cp312-win_amd64.pyd index 2fe7af7..13428d5 100644 Binary files a/src/xtquant/datacenter.cp312-win_amd64.pyd and b/src/xtquant/datacenter.cp312-win_amd64.pyd differ diff --git a/src/xtquant/datacenter.cp313-win_amd64.pyd b/src/xtquant/datacenter.cp313-win_amd64.pyd new file mode 100644 index 0000000..52beb91 Binary files /dev/null and b/src/xtquant/datacenter.cp313-win_amd64.pyd differ diff --git a/src/xtquant/datacenter.cp36-win_amd64.pyd b/src/xtquant/datacenter.cp36-win_amd64.pyd index 402ca23..0afecd6 100644 Binary files a/src/xtquant/datacenter.cp36-win_amd64.pyd and b/src/xtquant/datacenter.cp36-win_amd64.pyd differ diff --git a/src/xtquant/datacenter.cp37-win_amd64.pyd b/src/xtquant/datacenter.cp37-win_amd64.pyd index cfeb5d8..3a242d7 100644 Binary files a/src/xtquant/datacenter.cp37-win_amd64.pyd and b/src/xtquant/datacenter.cp37-win_amd64.pyd differ diff --git a/src/xtquant/datacenter.cp38-win_amd64.pyd b/src/xtquant/datacenter.cp38-win_amd64.pyd index 03e0860..99d670d 100644 Binary files a/src/xtquant/datacenter.cp38-win_amd64.pyd and b/src/xtquant/datacenter.cp38-win_amd64.pyd differ diff --git a/src/xtquant/datacenter.cp39-win_amd64.pyd b/src/xtquant/datacenter.cp39-win_amd64.pyd index d3aab12..8fa8ce3 100644 Binary files a/src/xtquant/datacenter.cp39-win_amd64.pyd and b/src/xtquant/datacenter.cp39-win_amd64.pyd differ diff --git a/src/xtquant/datacenter_shared.dll b/src/xtquant/datacenter_shared.dll new file mode 100644 index 0000000..cda66a2 Binary files /dev/null and b/src/xtquant/datacenter_shared.dll differ diff --git a/src/xtquant/doc/xtdata.md b/src/xtquant/doc/xtdata.md index ad58c19..c053deb 100644 --- a/src/xtquant/doc/xtdata.md +++ b/src/xtquant/doc/xtdata.md @@ -89,6 +89,12 @@ xtdata是xtquant库中提供行情相关数据的模块,本模块旨在提供 - `get_stock_list_in_sector` 增加`real_timetag`参数 - 2024-09-06 - 增加`subscribe_quote2`,与第一版相比,多一个除权参数 +- 2024-10-11 + - `data_dir`变量作用改为设置用户自定义数据路径 + - `get_data_dir`函数来返回数据路径 +- 2024-10-16 + - 删除`get_trading_time`函数 + - 增加`get_trading_period`,`get_kline_trading_period`,`get_all_trading_periods`,`get_all_kline_trading_periods`函数获取交易时段 ## 接口概述 @@ -759,6 +765,23 @@ get_full_kline(field_list = [], stock_list = [], period = '1m' - 返回 - dict - {field: DataFrame} +#### 获取本地数据路径 + +```python +get_data_dir() +``` + +- 释义 + - 获取本地数据路径 +- 参数 + - 无 +- 返回 + - str +- 备注 + - 如果更改过`xtdata.data_dir`变量的值,优先返回变量设置的值 + - 没有设置过,返回服务的数据路径 + - 注意----设置`xtdata.data_dir`的值可以强制指定读取本地数据的位置,谨慎修改 + ### 财务数据接口 #### 获取财务数据 @@ -1348,6 +1371,205 @@ download_index_weight() 'turnoverRate10' #10日换手 ``` +#### hfiopv - 高频IOPV + +```python +高频IOPV数据指标, 100ms推送频率 +普通指标: +'time' #时间戳 +'dIOPV' #动态IOPV +'dUpperLimitIOPV' #涨停IOPV +'dLowerLimitIOPV' #跌停IOPV +'dSidecarIOPV' #停牌IOPV +'dUpperLimitMarketValue' #涨停成分股市值 +'dLowerLimitMarketValue' #跌停成分股市值 +'dSidecarMarketValue' #停牌成分股市值 +'dUpperLimitMarketValue_local' #本市场涨停成分股市值 +'dLowerLimitMarketValue_local' #本市场跌停成分股市值 +'dSidecarMarketValue_local' #本市场停牌成分股市值 +'dUpperLimitMarketValue_SH' #上海市场涨停成分股市值 +'dLowerLimitMarketValue_SH' #上海市场跌停成分股市值 +'dSidecarMarketValue_SH' #上海市场停牌成分股市值 +'dUpperLimitMarketValue_SZ' #深圳市场涨停成分股市值 +'dLowerLimitMarketValue_SZ' #深圳市场跌停成分股市值 +'dSidecarMarketValue_SZ' #深圳市场停牌成分股市值 +'dIndexDeviation' #指数偏差 + +五档指标: +'purchaseIOPVs' #申购动态IOPV +'redemptionIOPVs' #赎回动态IOPV +'lxPurchaseIOPV' #申购IOPV +'lxRedemptionIOPV' #赎回IOPV +'lxPremiumNoRisk' #溢价无风险 +'lxDiscountNoRisk' #折价无风险 +'purchaseMarketValue' #申购市值 +'redemptionMarketValue' #赎回市值 +'purchaseMarketValue_local' #本市场申购市值 +'redemptionMarketValue_local' #本市场赎回市值 +'premiumProfits' #五档预估溢价 +'discountProfits' #五档预估折价 +'premiumCapacitys' #溢价容量 +'discountCapacitys' #折价容量 +``` + +#### fullspeedorderbook - 全速盘口 + +```python +'time' #时间戳 +'price' #最新成交价 +'bidPrice' #多档委买价列表 [1 - 20]档 +'bidVolume' #多档委买量列表 [1 - 20]档 +'askPrice' #多档委卖价列表 [1 - 20]档 +'askVolume' #多档委卖量列表 [1 - 20]档 +``` + +#### l2transactioncount - level2逐笔成交统计 + +```python +'time' #时间戳 +'bidNumber' #主买单总单数 +'offNumber' #主卖单总单数 +'ddx' #大单动向 +'ddy' #涨跌动因 +'ddz' #大单差分 +'netOrder' #净挂单量 +'netWithdraw' #净撤单量 +'withdrawBid' #总撤买量 +'withdrawOff' #总撤卖量 +'bidNumberDx' #主买单总单数增量 +'offNumberDx' #主卖单总单数增量 +'transactionNumber' #成交笔数增量 + +'bidMostAmount' #主买特大单成交额 +'bidBigAmount' #主买大单成交额 +'bidMediumAmount' #主买中单成交额 +'bidSmallAmount' #主买小单成交额 +'bidTotalAmount' #主买累计成交额 + +'offMostAmount' #主卖特大单成交额 +'offBigAmount' #主卖大单成交额 +'offMediumAmount' #主卖中单成交额 +'offSmallAmount' #主卖小单成交额 +'offTotalAmount' #主卖累计成交额 + +'unactiveBidMostAmount' #被动买特大单成交额 +'unactiveBidBigAmount' #被动买大单成交额 +'unactiveBidMediumAmount' #被动买中单成交额 +'unactiveBidSmallAmount' #被动买小单成交额 +'unactiveBidTotalAmount' #被动买累计成交额 + +'unactiveOffMostAmount' #被动卖特大单成交额 +'unactiveOffBigAmount' #被动卖大单成交额 +'unactiveOffMediumAmount' #被动卖中单成交额 +'unactiveOffSmallAmount' #被动卖小单成交额 +'unactiveOffTotalAmount' #被动卖累计成交额 + +'netInflowMostAmount' #净流入超大单成交额 +'netInflowBigAmount' #净流入大单成交额 +'netInflowMediumAmount' #净流入中单成交额 +'netInflowSmallAmount' #净流入小单成交额 + +'bidMostVolume' #主买特大单成交量 +'bidBigVolume' #主买大单成交量 +'bidMediumVolume' #主买中单成交量 +'bidSmallVolume' #主买小单成交量 +'bidTotalVolume' #主买累计成交量 + +'offMostVolume' #主卖特大单成交量 +'offBigVolume' #主卖大单成交量 +'offMediumVolume' #主卖中单成交量 +'offSmallVolume' #主卖小单成交量 +'offTotalVolume' #主卖累计成交量 + +'unactiveBidMostVolume' #被动买特大单成交量 +'unactiveBidBigVolume' #被动买大单成交量 +'unactiveBidMediumVolume' #被动买中单成交量 +'unactiveBidSmallVolume' #被动买小单成交量 +'unactiveBidTotalVolume' #被动买累计成交量 + +'unactiveOffMostVolume' #被动卖特大单成交量 +'unactiveOffBigVolume' #被动卖大单成交量 +'unactiveOffMediumVolume' #被动卖中单成交量 +'unactiveOffSmallVolume' #被动卖小单成交量 +'unactiveOffTotalVolume' #被动卖累计成交量 + +'netInflowMostVolume' #净流入超大单成交量 +'netInflowBigVolume' #净流入大单成交量 +'netInflowMediumVolume' #净流入中单成交量 +'netInflowSmallVolume' #净流入小单成交量 + +'bidMostAmountDx' #主买特大单成交额增量 +'bidBigAmountDx' #主买大单成交额增量 +'bidMediumAmountDx' #主买中单成交额增量 +'bidSmallAmountDx' #主买小单成交额增量 +'bidTotalAmountDx' #主买累计成交额增量 + +'offMostAmountDx' #主卖特大单成交额增量 +'offBigAmountDx' #主卖大单成交额增量 +'offMediumAmountDx' #主卖中单成交额增量 +'offSmallAmountDx' #主卖小单成交额增量 +'offTotalAmountDx' #主卖累计成交额增量 + +'unactiveBidMostAmountDx' #被动买特大单成交额增量 +'unactiveBidBigAmountDx' #被动买大单成交额增量 +'unactiveBidMediumAmountDx' #被动买中单成交额增量 +'unactiveBidSmallAmountDx' #被动买小单成交额增量 +'unactiveBidTotalAmountDx' #被动买累计成交额增量 + +'unactiveOffMostAmountDx' #被动卖特大单成交额增量 +'unactiveOffBigAmountDx' #被动卖大单成交额增量 +'unactiveOffMediumAmountDx' #被动卖中单成交额增量 +'unactiveOffSmallAmountDx' #被动卖小单成交额增量 +'unactiveOffTotalAmountDx' #被动卖累计成交额增量 + +'netInflowMostAmountDx' #净流入超大单成交额增量 +'netInflowBigAmountDx' #净流入大单成交额增量 +'netInflowMediumAmountDx' #净流入中单成交额增量 +'netInflowSmallAmountDx' #净流入小单成交额增量 + +'bidMostVolumeDx' #主买特大单成交量增量 +'bidBigVolumeDx' #主买大单成交量增量 +'bidMediumVolumeDx' #主买中单成交量增量 +'bidSmallVolumeDx' #主买小单成交量增量 +'bidTotalVolumeDx' #主买累计成交量增量 + +'offMostVolumeDx' #主卖特大单成交量增量 +'offBigVolumeDx' #主卖大单成交量增量 +'offMediumVolumeDx' #主卖中单成交量增量 +'offSmallVolumeDx' #主卖小单成交量增量 +'offTotalVolumeDx' #主卖累计成交量增量 + +'unactiveBidMostVolumeDx' #被动买特大单成交量增量 +'unactiveBidBigVolumeDx' #被动买大单成交量增量 +'unactiveBidMediumVolumeDx' #被动买中单成交量增量 +'unactiveBidSmallVolumeDx' #被动买小单成交量增量 +'unactiveBidTotalVolumeDx' #被动买累计成交量增量 + +'unactiveOffMostVolumeDx' #被动卖特大单成交量增量 +'unactiveOffBigVolumeDx' #被动卖大单成交量增量 +'unactiveOffMediumVolumeDx' #被动卖中单成交量增量 +'unactiveOffSmallVolumeDx' #被动卖小单成交量增量 +'unactiveOffTotalVolumeDx' #被动卖累计成交量增量 + +'netInflowMostVolumeDx' #净流入超大单成交量增量 +'netInflowBigVolumeDx' #净流入大单成交量增量 +'netInflowMediumVolumeDx' #净流入中单成交量增量 +'netInflowSmallVolumeDx' #净流入小单成交量增量 +``` + +#### l2thousand - level2委买委卖千档盘口 + +```python +'timeTag' #时间戳 +'price' #最新成交价 +'bidPrice' #多档委买价(向量) +'bidVolume' #多档委买量(向量),单位是手 +'offPrice' #多档委卖价(向量) +'offVolume' #多档委卖量(向量),单位是手 +``` + + + ### 数据字典 #### 证券状态 diff --git a/src/xtquant/doc/xttrader.md b/src/xtquant/doc/xttrader.md index 7383f01..43fc94a 100644 --- a/src/xtquant/doc/xttrader.md +++ b/src/xtquant/doc/xttrader.md @@ -77,10 +77,10 @@ XtQuant目前提供的库包括Python3.6、3.7、3.8版本,不同版本的pyth - `xtconstant.MARKET_CONVERT_1` - 市价最优一档即成剩转[中金所] - `xtconstant.MARKET_CONVERT_5` - 市价最优五档即成剩转[中金所] - 2023-10-20 -- 委托结构`XtOrder`,成交结构`XtTrade`,持仓结构`XtPosition` 新增多空字段 - - `direction` - 多空,股票不需要 -- 委托结构`XtOrder`,成交结构`XtTrade`新增交易操作字段 - - `offset_flag` - 交易操作,用此字段区分股票买卖,期货开、平仓,期权买卖等 + - 委托结构`XtOrder`,成交结构`XtTrade`,持仓结构`XtPosition` 新增多空字段 + - `direction` - 多空,股票不需要 + - 委托结构`XtOrder`,成交结构`XtTrade`新增交易操作字段 + - `offset_flag` - 交易操作,用此字段区分股票买卖,期货开、平仓,期权买卖等 - 2023-11-03 - 添加券源行情查询接口 `smt_query_quoter` - 添加库存券约券申请接口 `smt_negotiate_order` @@ -89,8 +89,6 @@ XtQuant目前提供的库包括Python3.6、3.7、3.8版本,不同版本的pyth - 委托类型增加ETF申赎 - 2024-02-29 - 添加期货持仓统计查询接口`query_position_statistics` -- 2024-04-25 - - 数据结构添加`stock_code1`字段以适配长代码 - 2024-05-24 - 添加通用数据导出接口export_data - 添加通用数据查询接口query_data @@ -99,6 +97,39 @@ XtQuant目前提供的库包括Python3.6、3.7、3.8版本,不同版本的pyth - 2024-08-27 - 成交结构`XtTrade`新增手续费字段 - `commission` - 手续费 +- 2024-11-28 + - 资产结构`XtAsset`新增可取资金字段 + - `fetch_balance` - 可取资金 + - 委托结构`XtOrder`新增证券名称、股东代码字段 + - `instrument_name` - 证券名称 + - `secu_account` - 股东代码 + - 成交结构`XtTrade`新增证券名称、股东代码字段 + - `instrument_name` - 证券名称 + - `secu_account` - 股东代码 + - 持仓结构`XtPosition`新增证券名称、当前价、盈亏比例、股东代码字段 + - `instrument_name` - 证券名称 + - `last_price` - 当前价 + - `profit_rate` - 盈亏比例 + - `secu_account` - 股东代码 + - 添加银证转账(银行转证券)接口`bank_transfer_in`/`bank_transfer_in_async` + - 添加银证转账(证券转银行)接口`bank_transfer_out`/`bank_transfer_out_async` + - 添加银行信息查询接口`query_bank_info` + - 添加银行转账流水查询接口`query_bank_transfer_stream` + - 添加股东账户查询接口`query_secu_account` +- 2025-02-13 + - 持仓结构`XtPosition`新增浮动盈亏字段 + - `float_profit` - 浮动盈亏 +- 2025-03-10 + - 添加银行余额查询接口`query_bank_amount` +- 2025-03-19 + - 持仓结构`XtPosition`新增开仓日期字段 + - `open_date` - 开仓日期,股票不需要 +- 2025-03-27 + - 添加CTP资金内转(期权转期货)接口`ctp_transfer_option_to_future`/`ctp_transfer_option_to_future_async` + - 添加CTP资金内转(期货转期权)接口`ctp_transfer_future_to_option`/`ctp_transfer_future_to_option_async` +- 2025-04-09 + - 持仓结构`XtPosition`新增持仓盈亏字段 + - `position_profit` - 持仓盈亏,股票不需要 ## 快速入门 @@ -385,7 +416,7 @@ XtQuant封装了策略交易所需要的Python API接口,可以和MiniQMT客 - 市价最优五档即成剩撤 - `xtconstant.MARKET_CANCEL_5` - 市价最优一档即成剩转 - `xtconstant.MARKET_CONVERT_1` - 市价最优五档即成剩转 - `xtconstant.MARKET_CONVERT_5` -- 上交所 股票 +- 上交所 北交所 股票 - 最优五档即时成交剩余撤销 - `xtconstant.MARKET_SH_CONVERT_5_CANCEL` - 最优五档即时成交剩转限价 - `xtconstant.MARKET_SH_CONVERT_5_LIMIT` - 对手方最优价格委托 - `xtconstant.MARKET_PEER_PRICE_FIRST` @@ -466,6 +497,7 @@ cash | float | 可用金额 frozen_cash |float | 冻结金额 market_value | float | 持仓市值 total_asset | float | 总资产 +fetch_balance | float | 可取资金 ### 委托XtOrder 属性|类型|注释 @@ -488,7 +520,8 @@ strategy_name | str | 策略名称 order_remark | str | 委托备注 direction | int | 多空方向,股票不需要;参见数据字典 offset_flag | int | 交易操作,用此字段区分股票买卖,期货开、平仓,期权买卖等;参见数据字典 -stock_code1 | str | 证券代码,例如"600000.SH" +instrument_name | str | 证券名称 +secu_account | str | 股东代码 ### 成交XtTrade 属性|类型|注释 @@ -507,9 +540,10 @@ order_sysid | str | 柜台合同编号 strategy_name | str | 策略名称 order_remark | str | 委托备注 direction | int | 多空方向,股票不需要;参见数据字典 -offset_flag | int | 交易操作,用此字段区分股票买卖,期货开、平仓,期权买卖等;参见数据字典 -stock_code1 | str | 证券代码,例如"600000.SH" +offset_flag | int | 交易操作,用此字段区分股票买卖,期货开、平仓,期权买卖等;参见数据字 commission | float | 手续费 +instrument_name | str | 证券名称 +secu_account | str | 股东代码 ### 持仓XtPosition 属性|类型|注释 @@ -526,7 +560,13 @@ on_road_volume | int | 在途股份 yesterday_volume | int | 昨夜拥股 avg_price | float | 成本价 direction | int | 多空方向,股票不需要;参见数据字典 -stock_code1 | str | 证券代码,例如"600000.SH" +instrument_name | str | 证券名称 +last_price | float | 当前价 +profit_rate | float | 盈亏比例 +secu_account | str | 股东代码 +float_profit | float | 浮动盈亏 +open_date | str | 开仓日期,股票不需要 +position_profit | float | 持仓盈亏,股票不需要 ### 期货持仓统计XtPositionStatistics @@ -738,6 +778,14 @@ status | int | 账号状态,参见数据字典 | msg | str | 反馈信息 | | apply_id | str | 若申请成功返回资券申请编号,否则返回-1 | +### 银证转账异步接口的反馈XtBankTransferResponse + +| 属性 | 类型 | 注释 | +| ------- | ---- | ------------ | +| seq | int | 异步请求序号 | +| success | bool | 是否成功 | +| msg | str | 反馈信息 | + ## XtQuant API说明 ### 系统设置接口 @@ -1145,6 +1193,253 @@ sync_transaction_from_external(operation, data_type, account, deal_list) #失败输出示例:{'error': {'msg': '[0-0: invalid operation type: ADDD], '}} ``` +#### 银证转账(银行转证券)同步接口 + +```python +bank_transfer_in(account, bank_no, bank_account, balance, bank_pwd, fund_pwd) +``` + +* 释义 + + - 银证转账(银行转证券) + +* 参数 + + - account - StockAccount 资金账号 + - bank_no - str 银行编号,可通过query_bank_info查回 + - bank_account - str 银行账号 + - balance - float 转账金额 + - bank_pwd - str 银行账号密码 + - fund_pwd - str 资金账号密码 + +* 返回 + + - (success, msg) + - success - bool 转账操作是否成功 + - msg - str 反馈信息 + +* 示例 + + ```python + account = StockAccount('1000008') + #xt_trader为XtQuant API实例对象 + result = xt_trader.bank_transfer_in(account, 'A', '0200205001003215076', 10, bank_pwd = 'abc123') + print(result) + ``` + + +#### 银证转账(银行转证券)异步接口 + +```python +bank_transfer_in_async(account, bank_no, bank_account, balance, bank_pwd, fund_pwd) +``` + +* 释义 + + - 银证转账(银行转证券)的异步接口,异步接口如果正常返回了请求序号seq,会收到on_bank_transfer_async_response的反馈 + +* 参数 + + - account - StockAccount 资金账号 + - bank_no - str 银行编号,可通过query_bank_info查回 + - bank_account - str 银行账号 + - balance - float 转账金额 + - bank_pwd - str 银行账号密码 + - fund_pwd - str 资金账号密码 + +* 返回 + + - 返回请求序号seq,成功发起申请后的请求序号为大于0的正整数,如果为-1表示发起申请失败 + +* 示例 + +```python +account = StockAccount('1000008') +#xt_trader为XtQuant API实例对象 +seq = xt_trader.bank_transfer_in_async(account, 'A', '0200205001003215076', 10, bank_pwd = 'abc123') +print(seq) +``` + +#### 银证转账(证券转银行)同步接口 + +```python +bank_transfer_out(account, bank_no, bank_account, balance, bank_pwd, fund_pwd) +``` + +* 释义 + + - 银证转账(证券转银行) + +* 参数 + + - account - StockAccount 资金账号 + - bank_no - str 银行编号,可通过query_bank_info查回 + - bank_account - str 银行账号 + - balance - float 转账金额 + - bank_pwd - str 银行账号密码 + - fund_pwd - str 资金账号密码 + +* 返回 + + - (success, msg) + - success - bool 转账操作是否成功 + - msg - str 反馈信息 + +* 示例 + + ```python + account = StockAccount('1000008') + #xt_trader为XtQuant API实例对象 + result = xt_trader.bank_transfer_out(account, 'A', '0200205001003215076', 10, fund_pwd = 'abc123') + print(result) + ``` + +#### 银证转账(证券转银行)异步接口 + +```python +bank_transfer_out_async(account, bank_no, bank_account, balance, bank_pwd, fund_pwd) +``` + +* 释义 + + - 银证转账(证券转银行)的异步接口,异步接口如果正常返回了请求序号seq,会收到on_bank_transfer_async_response的反馈 + +* 参数 + + - account - StockAccount 资金账号 + - bank_no - str 银行编号,可通过query_bank_info查回 + - bank_account - str 银行账号 + - balance - float 转账金额 + - bank_pwd - str 银行账号密码 + - fund_pwd - str 资金账号密码 + +* 返回 + + - 返回请求序号seq,成功发起申请后的请求序号为大于0的正整数,如果为-1表示发起申请失败 + +* 示例 + +```python +account = StockAccount('1000008') +#xt_trader为XtQuant API实例对象 +seq = xt_trader.bank_transfer_out_async(account, 'A', '0200205001003215076', 10, fund_pwd = 'abc123') +print(seq) +``` + +#### CTP资金内转(期权转期货)同步接口 + +```python +ctp_transfer_option_to_future(opt_account_id, ft_account_id, balance) +``` + +* 释义 + + - CTP资金内转(期权转期货) + +* 参数 + + - opt_account_id - str 期权资金账号 + - ft_account_id- str 期货资金账号 + - balance - float 转账金额 + +* 返回 + + - (success, msg) + - success - bool 转账操作是否成功 + - msg - str 反馈信息 + +* 示例 + + ```python + #xt_trader为XtQuant API实例对象 + result = xt_trader.ctp_transfer_option_to_future('60016061', '10001951', 10) + print(result) + ``` + + +#### CTP资金内转(期权转期货)异步接口 + +```python +ctp_transfer_option_to_future_async(opt_account_id, ft_account_id, balance) +``` + +* 释义 + + - CTP资金内转(期权转期货)的异步接口,异步接口如果正常返回了请求序号seq,会收到on_ctp_internal_transfer_async_response的反馈 + +* 参数 + + - opt_account_id - str 期权资金账号 + - ft_account_id- str 期货资金账号 + - balance - float 转账金额 + +* 返回 + + - 返回请求序号seq,成功发起申请后的请求序号为大于0的正整数,如果为-1表示发起申请失败 + +* 示例 + +```python +#xt_trader为XtQuant API实例对象 +seq = xt_trader.ctp_transfer_option_to_future_async('60016061', '10001951', 10) +print(seq) +``` + +#### CTP资金内转(期货转期权)同步接口 + +```python +ctp_transfer_future_to_option(opt_account_id, ft_account_id, balance) +``` + +* 释义 + + - CTP资金内转(期权转期货) + +* 参数 + + - opt_account_id - str 期权资金账号 + - ft_account_id- str 期货资金账号 + - balance - float 转账金额 + +* 返回 + + - (success, msg) + - success - bool 转账操作是否成功 + - msg - str 反馈信息 + +* 示例 + + ```python + #xt_trader为XtQuant API实例对象 + result = xt_trader.ctp_transfer_future_to_option('60016061', '10001951', 15) + print(result) + ``` + +#### CTP资金内转(期货转期权)异步接口 + +```python +ctp_transfer_future_to_option_async(opt_account_id, ft_account_id, balance) +``` + +* 释义 + + - CTP资金内转(期货转期权)的异步接口,异步接口如果正常返回了请求序号seq,会收到on_ctp_internal_transfer_async_response的反馈 +* 参数 + + - opt_account_id - str 期权资金账号 + - ft_account_id- str 期货资金账号 + - balance - float 转账金额 + +* 返回 + + - 返回请求序号seq,成功发起申请后的请求序号为大于0的正整数,如果为-1表示发起申请失败 +* 示例 + +```python +#xt_trader为XtQuant API实例对象 +seq = xt_trader.ctp_transfer_future_to_option_async('60016061', '10001951', 15) +print(seq) +``` ### 股票查询接口 @@ -1557,6 +1852,146 @@ query_data(account, result_path, data_type, start_time = None, end_time = None, #失败输出示例:{'error': {'errorMsg': 'can not find account info, accountID:2000449 accountType:2'}} ``` +#### 银行信息查询 + +```python +query_bank_info(account) +``` + +* 释义 + + - 银行信息查询 +* 参数 + + - account - StockAccount 资金账号 +* 返回 + - result - dict 银行信息,包含以下字段 + - success - bool + - error_msg - str + - money_type - str 币种 + - bank_no - str 银行编号 + - bank_account - str 银行账号 + - bank_name - str 银行名称 + +* 示例 + + ```python + account = StockAccount('1000008') + #xt_trader为XtQuant API实例对象 + datas = xt_trader.query_bank_info(account) + for it in datas: + print({x:it.__getattribute__(x) for x in dir(it) if x[0] != '_'}) + ``` + +#### 银行余额查询 + +```python +query_bank_amount(account, bank_no, bank_account, bank_pwd) +``` + +* 释义 + + - 银行转账流水查询 + +* 参数 + + - account - StockAccount 资金账号 + - bank_no - str 银行编号,可通过query_bank_info查回 + - bank_account - str 银行账号 + - bank_pwd - str 银行账号密码 + +* 返回 + + - result - dict 银行转账流水信息,包含以下字段 + - success - bool + - error_msg - str + - account_id - str 资金账号 + - bank_account - str 银行账号 + - money_type - str 币种 + - balance - float 余额 + - enable_balance - float 可转金额 + +* 示例 + + ```python + account = StockAccount('1000008') + #xt_trader为XtQuant API实例对象 + datas = xt_trader.query_bank_amount(account, 'A', '0200205001003215076', 'abc123') + for it in datas: + print({x:it.__getattribute__(x) for x in dir(it) if x[0] != '_'}) + ``` + +#### 银行转账流水查询 + +```python +query_bank_transfer_stream(account, start_date, end_date, bank_no, bank_account) +``` + +* 释义 + + - 银行转账流水查询 +* 参数 + - account - StockAccount 资金账号 + - start_date - str 查询起始日期,如'20241125' + - end_date - str 查询截至日期,如'20241129' + - bank_no - str 银行编号,可通过query_bank_info查回 + - bank_account - str 银行账号 +* 返回 + - result - dict 银行转账流水信息,包含以下字段 + - success - bool + - error_msg - str + - date - str 日期 + - time - str 时间 + - transfer_no - str 转账流水号 + - transfer_direction - str 转账方向 '1':银行转证券,'2':证券转银行,'5':查询 + - bank_no - str 银行编号 + - bank_name - str 银行名称 + - bank_account - str 银行账号 + - money_type - str 币种 + - account_id - str 资金账号 + - balance - float 金额 + - remark - str 备注 + +* 示例 + + ```python + account = StockAccount('1000008') + #xt_trader为XtQuant API实例对象 + datas = xt_trader.query_bank_transfer_stream(account, '20241125', '20241129') + for it in datas: + print({x:it.__getattribute__(x) for x in dir(it) if x[0] != '_'}) + ``` + +#### 股东账户查询 + +```python +query_secu_account(account) +``` + +* 释义 + + - 股东账户查询 +* 参数 + + - account - StockAccount 资金账号 +* 返回 + - result - dict 银行信息,包含以下字段 + - success - bool + - error_msg - str + - main - bool 是否主股东 + - market - str 证券市场 + - secu_account - str 股东号 + +* 示例 + + ```python + account = StockAccount('1000008') + #xt_trader为XtQuant API实例对象 + datas = xt_trader.query_secu_account(account) + for it in datas: + print({x:it.__getattribute__(x) for x in dir(it) if x[0] != '_'}) + ``` + ### 约券相关接口 #### 券源行情查询 @@ -1773,6 +2208,13 @@ class MyXtQuantTraderCallback(XtQuantTraderCallback): """ print("on_smt_appointment_async_response") print(response.account_id, response.order_sysid, response.error_id, response.error_msg, response.seq) + def on_bank_transfer_async_response(self, response): + """ + :param response: XtBankTransferResponse 对象 + :return: + """ + print("on_bank_transfer_async_response") + print(response.seq, response.success, response.msg) ``` #### 连接状态回调 @@ -1908,5 +2350,35 @@ on_smt_appointment_async_response(data) - data - XtSmtAppointmentResponse 约券相关异步接口的反馈 * 返回 - 无 +* 备注 + - 无 + +#### 银证转账异步接口的回报推送 + +```python +on_bank_transfer_async_response(data) +``` + +* 释义 + - 银证转账异步接口的回报推送 +* 参数 + - data - XtBankTransferResponse 银证转账异步接口的反馈 +* 返回 + - 无 +* 备注 + - 无 + +#### CTP资金内转异步接口的回报推送 + +```python +on_ctp_internal_transfer_async_response(data) +``` + +* 释义 + - CTP资金内转异步接口的回报推送 +* 参数 + - data - XtBankTransferResponse 银证转账异步接口的反馈 +* 返回 + - 无 * 备注 - 无 \ No newline at end of file diff --git a/src/xtquant/metatable/__init__.py b/src/xtquant/metatable/__init__.py index f9ff711..e47c412 100644 --- a/src/xtquant/metatable/__init__.py +++ b/src/xtquant/metatable/__init__.py @@ -5,6 +5,7 @@ from .meta_config import ( get_metatable_list, get_metatable_info, get_metatable_fields, + download_metatable_data, ) from . import get_arrow diff --git a/src/xtquant/metatable/get_arrow.py b/src/xtquant/metatable/get_arrow.py index 67c2a98..8ea085c 100644 --- a/src/xtquant/metatable/get_arrow.py +++ b/src/xtquant/metatable/get_arrow.py @@ -27,7 +27,7 @@ def _get_tabular_feather_single_ori( file_path = os.path.join(xtdata.get_data_dir(), "EP", f"{table}_Xdat2", "data.fe") if not os.path.exists(file_path): - return + return None, None fe_table = fe.read_table(file_path) @@ -199,6 +199,36 @@ def _parse_keys(fields): return [(tb, sd['show'], sd['fe']) for tb, sd in tmp.items()] +def _datetime_to_timetag(timelabel, format=''): + ''' + timelabel: str '20221231' '20221231235959' + format: str '%Y%m%d' '%Y%m%d%H%M%S' + return: int 1672502399000 + ''' + import datetime as dt + if not format: + format = '%Y%m%d' if len(timelabel) == 8 else '%Y%m%d%H%M%S' + try: + return dt.datetime.strptime(timelabel, format).timestamp() * 1000 + except: + return 0 + +def _datetime_to_timetag_end(timelabel, format=''): + ''' + timelabel: str '20221231' '20221231235959' + format: str '%Y%m%d' '%Y%m%d%H%M%S' + return: int 1672502399000 + ''' + import datetime as dt + if not format: + format = '%Y%m%d' if len(timelabel) == 8 else '%Y%m%d%H%M%S' + try: + if len(timelabel) == 8: + return dt.datetime.strptime(timelabel, format).timestamp() * 1000 + 24*60*60*1000 - 1 + elif len(timelabel) == 14: + return dt.datetime.strptime(timelabel, format).timestamp() * 1000 + 1000 - 1 + except: + return 0 def get_tabular_fe_data( codes: list, @@ -229,22 +259,8 @@ def get_tabular_fe_data( table_fields = _parse_fields(fields) - def datetime_to_timetag(timelabel, format=''): - ''' - timelabel: str '20221231' '20221231235959' - format: str '%Y%m%d' '%Y%m%d%H%M%S' - return: int 1672502399000 - ''' - import datetime as dt - if not format: - format = '%Y%m%d' if len(timelabel) == 8 else '%Y%m%d%H%M%S' - try: - return dt.datetime.strptime(timelabel, format).timestamp() * 1000 - except: - return 0 - - start_timetag = datetime_to_timetag(start_time) - end_timetag = datetime_to_timetag(end_time) + start_timetag = _datetime_to_timetag(start_time) + end_timetag = _datetime_to_timetag_end(end_time) dfs = [] ordered_fields = [] @@ -309,22 +325,8 @@ def get_tabular_fe_bson( table_fields = _parse_keys(fields) - def datetime_to_timetag(timelabel, format=''): - ''' - timelabel: str '20221231' '20221231235959' - format: str '%Y%m%d' '%Y%m%d%H%M%S' - return: int 1672502399000 - ''' - import datetime as dt - if not format: - format = '%Y%m%d' if len(timelabel) == 8 else '%Y%m%d%H%M%S' - try: - return dt.datetime.strptime(timelabel, format).timestamp() * 1000 - except: - return 0 - - start_timetag = datetime_to_timetag(start_time) - end_timetag = datetime_to_timetag(end_time) + start_timetag = _datetime_to_timetag(start_time) + end_timetag = _datetime_to_timetag_end(end_time) def _get_convert(): import pyarrow as pa diff --git a/src/xtquant/qmttools/stgentry.py b/src/xtquant/qmttools/stgentry.py index 7a7501d..4195d84 100644 --- a/src/xtquant/qmttools/stgentry.py +++ b/src/xtquant/qmttools/stgentry.py @@ -13,6 +13,11 @@ def run_file(user_script, param = {}): lib_search = [os.path.abspath(p) for p in pypath.split(';')] sys.path = lib_search + [p for p in sys.path if p not in lib_search] + user_args = param.get('user_args') + if user_args and type(user_args) == dict: + for k, v in user_args.items(): + globals()[k] = v + user_module = compile(open(user_script, 'rb').read(), user_script, 'exec', optimize = 2) #print({'user_module': user_module}) diff --git a/src/xtquant/qmttools/stgframe.py b/src/xtquant/qmttools/stgframe.py index d46e1b7..a8129cf 100644 --- a/src/xtquant/qmttools/stgframe.py +++ b/src/xtquant/qmttools/stgframe.py @@ -73,10 +73,16 @@ class StrategyLoader: if C.start_time: C.start_time_str = C.start_time.replace('-', '').replace(' ', '').replace(':', '') - C.start_time_num = int(datetime_to_timetag(C.start_time_str)) + try: + C.start_time_num = int(datetime_to_timetag(C.start_time_str)) + except: + C.start_time_num = 0 if C.end_time: C.end_time_str = C.end_time.replace('-', '').replace(' ', '').replace(':', '') - C.end_time_num = int(datetime_to_timetag(C.end_time_str)) + try: + C.end_time_num = int(datetime_to_timetag(C.end_time_str)) + except: + C.end_time_num = 0 if 1: #register this.create_formula() @@ -126,11 +132,17 @@ class StrategyLoader: import datetime as dt if C.start_time: C.start_time_str = C.start_time.replace('-', '').replace(' ', '').replace(':', '') - C.start_time_num = int(datetime_to_timetag(C.start_time_str)) + try: + C.start_time_num = int(datetime_to_timetag(C.start_time_str)) + except: + C.start_time_num = 0 init_result['backtest']['start_time'] = dt.datetime.fromtimestamp(C.start_time_num / 1000).strftime('%Y-%m-%d %H:%M:%S') if C.end_time: C.end_time_str = C.end_time.replace('-', '').replace(' ', '').replace(':', '') - C.end_time_num = int(datetime_to_timetag(C.end_time_str)) + try: + C.end_time_num = int(datetime_to_timetag(C.end_time_str)) + except: + C.end_time_num = 0 init_result['backtest']['end_time'] = dt.datetime.fromtimestamp(C.end_time_num / 1000).strftime('%Y-%m-%d %H:%M:%S') this.call_formula('initcomplete', init_result) diff --git a/src/xtquant/xtconstant.py b/src/xtquant/xtconstant.py index 009bf68..c743aea 100644 --- a/src/xtquant/xtconstant.py +++ b/src/xtquant/xtconstant.py @@ -193,13 +193,13 @@ MARKET_CANCEL_5 = 22 MARKET_CONVERT_1 = 23 # 市价最优五档即成剩转[中金所][期货] MARKET_CONVERT_5 = 24 -# 最优五档即时成交剩余撤销[上交所][股票] +# 最优五档即时成交剩余撤销[上交所][北交所][股票] MARKET_SH_CONVERT_5_CANCEL = 42 -# 最优五档即时成交剩转限价[上交所][股票] +# 最优五档即时成交剩转限价[上交所][北交所][股票] MARKET_SH_CONVERT_5_LIMIT = 43 -# 对手方最优价格委托[上交所[股票]][深交所[股票][期权]] +# 对手方最优价格委托[上交所[股票]][深交所[股票][期权]][北交所[股票]] MARKET_PEER_PRICE_FIRST = 44 -# 本方最优价格委托[上交所[股票]][深交所[股票][期权]] +# 本方最优价格委托[上交所[股票]][深交所[股票][期权]][北交所[股票]] MARKET_MINE_PRICE_FIRST = 45 # 即时成交剩余撤销委托[深交所][股票][期权] MARKET_SZ_INSTBUSI_RESTCANCEL = 46 diff --git a/src/xtquant/xtdata.py b/src/xtquant/xtdata.py index e53534b..1ce388f 100644 --- a/src/xtquant/xtdata.py +++ b/src/xtquant/xtdata.py @@ -5,7 +5,8 @@ import time as _TIME_ import traceback as _TRACEBACK_ from . import xtbson as _BSON_ - +from .metatable import * +from .metatable import get_tabular_data as _get_tabular_data __all__ = [ @@ -35,7 +36,6 @@ __all__ = [ , 'download_index_weight' , 'get_holidays' , 'get_trading_calendar' - , 'get_trading_time' , 'get_etf_info' , 'download_etf_info' , 'get_main_contract' @@ -48,6 +48,7 @@ __all__ = [ , 'reset_sector' , 'get_period_list' , 'download_his_st_data' + , 'get_tabular_data' ] def try_except(func): @@ -192,9 +193,7 @@ def get_client(): def hello(): - global __client global enable_hello - if not enable_hello: return @@ -202,15 +201,18 @@ def hello(): peer_addr = None __data_dir_from_server = None + client = get_client() try: - server_info = _BSON_.BSON.decode(__client.get_server_tag()) - peer_addr = __client.get_peer_addr() - __data_dir_from_server = __client.get_data_dir() + server_info = _BSON_.BSON.decode(client.get_server_tag()) + peer_addr = client.get_peer_addr() + __data_dir_from_server = client.get_data_dir() except Exception as e: pass + import datetime as dt + cur = dt.datetime.now().strftime("%Y-%m-%d %H:%S:%M") print( -f'''***** xtdata连接成功 ***** +f'''***** xtdata连接成功 {cur}***** 服务信息: {server_info} 服务地址: {peer_addr} 数据路径: {__data_dir_from_server} @@ -220,7 +222,13 @@ f'''***** xtdata连接成功 ***** return -def get_current_data_dir(): +def get_data_dir(): + ''' + 如果更改过`xtdata.data_dir`变量的值,优先返回变量设置的值 + 没有设置过,返回服务的数据路径 + 注意----设置`xtdata.data_dir`的值可以强制指定读取本地数据的位置,谨慎修改 + ''' + cl = get_client() global data_dir global __data_dir_from_server return data_dir if data_dir != None else __data_dir_from_server @@ -380,18 +388,58 @@ def get_financial_data(stock_list, table_list=[], start_time='', end_time='', re return result +def get_financial_data_ori(stock_list, table_list=[], start_time='', end_time='', report_type='report_time'): + client = get_client() + all_table = { + 'Balance' : 'ASHAREBALANCESHEET' + , 'Income' : 'ASHAREINCOME' + , 'CashFlow' : 'ASHARECASHFLOW' + , 'Capital' : 'CAPITALSTRUCTURE' + , 'HolderNum' : 'SHAREHOLDER' + , 'Top10Holder' : 'TOP10HOLDER' + , 'Top10FlowHolder' : 'TOP10FLOWHOLDER' + , 'PershareIndex' : 'PERSHAREINDEX' + } + + if not table_list: + table_list = list(all_table.keys()) + + all_table_upper = {table.upper() : all_table[table] for table in all_table} + req_list = [] + names = {} + for table in table_list: + req_table = all_table_upper.get(table.upper(), table) + req_list.append(req_table) + names[req_table] = table + + data = {} + sl_len = 20 + stock_list2 = [stock_list[i : i + sl_len] for i in range(0, len(stock_list), sl_len)] + for sl in stock_list2: + data2 = client.get_financial_data(sl, req_list, start_time, end_time, report_type) + for s in data2: + data[s] = data2[s] + return data + + def get_market_data_ori( field_list = [], stock_list = [], period = '1d' , start_time = '', end_time = '', count = -1 , dividend_type = 'none', fill_data = True, enable_read_from_server = True , data_dir = None ): + import datetime as dt client = get_client() enable_read_from_local = period in {'1m', '5m', '15m', '30m', '60m', '1h', '1d', 'tick', '1w', '1mon', '1q', '1hy', '1y'} global debug_mode if data_dir == None: - data_dir = get_current_data_dir() + data_dir = get_data_dir() + + if isinstance(start_time, dt.datetime): + start_time = int(start_time.timestamp() * 1000) + if isinstance(end_time, dt.datetime): + end_time = int(end_time.timestamp() * 1000) return client.get_market_data3(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data, 'v2', enable_read_from_local, enable_read_from_server, debug_mode, data_dir) @@ -472,12 +520,18 @@ def get_market_data_ex_ori( , dividend_type = 'none', fill_data = True, enable_read_from_server = True , data_dir = None ): + import datetime as dt client = get_client() enable_read_from_local = period in {'1m', '5m', '15m', '30m', '60m', '1h', '1d', 'tick', '1w', '1mon', '1q', '1hy', '1y'} global debug_mode if data_dir == None: - data_dir = get_current_data_dir() + data_dir = get_data_dir() + + if isinstance(start_time, dt.datetime): + start_time = int(start_time.timestamp() * 1000) + if isinstance(end_time, dt.datetime): + end_time = int(end_time.timestamp() * 1000) return client.get_market_data3(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data, 'v3', enable_read_from_local, enable_read_from_server, debug_mode, data_dir) @@ -491,25 +545,25 @@ def get_market_data_ex( showbrokename = period == 'hkbrokerqueue2' return get_broker_queue_data(stock_list, start_time, end_time, count, showbrokename) - period = _get_tuple_period(period) or period - if isinstance(period, tuple): - return _get_market_data_ex_tuple_period(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data) + spec_period, meta_id, period_num = _validate_period(period) + if meta_id > 0: + return _get_market_data_ex_tuple_period(field_list, stock_list, (meta_id, period_num), start_time, end_time, count, dividend_type, fill_data) - if period in {'1m', '5m', '15m', '30m', '60m', '1h', '1d', '1w', '1mon', '1q', '1hy', '1y'}: - return _get_market_data_ex_ori_221207(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data) + if spec_period in {'1m', '5m', '15m', '30m', '60m', '1h', '1d', '1w', '1mon', '1q', '1hy', '1y'}: + return _get_market_data_ex_ori_221207(field_list, stock_list, spec_period, start_time, end_time, count, dividend_type, fill_data) import pandas as pd result = {} ifield = 'time' query_field_list = field_list if (not field_list) or (ifield in field_list) else [ifield] + field_list - ori_data = get_market_data_ex_ori(query_field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data) + ori_data = get_market_data_ex_ori(query_field_list, stock_list, spec_period, start_time, end_time, count, dividend_type, fill_data) if not ori_data: return result fl = field_list - stime_fmt = '%Y%m%d' if period == '1d' else '%Y%m%d%H%M%S' + stime_fmt = '%Y%m%d' if spec_period == '1d' else '%Y%m%d%H%M%S' if fl: fl2 = fl if ifield in fl else [ifield] + fl for s in ori_data: @@ -518,7 +572,7 @@ def get_market_data_ex( sdata2.index = [timetag_to_datetime(t, stime_fmt) for t in sdata[ifield]] result[s] = sdata2 else: - needconvert, metaid = _needconvert_period(period) + needconvert, metaid = _needconvert_period(spec_period) if needconvert: convert_field_list = get_field_list(metaid) @@ -532,7 +586,8 @@ def get_market_data_ex( odata = convert_data_list sdata = pd.DataFrame(odata) - sdata.index = [timetag_to_datetime(t, stime_fmt) for t in sdata[ifield]] + if ifield in sdata.columns: + sdata.index = [timetag_to_datetime(t, stime_fmt) for t in sdata[ifield]] result[s] = sdata else: for s in ori_data: @@ -551,12 +606,19 @@ def _get_market_data_ex_ori_221207( ): import numpy as np import pandas as pd + import datetime as dt + client = get_client() enable_read_from_local = period in {'1m', '5m', '15m', '30m', '60m', '1h', '1d', 'tick', '1w', '1mon', '1q', '1hy', '1y'} global debug_mode if data_dir == None: - data_dir = get_current_data_dir() + data_dir = get_data_dir() + + if isinstance(start_time, dt.datetime): + start_time = int(start_time.timestamp() * 1000) + if isinstance(end_time, dt.datetime): + end_time = int(end_time.timestamp() * 1000) ret = client.get_market_data3(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data, 'v4', enable_read_from_local, enable_read_from_server, debug_mode, data_dir) @@ -602,6 +664,42 @@ def _get_market_data_ex_221207( get_market_data3 = _get_market_data_ex_221207 + +def _get_market_data_ex_250414( + field_list = [], stock_list = [], period = '1d' + , start_time = '', end_time = '', count = -1 + , dividend_type = 'none', fill_data = True, enable_read_from_server = True + , data_dir = None +): + client = get_client() + + enable_read_from_local = period in { + '1m', '5m', '15m', '30m', '60m', '1h' + , '1d', 'tick', '1w', '1mon', '1q', '1hy', '1y' + } + + global debug_mode + + if data_dir == None: + data_dir = get_data_dir() + + result = client.get_market_data3( + field_list, stock_list, period + , start_time, end_time, count + , dividend_type, fill_data + , 'v5', enable_read_from_local, enable_read_from_server + , debug_mode, data_dir + ) + + import pyarrow as pa + result = pa.ipc.open_stream(result).read_all().to_pandas() + + import pandas as pd + result.index = pd.to_datetime(result['time'] + 28800000, unit = 'ms') + + return result + + def _get_data_file_path(stocklist, period, date = '20380119'): if isinstance(period, tuple): @@ -649,7 +747,7 @@ __TUPLE_PERIODS = { , 'riskfreerate' : (2032, 86400000, '') #以下内置已加 , 'etfstatistics': (3030, 0, '') - , 'etfstatisticsl2': (1830, 0, '') + , 'hfetfstatistics': (1830, 0, '') , 'northfinancechange1m': (3006, 60000, '') , 'northfinancechange1d': (3006, 86400000, '') , 'stoppricedata': (9506, 86400000, '') @@ -672,16 +770,33 @@ def _needconvert_period(period): } return period in datas, datas.get(period, -1) -def _get_tuple_period(period): +def _validate_period(period): + ''' + 验证周期的有效性。 + + 根据输入周期类型(元组或字符串),在预定义的周期映射中查找并返回标准化后的周期信息。 + + Args: + period (tuple | str): 需要验证的周期。 + - 如果是元组,期望格式为 (metaid, period_num),例如 (3001, 60000)。 + - 如果是字符串,例如 '1m', 'etfiopv'。 + + Returns: + tuple: 包含三个元素的元组 (str_period, meta_id, period_num) + - str_period (str): 标准化的周期字符串。如果输入是元组且在 __STR_PERIODS 中找不到,则为空字符串。 + 如果输入是字符串,则为原始字符串或在 __TUPLE_PERIODS 中定义的名称。 + - meta_id (int): 周期的元数据ID。如果找不到,则为 -1 (当输入为字符串时) 或元组中的原始值。 + - period_num (int): 周期的数值表示。如果找不到,则为 -1 (当输入为字符串时) 或元组中的原始值。 + ''' if isinstance(period, tuple): - return __STR_PERIODS.get(period, None) + return (__STR_PERIODS.get(period, ''), *period) else: res = __TUPLE_PERIODS.get(period, None) if res: metaid, p, desc = res - return (metaid, p) + return (period, metaid, p) else: - return None + return (period, -1, -1) def _get_market_data_ex_tuple_period_ori( @@ -693,7 +808,11 @@ def _get_market_data_ex_tuple_period_ori( data_path_dict = _get_data_file_path(stock_list, period) - import pandas as pd + import datetime as dt + if isinstance(start_time, dt.datetime): + start_time = int(start_time.timestamp() * 1000) + if isinstance(end_time, dt.datetime): + end_time = int(end_time.timestamp() * 1000) ori_data = {} for stockcode in data_path_dict: @@ -726,7 +845,7 @@ def _convert_component_info(data, convert_field_list): return new_data def _get_market_data_ex_tuple_period( - field_list = [], stock_list = [], period = '1d' + field_list = [], stock_list = [], period = None , start_time = '', end_time = '', count = -1 , dividend_type = 'none', fill_data = True, enable_read_from_server = True ): @@ -753,15 +872,10 @@ def _get_market_data_ex_tuple_period( return ori_data -def get_data_dir(): - cl = get_client() - return _OS_.path.abspath(cl.get_data_dir()) - - def get_local_data(field_list=[], stock_list=[], period='1d', start_time='', end_time='', count=-1, dividend_type='none', fill_data=True, data_dir=None): if data_dir == None: - data_dir = get_current_data_dir() + data_dir = get_data_dir() if period in {'1m', '5m', '15m', '30m', '60m', '1h', '1d', '1w', '1mon', '1q', '1hy', '1y'}: return _get_market_data_ex_ori_221207(field_list, stock_list, period, start_time, end_time, count, @@ -800,8 +914,14 @@ def get_l2_quote(field_list=[], stock_code='', start_time='', end_time='', count ''' level2实时行情 ''' + import datetime as dt global debug_mode client = get_client() + + if isinstance(start_time, dt.datetime): + start_time = int(start_time.timestamp() * 1000) + if isinstance(end_time, dt.datetime): + end_time = int(end_time.timestamp() * 1000) datas = client.get_market_data3(field_list, [stock_code], 'l2quote', start_time, end_time, count, 'none', False, '', False, True, debug_mode, '') if datas: return datas[stock_code] @@ -812,8 +932,13 @@ def get_l2_order(field_list=[], stock_code='', start_time='', end_time='', count ''' level2逐笔委托 ''' + import datetime as dt global debug_mode client = get_client() + if isinstance(start_time, dt.datetime): + start_time = int(start_time.timestamp() * 1000) + if isinstance(end_time, dt.datetime): + end_time = int(end_time.timestamp() * 1000) datas = client.get_market_data3(field_list, [stock_code], 'l2order', start_time, end_time, count, 'none', False, '', False, True, debug_mode, '') if datas: return datas[stock_code] @@ -824,8 +949,13 @@ def get_l2_transaction(field_list=[], stock_code='', start_time='', end_time='', ''' level2逐笔成交 ''' + import datetime as dt global debug_mode client = get_client() + if isinstance(start_time, dt.datetime): + start_time = int(start_time.timestamp() * 1000) + if isinstance(end_time, dt.datetime): + end_time = int(end_time.timestamp() * 1000) datas = client.get_market_data3(field_list, [stock_code], 'l2transaction', start_time, end_time, count, 'none', False, '', False, True, debug_mode, '') if datas: return datas[stock_code] @@ -875,21 +1005,21 @@ def get_main_contract(code_market: str, start_time: str = "", end_time: str = "" xtdata.get_main_contract("AP00.ZF") # 取当前主力合约 xtdata.get_main_contract("AP00.ZF","20230101") # 取历史某一天主力合约 - + xtdata.get_main_contract("AP00.ZF","20230101","20240306") # 取某个时间段的主力合约序列 ''' period = 'historymaincontract' marker_code = code_market.split(".")[1] - + if start_time == "" and end_time == "": client = get_client() return client.get_main_contract(code_market) + "." + marker_code elif start_time and end_time == "": # 当指定start_time时,返回指定日期主力合约代码\n - data = get_market_data_ex([], [code_market], period)[code_market] - s_timetag = datetime_to_timetag(start_time, "%Y%m%d") + data = get_market_data_ex([],[code_market],period)[code_market] + s_timetag = datetime_to_timetag(start_time,"%Y%m%d") - data = data.loc[data.iloc[:, 0] < s_timetag] + data = data.loc[data.iloc[:, 0] <= s_timetag] if data.shape[0] > 0: return data['合约在交易所的代码'].iloc[-1] + "." + marker_code else: @@ -1076,7 +1206,9 @@ def subscribe_quote(stock_code, period='1d', start_time='', end_time='', count=0 订阅股票行情数据 :param stock_code: 股票代码 e.g. "000001.SZ" :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"等周期 - :param start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000" + :param start_time: 开始时间,支持以下格式: + - str格式: YYYYMMDD/YYYYMMDDhhmmss,e.g."20200427" "20200427093000" + - datetime对象 若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000" :param end_time: 结束时间 同“开始时间” :param count: 数量 -1全部/n: 从结束时间向前数n个 @@ -1094,7 +1226,9 @@ def subscribe_quote2(stock_code, period='1d', start_time='', end_time='', count= :param stock_code: 股票代码 e.g. "000001.SZ" :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"等周期 - :param start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000" + :param start_time: 开始时间,支持以下格式: + - str格式: YYYYMMDD/YYYYMMDDhhmmss,e.g."20200427" "20200427093000" + - datetime对象 若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000" :param end_time: 结束时间 同“开始时间” :param count: 数量 -1全部/n: 从结束时间向前数n个 @@ -1104,6 +1238,12 @@ def subscribe_quote2(stock_code, period='1d', start_time='', end_time='', count= :param datas: {stock : [data1, data2, ...]} 数据字典 :return: int 订阅序号 ''' + import datetime as dt + if isinstance(start_time, dt.datetime): + start_time = int(start_time.timestamp() * 1000) + if isinstance(end_time, dt.datetime): + end_time = int(end_time.timestamp() * 1000) + if callback: needconvert, metaid = _needconvert_period(period) if needconvert: @@ -1113,21 +1253,38 @@ def subscribe_quote2(stock_code, period='1d', start_time='', end_time='', count= else: callback = subscribe_callback_wrapper(callback) - period = _get_tuple_period(period) or period - if isinstance(period, tuple): - metaid, periodNum = period - meta = {'stockCode': stock_code, 'period': period, 'metaid': metaid, 'periodnum': periodNum, 'dividendtype': dividend_type} - else: - meta = {'stockCode': stock_code, 'period': period, 'metaid': -1, 'periodnum': -1, 'dividendtype': dividend_type} + spec_period, meta_id, period_num = _validate_period(period) + meta = {'stockCode': stock_code, 'period': spec_period, 'metaid': meta_id, 'periodnum': period_num, 'dividendtype': dividend_type} region = {'startTime': start_time, 'endTime': end_time, 'count': count} - client = get_client() - return client.subscribe_quote(_BSON_.BSON.encode(meta), _BSON_.BSON.encode(region), callback) + param = {'needCallback': callback != None} + return get_client().subscribe_quote(_BSON_.BSON.encode(meta), _BSON_.BSON.encode(region), _BSON_.BSON.encode(param), callback) -def subscribe_l2thousand(stock_code, gear_num = 0, callback = None): +def subscribe_l2thousand(stock_code, gear_num = None, callback = None): ''' 订阅千档盘口 + + 参数: + stock_code: + str 股票代码 例如 '000001.SZ' + gear_num: + int 订阅的档位数 + 传 None 表示订阅全部档位 + callback: + def ondata(data): + print(data) + 返回: + int 订阅号 + + 示例: + def on_data(data): + print(data) + seq = xtdata.subscribe_l2thousand('000001.SZ', gear_num = 10, callback = on_data) + + 数据示例: + data: dict + {'002594.SZ': [{'time': 1733120580630, 'askPrice': [282.14, 282.18, 282.19, 282.2, 282.21, 282.22, 282.24, 282.25, 282.26, 282.29], 'askVolume': [4, 2, 3, 4, 5, 6, 54, 3, 1, 4], 'bidPrice': [282.08, 282.06, 282.05, 282.02, 282.01, 282.0, 281.99, 281.98, 281.95, 281.94], 'bidVolume': [3, 3, 3, 2, 5, 58, 1, 2, 1, 4], 'price': 282.14}]} ''' if callback: callback = subscribe_callback_wrapper(callback) @@ -1136,38 +1293,64 @@ def subscribe_l2thousand(stock_code, gear_num = 0, callback = None): region = {'thousandGearNum': gear_num, 'thousandDetailGear': 0, 'thousandDetailNum': 0} client = get_client() - return client.subscribe_quote(_BSON_.BSON.encode(meta), _BSON_.BSON.encode(region), callback) + param = {'needCallback': callback != None} + return client.subscribe_quote(_BSON_.BSON.encode(meta), _BSON_.BSON.encode(region), _BSON_.BSON.encode(param), callback) def subscribe_l2thousand_queue( stock_code, callback = None - , gear = None + , gear_num = None , price = None ): ''' - 根据档位或价格订阅千档 - stock_code: 股票代码 e.g. "000001.SZ" + 订阅千档盘口队列 + + 参数: + stock_code: + str 股票代码 例如 '000001.SZ' callback: - 订阅回调函数onSubscribe(datas) - gear: 按档位订阅 eg. - price: 单个价格:float, 价格范围:eg.[8.66, 8.88], 一组价格list - return: int 订阅序号 - 例: - def on_data(datas): - for stock_code in datas: - print(stock_code, datas[stock_code]) - subscribe_l2thousand_queue(‘000001.SZ’, callback = on_data, gear = 3)#订阅买卖3档数据 - subscribe_l2thousand_queue(‘000001.SZ’, callback = on_data, price = (8.68, 8.88))#订阅[8.68, 8.88]价格区间的数据 + def ondata(data): + print(data) + gear_num: + int 订阅的档位数 + 传 None 表示订阅全部档位 + price: + float 指定一个订阅价格档位 + list[float] 指定多个订阅价格档位 + tuple(2) 指定价格范围,从tuple[0]到tuple[1],精度0.01 + 传 None 表示订阅全部价格 + 返回: + int 订阅号 + + 示例: + def ondata(data): + print(data) + + # 订阅买卖2档 + seq1 = xtdata.subscribe_l2thousand_queue('000001.SZ', callback = ondata, gear_num = 2) + + # 订阅价格为11.3的档位 + seq2 = xtdata.subscribe_l2thousand_queue('000001.SZ', callback = ondata, price = 11.3) + + # 订阅价格范围为11.3到11.4的档位 + seq3 = xtdata.subscribe_l2thousand_queue('000001.SZ', callback = ondata, price = (11.3, 11.4)) + + # 订阅价格为11.3和11.4的档位,只包含这两个具体价格 + seq4 = xtdata.subscribe_l2thousand_queue('000001.SZ', callback = ondata, price = [11.3, 11.4]) + + 数据示例: + data: dict + {'000001.SZ': [{'time': 1733120970090, 'bidGear': [1, 2], 'bidPrice': [11.36, 11.35], 'bidVolume': [[91, 100, 100, 100, 20, 100, 50, 29, 3, 51, 12, 308, 8, 20, 10, 5, 1, 1, 3, 12, 100, 100, 10, 62, 2, 35, 300, 51, 9, 100, 100, 10, 131, 5, 30, 4, 20, 30, 5, 20, 20, 12, 5, 3, 19, 11, 9, 5, 10, 5], [38, 26, 7, 15, 29, 3, 6, 25, 30, 20, 100, 17, 10, 60, 3, 38, 4, 3, 119, 200, 8, 5, 78, 2, 2, 1, 10, 22, 2, 13, 50, 2, 2, 100, 5, 8, 10, 12, 5, 10, 10, 50, 40, 3, 10, 1, 16, 10, 100, 24]], 'askGear': [1, 2], 'askPrice': [11.37, 11.38], 'askVolume': [[11, 15, 18, 10, 1, 2, 2, 1, 5, 2, 1, 5, 21, 5, 1, 67, 2, 225, 1, 3, 5, 5, 104, 4, 21, 300, 3, 18, 17, 1, 102, 6, 2, 4, 2, 2, 4, 2, 4, 2, 1, 5, 2, 2, 34, 2, 1, 60, 1, 118], [12, 7, 20, 1, 10, 6, 5, 71, 1, 7, 794, 2, 100, 40, 28, 429, 13, 16, 7, 9, 130, 6, 11, 3, 4, 1, 5, 1, 167, 11, 12, 84, 56, 7, 3, 2, 10, 1, 1, 20, 10, 1, 22, 10, 2, 70, 30, 7, 3, 1]]}]} ''' if callback: callback = subscribe_callback_wrapper(callback) - if gear is not None and price is not None: - raise Exception('不能同时订阅档位和价格!') + if gear_num is not None and price is not None: + raise Exception('不能同时指定档位和价格') - if gear is None: - gear = 0 + if gear_num is None: + gear_num = 0 if price is not None: if isinstance(price, float): price = [int(price * 10000)] @@ -1178,23 +1361,34 @@ def subscribe_l2thousand_queue( price = [i * 10000 for i in price] price.sort() - meta = {'stockCode': stock_code, 'isSubscribeByType': True, 'gear': gear, 'price': price, 'period': 'l2thousand', + meta = {'stockCode': stock_code, 'isSubscribeByType': True, 'gear': gear_num, 'price': price, 'period': 'l2thousandqueue', 'metaid': -1, 'periodnum': -1} region = {'thousandDetailGear': 1000, 'thousandDetailNum': 1000} client = get_client() - return client.subscribe_quote(_BSON_.BSON.encode(meta), _BSON_.BSON.encode(region), callback) + param = {'needCallback': callback != None} + return client.subscribe_quote(_BSON_.BSON.encode(meta), _BSON_.BSON.encode(region), _BSON_.BSON.encode(param), callback) -def get_l2thousand_queue(stock_code, gear = None, price = None): +def get_l2thousand_queue(stock_code, gear_num = None, price = None): ''' - 根据档位或价格获取前档 - stock_code 股票代码 e.g. "000001.SZ" - gear: Optional[int], - price: Optional[list(float), tuple(2)] + 获取千档盘口队列数据 + + 参数: + stock_code: + str 股票代码 例如 '000001.SZ' + gear_num: + int 订阅的档位数 + 传 None 表示订阅全部档位 + price: + list[float] | tuple(2) 订阅的价格范围 + 传 None 表示订阅全部价格 + 返回: + dict ''' - if gear is None: - gear = 0 + + if gear_num is None: + gear_num = 0 if price is not None: if isinstance(price, float): price = [int(price * 10000)] @@ -1210,7 +1404,7 @@ def get_l2thousand_queue(stock_code, gear = None, price = None): data = {} data['stockcode'] = stock_code data['period'] = 'l2thousand' - data['gear'] = gear + data['gear'] = gear_num data['price'] = price result_bson = client.commonControl('getl2thousandqueue', _BSON_.BSON.encode(data)) @@ -1218,20 +1412,90 @@ def get_l2thousand_queue(stock_code, gear = None, price = None): return result.get('result') -def subscribe_whole_quote(code_list, callback=None): +def _get_index_mirror_data(code_list, period): + ''' + 获取指标全推数据 + + 参数: + code_list: + list[str] 市场或股票代码列表 + period: + str 指标全推支持周期 + + hftransactioncount 大单统计 + fullspeedorderbook 全速盘口 + 返回: + dict + ''' + client = get_client() + data = _BSON_call_common( + client.commonControl + , 'getindexmirrordata' + , { + 'stocklist': code_list + , 'period': period + } + ) + return data + + +def get_transactioncount(code_list): + ''' + 获取大单统计数据 + + 参数: + code_list: + list[str] 市场或股票代码列表 + 返回: + dict + ''' + return _get_index_mirror_data(code_list, 'hftransactioncount') + + +def get_fullspeed_orderbook(code_list): + ''' + 获取全速盘口数据 + + 参数: + code_list: + list[str] 市场或股票代码列表 + 返回: + dict + ''' + return _get_index_mirror_data(code_list, 'fullspeedorderbook') + + +def subscribe_whole_quote(code_list, callback = None): ''' 订阅全推数据 - :param code_list: 市场代码列表 ["SH", "SZ"] - :param callback: - 订阅回调函数onSubscribe(datas) - :param datas: {stock1 : data1, stock2 : data2, ...} 数据字典 - :return: int 订阅序号 + + 参数: + code_list: + list + [market1, market2, ...] + 或 [stock1, stock2, ...] + callback: + def ondata(datas): + pass + datas: + {stock1 : data1, stock2 : data2, ...} + 返回: + int 订阅号 + 示例: + def on_data(datas): + print(datas) + seq1 = xtdata.subscribe_whole_quote(['SH', 'SZ'], on_data) + seq2 = xtdata.subscribe_whole_quote(['600000.SH', '000001.SZ'], on_data) + + 数据示例: + datas: dict + {'000001.SZ': {'time': 1733118954000, 'lastPrice': 11.39, 'open': 11.39, 'high': 11.4, 'low': 11.31, 'lastClose': 11.38, 'amount': 862127800.0, 'volume': 758613, 'pvolume': 75861284, 'stockStatus': 3, 'openInt': 13, 'transactionNum': 37062, 'lastSettlementPrice': 11.38, 'settlementPrice': 0.0, 'pe': 0.0, 'askPrice': [11.4, 11.41, 11.42, 11.43, 11.44], 'bidPrice': [11.39, 11.38, 11.370000000000001, 11.36, 11.35], 'askVol': [10929, 12401, 6671, 4555, 6708], 'bidVol': [2429, 7127, 7146, 9111, 12189], 'volRatio': 0.0, 'speed1Min': 0.0, 'speed5Min': 0.0}} ''' if callback: callback = subscribe_callback_wrapper(callback) - client = get_client() - return client.subscribe_whole_quote(code_list, callback) + param = {'needCallback': callback != None} + return get_client().subscribe_whole_quote(code_list, _BSON_.BSON.encode(param), callback) def unsubscribe_quote(seq): @@ -1294,6 +1558,50 @@ def get_sector_list(): client = get_client() return client.get_sector_list() +def get_sector_info(sector_name = ''): + ''' + 获取板块信息 + :param sector_name: (str) 板块名称,默认为空字符串,表示获取所有板块信息 + :return: (pandas.DataFrame) 包含板块信息的数据框 + ''' + import os + from pyarrow import feather + import pandas as pd + + client = get_client() + sector_dir = os.path.join(client.get_data_dir(), 'SectorData', 'latest') + + result = {'sector':[], 'category':[]} + + def _get_sector_info_from_file(sector_name): + fe_file = os.path.join(sector_dir, sector_name + '.fe') + try: + fe_table = feather.read_table(source=fe_file) + if fe_table is None: + return None, None + except: + return None, None + fe_metadata = fe_table.schema.metadata + name = fe_metadata.get(b'original_name', b'') + category = fe_metadata.get(b'category', b'') + return name.decode('utf-8'), category.decode('utf-8') + + if sector_name: + name, category = _get_sector_info_from_file(sector_name) + if category is not None: + result['sector'].append(name if name else sector_name) + result['category'].append(category) + else: + for file in os.listdir(sector_dir): + if not file.endswith('.fe'): + continue + sector_name = os.path.splitext(file)[0] + name, category = _get_sector_info_from_file(sector_name) + if category: + result['sector'].append(name if name else sector_name) + result['category'].append(category) + + return pd.DataFrame(result) def add_sector(sector_name, stock_list): ''' @@ -1361,7 +1669,47 @@ def _get_instrument_detail(stock_code): if len(inst) != 1: return None - return inst[0] + ret = inst[0] + + if 'ExtendInfo' in ret and ret.get('ExtendInfo').get('OptionType', -1) in [-1, 0]: + OptionType = -1 + + market = ret.get('ExchangeID') + if market in ['SHO', 'SZO', 'CFFEX', 'IF', 'SF', 'SHFE', 'DF', 'DCE', 'INE', 'GF', 'GFEX', 'ZF', 'CZCE']: + + instrumentName = ret.get('InstrumentName') + if '购' in instrumentName: + OptionType = 0 + elif '沽' in instrumentName: + OptionType = 1 + + if OptionType == -1: + ProductCode = ret.get('ProductID', '') + if market in ['ZF', 'CZCE'] and len(ProductCode) == 3: + opttype = ProductCode[-1] + if opttype == 'C': + OptionType = 0 + elif opttype == 'P': + OptionType = 1 + elif market in ['IF', 'CFFEX']: + code = ret.get('InstrumentID', '') + if code.find('-') >= 0: + if code.find('C') >= 0: + OptionType = 0 + elif code.find('P') >= 0: + OptionType = 1 + elif ProductCode.endswith('_o'): + Product = ProductCode[:-2] + code = ret.get('InstrumentID', '') + if code.startswith(Product): + if code.find('C') >= 0: + OptionType = 0 + elif code.find('P') >= 0: + OptionType = 1 + + ret['ExtendInfo']['OptionType'] = OptionType + + return ret def get_instrument_detail(stock_code, iscomplete = False): ''' @@ -1414,6 +1762,7 @@ def get_instrument_detail(stock_code, iscomplete = False): convNum2Str('OpenDate') convNum2Str('ExpireDate') convNum2Str('EndDelivDate') + convNum2Str('TradingDay') if inst.get('FloatVolume', None) is None: inst['FloatVolume'] = inst.get('FloatVolumn') @@ -1435,6 +1784,7 @@ def get_instrument_detail(stock_code, iscomplete = False): , 'CreateDate' , 'OpenDate' , 'ExpireDate' + , 'TradingDay' , 'PreClose' , 'SettlementPrice' , 'UpStopPrice' @@ -1471,6 +1821,7 @@ def get_instrument_detail(stock_code, iscomplete = False): convNum2Str('CreateDate') convNum2Str('OpenDate') convNum2Str('ExpireDate') + convNum2Str('TradingDay') if ret.get('FloatVolume', None) is None: ret['FloatVolume'] = inst.get('FloatVolumn') @@ -1481,6 +1832,23 @@ def get_instrument_detail(stock_code, iscomplete = False): return ret +def get_instrument_detail_list(stock_list, iscomplete = False): + ''' + 获取合约信息列表 + + stock_list: list + 股票代码列表 [ stock1, stock2,... ] + iscomplete: bool + 是否返回完整信息,默认False,只返回部分信息 + + return: dict + 合约信息列表 { stock1: inst1, stock2: inst2, ... } + stock: 股票代码 + inst: 合约信息字典,格式同get_instrument_detail返回值 + ''' + return {s: get_instrument_detail(s, iscomplete) for s in stock_list} + + def download_index_weight(): ''' 下载指数权重数据 @@ -1489,12 +1857,13 @@ def download_index_weight(): client.down_index_weight() -def download_history_contracts(): +def download_history_contracts(incrementally = True): ''' 下载过期合约数据 + incrementally: bool 是否增量 ''' client = get_client() - client.down_history_contracts() + client.down_history_contracts(incrementally) def _download_history_data_by_metaid(stock_code, metaid, period, start_time = '', end_time = '', incrementally = True): @@ -1524,15 +1893,17 @@ def download_history_data(stock_code, period, start_time = '', end_time = '', in ''' :param stock_code: str 品种代码,例如:'000001.SZ' :param period: str 数据周期 - :param start_time: str 开始时间 - 格式为 YYYYMMDD 或 YYYYMMDDhhmmss 或 '' - 例如:'20230101' '20231231235959' - 空字符串代表全部,自动扩展到完整范围 + :param start_time: 开始时间,支持以下格式: + - str格式: YYYYMMDD/YYYYMMDDhhmmss 或 '' + 例如:'20230101' '20231231235959' + 空字符串代表全部,自动扩展到完整范围 + - datetime.datetime对象c :param end_time: str 结束时间 格式同开始时间 :param incrementally: 是否增量下载 bool: 是否增量下载 None: 使用start_time控制,start_time为空则增量下载 ''' + import datetime as dt client = get_client() @@ -1540,29 +1911,39 @@ def download_history_data(stock_code, period, start_time = '', end_time = '', in if incrementally is None: incrementally = False if start_time else True - period = _get_tuple_period(period) or period + spec_period, meta_id, period_num = _validate_period(period) + if isinstance(start_time, dt.datetime): + start_time = start_time.strftime('%Y%m%d%H%M%S') + if isinstance(end_time, dt.datetime): + end_time = end_time.strftime('%Y%m%d%H%M%S') - if isinstance(period, tuple): - metaid, periodNum = period - return _download_history_data_by_metaid(stock_code, metaid, periodNum, start_time, end_time, incrementally) + if meta_id > 0: + if not spec_period or not isinstance(period, tuple): + return _download_history_data_by_metaid(stock_code, meta_id, period_num, start_time, end_time, incrementally) - return _download_history_data(stock_code, period, start_time, end_time) + return _download_history_data(stock_code, spec_period, start_time, end_time) else: return download_history_data2([stock_code], period, start_time, end_time, None, incrementally) supply_history_data = download_history_data +_download_msg = {} def download_history_data2(stock_list, period, start_time='', end_time='', callback=None, incrementally = None): ''' :param stock_list: 股票代码列表 e.g. ["000001.SZ"] :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d" - :param start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000" - 若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000" + :param start_time: 开始时间,支持以下格式: + - str格式: YYYYMMDD/YYYYMMDDhhmmss + 例如:'20200427' '20200427093000' + 若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000" + - datetime.datetime对象 :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间 :return: bool 是否成功 ''' + import datetime as dt + client = get_client() if isinstance(stock_list, str): @@ -1571,21 +1952,37 @@ def download_history_data2(stock_list, period, start_time='', end_time='', callb if incrementally is None: incrementally = False if start_time else True + if isinstance(start_time, dt.datetime): + start_time = start_time.strftime('%Y%m%d%H%M%S') + if isinstance(end_time, dt.datetime): + end_time = end_time.strftime('%Y%m%d%H%M%S') + param = {'incrementally' : incrementally} - period = _get_tuple_period(period) or period - if isinstance(period, tuple): - metaid, periodNum = period - period = '' - param['metaid'] = metaid - param['period'] = periodNum + spec_period, meta_id, period_num = _validate_period(period) + if meta_id > 0: + param['metaid'] = meta_id + param['period'] = period_num - status = [False, 0, 1, ''] + status = [False, 0, 1, '', {}] def on_progress(data): try: finished = data['finished'] total = data['total'] done = (finished >= total) + + if total < 0: + raise Exception('下载数据失败:' + data.get('message', '')) + + if finished == total: + if 'result' in data: + regino_result = _BSON_.BSON.decode(data.get('result')) + for stock, info in regino_result.items(): + info['start_time'] = dt.datetime.fromtimestamp(info.get('start_time') / 1000) + info['end_time'] = dt.datetime.fromtimestamp(info.get('end_time') / 1000) + + status[4][stock] = info + status[0] = done status[1] = finished status[2] = total @@ -1599,9 +1996,9 @@ def download_history_data2(stock_list, period, start_time='', end_time='', callb return done except: status[0] = True - status[3] = 'exception' + status[3] = data.get('message', '') return True - result = client.supply_history_data2(stock_list, period, start_time, end_time, _BSON_.BSON.encode(param), on_progress) + result = client.supply_history_data2(stock_list, spec_period, start_time, end_time, _BSON_.BSON.encode(param), on_progress) if not result: import time try: @@ -1615,7 +2012,11 @@ def download_history_data2(stock_list, period, start_time='', end_time='', callb raise Exception('行情服务连接断开') if status[3]: raise Exception('下载数据失败:' + status[3]) - return + else: + while not status[0] and client.is_connected(): + _TIME_.sleep(0.1) + + return status[4] def download_financial_data(stock_list, table_list=[], start_time='', end_time='', incrementally = None): @@ -1623,7 +2024,10 @@ def download_financial_data(stock_list, table_list=[], start_time='', end_time=' :param stock_list: 股票代码列表 :param table_list: 财务数据表名列表,[]为全部表 可选范围:['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex'] - :param start_time: 开始时间,格式YYYYMMDD,e.g."20200427" + :param start_time: 开始时间,支持以下格式: + - str格式: YYYYMMDD + 例如:'20200427' + - datetime.datetime对象 :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间 ''' client = get_client() @@ -1639,13 +2043,22 @@ def download_financial_data2(stock_list, table_list=[], start_time='', end_time= :param stock_list: 股票代码列表 :param table_list: 财务数据表名列表,[]为全部表 可选范围:['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex'] - :param start_time: 开始时间,格式YYYYMMDD,e.g."20200427" + :param start_time: 开始时间,支持以下格式: + - str格式: YYYYMMDD + 例如:'20200427' + - datetime.datetime对象 :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间 ''' client = get_client() if not table_list: table_list = ['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex'] + import datetime as dt + if isinstance(start_time, dt.datetime): + start_time = start_time.strftime('%Y%m%d') + if isinstance(end_time, dt.datetime): + end_time = end_time.strftime('%Y%m%d') + data = {} data['total'] = len(table_list) * len(stock_list) finish = 0 @@ -1692,8 +2105,8 @@ def download_sector_data(): ''' 下载行业板块数据 ''' - client = get_client() - client.down_all_sector_data() + download_history_data2([], (2009, 86400000)) + def download_holiday_data(incrementally = True): cl = get_client() @@ -1723,10 +2136,13 @@ def get_market_last_trade_date(market): def get_trading_calendar(market, start_time = '', end_time = ''): ''' 获取指定市场交易日历 + 未来交易日根据节假日推算 :param market: str 市场 :param start_time: str 起始时间 '20200101' :param end_time: str 结束时间 '20201231' :return: + + note: 查看节假日未公布的未来交易日,可以使用compute_coming_trading_calendar函数 ''' import datetime as dt @@ -1747,25 +2163,25 @@ def get_trading_calendar(market, start_time = '', end_time = ''): hl = [dt.datetime(hh // 10000, ((hh // 100) % 100), hh % 100, 0, 0) for hh in hl] if start_time: - ss = dt.datetime.strptime(start_time, '%Y%m%d') - ts = max(ss - dt.timedelta(days = 1), tdl[-1]) + start = dt.datetime.strptime(start_time, '%Y%m%d') + ts = max(start - dt.timedelta(days = 1), tdl[-1]) else: - ss = tdl[0] + start = tdl[0] ts = tdl[-1] if end_time: - te = dt.datetime.strptime(end_time, '%Y%m%d') + end = dt.datetime.strptime(end_time, '%Y%m%d') else: - te = dt.datetime(hl[-1].year, 12, 31, 0, 0) + end = max(dt.datetime(hl[-1].year, 12, 31, 0, 0), tdl[-1]) - if hl[-1].year < te.year: + if hl[-1].year < end.year: raise Exception(f'end_time({end_time}) 超出现有节假日数据({hl[-1].year}1231)') hdset = set(hl) - res = [tt for tt in tdl if tt >= ss] + res = [tt for tt in tdl if start <= tt <= end] tt = ts + dt.timedelta(days = 1) - while tt <= te: + while tt <= end: if tt not in hdset and tt.weekday() < 5: res.append(tt) @@ -1774,32 +2190,6 @@ def get_trading_calendar(market, start_time = '', end_time = ''): return [tt.strftime('%Y%m%d') for tt in res] -def get_trading_time(stockcode): - ''' - 返回指定股票的交易时段 - :param stockcode: 代码.市场 例如 '600000.SH' - :return: 返回交易时段列表,第一位是开始时间,第二位结束时间,第三位交易类型 (2 - 开盘竞价, 3 - 连续交易, 8 - 收盘竞价, 9 - 盘后定价) - :note: 需要转换为datetime时,可以用以下方法转换 - import datetime as dt - dt.datetime.combine(dt.date.today(), dt.time()) + dt.timedelta(seconds = 34200) - ''' - cl = get_client() - - split_codes = stockcode.rsplit('.', 1) - if len(split_codes) == 2: - code = split_codes[0] - market = split_codes[1] - else: - return [] - - inst = _BSON_call_common( - cl.commonControl, 'gettradingtime', { - 'market': market - , 'code': code - } - ) - return inst.get('result', []) - def is_stock_type(stock, tag): client = get_client() return client.is_stock_type(stock, tag) @@ -1807,12 +2197,12 @@ def is_stock_type(stock, tag): def download_cb_data(): client = get_client() return client.down_cb_data() - + def get_cb_info(stockcode): client = get_client() inst = client.get_cb_info(stockcode) return _BSON_.BSON.decode(inst) - + def get_option_detail_data(optioncode): inst = _get_instrument_detail(optioncode) if not inst: @@ -1853,6 +2243,7 @@ def get_option_detail_data(optioncode): 'OptUnit' , 'MarginUnit' , 'OptUndlCode' + , 'OptUndlUniCode' , 'OptUndlMarket' , 'OptUndlCodeFull' , 'OptExercisePrice' @@ -1860,6 +2251,7 @@ def get_option_detail_data(optioncode): , 'OptUndlRiskFreeRate' , 'OptUndlHistoryRate' , 'EndDelivDate' + , 'OptEstimatedMargin' ] inst_ex = inst.get('ExtendInfo', {}) for field in exfield_list: @@ -1893,7 +2285,7 @@ def get_option_detail_data(optioncode): ret['optType'] = optType - ret['OptUndlCodeFull'] = ret['OptUndlCode'] + '.' + ret['OptUndlMarket'] + ret['OptUndlCodeFull'] = ret['OptUndlUniCode'] + '.' + ret['OptUndlMarket'] ProductCode = ret['ProductID'] if ProductCode.endswith('_o'): @@ -1913,6 +2305,12 @@ def get_option_undl_data(undl_code_ref): return inst['OptUndlCode'] + '.' + inst['OptUndlMarket'] return '' + def get_option_undl_uni(opt_code): + inst = get_option_detail_data(opt_code) + if inst and 'OptUndlUniCode' in inst and 'OptUndlMarket' in inst: + return inst['OptUndlUniCode'] + '.' + inst['OptUndlMarket'] + return '' + if undl_code_ref: c_undl_code_ref = undl_code_ref inst = get_instrument_detail(undl_code_ref) @@ -1942,7 +2340,7 @@ def get_option_undl_data(undl_code_ref): opt_list = get_stock_list_in_sector('能源中心期权') data = [] for opt_code in opt_list: - undl_code = get_option_undl(opt_code) + undl_code = get_option_undl_uni(opt_code) if undl_code == c_undl_code_ref: data.append(opt_code) return data @@ -1971,10 +2369,12 @@ def get_option_list(undl_code, dedate, opttype = "", isavailavle = False): if (len(marketcodeList) != 2): return [] undlCode = marketcodeList[0] + undlCode_ori = undlCode undlMarket = marketcodeList[1] inst_data = get_instrument_detail(undl_code) - if inst_data and 'UniCode' in inst_data: - undlCode = inst_data['UniCode'] + if inst_data: + undlCode = inst_data.get('UniCode', undlCode) + undlCode_ori = inst_data.get('InstrumentID', undlCode) market = "" if (undlMarket == "SH"): if undlCode == "000016" or undlCode == "000300" or undlCode == "000852" or undlCode == "000905": @@ -2034,7 +2434,7 @@ def get_option_list(undl_code, dedate, opttype = "", isavailavle = False): endDate = inst['ExpireDate'] if (isavailavle and endDate < dedate): continue - if inst['OptUndlCode'].find(undlCode) >= 0: + if inst['OptUndlCode'] == undlCode or inst['OptUndlCode'] == undlCode_ori: result.append(opt) return result @@ -2268,6 +2668,9 @@ def subscribe_formula(formula_name, stock_code, period, start_time = '', end_tim , 'dividendtype': dividend_type if dividend_type else 'none' , 'extendparam': extend_param , 'create': True + , 'historycallback': 1 if callback else 0 + , 'realtimecallback': 1 if callback else 0 + , 'barmode' : int(extend_param.get('barmode', 0)) } if callback: @@ -2277,19 +2680,53 @@ def subscribe_formula(formula_name, stock_code, period, start_time = '', end_tim return request_id -def get_formula_result(request_id, start_time = '', end_time = '', count = -1): +def get_formula_result(request_id, start_time = '', end_time = '', count = -1, timeout_second = -1): + ''' + 根据模型ID获取模型结果 + request_id: 模型ID,例如subscribe_formula返回值 + start_time: 起始时间 "20200101" "20200101093000" + end_time: 结束时间 "20201231" "20201231150000" + count: 数量 -1全部/n: 从结束时间向前数n个 + timeout_second: 等待时间,-1无限等待,0立即返回,+n等待n秒,超时抛异常 + ''' + res = {} + + import time + begin_time = time.time() + cl = get_client() - res = _BSON_.BSON.decode( - cl.commonControl( - 'getformularesult' - , _BSON_.BSON.encode({ - 'requestid': request_id - , 'starttime': start_time - , 'endtime': end_time - , 'count': count - }) - ) - ) + while 1: + status = _BSON_.BSON.decode( + cl.commonControl( + 'checkformulafinished' + , _BSON_.BSON.encode({ + 'requestid': request_id + }) + ) + ).get('result', -1) + + if status == -1: + raise Exception(f"not find formula {request_id}") + + if status == 1 or timeout_second == 0: + res = _BSON_.BSON.decode( + cl.commonControl( + 'getformularesult' + , _BSON_.BSON.encode({ + 'requestid': request_id + , 'starttime': start_time + , 'endtime': end_time + , 'count': count + }) + ) + ) + break + + if timeout_second > 0: + end_time = time.time() + if end_time - begin_time > timeout_second: + raise Exception(f"wait formula {request_id} result timeout") + time.sleep(0.5) return res @@ -2789,6 +3226,26 @@ def get_quote_server_status(): return result +def show_quote_server_status(): + ''' + 获取每个key对应的连接的地址 + 返回:dict,{'0_SH_L1':'ip:port', ...} + ''' + result = {} + cl = get_client() + + inst = _BSON_call_common( + cl.commonControl, 'getquoteserverstatus', {} + ) + inst = inst.get('result', []) + + for data in inst: + key = data.get('key', '') + info = data.get('info', {}) + result[key] = f"{info.get('ip', '')}:{info.get('port', '')}" + return result + + def watch_quote_server_status(callback): ''' 监控全局连接状态变化 @@ -2807,7 +3264,7 @@ def watch_quote_server_status(callback): _BSON_call_common(cl.commonControl, "watchquoteserverstatus", {}) return -def fetch_quote(root_path, key_list): +def fetch_quote_server_from_config(root_path, key_list): root_path = _OS_.path.abspath(root_path) cl = get_client() inst = _BSON_call_common( @@ -2865,16 +3322,34 @@ def fetch_quote(root_path, key_list): def get_etf_info(): - period = _get_tuple_period('etfredemptionlist') - if not isinstance(period, tuple): + spec_period, meta_id, period_num = _validate_period('etfredemptionlist') + if meta_id < 0: return {} - all_data = _get_market_data_ex_tuple_period_ori(['XXXXXX.SH', 'XXXXXX.SZ'], period) + all_data = _get_market_data_ex_tuple_period_ori(['XXXXXX.SH', 'XXXXXX.SZ'], (meta_id, period_num)) - metaid, periodNum = period - convert_field_list = get_field_list(metaid) + convert_field_list = get_field_list(meta_id) result = {} + + def _self_convert_component_info(data, convert_field_list): + if not isinstance(data, dict): + return data + + new_data = {} + for key, value in data.items(): + if key in ['25', '26', '27']: + continue + + name = convert_field_list.get(key, key) + if isinstance(value, dict): + new_data[name] = _self_convert_component_info(value, convert_field_list) + elif isinstance(value, list): + new_data[name] = [_self_convert_component_info(item, convert_field_list) for item in value] + else: + new_data[name] = value + return new_data + for stockcode, data_list in all_data.items(): market = stockcode.split('.')[1] @@ -2882,7 +3357,7 @@ def get_etf_info(): convert_data = {'market': market} if convert_field_list: - data = _convert_component_info(data, convert_field_list) + data = _self_convert_component_info(data, convert_field_list) convert_data.update(data) stock_market = '' @@ -3112,33 +3587,44 @@ def generate_index_data( return + +from .metatable import * + def download_tabular_data(stock_list, period, start_time = '', end_time = '', incrementally = None, download_type = 'validationbypage', source = ''): ''' 下载表数据,可以按条数或按时间范围下载 - stock_list: - list 股票列表 - period: - str 周期 - '1m' '5m' '1d' - start_time: - str 起始时间 '20240101' '20240101000000' - '' - '19700101' - end_time: - str 结束时间 '20241231' '20241231235959' - '' - '20380119' - incrementally: - bool 是否增量 - 'fixed' - 固定值填充 - 'forward' - 向前延续 - download_type: - str 下载类型 + stock_list: 股票列表 + - list + period: 周期 + - str 例如 '1m' '5m' '1d' + start_time: 起始时间 + - str 格式yyyyMMdd/yyyyMMddHHmmss,例如: + '20240101' '20240101000000' + '' 代表 '19700101' + - datetime.datetime对象 + end_time: 结束时间 + - str 格式yyyyMMdd/yyyyMMddHHmmss,例如: + '20241231' '20241231235959' + '' 代表 '20380119' + - datetime.datetime对象 + incrementally: 是否增量 + - bool + download_type: 下载类型 + - str 'bypage' - 按条数下载 'byregion' - 按时间范围下载 'validatebypage' - 数据校验按条数下载 - source: - str 指定下载地址 + source: 指定下载地址 + - str ''' + import datetime as dt + + if isinstance(start_time, dt.datetime): + start_time = start_time.strftime('%Y%m%d%H%M%S') + if isinstance(end_time, dt.datetime): + end_time = end_time.strftime('%Y%m%d%H%M%S') + if incrementally is None: incrementally = False if start_time else True @@ -3263,20 +3749,58 @@ def get_trading_contract_list(stockcode, date = None): def get_trading_period(stock_code): ''' - 获取合约最新交易时间段 - stock_code: 合约市场代码,例如:600000.SH - 返回值:dict - {market, codeRegex, product, category, tradings: [type, bartime:[dayoffset, start, end]]} - market:市场 - codeRegex:代码匹配规则 - product:产品类型 - category:证券分类 - codeRegex, product, category,三个规则,每次只有一个规则有数据。数据中*代表任意 - tradings, list: - type:交易类型(2盘前竞价,3连续交易,8尾盘竞价) - dayoffset:交易日偏移 - start, int:开始时间,时分秒 - end, int:结束时间,时分秒 + 获取指定品质真实交易时间段 + stock_code: str 合约代码 + + 返回:dict + { + 'market': market, + 'codeRegex': codeRegex, + 'product': [ product_code1, product_code2, ... ], + 'category': [ category1, category2, ... ], + 'tradings': [ trading_period1, trading_period2, ... ], + } + market: str 市场代码 + codeRegex: str 代码匹配规则 + product_code: str 产品代码 + category: int 证券分类 + + 通过指定stock_code获取到的交易时段信息已经是和这个品种匹配的, + 通常不需要使用codeRegex, product, category这三个字段 + + trading_period: dict 交易时段 + { + 'status': status, + 'time': [ + trading_day_offset + , [ begin_time, boundary_type ] + , [ end_time, boundary_type ] + ], + } + + status: int 交易时段类型 + 2 - 盘前竞价 + 3 - 连续交易 + 8 - 尾盘竞价 + 15 - 集合竞价对盘时段(港股) + + trading_day_offset: int 交易日偏移 + + begin_time: int 开始时间, 时分秒 + 例如 930000 表示 09:30:00 + 1130000 表示 11:30:00 + 特殊地,负数表示小时为0点以前的时间,例如 -45500 表示前一个自然日的 20:55:00 + 超过24小时的时间,表示24点后的时间,例如 263000 表示下一个自然日的 02:30:00 + + end_time: int 结束时间, 时分秒 + + boundary_type: int 边界类型, 范围为 -1 0 1 + 以begin_time为例, + -1表示边界时间点小于begin_time + 0表示边界时间点等于begin_time + 1表示边界时间点大于begin_time + 例如begin_time为93000, boundary_type为1, 则开始时间为09:30:00之后,且09:30:00不在范围内 + 例如end_time为210000, boundary_type为-1, 则结束时间为21:00:00之前,且21:00:00不在范围内 ''' cl = get_client() @@ -3284,7 +3808,7 @@ def get_trading_period(stock_code): cl.commonControl , 'getopenclosetradetimebystock' , { - "stockMarket" : stock_code + "stockcode" : stock_code } ) @@ -3293,7 +3817,71 @@ def get_trading_period(stock_code): def get_kline_trading_period(stock_code): ''' - 与交易时间相似,区别在于把尾盘竞价和盘中交易合并 + 获取指定品种的K线时段 + + stock_code: str 合约代码 + + 返回: dict + { + 'market': market, + 'codeRegex': codeRegex, + 'product': [ product_code1, product_code2, ... ], + 'category': [ category1, category2, ... ], + 'tradings': [ trading_period1, trading_period2, ... ], + } + + market: str 市场代码 + codeRegex: str 代码匹配规则 + product_code: str 产品代码 + category: int 证券分类 + + 通过指定stock_code获取到的交易时段信息已经是和这个品种匹配的, + 通常不需要使用codeRegex, product, category这三个字段 + + trading_period: dict 交易时段 + { 'type': type, ... } + + type: str 交易时段类型 + 'auction' - 竞价交易 + 'continuous' - 连续交易 + type为不同类型时,其余字段内容不同 + + type为auction时,字段内容如下: + { + 'type': 'auction', + 'source': [ + trading_day_offset + , [ begin_time, boundary_type ] + , [ end_time, boundary_type ] + ], + 'bartime': [ trading_day_offset, target_time ], + } + 使用竞价交易时段合并K线时,任何在source范围内的tick数据都应该被视为时间点为bartime的tick数据 + + type为continuous时,字段内容如下: + { + 'type': 'continuous', + 'bartime': [ trading_day_offset, begin_time, end_time ], + } + 使用连续交易时段合并K线时,在begin_time和end_time之间的tick数据按具体K线周期合并为K线 + + trading_day_offset: int 交易日偏移 + + begin_time: int 开始时间, 时分秒 + 例如 930000 表示 09:30:00 + 1130000 表示 11:30:00 + 特殊地,负数表示小时为0点以前的时间,例如 -45500 表示前一个自然日的 20:55:00 + 超过24小时的时间,表示24点后的时间,例如 263000 表示下一个自然日的 02:30:00 + + end_time: int 结束时间, 时分秒 + + boundary_type: int 边界类型, 范围为 -1 0 1 + 以begin_time为例, + -1表示边界时间点小于begin_time + 0表示边界时间点等于begin_time + 1表示边界时间点大于begin_time + 例如begin_time为93000, boundary_type为1, 则开始时间为09:30:00之后,且09:30:00不在范围内 + 例如end_time为210000, boundary_type为-1, 则结束时间为21:00:00之前,且21:00:00不在范围内 ''' cl = get_client() @@ -3301,7 +3889,7 @@ def get_kline_trading_period(stock_code): cl.commonControl , 'getopencloseklinetimebystock' , { - "stockMarket": stock_code + "stockcode": stock_code } ) @@ -3310,7 +3898,7 @@ def get_kline_trading_period(stock_code): def get_all_trading_periods(): ''' - 获取全部市场划分出来的交易时间段 + 获取全部市场的真实交易时间段 ''' cl = get_client() @@ -3326,7 +3914,7 @@ def get_all_trading_periods(): def get_all_kline_trading_periods(): ''' - 获取全部市场划分出来的K线交易时间段 + 获取全部市场的分割K线交易时间段 ''' cl = get_client() @@ -3348,5 +3936,213 @@ def get_authorized_market_list(): return _BSON_call_common(get_client().commonControl, 'getauthorizedmarketlist', {}).get('result', []) -from .metatable import * +def compute_coming_trading_calendar(market, start_time = '', end_time = ''): + ''' + 未来交易日函数 + note: 历史交易日,可以使用get_trading_calendar函数 + ''' + if market not in ["SH", "SZ"]: + raise Exception("暂不支持除SH,SZ以外市场的交易日历") + data = _BSON_call_common(get_client().commonControl, 'getcomingtradedate', {}).get('result', []) + + import datetime as dt + if start_time: + ds = dt.datetime.strptime(start_time, '%Y%m%d') + else: + ds = dt.datetime(1980, 1, 1, 0, 0) + + if end_time: + de = dt.datetime.strptime(end_time, '%Y%m%d') + else: + de = dt.datetime(2038, 12, 31, 0, 0) + + ss = ds.timestamp() * 1000 + se = de.timestamp() * 1000 + + return [timetag_to_datetime(d, '%Y%m%d') for d in data if ss <= d <= se] + + +def get_tabular_formula( + codes: list, + fields: list, + period: str, + start_time: str, + end_time: str, + count: int = -1, + dividend_type = 'none', + **kwargs +): + def _parse_fields(fields): + tmp = {} # { table: [{}] } + idx = 1 + for field in fields: + if field.find('.') != -1: + table = field.split('.')[0] + ifield = field.split('.')[1] + + if table not in tmp: + tmp[table] = [] + val = {'key': '0', 'fieldNameCn': '股票代码', 'modelName': 'stock', 'type': 'string', 'unit': ''} + tmp[table].append(val) + val = {'key': '1', 'fieldNameCn': '时间戳', 'modelName': 'timetag', 'type': 'int', 'unit': ''} + tmp[table].append(val) + + idx += 1 + val = {'key': str(idx), 'fieldNameCn': ifield, 'modelName': ifield, 'unit': ''} + tmp[table].append(val) + + return tmp + all_fields = _parse_fields(fields) + + from .qmttools.functions import call_formula_batch + formula_names = list(all_fields.keys()) + result = call_formula_batch(formula_names=formula_names, stock_codes=codes, period=period, start_time=start_time, end_time=end_time, count=count, dividend_type=dividend_type) + + from . import xtbson + stock_formula_result = [] + for res in result: + stock = res.get('stock', '') + formula = res.get('formula', '') + rst = res.get('result', {}) + fields = all_fields[formula] + + timelist = rst.get('timelist', []) + outputs = rst.get('outputs', {}) + val = {} + for i, t in enumerate(timelist): + val['0'] = stock + val['1'] = t + for field in fields: + if field['modelName'] in outputs: + if 'type' not in field: + t = type(outputs[field['modelName']][i]) + if t == int: + field['type'] = 'int' + elif t == str: + field['type'] = 'string' + elif t == float: + field['type'] = 'double' + + val[field['key']] = outputs[field['modelName']][i] + stock_formula_result.append(xtbson.encode(val)) + + head_fields = [] + for f in list(all_fields.values()): + head_fields.extend(f) + heads = {'modelName': '', 'tableNameCn': '', 'fields': head_fields} + + stock_formula_result.insert(0, xtbson.encode(heads)) + return stock_formula_result + + +def bnd_get_conversion_price(stock_code, start_time="", end_time=""): + ''' + 查询可转债转股价变动信息 + stock_code: str 转债代码 + start_time: str 开始时间(可不填),格式为"%Y%m%d",默认为"" + end_time: str 结束时间(可不填),格式为"%Y%m%d",默认为"" + ''' + return _get_tabular_data([stock_code], ['bond_conv_price_info'], '', start_time, end_time) + + +def bnd_get_call_info(stock_code, start_time="", end_time=""): + ''' + 查询可转债赎回信息 + stock_code: str 转债代码 + start_time: str 开始时间(可不填),格式为"%Y%m%d",默认为"" + end_time: str 结束时间(可不填),格式为"%Y%m%d",默认为"" + ''' + return _get_tabular_data([stock_code], ['bond_call_info'], '', start_time, end_time) + + +def bnd_get_put_info(stock_code, start_time="", end_time=""): + ''' + 查询可转债回售信息 + stock_code: str 转债代码 + start_time: str 开始时间(可不填),格式为"%Y%m%d",默认为"" + end_time: str 结束时间(可不填),格式为"%Y%m%d",默认为"" + ''' + return _get_tabular_data([stock_code], ['bond_put_info'], '', start_time, end_time) + + +def bnd_get_amount_change(stock_code, start_time="", end_time=""): + ''' + 查询可转债剩余规模变动 + stock_code: str 转债代码 + start_time: str 开始时间(可不填),格式为"%Y%m%d",默认为"" + end_time: str 结束时间(可不填),格式为"%Y%m%d",默认为"" + ''' + return _get_tabular_data([stock_code], ['bond_amount_chg'], '', start_time, end_time) + + +def get_tabular_data( + field_list = [], stock_list = [], period = '1d' + , start_time = '', end_time = '', count = -1 + , dividend_type = 'none', fill_data = True +): + ''' + 获取历史行情数据 + :param field_list: 行情数据字段列表,[]为全部字段 + K线可选字段: + "time" #时间戳 + "open" #开盘价 + "high" #最高价 + "low" #最低价 + "close" #收盘价 + "volume" #成交量 + "amount" #成交额 + "settle" #今结算 + "openInterest" #持仓量 + :param stock_list: 股票代码 "000001.SZ" + :param period: 周期 分钟线"1m"/"5m"/"15m" 日线"1d" + :param start_time: 起始时间 "20200101" "20200101093000" + :param end_time: 结束时间 "20201231" "20201231150000" + :param count: 数量 -1全部/n: 从结束时间向前数n个 + :param dividend_type: 除权类型"none" "front" "back" "front_ratio" "back_ratio" + :param fill_data: 对齐时间戳时是否填充数据,仅对K线有效,分笔周期不对齐时间戳 + 为True时,以缺失数据的前一条数据填充 + open、high、low、close 为前一条数据的close + amount、volume为0 + settle、openInterest 和前一条数据相同 + 为False时,缺失数据所有字段填NaN + :return: pd.DataFrame 字段对应的数据,各字段维度相同,index为为time_list,包含symbol列 + ''' + if period in {'1m', '5m', '15m', '30m', '60m', '1h', '1d', '1w', '1mon', '1q', '1hy', '1y'}: + return _get_market_data_ex_250414(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data) + + return _get_tabular_data(stock_list, field_list, period, start_time, end_time, count, dividend_type=dividend_type, fill_data=fill_data) + +def get_order_rank(code, order_time, order_type, order_price, order_volume, order_left_volume): + ''' + 获取委托在千档队列中的排名, 需要订阅千档数据,并且数据源为本地计算的千档数据 + :param code: 股票代码 e.g. "000001.SZ" + :param order_time: 委托时间 支持以下格式: + - str格式: YYYYMMDD/YYYYMMDDhhmmss,e.g."20200427" "20200427093000" + - datetime对象 + :param order_type: 委托类型,即买卖方向,e.g.'buy' 'sell' + :param order_price: 委托价格 + :param order_volume: 委托量 + :param order_left_volume: 委托未成量 + :return: dict + pricerank:价内排名 + ''' + + import datetime as dt + if isinstance(order_time, dt.datetime): + timetag = int(order_time.timestamp() * 1000) + elif isinstance(order_time, str): + if len(order_time) == 8: # YYYYMMDD + timetag = int(dt.datetime.strptime(order_time, "%Y%m%d").timestamp() * 1000) + elif len(order_time) == 14: # YYYYMMDDhhmmss + timetag = int(dt.datetime.strptime(order_time, "%Y%m%d%H%M%S").timestamp() * 1000) + + param = {} + param['stockcode'] = code + param['time'] = timetag + param['type'] = order_type + param['price'] = order_price + param['volume'] = order_volume + param['leftvolume'] = order_left_volume + + return _BSON_call_common(get_client().commonControl, 'getorderrank', param) diff --git a/src/xtquant/xtdatacenter.py b/src/xtquant/xtdatacenter.py index ae785b6..02e2b68 100644 --- a/src/xtquant/xtdatacenter.py +++ b/src/xtquant/xtdatacenter.py @@ -110,7 +110,8 @@ def set_kline_mirror_markets(markets): def set_allow_optmize_address(allow_list = []): ''' - 设置连接池,行情仅从连接池内的地址中选择连接,此接口应该先于init调用 + 设置连接池,此接口应该先于init调用 + 设置后,行情仅从连接池内的地址中选择连接,并且使用第一个地址作为全推行情地址 地址格式为'127.0.0.1:55300' 设置为空时,行情从全部的可用地址中选择连接 ''' @@ -158,7 +159,7 @@ def set_index_mirror_enabled(enable): 设置指标全推功能是否开启,此接口应该先于init调用 此功能默认关闭 ''' - __dc.set_index_mirror_enabled(["SH", "SZ", "SHO", "SZO", "IF", "DF", "SF", "ZF", "GF", "INE"] if enable else []) + __dc.set_index_mirror_enabled(['SH', 'SZ', 'SHO', 'SZO', 'IF', 'DF', 'SF', 'ZF', 'GF', 'INE'] if enable else []) return @@ -174,6 +175,41 @@ def set_index_mirror_markets(markets): return +def set_kline_cutting_mode(mode): + ''' + 设置多周期数据切割按累计交易时间还是固定交易间隔,此接口应该先于init调用 + mode: str, 切割方式 + 'accumulate',累计交易时间 + 'fixed',固定交易间隔 + 例如 期货交易时间10:00-10:15, 10:30-11:30, 以30分钟k线切割划分为依据 + 按累计交易时间方式结果为10:00-10:45, 10:45-11:15,累计够30分钟,做一次切割,默认使用当前方式 + 按固定交易间隔方式结果为10:00-10:15, 10:30-11:00,是按固定30分钟切割划分一次 + 默认按累计交易时间 + ''' + __dc.set_kline_cutting_mode(mode) + + +def set_quote_time_mode_v2(enable): + ''' + 设置是否用新版交易时段,此接口应该先于init调用 + ''' + __dc.set_quote_time_version(enable) + +def set_thousand_source_mode(mode): + ''' + 设置千档数据源模式: + mode: str, 千档数据源模式 + 'server',使用服务计算的千档数据 + 'local' ,使用本地计算的千档数据 + 示例: + from xtquant import xtdatacenter as xtdc + xtdc.set_thousand_source_mode('server') # 使用服务计算的千档数据 + xtdc.set_thousand_source_mode('local') # 使用本地计算的千档数据 + + 默认使用服务计算的千档数据 + ''' + __dc.set_thousand_source_mode(mode) + def init(start_local_service = True): ''' 初始化行情模块 @@ -182,8 +218,8 @@ def init(start_local_service = True): ''' import time - __dc.set_config_dir(__config_dir) - __dc.set_data_home_dir(__data_home_dir) + __dc.set_config_dir(str(__config_dir)) + __dc.set_data_home_dir(str(__data_home_dir)) __dc.set_token(__quote_token) __dc.log_init() __dc.start_init_quote() @@ -209,8 +245,10 @@ def init(start_local_service = True): status_show[srv_addr] = info['boerror'] else: status_show[srv_addr] = info['resultdesc'] + if info['resultcode'] != 0: + status_show[srv_addr] = status_show[srv_addr] + ', ' + info['reason'] - raise ConnectionError(f'行情连接初始化异常, 当前状态:{status_show}') + raise ConnectionError(f'行情连接初始化异常, 未获取到市场权限, 当前连接状态:{status_show}') market_keys = result.get('markets', []) ''' @@ -230,14 +268,14 @@ def init(start_local_service = True): srv_addr = info['loginparam']['ip'] + ':' + str(info['loginparam']['port']) error = info['boerror'] - raise ConnectionError(f'行情连接初始化异常 {mkt} {srv_addr} {error}') + raise ConnectionError(f'行情连接初始化异常 {mkt}, {srv_addr} {error}') if info['resultcode'] != 0: srv_addr = info['loginparam']['ip'] + ':' + str(info['loginparam']['port']) error = info['resultdesc'] reason = info['reason'] - raise ConnectionError(f'行情连接初始化异常 {mkt} {srv_addr} {error} {reason}') + raise ConnectionError(f'行情连接初始化异常 {mkt}, {srv_addr} {error} {reason}') else: status = bson.decode(__dc.fetch_server_list_status()) @@ -250,8 +288,10 @@ def init(start_local_service = True): status_show[srv_addr] = info['boerror'] else: status_show[srv_addr] = info['resultdesc'] + if info['resultcode'] != 0: + status_show[srv_addr] = status_show[srv_addr] + ', ' + info['reason'] - raise ConnectionError(f'行情连接初始化异常 {mkt}, 当前状态:{status_show}') + raise ConnectionError(f'行情连接初始化异常 {mkt}, 未找到支持该市场的连接, 当前连接状态:{status_show}') global init_complete init_complete = True diff --git a/src/xtquant/xtpythonclient.cp310-win_amd64.pyd b/src/xtquant/xtpythonclient.cp310-win_amd64.pyd index ffb799f..7fccdf0 100644 Binary files a/src/xtquant/xtpythonclient.cp310-win_amd64.pyd and b/src/xtquant/xtpythonclient.cp310-win_amd64.pyd differ diff --git a/src/xtquant/xtpythonclient.cp311-win_amd64.pyd b/src/xtquant/xtpythonclient.cp311-win_amd64.pyd index eb9c2b0..943a57e 100644 Binary files a/src/xtquant/xtpythonclient.cp311-win_amd64.pyd and b/src/xtquant/xtpythonclient.cp311-win_amd64.pyd differ diff --git a/src/xtquant/xtpythonclient.cp312-win_amd64.pyd b/src/xtquant/xtpythonclient.cp312-win_amd64.pyd index fa32498..806f597 100644 Binary files a/src/xtquant/xtpythonclient.cp312-win_amd64.pyd and b/src/xtquant/xtpythonclient.cp312-win_amd64.pyd differ diff --git a/src/xtquant/xtpythonclient.cp313-win_amd64.pyd b/src/xtquant/xtpythonclient.cp313-win_amd64.pyd new file mode 100644 index 0000000..9e668df Binary files /dev/null and b/src/xtquant/xtpythonclient.cp313-win_amd64.pyd differ diff --git a/src/xtquant/xtpythonclient.cp36-win_amd64.pyd b/src/xtquant/xtpythonclient.cp36-win_amd64.pyd index df6119a..bc24023 100644 Binary files a/src/xtquant/xtpythonclient.cp36-win_amd64.pyd and b/src/xtquant/xtpythonclient.cp36-win_amd64.pyd differ diff --git a/src/xtquant/xtpythonclient.cp37-win_amd64.pyd b/src/xtquant/xtpythonclient.cp37-win_amd64.pyd index e0b422a..72625a4 100644 Binary files a/src/xtquant/xtpythonclient.cp37-win_amd64.pyd and b/src/xtquant/xtpythonclient.cp37-win_amd64.pyd differ diff --git a/src/xtquant/xtpythonclient.cp38-win_amd64.pyd b/src/xtquant/xtpythonclient.cp38-win_amd64.pyd index 26d855f..68375fd 100644 Binary files a/src/xtquant/xtpythonclient.cp38-win_amd64.pyd and b/src/xtquant/xtpythonclient.cp38-win_amd64.pyd differ diff --git a/src/xtquant/xtpythonclient.cp39-win_amd64.pyd b/src/xtquant/xtpythonclient.cp39-win_amd64.pyd index ed65500..35202fb 100644 Binary files a/src/xtquant/xtpythonclient.cp39-win_amd64.pyd and b/src/xtquant/xtpythonclient.cp39-win_amd64.pyd differ diff --git a/src/xtquant/xttrader.py b/src/xtquant/xttrader.py index db27699..e8761d2 100644 --- a/src/xtquant/xttrader.py +++ b/src/xtquant/xttrader.py @@ -102,6 +102,20 @@ class XtQuantTraderCallback(object): :return: """ pass + + def on_bank_transfer_async_response(self, response): + """ + :param response: XtBankTransferResponse 对象 + :return: + """ + pass + + def on_ctp_internal_transfer_async_response(self, response): + """ + :param response: XtBankTransferResponse 对象 + :return: + """ + pass class XtQuantTrader(object): def __init__(self, path, session, callback=None): @@ -187,7 +201,13 @@ class XtQuantTrader(object): self.async_client.bindOnQueryPositionStatisticsRespCallback(on_common_resp_callback) self.async_client.bindOnExportDataRespCallback(on_common_resp_callback) self.async_client.bindOnSyncTransactionFromExternalRespCallback(on_common_resp_callback) - + self.async_client.bindOnBankTransferRespCallback(on_common_resp_callback) + self.async_client.bindOnQueryBankInfoRespCallback(on_common_resp_callback) + self.async_client.bindOnQueryBankAmountRespCallback(on_common_resp_callback) + self.async_client.bindOnQueryBankTransferStreamRespCallback(on_common_resp_callback) + self.async_client.bindOnQuerySecuAccountRespCallback(on_common_resp_callback) + self.async_client.bindOnCtpInternalTransferRespCallback(on_common_resp_callback) + self.async_client.bindOnQueryAccountInfosCallback(on_common_resp_callback) self.async_client.bindOnQueryAccountStatusCallback(on_common_resp_callback) ######################### @@ -311,7 +331,27 @@ class XtQuantTrader(object): if enable_push: self.async_client.bindOnSmtAppointmentRespCallback(on_common_push_callback_wrapper(2, on_push_SmtAppointmentAsyncResponse)) + + def on_push_bankTransferAsyncResponse(seq, resp): + callback = self.cbs.pop(seq, None) + if callback: + resp = _XTTYPE_.XtBankTransferResponse(seq, resp.success, resp.error_msg) + callback(resp) + return + if enable_push: + self.async_client.bindOnBankTransferRespCallback(on_common_push_callback_wrapper(2, on_push_bankTransferAsyncResponse)) + + def on_push_ctpInternalTransferAsyncResponse(seq, resp): + callback = self.cbs.pop(seq, None) + if callback: + resp = _XTTYPE_.XtBankTransferResponse(seq, resp.success, resp.error_msg) + callback(resp) + return + + if enable_push: + self.async_client.bindOnCtpInternalTransferRespCallback(on_common_push_callback_wrapper(2, on_push_ctpInternalTransferAsyncResponse)) + ######################## def common_op_async_with_seq(self, seq, callable, callback): @@ -433,6 +473,7 @@ class XtQuantTrader(object): req.m_strOrderRemarkNew = order_remark req.m_dOrderAmount = order_volume req.m_strStockCode1 = stock_code + req.m_strAccountID1 = account.account_id seq = self.async_client.nextSeq() self.queuing_order_seq.add(seq) @@ -466,6 +507,7 @@ class XtQuantTrader(object): req.m_strOrderRemarkNew = order_remark req.m_dOrderAmount = order_volume req.m_strStockCode1 = stock_code + req.m_strAccountID1 = account.account_id seq = self.async_client.nextSeq() self.queuing_order_seq.add(seq) @@ -1474,3 +1516,257 @@ class XtQuantTrader(object): result = json.loads(resp) return result + def bank_transfer_in(self, account, bank_no, bank_account, balance, bank_pwd = '', fund_pwd = ''): + """ + :param account - StockAccount: 资金账号 + :param bank_no - str: 银行编号,可通过query_bank_info查回 + :param bank_account - str: 银行账号 + :param balance - float: 转账金额 + :param bank_pwd - str: 银行账号密码 + :param fund_pwd - str: 资金账号密码 + :return: 返回转账结果 + """ + req = _XTQC_.BankTransferReq() + req.account_type = account.account_type + req.account_id = account.account_id + req.fund_pwd = str(fund_pwd) + req.direction = 501 + req.bank_account = str(bank_account) + req.bank_no = str(bank_no) + req.bank_pwd = str(bank_pwd) + req.balance = float(balance) + + seq = self.async_client.nextSeq() + result = self.common_op_sync_with_seq( + seq, + (self.async_client.bankTransferWithSeq, seq, req) + ) + return result.success, result.msg + + def bank_transfer_in_async(self, account, bank_no, bank_account, balance, bank_pwd = '', fund_pwd = ''): + """ + :param account - StockAccount: 资金账号 + :param bank_no - str: 银行编号,可通过query_bank_info查回 + :param bank_account - str: 银行账号 + :param balance - float: 转账金额 + :param bank_pwd - str: 银行账号密码 + :param fund_pwd - str: 资金账号密码 + :return: 返回请求序号, 成功请求后的序号为大于0的正整数, 如果为-1表示请求失败 + """ + req = _XTQC_.BankTransferReq() + req.account_type = account.account_type + req.account_id = account.account_id + req.fund_pwd = str(fund_pwd) + req.direction = 501 + req.bank_account = str(bank_account) + req.bank_no = str(bank_no) + req.bank_pwd = str(bank_pwd) + req.balance = float(balance) + + seq = self.async_client.nextSeq() + self.cbs[seq] = self.callback.on_bank_transfer_async_response + self.async_client.bankTransferWithSeq(seq, req) + return seq + + def bank_transfer_out(self, account, bank_no, bank_account, balance, bank_pwd = '', fund_pwd = ''): + """ + :param account - StockAccount: 资金账号 + :param bank_no - str: 银行编号,可通过query_bank_info查回 + :param bank_account - str: 银行账号 + :param balance - float: 转账金额 + :param bank_pwd - str: 银行账号密码 + :param fund_pwd - str: 资金账号密码 + :return: 返回转账结果 + """ + req = _XTQC_.BankTransferReq() + req.account_type = account.account_type + req.account_id = account.account_id + req.fund_pwd = str(fund_pwd) + req.direction = 502 + req.bank_account = str(bank_account) + req.bank_no = str(bank_no) + req.bank_pwd = str(bank_pwd) + req.balance = float(balance) + + seq = self.async_client.nextSeq() + result = self.common_op_sync_with_seq( + seq, + (self.async_client.bankTransferWithSeq, seq, req) + ) + return result.success, result.msg + + def bank_transfer_out_async(self, account, bank_no, bank_account, balance, bank_pwd = '', fund_pwd = ''): + """ + :param account - StockAccount: 资金账号 + :param bank_no - str: 银行编号,可通过query_bank_info查回 + :param bank_account - str: 银行账号 + :param balance - float: 转账金额 + :param bank_pwd - str: 银行账号密码 + :param fund_pwd - str: 资金账号密码 + :return: 返回请求序号, 成功请求后的序号为大于0的正整数, 如果为-1表示请求失败 + """ + req = _XTQC_.BankTransferReq() + req.account_type = account.account_type + req.account_id = account.account_id + req.fund_pwd = str(fund_pwd) + req.direction = 502 + req.bank_account = str(bank_account) + req.bank_no = str(bank_no) + req.bank_pwd = str(bank_pwd) + req.balance = float(balance) + + seq = self.async_client.nextSeq() + self.cbs[seq] = self.callback.on_bank_transfer_async_response + self.async_client.bankTransferWithSeq(seq, req) + return seq + + def query_bank_info(self, account): + """ + :param account - StockAccount: 资金账号 + :return: 返回BankInfo结构组成的list + """ + req = _XTQC_.QueryBankInfoReq() + req.account_type = account.account_type + req.account_id = account.account_id + + seq = self.async_client.nextSeq() + return self.common_op_sync_with_seq( + seq, + (self.async_client.queryBankInfoWithSeq, seq, req) + ) + + def query_bank_amount(self, account, bank_no, bank_account, bank_pwd): + """ + :param account - StockAccount: 资金账号 + :param bank_no - str: 银行编号,可通过query_bank_info查回 + :param bank_account - str: 银行账号 + :param bank_pwd - str: 银行账号密码 + :return: 返回BankAmount组成的list + """ + req = _XTQC_.QueryBankAmountReq() + req.account_type = account.account_type + req.account_id = account.account_id + req.bank_no = str(bank_no) + req.bank_account = str(bank_account) + req.bank_pwd = str(bank_pwd) + + seq = self.async_client.nextSeq() + return self.common_op_sync_with_seq( + seq, + (self.async_client.queryBankAmountWithSeq, seq, req) + ) + + def query_bank_transfer_stream(self, account, start_date, end_date, bank_no = '', bank_account = ''): + """ + :param account - StockAccount: 资金账号 + :param start_date - str: 查询起始日期,如'20241125' + :param end_date - str: 查询截至日期,如'20241129' + :param bank_no - str: 银行编号,可通过query_bank_info查回 + :param bank_account - str: 银行账号 + :return: 返回BankTransferStream组成的list + """ + req = _XTQC_.QueryBankTransferStreamReq() + req.account_type = account.account_type + req.account_id = account.account_id + req.start_date = str(start_date) + req.end_date = str(end_date) + req.bank_no = str(bank_no) + req.bank_account = str(bank_account) + + seq = self.async_client.nextSeq() + return self.common_op_sync_with_seq( + seq, + (self.async_client.queryBankTransferStreamWithSeq, seq, req) + ) + + def query_secu_account(self, account): + """ + :param account - StockAccount: 资金账号 + :return: 返回SecuAccount结构组成的list + """ + req = _XTQC_.QuerySecuAccountReq() + req.account_type = account.account_type + req.account_id = account.account_id + + seq = self.async_client.nextSeq() + return self.common_op_sync_with_seq( + seq, + (self.async_client.querySecuAccountWithSeq, seq, req) + ) + + def ctp_transfer_option_to_future(self, opt_account_id, ft_account_id, balance): + """ + :param opt_account_id - string: 期权资金账号 + :param ft_account_id - string: 期货资金账号 + :param balance - float: 转账金额 + :return: 返回内转结果 + """ + req = _XTQC_.CtpInternalTransferReq() + req.opt_account_id = str(opt_account_id) + req.ft_account_id = str(ft_account_id) + req.direction = 515 + req.balance = float(balance) + + seq = self.async_client.nextSeq() + result = self.common_op_sync_with_seq( + seq, + (self.async_client.ctpInternalTransferWithSeq, seq, req) + ) + return result.success, result.msg + + def ctp_transfer_option_to_future_async(self, opt_account_id, ft_account_id, balance): + """ + :param opt_account_id - string: 期权资金账号 + :param ft_account_id - string: 期货资金账号 + :param balance - float: 转账金额 + :return: 返回请求序号, 成功请求后的序号为大于0的正整数, 如果为-1表示请求失败 + """ + req = _XTQC_.CtpInternalTransferReq() + req.opt_account_id = str(opt_account_id) + req.ft_account_id = str(ft_account_id) + req.direction = 515 + req.balance = float(balance) + + seq = self.async_client.nextSeq() + self.cbs[seq] = self.callback.on_ctp_internal_transfer_async_response + self.async_client.ctpInternalTransferWithSeq(seq, req) + return seq + + def ctp_transfer_future_to_option(self, opt_account_id, ft_account_id, balance): + """ + :param opt_account_id - string: 期权资金账号 + :param ft_account_id - string: 期货资金账号 + :param balance - float: 转账金额 + :return: 返回内转结果 + """ + req = _XTQC_.CtpInternalTransferReq() + req.opt_account_id = str(opt_account_id) + req.ft_account_id = str(ft_account_id) + req.direction = 516 + req.balance = float(balance) + + seq = self.async_client.nextSeq() + result = self.common_op_sync_with_seq( + seq, + (self.async_client.ctpInternalTransferWithSeq, seq, req) + ) + return result.success, result.msg + + def ctp_transfer_future_to_option_async(self, opt_account_id, ft_account_id, balance): + """ + :param opt_account_id - string: 期权资金账号 + :param ft_account_id - string: 期货资金账号 + :param balance - float: 转账金额 + :return: 返回请求序号, 成功请求后的序号为大于0的正整数, 如果为-1表示请求失败 + """ + req = _XTQC_.CtpInternalTransferReq() + req.opt_account_id = str(opt_account_id) + req.ft_account_id = str(ft_account_id) + req.direction = 516 + req.balance = float(balance) + + seq = self.async_client.nextSeq() + self.cbs[seq] = self.callback.on_ctp_internal_transfer_async_response + self.async_client.ctpInternalTransferWithSeq(seq, req) + return seq + diff --git a/src/xtquant/xttype.py b/src/xtquant/xttype.py index 67a77e1..75a280f 100644 --- a/src/xtquant/xttype.py +++ b/src/xtquant/xttype.py @@ -36,13 +36,14 @@ class XtAsset(object): """ 迅投股票账号资金结构 """ - def __init__(self, account_id, cash, frozen_cash, market_value, total_asset): + def __init__(self, account_id, cash, frozen_cash, market_value, total_asset, fetch_balance): """ :param account_id: 资金账号 :param cash: 可用 :param frozen_cash: 冻结 :param market_value: 持仓市值 :param total_asset: 总资产 + :param fetch_balance: 可取资金 """ self.account_type = _XTCONST_.SECURITY_ACCOUNT self.account_id = account_id @@ -50,6 +51,7 @@ class XtAsset(object): self.frozen_cash = frozen_cash self.market_value = market_value self.total_asset = total_asset + self.fetch_balance = fetch_balance class XtOrder(object): @@ -60,7 +62,7 @@ class XtOrder(object): order_id, order_sysid, order_time, order_type, order_volume, price_type, price, traded_volume, traded_price, order_status, status_msg, strategy_name, order_remark, direction, offset_flag, - stock_code1): + secu_account, instrument_name): """ :param account_id: 资金账号 :param stock_code: 证券代码, 例如"600000.SH" @@ -79,6 +81,8 @@ class XtOrder(object): :param order_remark: 委托备注 :param direction: 多空, 股票不需要 :param offset_flag: 交易操作,用此字段区分股票买卖,期货开、平仓,期权买卖等 + :param secu_account: 股东代码 + :param instrument_name: 证券名称 """ self.account_type = _XTCONST_.SECURITY_ACCOUNT self.account_id = account_id @@ -98,7 +102,8 @@ class XtOrder(object): self.order_remark = order_remark self.direction = direction self.offset_flag = offset_flag - self.stock_code1 = stock_code1 + self.secu_account = secu_account + self.instrument_name = instrument_name class XtTrade(object): @@ -108,7 +113,7 @@ class XtTrade(object): def __init__(self, account_id, stock_code, order_type, traded_id, traded_time, traded_price, traded_volume, traded_amount, order_id, order_sysid, strategy_name, order_remark, direction, offset_flag, - stock_code1, commission): + commission, secu_account, instrument_name): """ :param account_id: 资金账号 :param stock_code: 证券代码, 例如"600000.SH" @@ -125,6 +130,8 @@ class XtTrade(object): :param direction: 多空, 股票不需要 :param offset_flag: 交易操作,用此字段区分股票买卖,期货开、平仓,期权买卖等 :param commission: 手续费 + :param secu_account: 股东代码 + :param instrument_name: 证券名称 """ self.account_type = _XTCONST_.SECURITY_ACCOUNT self.account_id = account_id @@ -141,8 +148,9 @@ class XtTrade(object): self.order_remark = order_remark self.direction = direction self.offset_flag = offset_flag - self.stock_code1 = stock_code1 self.commission = commission + self.secu_account = secu_account + self.instrument_name = instrument_name class XtPosition(object): @@ -152,7 +160,7 @@ class XtPosition(object): def __init__(self, account_id, stock_code, volume, can_use_volume, open_price, market_value, frozen_volume, on_road_volume, yesterday_volume, avg_price, direction, - stock_code1): + last_price, profit_rate, secu_account, instrument_name): """ :param account_id: 资金账号 :param stock_code: 证券代码, 例如"600000.SH" @@ -165,6 +173,10 @@ class XtPosition(object): :param yesterday_volume: 昨夜拥股 :param avg_price: 成本价 :param direction: 多空, 股票不需要 + :param last_price: 当前价 + :param profit_rate: 盈亏比例 + :param secu_account: 股东代码 + :param instrument_name: 证券名称 """ self.account_type = _XTCONST_.SECURITY_ACCOUNT self.account_id = account_id @@ -178,7 +190,10 @@ class XtPosition(object): self.yesterday_volume = yesterday_volume self.avg_price = avg_price self.direction = direction - self.stock_code1 = stock_code1 + self.last_price = last_price + self.profit_rate = profit_rate + self.secu_account = secu_account + self.instrument_name = instrument_name class XtOrderError(object): @@ -371,3 +386,18 @@ class XtSmtAppointmentResponse(object): self.success = success self.msg = msg self.apply_id = apply_id + +class XtBankTransferResponse(object): + """ + 迅投银证转账异步接口的反馈 + """ + def __init__(self, seq, success, msg): + """ + :param seq: 异步请求序号 + :param success: 是否成功 + :param msg: 反馈信息 + """ + self.seq = seq + self.success = success + self.msg = msg + diff --git a/src/xtquant/xtview.py b/src/xtquant/xtview.py index b9f8408..ce64fc4 100644 --- a/src/xtquant/xtview.py +++ b/src/xtquant/xtview.py @@ -20,12 +20,22 @@ def connect(ip = '', port = None, remember_if_success = True): from . import xtconn + start_port = 0 + end_port = 65535 + + if isinstance(port, tuple): + start_port = port[0] + end_port = port[1] + + if start_port > end_port: + start_port, end_port = end_port, start_port + if not ip: ip = 'localhost' if port: server_list = [f'{ip}:{port}'] - __client = xtconn.connect_any(server_list) + __client = xtconn.connect_any(server_list, start_port, end_port) else: server_list = xtconn.scan_available_server_addr() @@ -33,7 +43,7 @@ def connect(ip = '', port = None, remember_if_success = True): if not default_addr in server_list: server_list.append(default_addr) - __client = xtconn.connect_any(server_list) + __client = xtconn.connect_any(server_list, start_port, end_port) if not __client or not __client.is_connected(): raise Exception("无法连接xtquant服务,请检查QMT-投研版或QMT-极简版是否开启") @@ -324,3 +334,51 @@ def push_xtview_data(data_type, time, datas): ) return + +class UIPanel: + code = '' + period = '1d' + figures = [] + startX = -1 + startY = -1 + width = -1 + height = -1 + + def __init__(self, code, period = '1d', figures = [], startX = -1, startY = -1, width = -1, height = -1): + self.code = code + self.period = period + self.figures = figures + self.startX = startX + self.startY = startY + self.width = width + self.height = height + + +def apply_ui_panel_control(info: list): + ''' + 控制主图界面展示 + 用法: + apply_ui_panel_control(info:list[UIPanel]) + + 参数: + info,list[UIPanel]类型,每个UIPanel为一个行情页面,code为必填项 + code:str,代码市场,为必填项 + period:str,周期,'tick','1m','5m','1d'等 + figures:list,内部存放附图指标名称 + startX: int, 距屏幕左上角横坐标的位置 + startY: int, 距屏幕左上角纵坐标的位置 + width: int, 宽度 + height: int, 高度 + + 示例: + from xtquant import xtview + x=xtview.UIPanel('600000.SH','1d', figures=[{'ma': {'n1': 5}}]) + y=xtview.UIPanel(code='600030.SH',period='1m',startX=-1,startY=-1, width=-1, height=-1) + xtview.apply_ui_panel_control([x,y]) + ''' + data = [] + for i in info: + data.append(i.__dict__) + + result = _BSON_call_common(get_client().commonControl, 'applyuipanelcontrol', {'data': data}) + return