lib-x17-fintech 2.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. lib_x17_fintech-2.1.3.dist-info/METADATA +633 -0
  2. lib_x17_fintech-2.1.3.dist-info/RECORD +282 -0
  3. lib_x17_fintech-2.1.3.dist-info/WHEEL +5 -0
  4. lib_x17_fintech-2.1.3.dist-info/licenses/LICENSE +1 -0
  5. lib_x17_fintech-2.1.3.dist-info/top_level.txt +1 -0
  6. xfintech/__init__.py +0 -0
  7. xfintech/connect/__init__.py +18 -0
  8. xfintech/connect/artifact/__init__.py +5 -0
  9. xfintech/connect/artifact/artifact.py +168 -0
  10. xfintech/connect/artifact/tests/__init__.py +3 -0
  11. xfintech/connect/artifact/tests/test_class_artifact_all.py +564 -0
  12. xfintech/connect/common/__init__.py +12 -0
  13. xfintech/connect/common/connect.py +49 -0
  14. xfintech/connect/common/connectref.py +119 -0
  15. xfintech/connect/common/error.py +62 -0
  16. xfintech/connect/common/tests/__init__.py +1 -0
  17. xfintech/connect/common/tests/test_class_connectlike_all.py +544 -0
  18. xfintech/connect/common/tests/test_class_connectref_all.py +586 -0
  19. xfintech/connect/common/tests/test_class_errors_all.py +524 -0
  20. xfintech/connect/instance/__init__.py +7 -0
  21. xfintech/connect/instance/macos.py +121 -0
  22. xfintech/connect/instance/s3.py +176 -0
  23. xfintech/connect/instance/tests/__init__.py +1 -0
  24. xfintech/connect/instance/tests/test_class_macosconnect_all.py +692 -0
  25. xfintech/connect/instance/tests/test_class_s3connect_all.py +603 -0
  26. xfintech/data/__init__.py +20 -0
  27. xfintech/data/common/__init__.py +15 -0
  28. xfintech/data/common/cache.py +186 -0
  29. xfintech/data/common/coolant.py +171 -0
  30. xfintech/data/common/metric.py +138 -0
  31. xfintech/data/common/paginate.py +132 -0
  32. xfintech/data/common/params.py +162 -0
  33. xfintech/data/common/retry.py +201 -0
  34. xfintech/data/common/tests/__init__.py +1 -0
  35. xfintech/data/common/tests/test_class_cache_all.py +681 -0
  36. xfintech/data/common/tests/test_class_coolant_all.py +534 -0
  37. xfintech/data/common/tests/test_class_metric_all.py +705 -0
  38. xfintech/data/common/tests/test_class_paginate_all.py +508 -0
  39. xfintech/data/common/tests/test_class_params_all.py +891 -0
  40. xfintech/data/common/tests/test_class_retry_all.py +714 -0
  41. xfintech/data/job/__init__.py +17 -0
  42. xfintech/data/job/errors.py +112 -0
  43. xfintech/data/job/house.py +156 -0
  44. xfintech/data/job/job.py +247 -0
  45. xfintech/data/job/joblike.py +47 -0
  46. xfintech/data/job/tests/__init__.py +1 -0
  47. xfintech/data/job/tests/test_class_errors_all.py +275 -0
  48. xfintech/data/job/tests/test_class_house_all.py +801 -0
  49. xfintech/data/job/tests/test_class_job_all.py +684 -0
  50. xfintech/data/job/tests/test_class_joblike_all.py +482 -0
  51. xfintech/data/relay/__init__.py +7 -0
  52. xfintech/data/relay/client.py +114 -0
  53. xfintech/data/relay/clientlike.py +45 -0
  54. xfintech/data/relay/tests/test_class_relayclient_all.py +484 -0
  55. xfintech/data/relay/tests/test_class_relayclientlike_all.py +500 -0
  56. xfintech/data/source/__init__.py +7 -0
  57. xfintech/data/source/baostock/__init__.py +21 -0
  58. xfintech/data/source/baostock/job/__init__.py +5 -0
  59. xfintech/data/source/baostock/job/job.py +217 -0
  60. xfintech/data/source/baostock/job/tests/__init__.py +0 -0
  61. xfintech/data/source/baostock/job/tests/test_class_baostockjob_all.py +547 -0
  62. xfintech/data/source/baostock/session/__init__.py +8 -0
  63. xfintech/data/source/baostock/session/relay.py +223 -0
  64. xfintech/data/source/baostock/session/session.py +241 -0
  65. xfintech/data/source/baostock/session/tests/__init__.py +0 -0
  66. xfintech/data/source/baostock/session/tests/test_class_relay_all.py +694 -0
  67. xfintech/data/source/baostock/session/tests/test_class_session_all.py +505 -0
  68. xfintech/data/source/baostock/stock/__init__.py +0 -0
  69. xfintech/data/source/baostock/stock/hs300stock/__init__.py +3 -0
  70. xfintech/data/source/baostock/stock/hs300stock/constant.py +49 -0
  71. xfintech/data/source/baostock/stock/hs300stock/hs300stock.py +133 -0
  72. xfintech/data/source/baostock/stock/hs300stock/tests/__init__.py +1 -0
  73. xfintech/data/source/baostock/stock/hs300stock/tests/test_class_hs300index_all.py +413 -0
  74. xfintech/data/source/baostock/stock/minuteline/__init__.py +19 -0
  75. xfintech/data/source/baostock/stock/minuteline/constant.py +89 -0
  76. xfintech/data/source/baostock/stock/minuteline/minuteline.py +163 -0
  77. xfintech/data/source/baostock/stock/minuteline/tests/__init__.py +0 -0
  78. xfintech/data/source/baostock/stock/minuteline/tests/test_class_minuteline_all.py +582 -0
  79. xfintech/data/source/baostock/stock/stock/__init__.py +19 -0
  80. xfintech/data/source/baostock/stock/stock/constant.py +55 -0
  81. xfintech/data/source/baostock/stock/stock/stock.py +149 -0
  82. xfintech/data/source/baostock/stock/stock/tests/__init__.py +0 -0
  83. xfintech/data/source/baostock/stock/stock/tests/test_class_stock_all.py +508 -0
  84. xfintech/data/source/baostock/stock/stockinfo/__init__.py +5 -0
  85. xfintech/data/source/baostock/stock/stockinfo/constant.py +66 -0
  86. xfintech/data/source/baostock/stock/stockinfo/stockinfo.py +176 -0
  87. xfintech/data/source/baostock/stock/stockinfo/tests/__init__.py +1 -0
  88. xfintech/data/source/baostock/stock/stockinfo/tests/test_class_stockinfo_all.py +617 -0
  89. xfintech/data/source/baostock/stock/sz50stock/__init__.py +3 -0
  90. xfintech/data/source/baostock/stock/sz50stock/constant.py +49 -0
  91. xfintech/data/source/baostock/stock/sz50stock/sz50stock.py +133 -0
  92. xfintech/data/source/baostock/stock/sz50stock/tests/__init__.py +1 -0
  93. xfintech/data/source/baostock/stock/sz50stock/tests/test_class_sz50stock_all.py +397 -0
  94. xfintech/data/source/baostock/stock/tradedate/__init__.py +19 -0
  95. xfintech/data/source/baostock/stock/tradedate/constant.py +72 -0
  96. xfintech/data/source/baostock/stock/tradedate/tests/__init__.py +0 -0
  97. xfintech/data/source/baostock/stock/tradedate/tests/test_class_tradedate_all.py +695 -0
  98. xfintech/data/source/baostock/stock/tradedate/tradedate.py +208 -0
  99. xfintech/data/source/baostock/stock/zz500stock/__init__.py +3 -0
  100. xfintech/data/source/baostock/stock/zz500stock/constant.py +55 -0
  101. xfintech/data/source/baostock/stock/zz500stock/tests/__init__.py +1 -0
  102. xfintech/data/source/baostock/stock/zz500stock/tests/test_class_zz500stock_all.py +421 -0
  103. xfintech/data/source/baostock/stock/zz500stock/zz500stock.py +133 -0
  104. xfintech/data/source/tushare/__init__.py +61 -0
  105. xfintech/data/source/tushare/job/__init__.py +5 -0
  106. xfintech/data/source/tushare/job/job.py +257 -0
  107. xfintech/data/source/tushare/job/tests/test_class_tusharejob_all.py +589 -0
  108. xfintech/data/source/tushare/session/__init__.py +5 -0
  109. xfintech/data/source/tushare/session/relay.py +231 -0
  110. xfintech/data/source/tushare/session/session.py +239 -0
  111. xfintech/data/source/tushare/session/tests/test_class_relay_all.py +719 -0
  112. xfintech/data/source/tushare/session/tests/test_class_session_all.py +705 -0
  113. xfintech/data/source/tushare/stock/__init__.py +55 -0
  114. xfintech/data/source/tushare/stock/adjfactor/__init__.py +19 -0
  115. xfintech/data/source/tushare/stock/adjfactor/adjfactor.py +150 -0
  116. xfintech/data/source/tushare/stock/adjfactor/constant.py +71 -0
  117. xfintech/data/source/tushare/stock/adjfactor/tests/__init__.py +0 -0
  118. xfintech/data/source/tushare/stock/adjfactor/tests/test_class_adjfactor_all.py +372 -0
  119. xfintech/data/source/tushare/stock/capflow/__init__.py +19 -0
  120. xfintech/data/source/tushare/stock/capflow/capflow.py +171 -0
  121. xfintech/data/source/tushare/stock/capflow/constant.py +105 -0
  122. xfintech/data/source/tushare/stock/capflow/tests/__init__.py +0 -0
  123. xfintech/data/source/tushare/stock/capflow/tests/test_class_capflow_all.py +589 -0
  124. xfintech/data/source/tushare/stock/capflowdc/__init__.py +19 -0
  125. xfintech/data/source/tushare/stock/capflowdc/capflowdc.py +167 -0
  126. xfintech/data/source/tushare/stock/capflowdc/constant.py +95 -0
  127. xfintech/data/source/tushare/stock/capflowdc/tests/__init__.py +0 -0
  128. xfintech/data/source/tushare/stock/capflowdc/tests/test_class_capflowdc_all.py +814 -0
  129. xfintech/data/source/tushare/stock/capflowths/__init__.py +19 -0
  130. xfintech/data/source/tushare/stock/capflowths/capflowths.py +173 -0
  131. xfintech/data/source/tushare/stock/capflowths/constant.py +92 -0
  132. xfintech/data/source/tushare/stock/capflowths/tests/__init__.py +0 -0
  133. xfintech/data/source/tushare/stock/capflowths/tests/test_class_capflowths_all.py +551 -0
  134. xfintech/data/source/tushare/stock/company/__init__.py +19 -0
  135. xfintech/data/source/tushare/stock/company/company.py +188 -0
  136. xfintech/data/source/tushare/stock/company/constant.py +92 -0
  137. xfintech/data/source/tushare/stock/company/tests/__init__.py +1 -0
  138. xfintech/data/source/tushare/stock/company/tests/test_class_company_all.py +829 -0
  139. xfintech/data/source/tushare/stock/companybusiness/__init__.py +21 -0
  140. xfintech/data/source/tushare/stock/companybusiness/companybusiness.py +183 -0
  141. xfintech/data/source/tushare/stock/companybusiness/constant.py +91 -0
  142. xfintech/data/source/tushare/stock/companybusiness/tests/__init__.py +0 -0
  143. xfintech/data/source/tushare/stock/companybusiness/tests/test_class_companybusiness_all.py +633 -0
  144. xfintech/data/source/tushare/stock/companycashflow/__init__.py +21 -0
  145. xfintech/data/source/tushare/stock/companycashflow/companycashflow.py +277 -0
  146. xfintech/data/source/tushare/stock/companycashflow/constant.py +293 -0
  147. xfintech/data/source/tushare/stock/companycashflow/tests/__init__.py +0 -0
  148. xfintech/data/source/tushare/stock/companycashflow/tests/test_class_companycashflow_all.py +619 -0
  149. xfintech/data/source/tushare/stock/companydebt/__init__.py +19 -0
  150. xfintech/data/source/tushare/stock/companydebt/companydebt.py +339 -0
  151. xfintech/data/source/tushare/stock/companydebt/constant.py +403 -0
  152. xfintech/data/source/tushare/stock/companydebt/tests/__init__.py +0 -0
  153. xfintech/data/source/tushare/stock/companydebt/tests/test_class_companydebt_all.py +655 -0
  154. xfintech/data/source/tushare/stock/companyoverview/__init__.py +21 -0
  155. xfintech/data/source/tushare/stock/companyoverview/companyoverview.py +214 -0
  156. xfintech/data/source/tushare/stock/companyoverview/constant.py +152 -0
  157. xfintech/data/source/tushare/stock/companyoverview/tests/__init__.py +0 -0
  158. xfintech/data/source/tushare/stock/companyoverview/tests/test_class_companyoverview_all.py +647 -0
  159. xfintech/data/source/tushare/stock/companyprofit/__init__.py +21 -0
  160. xfintech/data/source/tushare/stock/companyprofit/companyprofit.py +272 -0
  161. xfintech/data/source/tushare/stock/companyprofit/constant.py +259 -0
  162. xfintech/data/source/tushare/stock/companyprofit/tests/__init__.py +0 -0
  163. xfintech/data/source/tushare/stock/companyprofit/tests/test_class_companyprofit_all.py +635 -0
  164. xfintech/data/source/tushare/stock/conceptcapflowdc/__init__.py +21 -0
  165. xfintech/data/source/tushare/stock/conceptcapflowdc/conceptcapflowdc.py +175 -0
  166. xfintech/data/source/tushare/stock/conceptcapflowdc/constant.py +106 -0
  167. xfintech/data/source/tushare/stock/conceptcapflowdc/tests/__init__.py +0 -0
  168. xfintech/data/source/tushare/stock/conceptcapflowdc/tests/test_class_conceptcapflowdc_all.py +568 -0
  169. xfintech/data/source/tushare/stock/conceptcapflowths/__init__.py +21 -0
  170. xfintech/data/source/tushare/stock/conceptcapflowths/conceptcapflowths.py +188 -0
  171. xfintech/data/source/tushare/stock/conceptcapflowths/constant.py +89 -0
  172. xfintech/data/source/tushare/stock/conceptcapflowths/tests/__init__.py +0 -0
  173. xfintech/data/source/tushare/stock/conceptcapflowths/tests/test_class_conceptcapflowths_all.py +516 -0
  174. xfintech/data/source/tushare/stock/dayline/__init__.py +19 -0
  175. xfintech/data/source/tushare/stock/dayline/constant.py +87 -0
  176. xfintech/data/source/tushare/stock/dayline/dayline.py +177 -0
  177. xfintech/data/source/tushare/stock/dayline/tests/__init__.py +0 -0
  178. xfintech/data/source/tushare/stock/dayline/tests/test_class_dayline_all.py +585 -0
  179. xfintech/data/source/tushare/stock/industrycapflowths/__init__.py +21 -0
  180. xfintech/data/source/tushare/stock/industrycapflowths/constant.py +89 -0
  181. xfintech/data/source/tushare/stock/industrycapflowths/industrycapflowths.py +192 -0
  182. xfintech/data/source/tushare/stock/industrycapflowths/tests/__init__.py +0 -0
  183. xfintech/data/source/tushare/stock/industrycapflowths/tests/test_class_industrycapflowths_all.py +683 -0
  184. xfintech/data/source/tushare/stock/marketindexcapflowdc/__init__.py +21 -0
  185. xfintech/data/source/tushare/stock/marketindexcapflowdc/constant.py +90 -0
  186. xfintech/data/source/tushare/stock/marketindexcapflowdc/marketindexcapflowdc.py +173 -0
  187. xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/__init__.py +0 -0
  188. xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/test_class_marketindexcapflowdc_all.py +793 -0
  189. xfintech/data/source/tushare/stock/monthline/__init__.py +19 -0
  190. xfintech/data/source/tushare/stock/monthline/constant.py +87 -0
  191. xfintech/data/source/tushare/stock/monthline/monthline.py +180 -0
  192. xfintech/data/source/tushare/stock/monthline/tests/__init__.py +0 -0
  193. xfintech/data/source/tushare/stock/monthline/tests/test_class_monthline_all.py +574 -0
  194. xfintech/data/source/tushare/stock/stock/__init__.py +19 -0
  195. xfintech/data/source/tushare/stock/stock/constant.py +105 -0
  196. xfintech/data/source/tushare/stock/stock/stock.py +193 -0
  197. xfintech/data/source/tushare/stock/stock/tests/__init__.py +0 -0
  198. xfintech/data/source/tushare/stock/stock/tests/test_class_stock_all.py +788 -0
  199. xfintech/data/source/tushare/stock/stockdividend/__init__.py +21 -0
  200. xfintech/data/source/tushare/stock/stockdividend/constant.py +111 -0
  201. xfintech/data/source/tushare/stock/stockdividend/stockdividend.py +180 -0
  202. xfintech/data/source/tushare/stock/stockdividend/tests/__init__.py +0 -0
  203. xfintech/data/source/tushare/stock/stockdividend/tests/test_class_stockdividend_all.py +725 -0
  204. xfintech/data/source/tushare/stock/stockinfo/__init__.py +19 -0
  205. xfintech/data/source/tushare/stock/stockinfo/constant.py +104 -0
  206. xfintech/data/source/tushare/stock/stockinfo/stockinfo.py +208 -0
  207. xfintech/data/source/tushare/stock/stockinfo/tests/__init__.py +0 -0
  208. xfintech/data/source/tushare/stock/stockinfo/tests/test_class_stockinfo_all.py +881 -0
  209. xfintech/data/source/tushare/stock/stockipo/__init__.py +19 -0
  210. xfintech/data/source/tushare/stock/stockipo/constant.py +90 -0
  211. xfintech/data/source/tushare/stock/stockipo/stockipo.py +234 -0
  212. xfintech/data/source/tushare/stock/stockipo/tests/__init__.py +1 -0
  213. xfintech/data/source/tushare/stock/stockipo/tests/test_class_stockipo_all.py +750 -0
  214. xfintech/data/source/tushare/stock/stockpledge/__init__.py +19 -0
  215. xfintech/data/source/tushare/stock/stockpledge/constant.py +72 -0
  216. xfintech/data/source/tushare/stock/stockpledge/stockpledge.py +158 -0
  217. xfintech/data/source/tushare/stock/stockpledge/tests/__init__.py +0 -0
  218. xfintech/data/source/tushare/stock/stockpledge/tests/test_class_stockpledge_all.py +664 -0
  219. xfintech/data/source/tushare/stock/stockpledgedetail/__init__.py +21 -0
  220. xfintech/data/source/tushare/stock/stockpledgedetail/constant.py +85 -0
  221. xfintech/data/source/tushare/stock/stockpledgedetail/stockpledgedetail.py +171 -0
  222. xfintech/data/source/tushare/stock/stockpledgedetail/tests/__init__.py +0 -0
  223. xfintech/data/source/tushare/stock/stockpledgedetail/tests/test_class_stockpledgedetail_all.py +112 -0
  224. xfintech/data/source/tushare/stock/stockst/__init__.py +19 -0
  225. xfintech/data/source/tushare/stock/stockst/constant.py +80 -0
  226. xfintech/data/source/tushare/stock/stockst/stockst.py +189 -0
  227. xfintech/data/source/tushare/stock/stockst/tests/__init__.py +0 -0
  228. xfintech/data/source/tushare/stock/stockst/tests/test_class_stockst_all.py +693 -0
  229. xfintech/data/source/tushare/stock/stocksuspend/__init__.py +21 -0
  230. xfintech/data/source/tushare/stock/stocksuspend/constant.py +75 -0
  231. xfintech/data/source/tushare/stock/stocksuspend/stocksuspend.py +151 -0
  232. xfintech/data/source/tushare/stock/stocksuspend/tests/__init__.py +0 -0
  233. xfintech/data/source/tushare/stock/stocksuspend/tests/test_class_stocksuspend_all.py +626 -0
  234. xfintech/data/source/tushare/stock/techindex/__init__.py +19 -0
  235. xfintech/data/source/tushare/stock/techindex/constant.py +600 -0
  236. xfintech/data/source/tushare/stock/techindex/techindex.py +314 -0
  237. xfintech/data/source/tushare/stock/techindex/tests/__init__.py +0 -0
  238. xfintech/data/source/tushare/stock/techindex/tests/test_class_techindex_all.py +576 -0
  239. xfintech/data/source/tushare/stock/tradedate/__init__.py +19 -0
  240. xfintech/data/source/tushare/stock/tradedate/constant.py +93 -0
  241. xfintech/data/source/tushare/stock/tradedate/tests/__init__.py +0 -0
  242. xfintech/data/source/tushare/stock/tradedate/tests/test_class_tradedate_all.py +947 -0
  243. xfintech/data/source/tushare/stock/tradedate/tradedate.py +234 -0
  244. xfintech/data/source/tushare/stock/weekline/__init__.py +19 -0
  245. xfintech/data/source/tushare/stock/weekline/constant.py +87 -0
  246. xfintech/data/source/tushare/stock/weekline/tests/__init__.py +0 -0
  247. xfintech/data/source/tushare/stock/weekline/tests/test_class_weekline_all.py +575 -0
  248. xfintech/data/source/tushare/stock/weekline/weekline.py +182 -0
  249. xfintech/fabric/__init__.py +18 -0
  250. xfintech/fabric/column/__init__.py +7 -0
  251. xfintech/fabric/column/info.py +202 -0
  252. xfintech/fabric/column/kind.py +102 -0
  253. xfintech/fabric/column/tests/__init__.py +0 -0
  254. xfintech/fabric/column/tests/test_class_info_all.py +207 -0
  255. xfintech/fabric/column/tests/test_class_kind_all.py +80 -0
  256. xfintech/fabric/table/__init__.py +5 -0
  257. xfintech/fabric/table/info.py +263 -0
  258. xfintech/fabric/table/tests/__init__.py +0 -0
  259. xfintech/fabric/table/tests/test_class_info_all.py +547 -0
  260. xfintech/serde/__init__.py +35 -0
  261. xfintech/serde/common/__init__.py +9 -0
  262. xfintech/serde/common/dataformat.py +78 -0
  263. xfintech/serde/common/deserialiserlike.py +38 -0
  264. xfintech/serde/common/error.py +182 -0
  265. xfintech/serde/common/serialiserlike.py +38 -0
  266. xfintech/serde/common/tests/__init__.py +1 -0
  267. xfintech/serde/common/tests/test_class_dataformat_all.py +694 -0
  268. xfintech/serde/common/tests/test_class_deserialiserlike_all.py +500 -0
  269. xfintech/serde/common/tests/test_class_errors_all.py +518 -0
  270. xfintech/serde/common/tests/test_class_serialiserlike_all.py +401 -0
  271. xfintech/serde/deserialiser/__init__.py +7 -0
  272. xfintech/serde/deserialiser/pandas.py +113 -0
  273. xfintech/serde/deserialiser/python.py +68 -0
  274. xfintech/serde/deserialiser/tests/__init__.py +1 -0
  275. xfintech/serde/deserialiser/tests/test_class_pandasdeserialiser_all.py +503 -0
  276. xfintech/serde/deserialiser/tests/test_class_pythondeserialiser_all.py +570 -0
  277. xfintech/serde/serialiser/__init__.py +7 -0
  278. xfintech/serde/serialiser/pandas.py +116 -0
  279. xfintech/serde/serialiser/python.py +71 -0
  280. xfintech/serde/serialiser/tests/__init__.py +1 -0
  281. xfintech/serde/serialiser/tests/test_class_pandasserialiser_all.py +474 -0
  282. xfintech/serde/serialiser/tests/test_class_pythonserialiser_all.py +508 -0
