lixinger-python 0.3.12__tar.gz → 0.3.14__tar.gz

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 (497) hide show
  1. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.claude/settings.local.json +6 -1
  2. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/CHANGELOG.md +38 -1
  3. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/PKG-INFO +1 -1
  4. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/base.py +68 -5
  5. lixinger_python-0.3.14/lixinger/exceptions.py +38 -0
  6. lixinger_python-0.3.14/lixinger/utils/retry.py +63 -0
  7. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/pyproject.toml +1 -1
  8. lixinger_python-0.3.14/tests/test_no_data.py +126 -0
  9. lixinger_python-0.3.14/tests/test_retry.py +349 -0
  10. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/uv.lock +1 -1
  11. lixinger_python-0.3.12/lixinger/exceptions.py +0 -22
  12. lixinger_python-0.3.12/lixinger/utils/retry.py +0 -31
  13. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.env.example +0 -0
  14. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.github/copilot-instructions.md +0 -0
  15. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.github/workflows/README.md +0 -0
  16. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.github/workflows/pr-checks.yml +0 -0
  17. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.gitignore +0 -0
  18. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.pre-commit-config.yaml +0 -0
  19. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.python-version +0 -0
  20. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/.ruff.toml +0 -0
  21. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/ADD_NEW_API_QUICK.md +0 -0
  22. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/ARCHITECTURE.md +0 -0
  23. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/CLAUDE.md +0 -0
  24. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/DOCUMENTATION.md +0 -0
  25. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/LICENSE +0 -0
  26. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/MANIFEST.in +0 -0
  27. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/PUBLISHING.md +0 -0
  28. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/README.md +0 -0
  29. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/codecov.yml +0 -0
  30. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/client.md +0 -0
  31. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/announcement.md +0 -0
  32. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/candlestick.md +0 -0
  33. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/company.md +0 -0
  34. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/dividend.md +0 -0
  35. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/equity_change.md +0 -0
  36. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/fs/non_financial.md +0 -0
  37. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/fundamental/bank.md +0 -0
  38. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/fundamental/insurance.md +0 -0
  39. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/fundamental/non_financial.md +0 -0
  40. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/fundamental/other_financial.md +0 -0
  41. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/fundamental/security.md +0 -0
  42. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/indices.md +0 -0
  43. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/company/profile.md +0 -0
  44. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/fund/announcement.md +0 -0
  45. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/fund/asset_combination.md +0 -0
  46. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/fund/asset_industry_combination.md +0 -0
  47. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/fund/candlestick.md +0 -0
  48. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/fund/fund.md +0 -0
  49. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/fund/profile.md +0 -0
  50. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/fund/shareholdings.md +0 -0
  51. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/index/candlestick.md +0 -0
  52. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/index/constituent_weightings.md +0 -0
  53. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/index/constituents.md +0 -0
  54. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/index/drawdown.md +0 -0
  55. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/index/fundamental.md +0 -0
  56. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/index/index.md +0 -0
  57. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/index/tracking_fund.md +0 -0
  58. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/api/overview.md +0 -0
  59. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/development/code-style.md +0 -0
  60. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/development/contributing.md +0 -0
  61. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/development/testing.md +0 -0
  62. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/examples/company.md +0 -0
  63. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/examples/fund.md +0 -0
  64. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/examples/index.md +0 -0
  65. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/getting-started/configuration.md +0 -0
  66. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/getting-started/installation.md +0 -0
  67. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/getting-started/quickstart.md +0 -0
  68. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/docs/index.md +0 -0
  69. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/examples/company_example.py +0 -0
  70. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/examples/company_profile_example.py +0 -0
  71. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/examples/dividend_example.py +0 -0
  72. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/examples/fs_example.py +0 -0
  73. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/examples/index_constituent_weightings_example.py +0 -0
  74. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/examples/index_constituents_example.py +0 -0
  75. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/examples/index_info_example.py +0 -0
  76. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/examples/index_margin_trading_example.py +0 -0
  77. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/__init__.py +0 -0
  78. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/__init__.py +0 -0
  79. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/__init__.py +0 -0
  80. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/__init__.py +0 -0
  81. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/announcement.py +0 -0
  82. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/candlestick.py +0 -0
  83. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/company.py +0 -0
  84. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/dividend.py +0 -0
  85. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/equity_change.py +0 -0
  86. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/__init__.py +0 -0
  87. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/bank.py +0 -0
  88. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/insurance.py +0 -0
  89. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/non_financial.py +0 -0
  90. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/other_financial.py +0 -0
  91. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/security.py +0 -0
  92. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/__init__.py +0 -0
  93. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/bank.py +0 -0
  94. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/insurance.py +0 -0
  95. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/non_financial.py +0 -0
  96. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/other_financial.py +0 -0
  97. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/security.py +0 -0
  98. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/indices.py +0 -0
  99. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/namespace.py +0 -0
  100. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/company/profile.py +0 -0
  101. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/fund/__init__.py +0 -0
  102. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/fund/announcement.py +0 -0
  103. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/fund/asset_combination.py +0 -0
  104. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/fund/asset_industry_combination.py +0 -0
  105. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/fund/candlestick.py +0 -0
  106. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/fund/fund.py +0 -0
  107. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/fund/profile.py +0 -0
  108. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/fund/shareholdings.py +0 -0
  109. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/__init__.py +0 -0
  110. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/candlestick.py +0 -0
  111. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/constituent_weightings.py +0 -0
  112. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/constituents.py +0 -0
  113. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/drawdown.py +0 -0
  114. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/__init__.py +0 -0
  115. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/bank.py +0 -0
  116. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/hybrid.py +0 -0
  117. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/non_financial.py +0 -0
  118. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/security.py +0 -0
  119. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/fundamental.py +0 -0
  120. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/index.py +0 -0
  121. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/margin_trading.py +0 -0
  122. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/namespace.py +0 -0
  123. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/index/tracking_fund.py +0 -0
  124. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/industry/__init__.py +0 -0
  125. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/__init__.py +0 -0
  126. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/cni.py +0 -0
  127. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/sw.py +0 -0
  128. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/sw_2021.py +0 -0
  129. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/cn/industry/namespace.py +0 -0
  130. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/macro/__init__.py +0 -0
  131. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/macro/namespace.py +0 -0
  132. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/macro/national_debt.py +0 -0
  133. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/macro/rmb_deposits.py +0 -0
  134. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/macro/rmb_loans.py +0 -0
  135. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/api/macro/social_financing.py +0 -0
  136. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/client.py +0 -0
  137. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/config.py +0 -0
  138. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/__init__.py +0 -0
  139. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/__init__.py +0 -0
  140. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/__init__.py +0 -0
  141. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/announcement.py +0 -0
  142. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/candlestick.py +0 -0
  143. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/company.py +0 -0
  144. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/dividend.py +0 -0
  145. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/equity_change.py +0 -0
  146. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/__init__.py +0 -0
  147. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/bank.py +0 -0
  148. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/insurance.py +0 -0
  149. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/non_financial.py +0 -0
  150. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/other_financial.py +0 -0
  151. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/security.py +0 -0
  152. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/__init__.py +0 -0
  153. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/bank.py +0 -0
  154. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/insurance.py +0 -0
  155. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/non_financial.py +0 -0
  156. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/other_financial.py +0 -0
  157. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/security.py +0 -0
  158. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/company/indices.py +0 -0
  159. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/fund/__init__.py +0 -0
  160. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/fund/announcement.py +0 -0
  161. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/fund/asset_combination.py +0 -0
  162. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/fund/asset_industry_combination.py +0 -0
  163. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/fund/candlestick.py +0 -0
  164. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/fund/fund.py +0 -0
  165. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/fund/profile.py +0 -0
  166. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/fund/shareholdings.py +0 -0
  167. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/__init__.py +0 -0
  168. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/candlestick.py +0 -0
  169. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/constituent_weightings.py +0 -0
  170. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/constituents.py +0 -0
  171. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/drawdown.py +0 -0
  172. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/__init__.py +0 -0
  173. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/bank.py +0 -0
  174. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/hybrid.py +0 -0
  175. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/non_financial.py +0 -0
  176. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/security.py +0 -0
  177. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/fundamental.py +0 -0
  178. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/index.py +0 -0
  179. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/margin_trading.py +0 -0
  180. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/index/tracking_fund.py +0 -0
  181. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/industry/__init__.py +0 -0
  182. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/__init__.py +0 -0
  183. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/cni.py +0 -0
  184. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/sw.py +0 -0
  185. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/sw_2021.py +0 -0
  186. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/macro/__init__.py +0 -0
  187. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/macro/national_debt.py +0 -0
  188. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/macro/rmb_deposits.py +0 -0
  189. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/macro/rmb_loans.py +0 -0
  190. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/models/macro/social_financing.py +0 -0
  191. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/py.typed +0 -0
  192. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/utils/__init__.py +0 -0
  193. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/utils/api.py +0 -0
  194. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/utils/dataframe.py +0 -0
  195. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/utils/dict.py +0 -0
  196. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger/utils/rate_limiter.py +0 -0
  197. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/REMINDER.md +0 -0
  198. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/allotment.md +0 -0
  199. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/announcement.md +0 -0
  200. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/block-deal.md +0 -0
  201. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/candlestick.md +0 -0
  202. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/customers.md +0 -0
  203. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/dividend.md +0 -0
  204. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/equity-change.md +0 -0
  205. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/bank.md +0 -0
  206. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/insurance.md +0 -0
  207. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/non_financial.md +0 -0
  208. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/other_financial.md +0 -0
  209. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/security.md +0 -0
  210. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fund-collection-shareholders.md +0 -0
  211. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fund-shareholders.md +0 -0
  212. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/bank.md +0 -0
  213. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/insurance.md +0 -0
  214. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/non_financial.md +0 -0
  215. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/other_financial.md +0 -0
  216. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/security.md +0 -0
  217. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/capita.md +0 -0
  218. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/df.md +0 -0
  219. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/elr.md +0 -0
  220. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/esc.md +0 -0
  221. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mm_ha.md +0 -0
  222. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mssc.md +0 -0
  223. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mtasl.md +0 -0
  224. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/npd.md +0 -0
  225. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/ple.md +0 -0
  226. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/shnc.md +0 -0
  227. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/t_a.md +0 -0
  228. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/tr.md +0 -0
  229. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/tr_dri.md +0 -0
  230. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/indices.md +0 -0
  231. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/industries.md +0 -0
  232. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/inquiry.md +0 -0
  233. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/major-shareholders-shares-change.md +0 -0
  234. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/majority-shareholders.md +0 -0
  235. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/margin-trading-and-securities-lending.md +0 -0
  236. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/measures.md +0 -0
  237. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/mutual-market.md +0 -0
  238. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/nolimit-shareholders.md +0 -0
  239. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/operating-data.md +0 -0
  240. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/operation-revenue-constitution.md +0 -0
  241. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/pledge.md +0 -0
  242. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/profile.md +0 -0
  243. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/senior-executive-shares-change.md +0 -0
  244. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/shareholders-num.md +0 -0
  245. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/suppliers.md +0 -0
  246. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/trading-abnormal.md +0 -0
  247. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company/volatility.md +0 -0
  248. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/company.md +0 -0
  249. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/announcement.md +0 -0
  250. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/asset-combination.md +0 -0
  251. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/asset-industry-combination.md +0 -0
  252. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/candlestick.md +0 -0
  253. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/dividend.md +0 -0
  254. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/drawdown.md +0 -0
  255. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/fees.md +0 -0
  256. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/f_as.md +0 -0
  257. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/f_nlacan.md +0 -0
  258. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fet_s.md +0 -0
  259. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/ff.md +0 -0
  260. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fp.md +0 -0
  261. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fpr.md +0 -0
  262. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fss.md +0 -0
  263. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/manager.md +0 -0
  264. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/net-value-of-dividend-reinvestment.md +0 -0
  265. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/net-value.md +0 -0
  266. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/profile.md +0 -0
  267. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shareholders-structure.md +0 -0
  268. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shareholdings.md +0 -0
  269. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shares.md +0 -0
  270. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/split.md +0 -0
  271. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/total-net-value.md +0 -0
  272. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/turnover-rate.md +0 -0
  273. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund/volatility.md +0 -0
  274. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/asset-scale.md +0 -0
  275. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/fund-list.md +0 -0
  276. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/fund-manager-list.md +0 -0
  277. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/hot/fc_as.md +0 -0
  278. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/hot/fc_asr.md +0 -0
  279. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/shareholdings.md +0 -0
  280. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company.md +0 -0
  281. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/hot/fmi.md +0 -0
  282. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/hot/fmp.md +0 -0
  283. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/management-funds.md +0 -0
  284. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/profit-ratio.md +0 -0
  285. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/shareholdings.md +0 -0
  286. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager.md +0 -0
  287. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/fund.md +0 -0
  288. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/candlestick.md +0 -0
  289. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/constituent-weightings.md +0 -0
  290. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/constituents.md +0 -0
  291. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/drawdown.md +0 -0
  292. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/bank.md +0 -0
  293. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/hybrid.md +0 -0
  294. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/non_financial.md +0 -0
  295. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/security.md +0 -0
  296. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/fundamental.md +0 -0
  297. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/cp.md +0 -0
  298. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/ic.md +0 -0
  299. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/ifet_sni.md +0 -0
  300. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/mm_ha.md +0 -0
  301. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/mtasl.md +0 -0
  302. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/tr.md +0 -0
  303. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/tr_cp.md +0 -0
  304. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/margin-trading-and-securities-lending.md +0 -0
  305. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/mutual-market.md +0 -0
  306. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/tracking-fund.md +0 -0
  307. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index/volatility.md +0 -0
  308. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/index.md +0 -0
  309. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/cni.md +0 -0
  310. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/sw.md +0 -0
  311. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/sw_2021.md +0 -0
  312. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/bank.md +0 -0
  313. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/hybrid.md +0 -0
  314. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/insurance.md +0 -0
  315. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/non_financial.md +0 -0
  316. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/security.md +0 -0
  317. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/bank.md +0 -0
  318. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/hybrid.md +0 -0
  319. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/insurance.md +0 -0
  320. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/non_financial.md +0 -0
  321. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/security.md +0 -0
  322. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/bank.md +0 -0
  323. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/hybrid.md +0 -0
  324. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/insurance.md +0 -0
  325. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/non_financial.md +0 -0
  326. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/security.md +0 -0
  327. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/cni.md +0 -0
  328. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/sw.md +0 -0
  329. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/sw_2021.md +0 -0
  330. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/cni.md +0 -0
  331. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/sw.md +0 -0
  332. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/sw_2021.md +0 -0
  333. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/cni.md +0 -0
  334. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/sw.md +0 -0
  335. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/sw_2021.md +0 -0
  336. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/cni.md +0 -0
  337. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/sw.md +0 -0
  338. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/sw_2021.md +0 -0
  339. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/cni.md +0 -0
  340. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/sw.md +0 -0
  341. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/sw_2021.md +0 -0
  342. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/cn/industry.md +0 -0
  343. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/allotment.md +0 -0
  344. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/announcement.md +0 -0
  345. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/candlestick.md +0 -0
  346. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/dividend.md +0 -0
  347. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/employee.md +0 -0
  348. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/equity-change.md +0 -0
  349. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/bank.md +0 -0
  350. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/insurance.md +0 -0
  351. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/non_financial.md +0 -0
  352. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/other_financial.md +0 -0
  353. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/reit.md +0 -0
  354. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/security.md +0 -0
  355. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fund-collection-shareholders.md +0 -0
  356. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fund-shareholders.md +0 -0
  357. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/bank.md +0 -0
  358. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/insurance.md +0 -0
  359. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/non_financial.md +0 -0
  360. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/other_financial.md +0 -0
  361. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/reit.md +0 -0
  362. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/security.md +0 -0
  363. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/capita.md +0 -0
  364. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/director_equity_change.md +0 -0
  365. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/mm_ah.md +0 -0
  366. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/npd.md +0 -0
  367. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/rep.md +0 -0
  368. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/ss.md +0 -0
  369. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/ss_ha.md +0 -0
  370. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/tr.md +0 -0
  371. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/tr_dri.md +0 -0
  372. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/indices.md +0 -0
  373. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/industries.md +0 -0
  374. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/latest-shareholders.md +0 -0
  375. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/mutual-market.md +0 -0
  376. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/operation-revenue-constitution.md +0 -0
  377. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/profile.md +0 -0
  378. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/repurchase.md +0 -0
  379. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/shareholders-equity-change.md +0 -0
  380. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/short-selling.md +0 -0
  381. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/split.md +0 -0
  382. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company/volatility.md +0 -0
  383. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/company.md +0 -0
  384. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/candlestick.md +0 -0
  385. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/constituents.md +0 -0
  386. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/drawdown.md +0 -0
  387. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/fs/hybrid.md +0 -0
  388. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/fs/non_financial.md +0 -0
  389. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/fundamental.md +0 -0
  390. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/cp.md +0 -0
  391. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/ic.md +0 -0
  392. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/ifet_sni.md +0 -0
  393. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/mm_ah.md +0 -0
  394. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/mutual-market.md +0 -0
  395. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/tracking-fund.md +0 -0
  396. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index/volatility.md +0 -0
  397. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/index.md +0 -0
  398. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/industry/constituents/hsi.md +0 -0
  399. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fs/hsi/hybrid.md +0 -0
  400. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fs/hsi/non_financial.md +0 -0
  401. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fundamental/hsi.md +0 -0
  402. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/industry/hot/mm_ah/hsi.md +0 -0
  403. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/industry/mutual-market/hsi.md +0 -0
  404. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/hk/industry.md +0 -0
  405. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/bop.md +0 -0
  406. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/central-bank-balance-sheet.md +0 -0
  407. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/credit-securities-account.md +0 -0
  408. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/crude-oil.md +0 -0
  409. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/currency-exchange-rate.md +0 -0
  410. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/domestic-debt-securities.md +0 -0
  411. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/domestic-trade.md +0 -0
  412. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/energy.md +0 -0
  413. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/foreign-assets.md +0 -0
  414. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/foreign-trade.md +0 -0
  415. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/gdp.md +0 -0
  416. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/gold-price.md +0 -0
  417. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/industrialization.md +0 -0
  418. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/interest-rates.md +0 -0
  419. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/investment-in-fixed-assets.md +0 -0
  420. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/investor.md +0 -0
  421. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/leverage-ratio.md +0 -0
  422. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/money-supply.md +0 -0
  423. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/national-debt.md +0 -0
  424. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/national-finance.md +0 -0
  425. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/natural-gas.md +0 -0
  426. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/non-ferrous-metals.md +0 -0
  427. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/official-reserve-assets.md +0 -0
  428. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/platinum-price.md +0 -0
  429. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/population.md +0 -0
  430. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/price-index.md +0 -0
  431. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/real-estate.md +0 -0
  432. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/required-reserves.md +0 -0
  433. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/rmb-deposits.md +0 -0
  434. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/rmb-loans.md +0 -0
  435. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/rmbidx.md +0 -0
  436. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/silver-price.md +0 -0
  437. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/social-financing.md +0 -0
  438. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/stamp-duty.md +0 -0
  439. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/traffic-transportation.md +0 -0
  440. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/unemployment-rate.md +0 -0
  441. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/usdx.md +0 -0
  442. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/macro/vix-fear-index.md +0 -0
  443. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/candlestick.md +0 -0
  444. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/constituents.md +0 -0
  445. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/drawdown.md +0 -0
  446. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/fs/non_financial.md +0 -0
  447. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/fundamental.md +0 -0
  448. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/hot/cp.md +0 -0
  449. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/hot/ifet_sni.md +0 -0
  450. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/tracking-fund.md +0 -0
  451. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index/volatility.md +0 -0
  452. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/lixinger-api/us/index.md +0 -0
  453. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/mkdocs.yml +0 -0
  454. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/mypy.ini +0 -0
  455. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/scripts/explore_api.py +0 -0
  456. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/scripts/generate_docs.py +0 -0
  457. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/scripts/publish.sh +0 -0
  458. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/api/cn/company/test_announcement.py +0 -0
  459. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/api/cn/company/test_dividend.py +0 -0
  460. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/api/cn/index/test_constituents.py +0 -0
  461. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/conftest.py +0 -0
  462. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_bank_statements.py +0 -0
  463. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_candlestick.py +0 -0
  464. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_client.py +0 -0
  465. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_cn_index_candlestick.py +0 -0
  466. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_cn_index_constituent_weightings.py +0 -0
  467. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_company.py +0 -0
  468. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_company_profile.py +0 -0
  469. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_equity_change.py +0 -0
  470. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fund.py +0 -0
  471. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fund_announcement.py +0 -0
  472. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fund_asset_combination.py +0 -0
  473. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fund_asset_industry_combination.py +0 -0
  474. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fund_candlestick.py +0 -0
  475. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fund_profile.py +0 -0
  476. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fund_shareholdings.py +0 -0
  477. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fundamental.py +0 -0
  478. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fundamental_bank.py +0 -0
  479. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_fundamental_security.py +0 -0
  480. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index.py +0 -0
  481. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index_constituents.py +0 -0
  482. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index_drawdown.py +0 -0
  483. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index_fs_bank.py +0 -0
  484. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index_fs_hybrid.py +0 -0
  485. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index_fs_non_financial.py +0 -0
  486. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index_fs_security.py +0 -0
  487. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index_fundamental.py +0 -0
  488. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_index_margin_trading.py +0 -0
  489. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_indices.py +0 -0
  490. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_industry_margin_trading.py +0 -0
  491. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_insurance_statements.py +0 -0
  492. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_integration.py +0 -0
  493. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_macro.py +0 -0
  494. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_non_financial_statements.py +0 -0
  495. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_other_financial_statements.py +0 -0
  496. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_security_statements.py +0 -0
  497. {lixinger_python-0.3.12 → lixinger_python-0.3.14}/tests/test_tracking_fund.py +0 -0
