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.
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.claude/settings.local.json +5 -1
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/CHANGELOG.md +22 -1
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/PKG-INFO +1 -1
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/base.py +20 -2
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/retry.py +15 -4
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/pyproject.toml +1 -1
- lixinger_python-0.3.14/tests/test_no_data.py +126 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_retry.py +105 -13
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/uv.lock +1 -1
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.env.example +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.github/copilot-instructions.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.github/workflows/README.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.github/workflows/pr-checks.yml +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.gitignore +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.pre-commit-config.yaml +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.python-version +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/.ruff.toml +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/ADD_NEW_API_QUICK.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/ARCHITECTURE.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/CLAUDE.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/DOCUMENTATION.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/LICENSE +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/MANIFEST.in +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/PUBLISHING.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/README.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/codecov.yml +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/client.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/announcement.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/company.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/dividend.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/equity_change.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fs/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/insurance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/other_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/indices.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/profile.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/announcement.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/asset_combination.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/asset_industry_combination.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/fund.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/profile.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/shareholdings.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/constituent_weightings.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/constituents.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/drawdown.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/fundamental.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/index.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/index/tracking_fund.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/overview.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/development/code-style.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/development/contributing.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/development/testing.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/examples/company.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/examples/fund.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/examples/index.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/getting-started/configuration.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/getting-started/installation.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/getting-started/quickstart.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/index.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/company_example.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/company_profile_example.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/dividend_example.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/fs_example.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_constituent_weightings_example.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_constituents_example.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_info_example.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_margin_trading_example.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/announcement.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/company.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/dividend.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/equity_change.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/bank.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/insurance.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/non_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/other_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fs/security.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/bank.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/insurance.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/non_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/other_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/fundamental/security.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/indices.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/namespace.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/company/profile.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/announcement.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/asset_combination.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/asset_industry_combination.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/fund.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/profile.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/fund/shareholdings.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/constituent_weightings.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/constituents.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/drawdown.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/bank.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/hybrid.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/non_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fs/security.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/fundamental.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/index.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/margin_trading.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/namespace.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/index/tracking_fund.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/cni.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/sw.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/margin_trading/sw_2021.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/cn/industry/namespace.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/namespace.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/national_debt.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/rmb_deposits.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/rmb_loans.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/api/macro/social_financing.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/client.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/config.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/exceptions.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/announcement.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/company.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/dividend.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/equity_change.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/bank.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/insurance.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/non_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/other_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fs/security.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/bank.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/insurance.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/non_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/other_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/fundamental/security.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/company/indices.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/announcement.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/asset_combination.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/asset_industry_combination.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/fund.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/profile.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/fund/shareholdings.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/constituent_weightings.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/constituents.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/drawdown.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/bank.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/hybrid.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/non_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fs/security.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/fundamental.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/index.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/margin_trading.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/index/tracking_fund.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/cni.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/sw.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/cn/industry/margin_trading/sw_2021.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/national_debt.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/rmb_deposits.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/rmb_loans.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/models/macro/social_financing.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/py.typed +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/__init__.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/api.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/dataframe.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/dict.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger/utils/rate_limiter.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/REMINDER.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/allotment.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/announcement.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/block-deal.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/customers.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/dividend.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/equity-change.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/insurance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/other_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fs/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fund-collection-shareholders.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fund-shareholders.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/insurance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/other_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/fundamental/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/capita.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/df.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/elr.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/esc.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mm_ha.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mssc.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/mtasl.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/npd.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/ple.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/shnc.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/t_a.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/tr.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/hot/tr_dri.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/indices.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/industries.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/inquiry.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/major-shareholders-shares-change.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/majority-shareholders.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/margin-trading-and-securities-lending.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/measures.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/mutual-market.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/nolimit-shareholders.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/operating-data.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/operation-revenue-constitution.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/pledge.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/profile.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/senior-executive-shares-change.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/shareholders-num.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/suppliers.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/trading-abnormal.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company/volatility.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/company.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/announcement.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/asset-combination.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/asset-industry-combination.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/dividend.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/drawdown.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/fees.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/f_as.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/f_nlacan.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fet_s.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/ff.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fp.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fpr.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/hot/fss.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/manager.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/net-value-of-dividend-reinvestment.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/net-value.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/profile.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shareholders-structure.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shareholdings.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/shares.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/split.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/total-net-value.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/turnover-rate.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund/volatility.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/asset-scale.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/fund-list.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/fund-manager-list.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/hot/fc_as.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/hot/fc_asr.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company/shareholdings.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-company.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/hot/fmi.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/hot/fmp.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/management-funds.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/profit-ratio.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager/shareholdings.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund-manager.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/fund.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/constituent-weightings.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/constituents.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/drawdown.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/hybrid.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fs/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/fundamental.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/cp.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/ic.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/ifet_sni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/mm_ha.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/mtasl.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/tr.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/hot/tr_cp.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/margin-trading-and-securities-lending.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/mutual-market.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/tracking-fund.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index/volatility.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/index.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/cni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/sw.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/constituents/sw_2021.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/hybrid.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/insurance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/cni/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/hybrid.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/insurance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/hybrid.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/insurance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fs/sw_2021/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/cni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/sw.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/fundamental/sw_2021.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/cni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/sw.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mm_ha/sw_2021.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/cni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/sw.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/hot/mtasl/sw_2021.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/cni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/sw.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/margin-trading-and-securities-lending/sw_2021.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/cni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/sw.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry/mutual-market/sw_2021.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/cn/industry.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/allotment.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/announcement.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/dividend.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/employee.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/equity-change.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/insurance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/other_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/reit.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fs/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fund-collection-shareholders.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fund-shareholders.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/bank.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/insurance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/other_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/reit.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/fundamental/security.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/capita.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/director_equity_change.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/mm_ah.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/npd.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/rep.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/ss.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/ss_ha.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/tr.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/hot/tr_dri.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/indices.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/industries.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/latest-shareholders.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/mutual-market.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/operation-revenue-constitution.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/profile.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/repurchase.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/shareholders-equity-change.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/short-selling.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/split.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company/volatility.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/company.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/constituents.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/drawdown.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/fs/hybrid.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/fs/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/fundamental.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/cp.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/ic.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/ifet_sni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/hot/mm_ah.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/mutual-market.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/tracking-fund.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index/volatility.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/index.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/constituents/hsi.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fs/hsi/hybrid.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fs/hsi/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/fundamental/hsi.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/hot/mm_ah/hsi.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry/mutual-market/hsi.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/hk/industry.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/bop.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/central-bank-balance-sheet.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/credit-securities-account.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/crude-oil.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/currency-exchange-rate.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/domestic-debt-securities.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/domestic-trade.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/energy.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/foreign-assets.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/foreign-trade.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/gdp.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/gold-price.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/industrialization.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/interest-rates.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/investment-in-fixed-assets.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/investor.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/leverage-ratio.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/money-supply.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/national-debt.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/national-finance.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/natural-gas.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/non-ferrous-metals.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/official-reserve-assets.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/platinum-price.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/population.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/price-index.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/real-estate.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/required-reserves.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/rmb-deposits.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/rmb-loans.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/rmbidx.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/silver-price.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/social-financing.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/stamp-duty.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/traffic-transportation.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/unemployment-rate.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/usdx.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/macro/vix-fear-index.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/candlestick.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/constituents.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/drawdown.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/fs/non_financial.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/fundamental.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/hot/cp.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/hot/ifet_sni.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/tracking-fund.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index/volatility.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/lixinger-api/us/index.md +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/mkdocs.yml +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/mypy.ini +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/scripts/explore_api.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/scripts/generate_docs.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/scripts/publish.sh +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/api/cn/company/test_announcement.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/api/cn/company/test_dividend.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/api/cn/index/test_constituents.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/conftest.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_bank_statements.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_client.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_cn_index_candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_cn_index_constituent_weightings.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_company.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_company_profile.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_equity_change.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_announcement.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_asset_combination.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_asset_industry_combination.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_candlestick.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_profile.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fund_shareholdings.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fundamental.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fundamental_bank.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_fundamental_security.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_constituents.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_drawdown.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fs_bank.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fs_hybrid.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fs_non_financial.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fs_security.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_fundamental.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_index_margin_trading.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_indices.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_industry_margin_trading.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_insurance_statements.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_integration.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_macro.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_non_financial_statements.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_other_financial_statements.py +0 -0
- {lixinger_python-0.3.13 → lixinger_python-0.3.14}/tests/test_security_statements.py +0 -0
- {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.
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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
|
|
|
@@ -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
|
|
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
|
|
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 ==
|
|
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
|
|
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
|
-
|
|
163
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/non_financial.md
RENAMED
|
File without changes
|
{lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/company/fundamental/other_financial.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lixinger_python-0.3.13 → lixinger_python-0.3.14}/docs/api/fund/asset_industry_combination.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lixinger_python-0.3.13 → lixinger_python-0.3.14}/examples/index_constituent_weightings_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|