lixinger-python 0.3.13__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 (495) hide show
  1. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.claude/settings.local.json +5 -1
  2. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/CHANGELOG.md +22 -1
  3. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/PKG-INFO +1 -1
  4. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/base.py +20 -2
  5. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/retry.py +15 -4
  6. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/pyproject.toml +1 -1
  7. lixinger_python-0.3.14/tests/test_no_data.py +126 -0
  8. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_retry.py +105 -13
  9. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/uv.lock +1 -1
  10. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.env.example +0 -0
  11. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.github/copilot-instructions.md +0 -0
  12. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.github/workflows/README.md +0 -0
  13. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.github/workflows/pr-checks.yml +0 -0
  14. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.gitignore +0 -0
  15. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.pre-commit-config.yaml +0 -0
  16. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.python-version +0 -0
  17. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.ruff.toml +0 -0
  18. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/ADD_NEW_API_QUICK.md +0 -0
  19. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/ARCHITECTURE.md +0 -0
  20. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/CLAUDE.md +0 -0
  21. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/DOCUMENTATION.md +0 -0
  22. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/LICENSE +0 -0
  23. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/MANIFEST.in +0 -0
  24. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/PUBLISHING.md +0 -0
  25. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/README.md +0 -0
  26. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/codecov.yml +0 -0
  27. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/client.md +0 -0
  28. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/announcement.md +0 -0
  29. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/candlestick.md +0 -0
  30. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/company.md +0 -0
  31. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/dividend.md +0 -0
  32. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/equity_change.md +0 -0
  33. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fs/non_financial.md +0 -0
  34. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/bank.md +0 -0
  35. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/insurance.md +0 -0
  36. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/non_financial.md +0 -0
  37. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/other_financial.md +0 -0
  38. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/security.md +0 -0
  39. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/indices.md +0 -0
  40. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/profile.md +0 -0
  41. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/announcement.md +0 -0
  42. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/asset_combination.md +0 -0
  43. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/asset_industry_combination.md +0 -0
  44. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/candlestick.md +0 -0
  45. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/fund.md +0 -0
  46. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/profile.md +0 -0
  47. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/shareholdings.md +0 -0
  48. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/candlestick.md +0 -0
  49. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/constituent_weightings.md +0 -0
  50. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/constituents.md +0 -0
  51. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/drawdown.md +0 -0
  52. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/fundamental.md +0 -0
  53. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/index.md +0 -0
  54. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/tracking_fund.md +0 -0
  55. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/overview.md +0 -0
  56. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/development/code-style.md +0 -0
  57. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/development/contributing.md +0 -0
  58. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/development/testing.md +0 -0
  59. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/examples/company.md +0 -0
  60. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/examples/fund.md +0 -0
  61. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/examples/index.md +0 -0
  62. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/getting-started/configuration.md +0 -0
  63. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/getting-started/installation.md +0 -0
  64. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/getting-started/quickstart.md +0 -0
  65. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/index.md +0 -0
  66. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/company_example.py +0 -0
  67. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/company_profile_example.py +0 -0
  68. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/dividend_example.py +0 -0
  69. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/fs_example.py +0 -0
  70. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_constituent_weightings_example.py +0 -0
  71. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_constituents_example.py +0 -0
  72. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_info_example.py +0 -0
  73. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_margin_trading_example.py +0 -0
  74. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/__init__.py +0 -0
  75. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/__init__.py +0 -0
  76. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/__init__.py +0 -0
  77. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/__init__.py +0 -0
  78. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/announcement.py +0 -0
  79. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/candlestick.py +0 -0
  80. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/company.py +0 -0
  81. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/dividend.py +0 -0
  82. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/equity_change.py +0 -0
  83. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/__init__.py +0 -0
  84. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/bank.py +0 -0
  85. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/insurance.py +0 -0
  86. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/non_financial.py +0 -0
  87. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/other_financial.py +0 -0
  88. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/security.py +0 -0
  89. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/__init__.py +0 -0
  90. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/bank.py +0 -0
  91. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/insurance.py +0 -0
  92. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/non_financial.py +0 -0
  93. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/other_financial.py +0 -0
  94. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/security.py +0 -0
  95. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/indices.py +0 -0
  96. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/namespace.py +0 -0
  97. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/profile.py +0 -0
  98. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/__init__.py +0 -0
  99. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/announcement.py +0 -0
  100. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/asset_combination.py +0 -0
  101. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/asset_industry_combination.py +0 -0
  102. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/candlestick.py +0 -0
  103. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/fund.py +0 -0
  104. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/profile.py +0 -0
  105. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/shareholdings.py +0 -0
  106. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/__init__.py +0 -0
  107. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/candlestick.py +0 -0
  108. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/constituent_weightings.py +0 -0
  109. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/constituents.py +0 -0
  110. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/drawdown.py +0 -0
  111. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/__init__.py +0 -0
  112. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/bank.py +0 -0
  113. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/hybrid.py +0 -0
  114. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/non_financial.py +0 -0
  115. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/security.py +0 -0
  116. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fundamental.py +0 -0
  117. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/index.py +0 -0
  118. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/margin_trading.py +0 -0
  119. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/namespace.py +0 -0
  120. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/tracking_fund.py +0 -0
  121. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/__init__.py +0 -0
  122. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/__init__.py +0 -0
  123. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/cni.py +0 -0
  124. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/sw.py +0 -0
  125. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/sw_2021.py +0 -0
  126. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/namespace.py +0 -0
  127. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/__init__.py +0 -0
  128. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/namespace.py +0 -0
  129. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/national_debt.py +0 -0
  130. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/rmb_deposits.py +0 -0
  131. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/rmb_loans.py +0 -0
  132. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/social_financing.py +0 -0
  133. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/client.py +0 -0
  134. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/config.py +0 -0
  135. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/exceptions.py +0 -0
  136. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/__init__.py +0 -0
  137. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/__init__.py +0 -0
  138. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/__init__.py +0 -0
  139. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/announcement.py +0 -0
  140. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/candlestick.py +0 -0
  141. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/company.py +0 -0
  142. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/dividend.py +0 -0
  143. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/equity_change.py +0 -0
  144. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/__init__.py +0 -0
  145. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/bank.py +0 -0
  146. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/insurance.py +0 -0
  147. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/non_financial.py +0 -0
  148. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/other_financial.py +0 -0
  149. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/security.py +0 -0
  150. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/__init__.py +0 -0
  151. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/bank.py +0 -0
  152. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/insurance.py +0 -0
  153. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/non_financial.py +0 -0
  154. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/other_financial.py +0 -0
  155. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/security.py +0 -0
  156. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/indices.py +0 -0
  157. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/__init__.py +0 -0
  158. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/announcement.py +0 -0
  159. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/asset_combination.py +0 -0
  160. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/asset_industry_combination.py +0 -0
  161. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/candlestick.py +0 -0
  162. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/fund.py +0 -0
  163. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/profile.py +0 -0
  164. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/shareholdings.py +0 -0
  165. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/__init__.py +0 -0
  166. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/candlestick.py +0 -0
  167. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/constituent_weightings.py +0 -0
  168. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/constituents.py +0 -0
  169. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/drawdown.py +0 -0
  170. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/__init__.py +0 -0
  171. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/bank.py +0 -0
  172. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/hybrid.py +0 -0
  173. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/non_financial.py +0 -0
  174. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/security.py +0 -0
  175. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fundamental.py +0 -0
  176. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/index.py +0 -0
  177. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/margin_trading.py +0 -0
  178. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/tracking_fund.py +0 -0
  179. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/__init__.py +0 -0
  180. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/__init__.py +0 -0
  181. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/cni.py +0 -0
  182. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/sw.py +0 -0
  183. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/sw_2021.py +0 -0
  184. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/__init__.py +0 -0
  185. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/national_debt.py +0 -0
  186. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/rmb_deposits.py +0 -0
  187. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/rmb_loans.py +0 -0
  188. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/social_financing.py +0 -0
  189. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/py.typed +0 -0
  190. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/__init__.py +0 -0
  191. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/api.py +0 -0
  192. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/dataframe.py +0 -0
  193. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/dict.py +0 -0
  194. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/rate_limiter.py +0 -0
  195. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/REMINDER.md +0 -0
  196. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/allotment.md +0 -0
  197. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/announcement.md +0 -0
  198. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/block-deal.md +0 -0
  199. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/candlestick.md +0 -0
  200. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/customers.md +0 -0
  201. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/dividend.md +0 -0
  202. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/equity-change.md +0 -0
  203. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/bank.md +0 -0
  204. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/insurance.md +0 -0
  205. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/non_financial.md +0 -0
  206. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/other_financial.md +0 -0
  207. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/security.md +0 -0
  208. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fund-collection-shareholders.md +0 -0
  209. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fund-shareholders.md +0 -0
  210. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/bank.md +0 -0
  211. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/insurance.md +0 -0
  212. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/non_financial.md +0 -0
  213. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/other_financial.md +0 -0
  214. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/security.md +0 -0
  215. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/capita.md +0 -0
  216. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/df.md +0 -0
  217. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/elr.md +0 -0
  218. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/esc.md +0 -0
  219. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mm_ha.md +0 -0
  220. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mssc.md +0 -0
  221. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mtasl.md +0 -0
  222. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/npd.md +0 -0
  223. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/ple.md +0 -0
  224. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/shnc.md +0 -0
  225. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/t_a.md +0 -0
  226. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/tr.md +0 -0
  227. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/tr_dri.md +0 -0
  228. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/indices.md +0 -0
  229. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/industries.md +0 -0
  230. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/inquiry.md +0 -0
  231. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/major-shareholders-shares-change.md +0 -0
  232. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/majority-shareholders.md +0 -0
  233. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/margin-trading-and-securities-lending.md +0 -0
  234. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/measures.md +0 -0
  235. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/mutual-market.md +0 -0
  236. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/nolimit-shareholders.md +0 -0
  237. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/operating-data.md +0 -0
  238. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/operation-revenue-constitution.md +0 -0
  239. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/pledge.md +0 -0
  240. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/profile.md +0 -0
  241. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/senior-executive-shares-change.md +0 -0
  242. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/shareholders-num.md +0 -0
  243. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/suppliers.md +0 -0
  244. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/trading-abnormal.md +0 -0
  245. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/volatility.md +0 -0
  246. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company.md +0 -0
  247. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/announcement.md +0 -0
  248. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/asset-combination.md +0 -0
  249. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/asset-industry-combination.md +0 -0
  250. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/candlestick.md +0 -0
  251. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/dividend.md +0 -0
  252. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/drawdown.md +0 -0
  253. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/fees.md +0 -0
  254. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/f_as.md +0 -0
  255. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/f_nlacan.md +0 -0
  256. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fet_s.md +0 -0
  257. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/ff.md +0 -0
  258. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fp.md +0 -0
  259. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fpr.md +0 -0
  260. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fss.md +0 -0
  261. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/manager.md +0 -0
  262. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/net-value-of-dividend-reinvestment.md +0 -0
  263. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/net-value.md +0 -0
  264. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/profile.md +0 -0
  265. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shareholders-structure.md +0 -0
  266. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shareholdings.md +0 -0
  267. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shares.md +0 -0
  268. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/split.md +0 -0
  269. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/total-net-value.md +0 -0
  270. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/turnover-rate.md +0 -0
  271. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/volatility.md +0 -0
  272. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/asset-scale.md +0 -0
  273. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/fund-list.md +0 -0
  274. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/fund-manager-list.md +0 -0
  275. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/hot/fc_as.md +0 -0
  276. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/hot/fc_asr.md +0 -0
  277. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/shareholdings.md +0 -0
  278. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company.md +0 -0
  279. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/hot/fmi.md +0 -0
  280. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/hot/fmp.md +0 -0
  281. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/management-funds.md +0 -0
  282. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/profit-ratio.md +0 -0
  283. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/shareholdings.md +0 -0
  284. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager.md +0 -0
  285. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund.md +0 -0
  286. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/candlestick.md +0 -0
  287. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/constituent-weightings.md +0 -0
  288. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/constituents.md +0 -0
  289. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/drawdown.md +0 -0
  290. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/bank.md +0 -0
  291. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/hybrid.md +0 -0
  292. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/non_financial.md +0 -0
  293. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/security.md +0 -0
  294. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fundamental.md +0 -0
  295. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/cp.md +0 -0
  296. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/ic.md +0 -0
  297. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/ifet_sni.md +0 -0
  298. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/mm_ha.md +0 -0
  299. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/mtasl.md +0 -0
  300. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/tr.md +0 -0
  301. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/tr_cp.md +0 -0
  302. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/margin-trading-and-securities-lending.md +0 -0
  303. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/mutual-market.md +0 -0
  304. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/tracking-fund.md +0 -0
  305. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/volatility.md +0 -0
  306. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index.md +0 -0
  307. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/cni.md +0 -0
  308. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/sw.md +0 -0
  309. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/sw_2021.md +0 -0
  310. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/bank.md +0 -0
  311. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/hybrid.md +0 -0
  312. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/insurance.md +0 -0
  313. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/non_financial.md +0 -0
  314. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/security.md +0 -0
  315. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/bank.md +0 -0
  316. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/hybrid.md +0 -0
  317. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/insurance.md +0 -0
  318. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/non_financial.md +0 -0
  319. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/security.md +0 -0
  320. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/bank.md +0 -0
  321. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/hybrid.md +0 -0
  322. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/insurance.md +0 -0
  323. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/non_financial.md +0 -0
  324. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/security.md +0 -0
  325. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/cni.md +0 -0
  326. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/sw.md +0 -0
  327. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/sw_2021.md +0 -0
  328. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/cni.md +0 -0
  329. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/sw.md +0 -0
  330. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/sw_2021.md +0 -0
  331. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/cni.md +0 -0
  332. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/sw.md +0 -0
  333. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/sw_2021.md +0 -0
  334. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/cni.md +0 -0
  335. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/sw.md +0 -0
  336. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/sw_2021.md +0 -0
  337. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/cni.md +0 -0
  338. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/sw.md +0 -0
  339. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/sw_2021.md +0 -0
  340. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry.md +0 -0
  341. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/allotment.md +0 -0
  342. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/announcement.md +0 -0
  343. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/candlestick.md +0 -0
  344. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/dividend.md +0 -0
  345. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/employee.md +0 -0
  346. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/equity-change.md +0 -0
  347. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/bank.md +0 -0
  348. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/insurance.md +0 -0
  349. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/non_financial.md +0 -0
  350. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/other_financial.md +0 -0
  351. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/reit.md +0 -0
  352. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/security.md +0 -0
  353. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fund-collection-shareholders.md +0 -0
  354. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fund-shareholders.md +0 -0
  355. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/bank.md +0 -0
  356. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/insurance.md +0 -0
  357. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/non_financial.md +0 -0
  358. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/other_financial.md +0 -0
  359. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/reit.md +0 -0
  360. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/security.md +0 -0
  361. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/capita.md +0 -0
  362. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/director_equity_change.md +0 -0
  363. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/mm_ah.md +0 -0
  364. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/npd.md +0 -0
  365. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/rep.md +0 -0
  366. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/ss.md +0 -0
  367. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/ss_ha.md +0 -0
  368. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/tr.md +0 -0
  369. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/tr_dri.md +0 -0
  370. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/indices.md +0 -0
  371. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/industries.md +0 -0
  372. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/latest-shareholders.md +0 -0
  373. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/mutual-market.md +0 -0
  374. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/operation-revenue-constitution.md +0 -0
  375. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/profile.md +0 -0
  376. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/repurchase.md +0 -0
  377. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/shareholders-equity-change.md +0 -0
  378. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/short-selling.md +0 -0
  379. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/split.md +0 -0
  380. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/volatility.md +0 -0
  381. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company.md +0 -0
  382. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/candlestick.md +0 -0
  383. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/constituents.md +0 -0
  384. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/drawdown.md +0 -0
  385. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/fs/hybrid.md +0 -0
  386. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/fs/non_financial.md +0 -0
  387. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/fundamental.md +0 -0
  388. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/cp.md +0 -0
  389. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/ic.md +0 -0
  390. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/ifet_sni.md +0 -0
  391. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/mm_ah.md +0 -0
  392. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/mutual-market.md +0 -0
  393. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/tracking-fund.md +0 -0
  394. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/volatility.md +0 -0
  395. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index.md +0 -0
  396. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/constituents/hsi.md +0 -0
  397. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fs/hsi/hybrid.md +0 -0
  398. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fs/hsi/non_financial.md +0 -0
  399. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fundamental/hsi.md +0 -0
  400. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/hot/mm_ah/hsi.md +0 -0
  401. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/mutual-market/hsi.md +0 -0
  402. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry.md +0 -0
  403. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/bop.md +0 -0
  404. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/central-bank-balance-sheet.md +0 -0
  405. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/credit-securities-account.md +0 -0
  406. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/crude-oil.md +0 -0
  407. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/currency-exchange-rate.md +0 -0
  408. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/domestic-debt-securities.md +0 -0
  409. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/domestic-trade.md +0 -0
  410. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/energy.md +0 -0
  411. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/foreign-assets.md +0 -0
  412. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/foreign-trade.md +0 -0
  413. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/gdp.md +0 -0
  414. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/gold-price.md +0 -0
  415. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/industrialization.md +0 -0
  416. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/interest-rates.md +0 -0
  417. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/investment-in-fixed-assets.md +0 -0
  418. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/investor.md +0 -0
  419. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/leverage-ratio.md +0 -0
  420. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/money-supply.md +0 -0
  421. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/national-debt.md +0 -0
  422. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/national-finance.md +0 -0
  423. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/natural-gas.md +0 -0
  424. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/non-ferrous-metals.md +0 -0
  425. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/official-reserve-assets.md +0 -0
  426. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/platinum-price.md +0 -0
  427. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/population.md +0 -0
  428. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/price-index.md +0 -0
  429. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/real-estate.md +0 -0
  430. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/required-reserves.md +0 -0
  431. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/rmb-deposits.md +0 -0
  432. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/rmb-loans.md +0 -0
  433. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/rmbidx.md +0 -0
  434. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/silver-price.md +0 -0
  435. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/social-financing.md +0 -0
  436. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/stamp-duty.md +0 -0
  437. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/traffic-transportation.md +0 -0
  438. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/unemployment-rate.md +0 -0
  439. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/usdx.md +0 -0
  440. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/vix-fear-index.md +0 -0
  441. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/candlestick.md +0 -0
  442. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/constituents.md +0 -0
  443. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/drawdown.md +0 -0
  444. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/fs/non_financial.md +0 -0
  445. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/fundamental.md +0 -0
  446. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/hot/cp.md +0 -0
  447. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/hot/ifet_sni.md +0 -0
  448. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/tracking-fund.md +0 -0
  449. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/volatility.md +0 -0
  450. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index.md +0 -0
  451. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/mkdocs.yml +0 -0
  452. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/mypy.ini +0 -0
  453. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/scripts/explore_api.py +0 -0
  454. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/scripts/generate_docs.py +0 -0
  455. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/scripts/publish.sh +0 -0
  456. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/api/cn/company/test_announcement.py +0 -0
  457. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/api/cn/company/test_dividend.py +0 -0
  458. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/api/cn/index/test_constituents.py +0 -0
  459. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/conftest.py +0 -0
  460. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_bank_statements.py +0 -0
  461. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_candlestick.py +0 -0
  462. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_client.py +0 -0
  463. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_cn_index_candlestick.py +0 -0
  464. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_cn_index_constituent_weightings.py +0 -0
  465. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_company.py +0 -0
  466. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_company_profile.py +0 -0
  467. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_equity_change.py +0 -0
  468. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund.py +0 -0
  469. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_announcement.py +0 -0
  470. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_asset_combination.py +0 -0
  471. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_asset_industry_combination.py +0 -0
  472. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_candlestick.py +0 -0
  473. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_profile.py +0 -0
  474. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_shareholdings.py +0 -0
  475. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fundamental.py +0 -0
  476. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fundamental_bank.py +0 -0
  477. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fundamental_security.py +0 -0
  478. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index.py +0 -0
  479. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_constituents.py +0 -0
  480. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_drawdown.py +0 -0
  481. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fs_bank.py +0 -0
  482. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fs_hybrid.py +0 -0
  483. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fs_non_financial.py +0 -0
  484. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fs_security.py +0 -0
  485. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fundamental.py +0 -0
  486. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_margin_trading.py +0 -0
  487. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_indices.py +0 -0
  488. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_industry_margin_trading.py +0 -0
  489. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_insurance_statements.py +0 -0
  490. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_integration.py +0 -0
  491. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_macro.py +0 -0
  492. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_non_financial_statements.py +0 -0
  493. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_other_financial_statements.py +0 -0
  494. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_security_statements.py +0 -0
  495. {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_tracking_fund.py +0 -0
@@ -13,7 +13,11 @@
13
13
  "Bash(uv sync *)",
14
14
  "Bash(curl -s https://pypi.org/pypi/lixinger-python/0.3.11/json)",
15
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)"
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 *)"
17
21
  ]