@@ -12,7 +12,12 @@
12
12
  "Bash(git push *)",
13
13
  "Bash(uv sync *)",
14
14
  "Bash(curl -s https://pypi.org/pypi/lixinger-python/0.3.11/json)",
15
- "Bash(python3 -c \"import sys, json; d = json.load\\(sys.stdin\\); print\\('Name:', d['info']['name']\\); print\\('Version:', d['info']['version']\\); print\\('Files:', len\\(d['urls']\\)\\)\")"
15
+ "Bash(python3 -c \"import sys, json; d = json.load\\(sys.stdin\\); print\\('Name:', d['info']['name']\\); print\\('Version:', d['info']['version']\\); print\\('Files:', len\\(d['urls']\\)\\)\")",
16
+ "Bash(curl -s https://pypi.org/pypi/lixinger-python/0.3.12/json)",
17
+ "Bash(curl -s https://pypi.org/pypi/lixinger-python/0.3.13/json)",
18
+ "Bash(git diff *)",
19
+ "Read(//tmp/**)",
20
+ "Bash(git checkout *)"
16
21
  ]
17
22
  }
18
23
  }
@@ -11,6 +11,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
  - Add support for US stock market APIs
12
12
  - Add caching mechanism for API responses
13
13
 
14
+ ## [0.3.14] - 2026-07-05
15
+
16
+ ### Fixed
17
+ - `code=1, message="no data"` 响应不再被误报为错误. 之前会抛
18
+ `APIError("API returned error code 1: no data")`, 现在正确返回空 payload,
19
+ 下游得到空 `DataFrame`. Lixinger 在非交易日、空日期范围、停牌股票等
20
+ 场景会返回该响应.
21
+ - 服务端未返回 `Retry-After` header 的 429 响应现在退避 15 秒 (可通过
22
+ `DEFAULT_RATE_LIMIT_RETRY_AFTER` 观察), 而不是之前的 1/2/4 秒指数退避.
23
+ Lixinger 的速率窗口是 60 秒, 1 秒后重试几乎必然再 429, 白白浪费重试配额.
24
+
25
+ ### Changed
26
+ - `_request` 的成功判断从 `code == 1 AND message == "success"` 放宽为
27
+ `code == 1`. message 视为人类可读的描述.
28
+ - `_request` 会把 `data` 字段的 `None` / 缺失情况归一到 `[]`, 避免下游
29
+ 20+ 个遍历 `data` 的 API 方法崩在 `for item in None`.
30
+ - `async_retry_on_failure` 新增 `jitter: float = 0.2` 参数, 每次 sleep
31
+ 会在 `[base*(1-jitter), base*(1+jitter)]` 之间均匀采样, 避免多客户端
32
+ 惊群. 传 `jitter=0` 关闭 (方便测试和确定性场景).
33
+
34
+ ## [0.3.13] - 2026-07-05
35
+
36
+ ### Fixed
37
+ - `AuthenticationError` (401) 和 `ValidationError` 不再被重试. 之前会被
38
+ 重试装饰器兜底 catch 3 次, 白白浪费 ~7 秒和 3 次配额.
39
+ - 429 响应现在会尊重服务端返回的 `Retry-After` header, 按 header 指定的
40
+ 时长退避(同时支持 RFC 7231 的 `delta-seconds` 和 `HTTP-date` 两种格式);
41
+ header 缺失时保持原有的 1/2/4 秒指数退避.
42
+
43
+ ### Changed
44
+ - `async_retry_on_failure` 新增 `no_retry_on: tuple[type[Exception], ...]`
45
+ 参数, 命中即立即抛出.
46
+ - `RateLimitError` 新增 `retry_after: float | None` 属性; 若异常对象带
47
+ `retry_after` 属性, 重试装饰器会用它替代默认的指数退避.
48
+
14
49
  ## [0.3.12] - 2026-07-05