@@ -0,0 +1,231 @@
1
+ from __future__ import annotations
2
+
3
+ import gzip
4
+ import hashlib
5
+ import hmac
6
+ import io
7
+ import secrets
8
+ import time
9
+ from typing import Any, Callable, Dict, Optional
10
+
11
+ import pandas as pd
12
+ import requests
13
+
14
+ from xfintech.data.relay.client import RelayClient
15
+
16
+
17
+ class TushareRelayClient(RelayClient):
18
+ """
19
+ 描述:
20
+ - Tushare 中继服务客户端类,用于通过中继服务器访问 Tushare 数据。
21
+ - 实现 HMAC-SHA256 签名认证机制,确保请求安全性。
22
+ - 支持数据压缩和 Parquet 格式传输,提高数据传输效率。
23
+ - 提供健康检查功能,确保服务可用性。
24
+
25
+ 属性:
26
+ - url: str, 中继服务器 URL 地址。
27
+ - secret: str, 用于 HMAC 签名的密钥。
28
+ - timeout: int, 请求超时时间(秒),默认 180 秒。
29
+ - DEFAULT_TIMEOUT: int = 180, 默认超时时间常量。
30
+
31
+ 方法:
32
+ - call(method, limit, offset, params): 调用 Tushare API 方法并返回 DataFrame。
33
+ - check_health(): 检查中继服务器健康状态。
34
+ - canonical_json(value): 生成规范化的 JSON 字节串用于签名。
35
+
36
+ 例子:
37
+ ```python
38
+ from xfintech.data.source.tushare.session import TushareRelayClient
39
+
40
+ # 创建中继客户端
41
+ client = TushareRelayClient(
42
+ url="https://relay.example.com",
43
+ secret="your-secret-key",
44
+ timeout=120
45
+ )
46
+
47
+ # 调用 API 获取数据
48
+ df = client.call(
49
+ method="daily",
50
+ limit=100,
51
+ offset=0,
52
+ params={"ts_code": "000001.SZ", "start_date": "20240101"}
53
+ )
54
+ print(df.head())
55
+ ```
56
+ """
57
+
58
+ def __init__(
59
+ self,
60
+ url: str,
61
+ secret: str,
62
+ timeout: Optional[int] = None,
63
+ ) -> None:
64
+ super().__init__(
65
+ url=url,
66
+ secret=secret,
67
+ timeout=timeout,
68
+ )
69
+
70
+ def call(
71
+ self,
72
+ method: str,
73
+ limit: int | None,
74
+ offset: int | None,
75
+ params: Dict[str, Any],
76
+ ) -> pd.DataFrame:
77
+ payload: Dict[str, Any] = {
78
+ "path": f"{method}",
79
+ "params": params,
80
+ "limit": limit,
81
+ "offset": offset,
82
+ }
83
+ body = self.canonical_json(payload)
84
+ nonce = secrets.token_hex(16)
85
+ timestamp = str(int(time.time()))
86
+ msg = f"{nonce}.{timestamp}.".encode("utf-8") + body
87
+ sig = hmac.new(
88
+ self.secret.encode("utf-8"),
89
+ msg,
90
+ hashlib.sha256,
91
+ ).hexdigest()
92
+ url = f"{self.url}/v2/tushare/call"
93
+ response = requests.post(
94
+ url,
95
+ data=body,
96
+ headers={
97
+ "Content-Type": "application/json",
98
+ "X-YNONCE": nonce,
99
+ "X-YTS": timestamp,
100
+ "X-YSIGN": sig,
101
+ "X-Format": "parquet",
102
+ "X-Compression": "zstd+gzip",
103
+ },
104
+ timeout=self.timeout,
105
+ )
106
+ response.raise_for_status()
107
+ parquet_bytes = gzip.decompress(response.content)
108
+ return pd.read_parquet(io.BytesIO(parquet_bytes))
109
+
110
+ def refresh(
111
+ self,
112
+ ) -> bool:
113
+ try:
114
+ payload: Dict[str, Any] = {}
115
+ body = self.canonical_json(payload)
116
+ nonce = secrets.token_hex(16)
117
+ timestamp = str(int(time.time()))
118
+ msg = f"{nonce}.{timestamp}.".encode("utf-8") + body
119
+ sig = hmac.new(
120
+ self.secret.encode("utf-8"),
121
+ msg,
122
+ hashlib.sha256,
123
+ ).hexdigest()
124
+ url = f"{self.url}/v2/tushare/refresh"
125
+ response = requests.post(
126
+ url,
127
+ data=body,
128
+ headers={
129
+ "Content-Type": "application/json",
130
+ "X-YNONCE": nonce,
131
+ "X-YTS": timestamp,
132
+ "X-YSIGN": sig,
133
+ },
134
+ timeout=self.timeout,
135
+ )
136
+ response.raise_for_status()
137
+ data = response.json()
138
+ if data.get("status") != "ok":
139
+ msg = f"Refresh returned non-ok status: {data}"
140
+ raise RuntimeError(msg)
141
+ return True
142
+ except Exception as e:
143
+ msg = f"Tushare refresh failed: {e}"
144
+ raise RuntimeError(msg) from e
145
+
146
+ def check_health(
147
+ self,
148
+ ) -> bool:
149
+ try:
150
+ url = f"{self.url}/health"
151
+ response = requests.get(
152
+ url,
153
+ timeout=self.timeout,
154
+ )
155
+ response.raise_for_status()
156
+ data = response.json()
157
+ health = data.get("status") == "ok"
158
+ if not health:
159
+ raise RuntimeError("Health check returned non-ok status.")
160
+ return True
161
+ except Exception as e:
162
+ raise RuntimeError(f"Health check failed: {e}") from e
163
+
164
+
165
+ class RelayConnection:
166
+ """
167
+ 描述:
168
+ - Tushare 中继连接类,提供动态方法调用接口。
169
+ - 通过魔术方法 __getattr__ 实现类似 Tushare Pro API 的调用方式。
170
+ - 自动将方法调用转发到 TushareRelayClient 进行处理。
171
+
172
+ 属性:
173
+ - client: TushareRelayClient, 中继客户端实例。
174
+
175
+ 方法:
176
+ - 动态方法: 通过属性访问自动创建对应的 API 调用方法。
177
+
178
+ 例子:
179
+ ```python
180
+ from xfintech.data.source.tushare.session import TushareRelayClient, RelayConnection
181
+
182
+ # 创建客户端和连接
183
+ client = TushareRelayClient(
184
+ url="https://relay.example.com",
185
+ secret="your-secret-key"
186
+ )
187
+ connection = RelayConnection(client=client)
188
+
189
+ # 使用类似 Tushare Pro API 的方式调用
190
+ # 等同于 pro.daily() 的调用方式
191
+ df = connection.daily(
192
+ ts_code="000001.SZ",
193
+ start_date="20240101",
194
+ end_date="20240131",
195
+ limit=100,
196
+ offset=0
197
+ )
198
+ print(df.head())
199
+
200
+ # 调用其他方法
201
+ df_basic = connection.stock_basic(
202
+ exchange="SSE",
203
+ list_status="L"
204
+ )
205
+ ```
206
+ """
207
+
208
+ def __init__(
209
+ self,
210
+ client: TushareRelayClient,
211
+ ) -> None:
212
+ self.client = client
213
+
214
+ def __getattr__(
215
+ self,
216
+ method: str,
217
+ ) -> Callable[..., pd.DataFrame]:
218
+ def _call(
219
+ *,
220
+ limit: int | None = None,
221
+ offset: int | None = None,
222
+ **params: Any,
223
+ ) -> pd.DataFrame:
224
+ return self.client.call(
225
+ method=method,
226
+ limit=limit,
227
+ offset=offset,
228
+ params=params,
229
+ )
230
+
231
+ return _call
@@ -0,0 +1,239 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Literal, Optional
6
+
7
+ import pandas as pd
8
+ import tushare as ts
9
+
10
+ from xfintech.data.source.tushare.session.relay import (
11
+ RelayConnection,
12
+ TushareRelayClient,
13
+ )
14
+
15
+
16
+ class Session:
17
+ """
18
+ 描述:
19
+ - Tushare 数据源会话管理类,支持直接连接和通过中继服务器连接两种模式。
20
+ - 提供连接管理、状态跟踪和描述功能。
21
+ - 支持会话持续时间跟踪,记录连接开始和结束时间。
22
+
23
+ 属性:
24
+ - id: str, 会话唯一标识符(UUID 前 8 位)。
25
+ - mode: str, 连接模式,"direct" 或 "relay"。
26
+ - connection: object, Tushare 连接对象(pro_api 或 RelayConnection)。
27
+ - start_at: pd.Timestamp, 会话开始时间。
28
+ - finish_at: pd.Timestamp, 会话结束时间。
29
+ - relay_url: str | None, 中继服务器 URL(relay 模式下必填)。
30
+ - relay_secret: str | None, 中继服务器密钥(relay 模式下必填)。
31
+
32
+ 方法:
33
+ - connect(): 建立连接,根据模式创建 direct 或 relay 连接。
34
+ - disconnect(): 断开连接并记录结束时间。
35
+ - start(): 记录会话开始时间。
36
+ - end(): 记录会话结束时间。
37
+ - get_start_iso(): 返回 ISO 格式的开始时间。
38
+ - get_finish_iso(): 返回 ISO 格式的结束时间。
39
+ - describe(): 返回会话描述信息(敏感信息已脱敏)。
40
+ - to_dict(): 返回会话的完整字典表示。
41
+
42
+ 属性 (Property):
43
+ - duration: float, 会话持续时间(秒)。
44
+ - connected: bool, 是否已连接。
45
+
46
+ 例子:
47
+ ```python
48
+ from xfintech.data.source.tushare.session import Session
49
+
50
+ # 直接连接模式
51
+ session = Session(
52
+ credential="your-tushare-token",
53
+ mode="direct"
54
+ )
55
+ print(f"会话 ID: {session.id}")
56
+ print(f"连接状态: {session.connected}")
57
+
58
+ # 使用 Tushare API
59
+ df = session.connection.daily(ts_code="000001.SZ", start_date="20240101")
60
+
61
+ # 查看会话信息
62
+ print(session.describe())
63
+ print(f"会话持续时间: {session.duration} 秒")
64
+
65
+ # 关闭连接
66
+ session.disconnect()
67
+
68
+ # 中继连接模式
69
+ relay_session = Session(
70
+ credential="your-tushare-token",
71
+ mode="relay",
72
+ relay_url="https://relay.example.com",
73
+ relay_secret="your-relay-secret"
74
+ )
75
+ df = relay_session.connection.daily(ts_code="000001.SZ")
76
+ ```
77
+ """
78
+
79
+ def __init__(
80
+ self,
81
+ credential: Optional[str] = None,
82
+ mode: Literal["direct", "relay"] = "direct",
83
+ relay_url: str | None = None,
84
+ relay_secret: str | None = None,
85
+ ) -> None:
86
+ self._credential = credential
87
+ self.id = str(uuid.uuid4())[:8]
88
+ self.connection = None
89
+ self.start_at = None
90
+ self.finish_at = None
91
+ self.mode = self._resolve_mode(mode)
92
+ self.relay_url = self._resolve_relay_url(
93
+ relay_url,
94
+ self.mode,
95
+ )
96
+ self.relay_secret = self._resolve_relay_secret(
97
+ relay_secret,
98
+ self.mode,
99
+ )
100
+ self.connect()
101
+
102
+ def _resolve_mode(
103
+ self,
104
+ mode: Literal["direct", "relay"],
105
+ ) -> str:
106
+ mode = mode.lower()
107
+ if not mode:
108
+ return "direct"
109
+ if mode not in ["direct", "relay"]:
110
+ msg = f"Unsupported mode: {mode}"
111
+ raise ValueError(msg)
112
+ return mode
113
+
114
+ def _resolve_relay_url(
115
+ self,
116
+ url: str | None,
117
+ mode: str,
118
+ ) -> str | None:
119
+ if mode == "relay":
120
+ if not url:
121
+ msg = "URL must be provided in relay mode."
122
+ raise ValueError(msg)
123
+ return url
124
+ else:
125
+ return None
126
+
127
+ def _resolve_relay_secret(
128
+ self,
129
+ secret: str | None,
130
+ mode: str,
131
+ ) -> str | None:
132
+ if mode == "relay":
133
+ if not secret:
134
+ msg = "Secret must be provided in relay mode."
135
+ raise ValueError(msg)
136
+ return secret
137
+ else:
138
+ return None
139
+
140
+ @property
141
+ def duration(self) -> float:
142
+ if not self.start_at:
143
+ return 0.0
144
+ if not self.finish_at:
145
+ now = datetime.now()
146
+ delta = now - self.start_at
147
+ return delta.total_seconds()
148
+ delta = self.finish_at - self.start_at
149
+ return delta.total_seconds()
150
+
151
+ @property
152
+ def connected(self) -> bool:
153
+ return self.connection is not None
154
+
155
+ def __str__(self) -> str:
156
+ return f"{self.id}"
157
+
158
+ def __repr__(self) -> str:
159
+ return f"{self.__class__.__name__}(connected={self.connected}, mode={self.mode})"
160
+
161
+ def start(self) -> None:
162
+ self.start_at = pd.Timestamp.now()
163
+
164
+ def get_start_iso(self) -> Optional[str]:
165
+ if self.start_at is None:
166
+ return None
167
+ return self.start_at.isoformat()
168
+
169
+ def end(self) -> None:
170
+ self.finish_at = pd.Timestamp.now()
171
+
172
+ def get_finish_iso(self) -> Optional[str]:
173
+ if self.finish_at is None:
174
+ return None
175
+ return self.finish_at.isoformat()
176
+
177
+ def connect(self) -> object:
178
+ if self.connected:
179
+ return self.connection
180
+ if self.mode == "direct":
181
+ ts.set_token(self._credential)
182
+ self.connection = ts.pro_api()
183
+ else:
184
+ client = TushareRelayClient(
185
+ url=self.relay_url,
186
+ secret=self.relay_secret,
187
+ )
188
+ client.check_health()
189
+ self.connection = RelayConnection(
190
+ client=client,
191
+ )
192
+ self.start()
193
+ return self.connection
194
+
195
+ def disconnect(self) -> None:
196
+ self.connection = None
197
+ self.end()
198
+
199
+ def refresh(self) -> None:
200
+ if self.mode == "relay" and self.connected:
201
+ self.connection.client.refresh()
202
+ else:
203
+ self.disconnect()
204
+ self.connect()
205
+
206
+ def describe(self) -> Dict[str, Any]:
207
+ start_at_iso = self.get_start_iso()
208
+ finish_at_iso = self.get_finish_iso()
209
+ result = {}
210
+ result["id"] = self.id
211
+ result["mode"] = self.mode
212
+ if self._credential:
213
+ result["credential"] = "******"
214
+ if self.mode == "relay":
215
+ result["relay"] = {
216
+ "url": self.relay_url,
217
+ "secret": "******",
218
+ }
219
+ result["connected"] = self.connected
220
+ if start_at_iso:
221
+ result["start_at"] = start_at_iso
222
+ if finish_at_iso:
223
+ result["finish_at"] = finish_at_iso
224
+ return result
225
+
226
+ def to_dict(self) -> Dict[str, Any]:
227
+ return {
228
+ "id": self.id,
229
+ "connected": self.connected,
230
+ "credential": "******" if self._credential else None,
231
+ "mode": self.mode,
232
+ "relay": {
233
+ "url": self.relay_url,
234
+ "secret": "******" if self.relay_secret else None,
235
+ },
236
+ "start_at": self.get_start_iso(),
237
+ "finish_at": self.get_finish_iso(),
238
+ "duration": self.duration,
239
+ }