18
22
  }
19
23
  }
@@ -11,6 +11,26 @@ 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
+
14
34
  ## [0.3.13] - 2026-07-05
15
35
 
16
36
  ### Fixed
@@ -201,7 +221,8 @@ asyncio.run(main())
201
221
  - Pre-commit hooks
202
222
  - MkDocs for documentation
203
223
 
204
- [unreleased]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.13...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
205
226
  [0.3.13]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.12...v0.3.13
206
227
  [0.3.12]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.11...v0.3.12
207
228
  [0.3.11]: https://github.com/TedaLIEz/lixinger-python/compare/v0.3.10...v0.3.11
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lixinger-python
3
- Version: 0.3.13
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
@@ -15,6 +15,12 @@ _global_rate_limiter = AsyncRateLimiter(max_requests=1000)
15
15
  # Lazy initialization of global http client to avoid issues with proxy/config changes
16
16
  _global_http_client: httpx.AsyncClient | None = None
17
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
+
18
24
 
19
25
  def get_global_client() -> httpx.AsyncClient:
20
26
  """Get or create the global HTTP client."""
@@ -113,6 +119,10 @@ class BaseAPI:
113
119
 
114
120
  if response.status_code == 429:
115
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
116
126
  raise RateLimitError(
117
127
  "Rate limit exceeded",
118
128
  status_code=429,
@@ -133,7 +143,15 @@ class BaseAPI:
133
143
  code = data.get("code")
134
144
  message = data.get("message")
135
145
 
136
- 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:
137
152
  raise APIError(f"API returned error code {code}: {message}")
138
153
 
139
- return data.get("data")
154
+ payload = data.get("data")
155
+ if payload is None:
156
+ return []
157
+ return payload
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  from collections.abc import Awaitable, Callable
3
3
  from functools import wraps
4
+ import random
4
5
  from typing import Any, TypeVar
5
6
 
6
7
  T = TypeVar("T")
@@ -11,8 +12,9 @@ def async_retry_on_failure(
11
12
  backoff: float = 1.0,
12
13
  retry_on: tuple[type[Exception], ...] = (Exception,),
13
14
  no_retry_on: tuple[type[Exception], ...] = (),
15
+ jitter: float = 0.2,
14
16
  ) -> Callable[[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]]]:
15
- """Retry failed async requests with exponential backoff.
17
+ """Retry failed async requests with exponential backoff and jitter.
16
18
 
17
19
  Args:
18
20
  max_retries: Maximum number of retry attempts (total attempts = max_retries + 1).
@@ -21,6 +23,11 @@ def async_retry_on_failure(
21
23
  no_retry_on: Exception types that must NOT be retried even if matched by
22
24
  ``retry_on``. Use this to short-circuit on non-transient errors such
23
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.
24
31
 
25
32
  If the caught exception exposes a ``retry_after`` attribute (float seconds,
26
33
  typically parsed from a ``Retry-After`` HTTP header on 429 responses), that
@@ -41,9 +48,13 @@ def async_retry_on_failure(
41
48
  raise
42
49
  # Prefer server-provided retry hint when available.
43
50
  hint = getattr(e, "retry_after", None)
44
- wait_time = (
45
- float(hint) if isinstance(hint, int | float) and hint > 0 else backoff * (2**attempt)
46
- )
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
47
58
  await asyncio.sleep(wait_time)
48
59
  raise RuntimeError("Unreachable")
49
60
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lixinger-python"
3
- version = "0.3.13"
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
@@ -8,9 +8,8 @@ from unittest.mock import AsyncMock, Mock, patch
8
8
  import httpx
9
9
  import pytest
10
10
 
11
- from lixinger.api.base import BaseAPI, _parse_retry_after
11
+ from lixinger.api.base import DEFAULT_RATE_LIMIT_RETRY_AFTER, BaseAPI, _parse_retry_after
12
12
  from lixinger.exceptions import (
13
- APIError,
14
13
  AuthenticationError,
15
14
  RateLimitError,
16
15
  ValidationError,
@@ -95,7 +94,7 @@ async def test_validation_error_is_not_retried():
95
94
  # The retry decorator should honor no_retry_on for arbitrary exceptions too.
96
95
  calls = 0
97
96
 
98
- @async_retry_on_failure(max_retries=3, backoff=0, no_retry_on=(ValidationError,))
97
+ @async_retry_on_failure(max_retries=3, backoff=0, no_retry_on=(ValidationError,), jitter=0)
99
98
  async def fn():
100
99
  nonlocal calls
101
100
  calls += 1
@@ -113,7 +112,7 @@ async def test_validation_error_is_not_retried():
113
112
  async def test_429_with_retry_after_honors_header(monkeypatch):
114
113
  api = _make_api(monkeypatch)
115
114
 
116
- # First two responses 429 with Retry-After=2, third succeeds.
115
+ # First two responses 429 with Retry-After, third succeeds.
117
116
  responses = [
118
117
  _mock_response(429, headers={"Retry-After": "2"}),
119
118
  _mock_response(429, headers={"Retry-After": "3"}),
@@ -132,18 +131,25 @@ async def test_429_with_retry_after_honors_header(monkeypatch):
132
131
 
133
132
  assert data == [1, 2, 3]
134
133
  assert client.request.await_count == 3
135
- # Two sleeps between three attempts, both using the header value not backoff.
134
+ # Two sleeps between three attempts; jitter (±20%) is applied so we check bounds.
136
135
  sleeps = [call.args[0] for call in mock_sleep.await_args_list]
137
- assert sleeps == [2.0, 3.0]
136
+ assert len(sleeps) == 2
137
+ assert 2.0 * 0.8 <= sleeps[0] <= 2.0 * 1.2
138
+ assert 3.0 * 0.8 <= sleeps[1] <= 3.0 * 1.2
139
+
140
+
141
+ # --- 429 fallback (problem: 1/2/4s is too short for 60s window) -----------
138
142
 
139
143
 
140
144
  @pytest.mark.asyncio
141
- async def test_429_without_retry_after_falls_back_to_exponential_backoff(monkeypatch):
145
+ async def test_429_without_retry_after_uses_default_15s_fallback(monkeypatch):
146
+ """Plan A: when the server omits Retry-After we back off DEFAULT_RATE_LIMIT_RETRY_AFTER
147
+ (15s) instead of the short 1/2/4s exponential backoff — the latter almost always
148
+ fires inside the still-hot 60s rate-limit window."""
142
149
  api = _make_api(monkeypatch)
143
150
 
144
- # 429 without Retry-After header — decorator should use 1*2^attempt.
145
151
  responses = [
146
- _mock_response(429),
152
+ _mock_response(429), # no Retry-After header
147
153
  _mock_response(429),
148
154
  _mock_response(200, json_body={"code": 1, "message": "success", "data": []}),
149
155
  ]
@@ -159,8 +165,37 @@ async def test_429_without_retry_after_falls_back_to_exponential_backoff(monkeyp
159
165
  await api._request("POST", "/whatever", json={"a": 1})
160
166
 
161
167
  sleeps = [call.args[0] for call in mock_sleep.await_args_list]
162
- # base=1.0, attempts 0 and 1 -> 1.0, 2.0
163
- assert sleeps == [1.0, 2.0]
168
+ assert len(sleeps) == 2
169
+ # Both sleeps should sit within ±20% of the 15s default (not the old 1s/2s).
170
+ lo = DEFAULT_RATE_LIMIT_RETRY_AFTER * 0.8
171
+ hi = DEFAULT_RATE_LIMIT_RETRY_AFTER * 1.2
172
+ assert lo <= sleeps[0] <= hi
173
+ assert lo <= sleeps[1] <= hi
174
+ # Sanity: definitely NOT the old short backoff.
175
+ assert sleeps[0] > 5
176
+ assert sleeps[1] > 5
177
+
178
+
179
+ @pytest.mark.asyncio
180
+ async def test_429_default_fallback_is_stored_on_exception(monkeypatch):
181
+ """After exhausting retries, the raised RateLimitError should carry the
182
+ fallback so callers can introspect it."""
183
+ api = _make_api(monkeypatch)
184
+
185
+ responses = [_mock_response(429)] * 4 # 1 + 3 retries, all 429 without header
186
+
187
+ with (
188
+ patch("lixinger.api.base.get_global_client") as mock_client_factory,
189
+ patch("lixinger.utils.retry.asyncio.sleep", new=AsyncMock()),
190
+ ):
191
+ client = Mock(spec=httpx.AsyncClient)
192
+ client.request = AsyncMock(side_effect=responses)
193
+ mock_client_factory.return_value = client
194
+
195
+ with pytest.raises(RateLimitError) as exc:
196
+ await api._request("POST", "/whatever", json={"a": 1})
197
+
198
+ assert exc.value.retry_after == DEFAULT_RATE_LIMIT_RETRY_AFTER
164
199
 
165
200
 
166
201
  @pytest.mark.asyncio
@@ -223,7 +258,7 @@ async def test_retry_decorator_uses_retry_after_attribute():
223
258
  super().__init__("boom")
224
259
  self.retry_after = 7.5
225
260
 
226
- @async_retry_on_failure(max_retries=2, backoff=1.0)
261
+ @async_retry_on_failure(max_retries=2, backoff=1.0, jitter=0)
227
262
  async def fn():
228
263
  nonlocal calls
229
264
  calls += 1
@@ -235,15 +270,72 @@ async def test_retry_decorator_uses_retry_after_attribute():
235
270
  assert await fn() == "ok"
236
271
 
237
272
  sleeps = [call.args[0] for call in mock_sleep.await_args_list]
273
+ # jitter=0 disables the ±20% wobble so we get exact values.
238
274
  assert sleeps == [7.5, 7.5]
239
275
 
240
276
 
277
+ # --- Plan B: jitter -------------------------------------------------------
278
+
279
+
280
+ @pytest.mark.asyncio
281
+ async def test_jitter_bounds_default_20_percent():
282
+ """With default jitter=0.2, every sleep lies within ±20% of the intended base."""
283
+ calls = 0
284
+ base = 10.0
285
+
286
+ class TransientError(Exception):
287
+ def __init__(self):
288
+ super().__init__("x")
289
+ self.retry_after = base
290
+
291
+ @async_retry_on_failure(max_retries=50, backoff=1.0) # default jitter=0.2
292
+ async def fn():
293
+ nonlocal calls
294
+ calls += 1
295
+ raise TransientError()
296
+
297
+ with (
298
+ patch("lixinger.utils.retry.asyncio.sleep", new=AsyncMock()) as mock_sleep,
299
+ pytest.raises(TransientError),
300
+ ):
301
+ await fn()
302
+
303
+ sleeps = [call.args[0] for call in mock_sleep.await_args_list]
304
+ assert len(sleeps) == 50 # 50 retries, 50 sleeps
305
+ for s in sleeps:
306
+ assert base * 0.8 <= s <= base * 1.2
307
+ # And with 50 samples we should actually see some spread (jitter isn't a no-op).
308
+ assert min(sleeps) < max(sleeps)
309
+
310
+
311
+ @pytest.mark.asyncio
312
+ async def test_jitter_zero_disables_wobble():
313
+ """jitter=0 should give deterministic sleeps — critical for tests and users
314
+ who explicitly opt out."""
315
+ calls = 0
316
+
317
+ @async_retry_on_failure(max_retries=2, backoff=1.0, jitter=0)
318
+ async def fn():
319
+ nonlocal calls
320
+ calls += 1
321
+ if calls < 3:
322
+ raise RuntimeError("boom")
323
+ return "ok"
324
+
325
+ with patch("lixinger.utils.retry.asyncio.sleep", new=AsyncMock()) as mock_sleep:
326
+ await fn()
327
+
328
+ sleeps = [call.args[0] for call in mock_sleep.await_args_list]
329
+ # Pure exponential backoff, no wobble.
330
+ assert sleeps == [1.0, 2.0]
331
+
332
+
241
333
  # Sanity: real asyncio.sleep still works when the decorator retries once.
242
334
  @pytest.mark.asyncio
243
335
  async def test_retry_decorator_actually_sleeps():
244
336
  calls = 0
245
337
 
246
- @async_retry_on_failure(max_retries=1, backoff=0.01)
338
+ @async_retry_on_failure(max_retries=1, backoff=0.01, jitter=0)
247
339
  async def fn():
248
340
  nonlocal calls
249
341
  calls += 1
@@ -629,7 +629,7 @@ wheels = [
629
629
 
630
630
  [[package]]
631
631
  name = "lixinger-python"
632
- version = "0.3.13"
632
+ version = "0.3.14"
633
633
  source = { editable = "." }
634
634
  dependencies = [
635
635
  { name = "httpx", extra = ["socks"] },