15
50
 
16
51
  ### Added
@@ -186,7 +221,9 @@ asyncio.run(main())
186
221
  - Pre-commit hooks
187
222
  - MkDocs for documentation
188
223
 
189
- [unreleased]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.12...HEAD
224
+ [unreleased]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.14...HEAD
225
+ [0.3.14]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.13...v0.3.14
226
+ [0.3.13]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.12...v0.3.13
190
227
  [0.3.12]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.11...v0.3.12
191
228
  [0.3.11]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.10...v0.3.11
192
229
  [0.3.10]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.9...v0.3.10
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lixinger-python
3
- Version: 0.3.12
3
+ Version: 0.3.14
4
4
  Summary: Python SDK for Lixinger Financial Data API
5
5
  Project-URL: Homepage, https://www.lixinger.com
6
6
  Project-URL: Documentation, https://www.lixinger.com/open/api/doc
@@ -1,9 +1,11 @@
1
+ from datetime import UTC, datetime
2
+ from email.utils import parsedate_to_datetime
1
3
  from typing import Any
2
4
 
3
5
  import httpx
4
6
 
5
7
  from lixinger.config import Config, settings
6
- from lixinger.exceptions import APIError, AuthenticationError, RateLimitError
8
+ from lixinger.exceptions import APIError, AuthenticationError, RateLimitError, ValidationError
7
9
  from lixinger.utils.rate_limiter import AsyncRateLimiter
8
10
  from lixinger.utils.retry import async_retry_on_failure
9
11
 
@@ -13,6 +15,12 @@ _global_rate_limiter = AsyncRateLimiter(max_requests=1000)
13
15
  # Lazy initialization of global http client to avoid issues with proxy/config changes
14
16
  _global_http_client: httpx.AsyncClient | None = None
15
17
 
18
+ # Fallback delay in seconds when a 429 response omits Retry-After. The Lixinger
19
+ # rate-limit window is 60s, so short exponential backoff (1/2/4s) almost always
20
+ # fires inside the same window and gets 429ed again. 15s gives the window room
21
+ # to age and burns fewer retry attempts on doomed requests.
22
+ DEFAULT_RATE_LIMIT_RETRY_AFTER = 15.0
23
+
16
24
 
17
25
  def get_global_client() -> httpx.AsyncClient:
18
26
  """Get or create the global HTTP client."""
@@ -29,6 +37,39 @@ def get_global_client() -> httpx.AsyncClient:
29
37
  return _global_http_client
30
38
 
31
39
 
40
+ def _parse_retry_after(header_value: str | None) -> float | None:
41
+ """Parse a Retry-After header into seconds.
42
+
43
+ Accepts both formats defined by RFC 7231 §7.1.3:
44
+ - ``delta-seconds`` (e.g. ``"120"``)
45
+ - ``HTTP-date`` (e.g. ``"Wed, 21 Oct 2015 07:28:00 GMT"``)
46
+
47
+ Returns ``None`` when the header is missing or unparseable so the caller
48
+ can fall back to its default backoff.
49
+ """
50
+ if not header_value:
51
+ return None
52
+ value = header_value.strip()
53
+ # Try delta-seconds first — the common case.
54
+ try:
55
+ seconds = float(value)
56
+ except ValueError:
57
+ pass
58
+ else:
59
+ return seconds if seconds >= 0 else None
60
+ # Fall back to HTTP-date.
61
+ try:
62
+ target = parsedate_to_datetime(value)
63
+ except (TypeError, ValueError):
64
+ return None
65
+ if target.tzinfo is None:
66
+ # RFC 7231 HTTP-date is always GMT, so treat naive dates as UTC.
67
+ target = target.replace(tzinfo=UTC)
68
+ now = datetime.now(tz=target.tzinfo)
69
+ delta = (target - now).total_seconds()
70
+ return max(delta, 0.0)
71
+
72
+
32
73
  class BaseAPI:
33
74
  """Base class for API endpoint groups."""
34
75
 
@@ -42,7 +83,12 @@ class BaseAPI:
42
83
  self._config = config or settings
43
84
  self._rate_limiter = rate_limiter or _global_rate_limiter
44
85
 
45
- @async_retry_on_failure(max_retries=3, backoff=1.0)
86
+ @async_retry_on_failure(
87
+ max_retries=3,
88
+ backoff=1.0,
89
+ # Do NOT retry non-transient errors even though they inherit from Exception.
90
+ no_retry_on=(AuthenticationError, ValidationError),
91
+ )
46
92
  async def _request(
47
93
  self,
48
94
  method: str,
@@ -72,7 +118,16 @@ class BaseAPI:
72
118
  )
73
119
 
74
120
  if response.status_code == 429:
75
- raise RateLimitError("Rate limit exceeded", status_code=429)
121
+ retry_after = _parse_retry_after(response.headers.get("Retry-After"))
122
+ # Server didn't tell us how long to wait — pick a delay long enough
123
+ # for the 60s rate-limit window to actually age.
124
+ if retry_after is None:
125
+ retry_after = DEFAULT_RATE_LIMIT_RETRY_AFTER
126
+ raise RateLimitError(
127
+ "Rate limit exceeded",
128
+ status_code=429,
129
+ retry_after=retry_after,
130
+ )
76
131
  if response.status_code == 401:
77
132
  raise AuthenticationError("Authentication failed", status_code=401)
78
133
  if response.status_code != 200:
@@ -88,7 +143,15 @@ class BaseAPI:
88
143
  code = data.get("code")
89
144
  message = data.get("message")
90
145
 
91
- if code != 1 or message != "success":
146
+ # code is the machine-readable success signal; message is human text.
147
+ # Lixinger returns code=1 for success even when there's no data
148
+ # (e.g. message="no data" on non-trading days or empty ranges) —
149
+ # treat any code=1 as success and normalize a missing/null payload
150
+ # to [] so downstream iteration and get_response_df both work.
151
+ if code != 1:
92
152
  raise APIError(f"API returned error code {code}: {message}")
93
153
 
94
- return data.get("data")
154
+ payload = data.get("data")
155
+ if payload is None:
156
+ return []
157
+ return payload
@@ -0,0 +1,38 @@
1
+ class LixingerError(Exception):
2
+ """Base exception for Lixinger SDK."""
3
+
4
+
5
+ class APIError(LixingerError):
6
+ """API request failed."""
7
+
8
+ def __init__(self, message: str, status_code: int | None = None) -> None:
9
+ super().__init__(message)
10
+ self.status_code = status_code
11
+
12
+
13
+ class RateLimitError(APIError):
14
+ """Rate limit exceeded (429).
15
+
16
+ Attributes:
17
+ retry_after: Optional server-provided delay in seconds parsed from the
18
+ ``Retry-After`` response header. ``None`` when the header was absent
19
+ or malformed. The retry decorator honors this value in place of the
20
+ default exponential backoff.
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ message: str,
26
+ status_code: int | None = None,
27
+ retry_after: float | None = None,
28
+ ) -> None:
29
+ super().__init__(message, status_code=status_code)
30
+ self.retry_after = retry_after
31
+
32
+
33
+ class AuthenticationError(APIError):
34
+ """Authentication failed (401)."""
35
+
36
+
37
+ class ValidationError(LixingerError):
38
+ """Request validation failed."""
@@ -0,0 +1,63 @@
1
+ import asyncio
2
+ from collections.abc import Awaitable, Callable
3
+ from functools import wraps
4
+ import random
5
+ from typing import Any, TypeVar
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ def async_retry_on_failure(
11
+ max_retries: int = 3,
12
+ backoff: float = 1.0,
13
+ retry_on: tuple[type[Exception], ...] = (Exception,),
14
+ no_retry_on: tuple[type[Exception], ...] = (),
15
+ jitter: float = 0.2,
16
+ ) -> Callable[[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]]]:
17
+ """Retry failed async requests with exponential backoff and jitter.
18
+
19
+ Args:
20
+ max_retries: Maximum number of retry attempts (total attempts = max_retries + 1).
21
+ backoff: Base delay in seconds for exponential backoff (2**attempt * backoff).
22
+ retry_on: Exception types that trigger a retry.
23
+ no_retry_on: Exception types that must NOT be retried even if matched by
24
+ ``retry_on``. Use this to short-circuit on non-transient errors such
25
+ as authentication failures.
26
+ jitter: Multiplicative jitter fraction applied to every sleep. The actual
27
+ sleep is drawn from ``uniform(base * (1 - jitter), base * (1 + jitter))``
28
+ where ``base`` is either the ``retry_after`` hint or the exponential
29
+ backoff. Pass ``0`` to disable (mostly useful in tests). Values are
30
+ clamped so the sleep never goes negative.
31
+
32
+ If the caught exception exposes a ``retry_after`` attribute (float seconds,
33
+ typically parsed from a ``Retry-After`` HTTP header on 429 responses), that
34
+ value is used for the next sleep instead of the exponential backoff.
35
+ """
36
+
37
+ def decorator(func: Callable[..., Awaitable[T]]) -> Callable[..., Awaitable[T]]:
38
+ @wraps(func)
39
+ async def wrapper(*args: Any, **kwargs: Any) -> T:
40
+ for attempt in range(max_retries + 1):
41
+ try:
42
+ return await func(*args, **kwargs)
43
+ except retry_on as e:
44
+ # Bail out immediately on non-transient errors.
45
+ if no_retry_on and isinstance(e, no_retry_on):
46
+ raise
47
+ if attempt == max_retries:
48
+ raise
49
+ # Prefer server-provided retry hint when available.
50
+ hint = getattr(e, "retry_after", None)
51
+ base = float(hint) if isinstance(hint, int | float) and hint > 0 else backoff * (2**attempt)
52
+ if jitter > 0:
53
+ low = max(0.0, base * (1.0 - jitter))
54
+ high = base * (1.0 + jitter)
55
+ wait_time = random.uniform(low, high) # noqa: S311 (non-crypto jitter)
56
+ else:
57
+ wait_time = base
58
+ await asyncio.sleep(wait_time)
59
+ raise RuntimeError("Unreachable")
60
+
61
+ return wrapper
62
+
63
+ return decorator
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lixinger-python"
3
- version = "0.3.12"
3
+ version = "0.3.14"
4
4
  description = "Python SDK for Lixinger Financial Data API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -0,0 +1,126 @@
1
+ """Unit tests for `code=1` / "no data" handling in BaseAPI._request."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from unittest.mock import AsyncMock, Mock, patch
6
+
7
+ import httpx
8
+ import pandas as pd
9
+ import pytest
10
+
11
+ from lixinger.api.base import BaseAPI
12
+ from lixinger.exceptions import APIError
13
+ from lixinger.utils.rate_limiter import AsyncRateLimiter
14
+
15
+
16
+ def _mock_response(json_body: dict) -> Mock:
17
+ resp = Mock()
18
+ resp.status_code = 200
19
+ resp.text = "mock body"
20
+ resp.headers = {}
21
+ resp.json.return_value = json_body
22
+ return resp
23
+
24
+
25
+ def _make_api(monkeypatch: pytest.MonkeyPatch) -> BaseAPI:
26
+ monkeypatch.setenv("LIXINGER_API_KEY", "test_key")
27
+ return BaseAPI(rate_limiter=AsyncRateLimiter(max_requests=1000))
28
+
29
+
30
+ @pytest.mark.asyncio
31
+ async def test_no_data_message_returns_empty_list(monkeypatch):
32
+ """Lixinger returns code=1/message="no data" for successful requests that
33
+ happen to have nothing to return (non-trading days, empty ranges, etc.).
34
+ _request should treat this as success and return an empty payload rather
35
+ than raising APIError."""
36
+ api = _make_api(monkeypatch)
37
+
38
+ body = {"code": 1, "message": "no data", "data": None}
39
+
40
+ with patch("lixinger.api.base.get_global_client") as mock_client_factory:
41
+ client = Mock(spec=httpx.AsyncClient)
42
+ client.request = AsyncMock(return_value=_mock_response(body))
43
+ mock_client_factory.return_value = client
44
+
45
+ result = await api._request("POST", "/whatever", json={"a": 1})
46
+
47
+ assert result == []
48
+
49
+
50
+ @pytest.mark.asyncio
51
+ async def test_missing_data_key_returns_empty_list(monkeypatch):
52
+ """Some 'no data' responses omit the data key entirely instead of nulling it."""
53
+ api = _make_api(monkeypatch)
54
+
55
+ body = {"code": 1, "message": "no data"}
56
+
57
+ with patch("lixinger.api.base.get_global_client") as mock_client_factory:
58
+ client = Mock(spec=httpx.AsyncClient)
59
+ client.request = AsyncMock(return_value=_mock_response(body))
60
+ mock_client_factory.return_value = client
61
+
62
+ result = await api._request("POST", "/whatever", json={"a": 1})
63
+
64
+ assert result == []
65
+
66
+
67
+ @pytest.mark.asyncio
68
+ async def test_success_with_data_unchanged(monkeypatch):
69
+ """Regression guard: code=1/message="success" with real data still works."""
70
+ api = _make_api(monkeypatch)
71
+
72
+ body = {"code": 1, "message": "success", "data": [{"x": 1}, {"x": 2}]}
73
+
74
+ with patch("lixinger.api.base.get_global_client") as mock_client_factory:
75
+ client = Mock(spec=httpx.AsyncClient)
76
+ client.request = AsyncMock(return_value=_mock_response(body))
77
+ mock_client_factory.return_value = client
78
+
79
+ result = await api._request("POST", "/whatever", json={"a": 1})
80
+
81
+ assert result == [{"x": 1}, {"x": 2}]
82
+
83
+
84
+ @pytest.mark.asyncio
85
+ async def test_non_success_code_still_raises(monkeypatch):
86
+ """Real errors (code != 1) must still raise regardless of message text."""
87
+ api = _make_api(monkeypatch)
88
+
89
+ body = {"code": 0, "message": "bad token", "data": None}
90
+
91
+ with patch("lixinger.api.base.get_global_client") as mock_client_factory:
92
+ client = Mock(spec=httpx.AsyncClient)
93
+ client.request = AsyncMock(return_value=_mock_response(body))
94
+ mock_client_factory.return_value = client
95
+
96
+ with pytest.raises(APIError, match="error code 0"):
97
+ await api._request("POST", "/whatever", json={"a": 1})
98
+
99
+
100
+ @pytest.mark.asyncio
101
+ async def test_no_data_downstream_returns_empty_dataframe(monkeypatch):
102
+ """End-to-end check: an API method that iterates the payload and passes it
103
+ through get_response_df should return an empty DataFrame (not crash) when
104
+ the server returns code=1/message='no data'."""
105
+ # Late import so the AsyncLixingerClient instantiation picks up the env var.
106
+ from lixinger import AsyncLixingerClient
107
+
108
+ monkeypatch.setenv("LIXINGER_API_KEY", "test_key")
109
+ client = AsyncLixingerClient()
110
+
111
+ body = {"code": 1, "message": "no data", "data": None}
112
+
113
+ with patch.object(client._http_client, "request") as mock_request:
114
+ mock_request.return_value = Mock()
115
+ mock_request.return_value.status_code = 200
116
+ mock_request.return_value.headers = {}
117
+ mock_request.return_value.json.return_value = body
118
+
119
+ df = await client.cn_industry.margin_trading.sw.get_margin_trading(
120
+ stock_code="490000",
121
+ start_date="2025-06-13",
122
+ end_date="2026-06-13",
123
+ )
124
+
125
+ assert isinstance(df, pd.DataFrame)
126
+ assert df.empty