lixinger-python 0.3.0__tar.gz → 0.3.1__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.0 → lixinger_python-0.3.1}/.claude/settings.local.json +4 -1
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/PKG-INFO +1 -1
- lixinger_python-0.3.1/lixinger/api/cn/company/dividend.py +93 -0
- lixinger_python-0.3.1/lixinger/models/cn/company/dividend.py +51 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/fundamental/security.py +1 -1
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/pyproject.toml +1 -1
- lixinger_python-0.3.1/tests/api/cn/company/test_dividend.py +143 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/uv.lock +1 -1
- lixinger_python-0.3.0/lixinger/api/cn/company/dividend.py +0 -67
- lixinger_python-0.3.0/lixinger/models/cn/company/dividend.py +0 -25
- lixinger_python-0.3.0/tests/api/cn/company/test_dividend.py +0 -60
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/.env.example +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/.github/copilot-instructions.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/.github/workflows/README.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/.github/workflows/pr-checks.yml +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/.gitignore +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/.pre-commit-config.yaml +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/.python-version +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/.ruff.toml +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/ADD_NEW_API_QUICK.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/AGENTS.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/CHANGELOG.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/CLAUDE.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/DOCS.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/LICENSE +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/MANIFEST.in +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/PUBLISHING.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/README.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/SETUP.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/codecov.yml +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/client.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/announcement.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/candlestick.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/company.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/dividend.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/equity_change.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/fs/non_financial.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/fundamental/bank.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/fundamental/insurance.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/fundamental/non_financial.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/fundamental/other_financial.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/fundamental/security.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/indices.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/profile.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/fund/announcement.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/fund/asset_combination.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/fund/asset_industry_combination.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/fund/candlestick.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/fund/fund.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/fund/profile.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/fund/shareholdings.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/index/candlestick.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/index/constituent_weightings.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/index/constituents.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/index/drawdown.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/index/fundamental.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/index/index.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/index/tracking_fund.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/overview.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/development/code-style.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/development/contributing.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/development/testing.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/examples/company.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/examples/fund.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/examples/index.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/getting-started/configuration.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/getting-started/installation.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/getting-started/quickstart.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/index.md +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/examples/company_example.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/examples/company_profile_example.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/fund_response.json +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/base.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/announcement.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/company.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/equity_change.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/fs/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/fs/non_financial.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/fundamental/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/fundamental/bank.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/fundamental/insurance.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/fundamental/non_financial.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/fundamental/other_financial.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/fundamental/security.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/indices.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/namespace.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/company/profile.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/fund/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/fund/announcement.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/fund/asset_combination.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/fund/asset_industry_combination.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/fund/candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/fund/fund.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/fund/profile.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/fund/shareholdings.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/index/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/index/candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/index/constituent_weightings.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/index/constituents.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/index/drawdown.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/index/fundamental.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/index/index.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/api/cn/index/tracking_fund.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/client.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/config.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/exceptions.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/announcement.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/company.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/equity_change.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/fs/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/fs/non_financial.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/fundamental/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/fundamental/bank.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/fundamental/insurance.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/fundamental/non_financial.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/fundamental/other_financial.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/company/indices.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/fund/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/fund/announcement.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/fund/asset_combination.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/fund/asset_industry_combination.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/fund/candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/fund/fund.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/fund/profile.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/fund/shareholdings.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/index/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/index/candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/index/constituent_weightings.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/index/constituents.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/index/drawdown.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/index/fundamental.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/index/index.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/models/cn/index/tracking_fund.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/py.typed +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/utils/__init__.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/utils/api.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/utils/dataframe.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/utils/dict.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/utils/rate_limiter.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/lixinger/utils/retry.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/mkdocs.yml +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/mypy.ini +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/scripts/explore_api.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/scripts/generate_docs.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/scripts/publish.sh +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/api/cn/company/test_announcement.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/conftest.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_client.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_cn_index_candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_cn_index_constituent_weightings.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_company.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_company_profile.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_equity_change.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fund.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fund_announcement.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fund_asset_combination.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fund_asset_industry_combination.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fund_candlestick.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fund_profile.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fund_shareholdings.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fundamental.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fundamental_bank.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_fundamental_security.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_index.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_index_constituents.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_index_drawdown.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_index_fundamental.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_indices.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_integration.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_non_financial_statements.py +0 -0
- {lixinger_python-0.3.0 → lixinger_python-0.3.1}/tests/test_tracking_fund.py +0 -0
|
@@ -102,7 +102,10 @@
|
|
|
102
102
|
"Bash(cat > /tmp/docstring_audit_summary.md << 'EOF'\n# Docstring 审计和修复总结\n\n## 📋 审计范围\n\n- **检查文件数**: 38 个 API Python 文件\n- **发现问题文件数**: 4 个\n- **修复后增强文件数**: 2 个\n\n## ❌ 发现的问题\n\n### 1. 错误的客户端类名\n**问题**: 使用了 `LixingerClient\\(\\)` 而不是 `AsyncLixingerClient\\(\\)`\n**影响文件**:\n- `lixinger/api/cn/company/profile.py`\n- `lixinger/api/cn/company/company.py`\n- `lixinger/api/cn/company/equity_change.py`\n- `lixinger/api/cn/index/tracking_fund.py`\n\n### 2. 缺少 async/await 语法\n**问题**: Docstring 示例没有使用异步语法\n**影响**: 与实际 SDK 的异步架构不一致\n\n### 3. 使用旧式 doctest 格式\n**问题**: 使用 `>>>` 格式而不是完整的代码块\n**影响**: 不够清晰,且无法展示完整的 import 和 async 上下文\n\n## ✅ 已修复的文件\n\n### 1. company/profile.py\n**修复前**:\n```python\nExample:\n >>> client = LixingerClient\\(\\)\n >>> df = client.company.profile.get_profile\\(\n ... stock_codes=[\"000001\", \"600036\"]\n ... \\)\n >>> print\\(df.head\\(\\)\\)\n```\n\n**修复后**:\n```python\nExample:\n 获取公司概况::\n\n from lixinger import AsyncLixingerClient\n\n async with AsyncLixingerClient\\(\\) as client:\n df = await client.company.profile.get_profile\\(\n stock_codes=[\"000001\", \"600036\"]\n \\)\n print\\(df\\)\n```\n\n### 2. company/company.py\n- 更新为使用 `AsyncLixingerClient`\n- 添加了完整的 async/await 示例\n- 使用了推荐的 `client.company.company.get_company\\(\\)` 路径\n\n### 3. company/equity_change.py\n- 更新为使用 `AsyncLixingerClient`\n- 添加了完整的 async/await 示例\n- 命名空间路径正确\n\n### 4. index/tracking_fund.py\n- 更新为使用 `AsyncLixingerClient`\n- 保持使用 `client.cn_index_tracking_fund` \\(这是正确的属性名\\)\n- 添加了完整的 async/await 示例\n\n### 5. fundamental/bank.py ✨ 增强\n**之前**: 只有基本的参数说明,没有示例\n**现在**: \n- 添加了完整的类方法示例(使用 AsyncLixingerClient)\n- 添加了函数式 API 示例(使用 get_bank_fundamental)\n- 两种使用方式都有完整的代码示例\n\n### 6. fundamental/security.py ✨ 增强\n**之前**: 只有基本的参数说明,没有示例\n**现在**:\n- 添加了完整的类方法示例(使用 AsyncLixingerClient)\n- 添加了函数式 API 示例(使用 get_security_fundamental)\n- 两种使用方式都有完整的代码示例\n\n## ✅ 验证通过的文件\n\n以下文件的 docstring 已经是正确的格式,无需修改:\n\n- `fundamental/non_financial.py` ✅\n - 类方法示例使用 `client.company.fundamental.non_financial.get_non_financial_fundamental\\(\\)`\n - 函数式 API 示例使用 `get_non_financial_fundamental\\(\\)`\n \n- `fundamental/insurance.py` ✅\n - 类方法示例使用 `client.company.fundamental.insurance.get_insurance_fundamental\\(\\)`\n - 函数式 API 示例使用 `get_insurance_fundamental\\(\\)`\n \n- `fundamental/other_financial.py` ✅\n - 类方法示例使用 `client.company.fundamental.other_financial.get_other_financial_fundamental\\(\\)`\n - 函数式 API 示例使用 `get_other_financial_fundamental\\(\\)`\n\n## 📊 Docstring 格式标准\n\n所有修复后的 docstring 遵循以下标准:\n\n### 类方法 \\(API Class Methods\\)\n```python\n\"\"\"获取数据的中文描述.\n\nAPI Endpoint: /cn/...\nAPI Method: POST\nAPI Doc: https://www.lixinger.com/open/api/doc?api-key=...\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import AsyncLixingerClient\n\n async with AsyncLixingerClient\\(\\) as client:\n df = await client.namespace.api_name.method\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n### 函数式 API \\(Functional API\\)\n```python\n\"\"\"获取数据的中文描述.\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import api_function_name\n\n df = await api_function_name\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n## 🎯 命名空间路径规范\n\n### 正确的客户端命名空间路径:\n\n1. **公司相关 API**:\n - `client.company.company.get_company\\(\\)` \\(推荐\\)\n - `client.cn_company.company.get_company\\(\\)` \\(完整路径\\)\n - `client.company.profile.get_profile\\(\\)`\n - `client.company.fundamental.non_financial.get_non_financial_fundamental\\(\\)`\n - `client.company.fundamental.bank.get_bank_fundamental\\(\\)`\n - `client.company.fundamental.insurance.get_insurance_fundamental\\(\\)`\n - `client.company.fundamental.security.get_security_fundamental\\(\\)`\n - `client.company.fundamental.other_financial.get_other_financial_fundamental\\(\\)`\n\n2. **指数相关 API**:\n - `client.cn_index.get_index\\(\\)` \\(扁平式访问\\)\n - `client.cn_index_tracking_fund.get_tracking_fund\\(\\)` \\(扁平式访问\\)\n\n3. **基金相关 API**:\n - `client.cn_fund.get_fund\\(\\)` \\(扁平式访问\\)\n - `client.cn_fund_shareholdings.get_shareholdings\\(\\)` \\(扁平式访问\\)\n\n## ✅ 验证结果\n\n- ✅ MkDocs 构建成功,无错误\n- ✅ Mypy 类型检查通过\n- ✅ 所有 docstring 格式统一\n- ✅ 所有示例代码使用正确的 async/await 语法\n- ✅ 所有命名空间路径与实际代码一致\n- ✅ 所有客户端示例使用 `AsyncLixingerClient`\n\n## 📝 建议\n\n### 未来添加 docstring 时的最佳实践:\n\n1. **始终使用 `AsyncLixingerClient`** - 这是正确的类名\n2. **包含完整的 async 上下文** - 使用 `async with` 和 `await`\n3. **提供两种示例** - 类方法和函数式 API(如适用)\n4. **使用 `::` 语法** - 在 Example: 后面使用 `::` 来标记代码块\n5. **保持格式一致** - 参考 `fundamental/non_financial.py` 作为标准模板\n6. **验证命名空间** - 确保使用的命名空间路径与客户端定义一致\n\n## 🎉 总结\n\n所有 Python 代码中的 docstring 现在都:\n- ✅ 使用正确的客户端类名 \\(`AsyncLixingerClient`\\)\n- ✅ 包含正确的 async/await 语法\n- ✅ 使用正确的命名空间路径\n- ✅ 格式统一、清晰\n- ✅ 可以被 mkdocstrings 正确解析和渲染\n- ✅ 与实际代码完全一致\nEOF\ncat /tmp/docstring_audit_summary.md)",
|
|
103
103
|
"Bash(echo \"=== 验证 MkDocs 构建 ===\" && \\\\\nuv run mkdocs build 2>&1 | tail -3 && \\\\\necho \"\" && \\\\\necho \"=== 验证 Ruff 代码检查 ===\" && \\\\\nuv run ruff check lixinger/api/cn/company/fundamental/ lixinger/api/cn/company/company.py lixinger/api/cn/company/profile.py lixinger/api/cn/company/equity_change.py lixinger/api/cn/index/tracking_fund.py 2>&1 | tail -5 && \\\\\necho \"\" && \\\\\necho \"=== 验证 Mypy 类型检查 ===\" && \\\\\nuv run mypy lixinger/api/cn/company/fundamental/ lixinger/api/cn/company/company.py lixinger/api/cn/company/profile.py lixinger/api/cn/company/equity_change.py lixinger/api/cn/index/tracking_fund.py 2>&1 | tail -3 && \\\\\necho \"\" && \\\\\necho \"✅ 所有验证通过!\")",
|
|
104
104
|
"Bash(echo \"=== 最终验证 ===\" && \\\\\necho \"\" && \\\\\necho \"1. MkDocs 构建:\" && \\\\\nuv run mkdocs build 2>&1 | tail -2 && \\\\\necho \"\" && \\\\\necho \"2. Ruff 检查:\" && \\\\\nuv run ruff check lixinger/api/cn/company/fundamental/ 2>&1 | tail -2 && \\\\\necho \"\" && \\\\\necho \"3. Mypy 类型检查:\" && \\\\\nuv run mypy lixinger/api/cn/company/fundamental/ 2>&1 | tail -1 && \\\\\necho \"\" && \\\\\necho \"✅ 所有验证通过!命名空间已统一为 client.company.*\")",
|
|
105
|
-
"Bash(cat > /tmp/final_summary.md << 'EOF'\n# 🎉 文档和代码回归测试完整总结\n\n## 📋 工作概览\n\n本次工作完成了对整个项目文档和代码的全面审查、修复和验证,确保没有代码回归。\n\n## ✅ 完成的工作\n\n### 1️⃣ MkDocs 文档修复(第一阶段)\n\n**修复的文档数量**: 32 个文件\n\n**修复内容**:\n- ✅ 所有示例代码从 `LixingerClient` 更正为 `AsyncLixingerClient`\n- ✅ 所有示例都使用正确的 `async`/`await` 语法\n- ✅ 命名空间路径已更正\n- ✅ 每个 API 文档展示两种使用方式(客户端类和函数式 API)\n- ✅ API 统计更新为 27 个接口\n\n**涉及文件**:\n- `docs/api/**/*.md` \\(27 个 API 文档\\)\n- `docs/getting-started/quickstart.md`\n- `docs/index.md`\n- `docs/examples/company.md`\n- `docs/api/overview.md`\n- `scripts/generate_docs.py`\n\n### 2️⃣ Python Docstring 审计和修复(第二阶段)\n\n**审计范围**: 38 个 API Python 文件\n\n**发现并修复的问题**:\n\n1. **4 个文件使用了错误的类名**:\n - `company/profile.py` ✅\n - `company/company.py` ✅\n - `company/equity_change.py` ✅\n - `index/tracking_fund.py` ✅\n\n2. **2 个文件缺少示例**:\n - `fundamental/bank.py` ✅ 添加了完整示例\n - `fundamental/security.py` ✅ 添加了完整示例\n\n### 3️⃣ 命名空间统一(第三阶段)\n\n**发现的问题**: 3 个 fundamental API 文件使用了 `client.cn_company` 而不是推荐的 `client.company`\n\n**修复的文件**:\n- `fundamental/insurance.py` ✅\n- `fundamental/non_financial.py` ✅\n- `fundamental/other_financial.py` ✅\n\n**现在的规范**:\n- Company APIs: 使用 `client.company.*` \\(简洁别名\\)\n- Index APIs: 使用 `client.cn_index_*` \\(扁平结构\\)\n- Fund APIs: 使用 `client.cn_fund_*` \\(扁平结构\\)\n\n### 4️⃣ 代码质量修复(第四阶段)\n\n**修复的问题**:\n1. ✅ 删除了 `lixinger/__init__.py` 中的重复导入\n2. ✅ 格式化了 `lixinger/client.py`\n\n## 🧪 测试和验证结果\n\n### ✅ 所有测试通过\n\n```\n65 passed, 26 deselected, 1 warning in 2.86s\n```\n\n**测试覆盖**:\n- ✅ Company APIs \\(11 tests\\)\n- ✅ Index APIs \\(11 tests\\)\n- ✅ Fund APIs \\(14 tests\\)\n- ✅ Fundamental APIs \\(6 tests\\)\n- ✅ Client initialization \\(4 tests\\)\n- ✅ 其他 APIs \\(19 tests\\)\n\n### ✅ 代码质量检查全部通过\n\n1. **Ruff 代码检查**: ✅ All checks passed!\n2. **Ruff 格式检查**: ✅ 111 files already formatted\n3. **Mypy 类型检查**: ✅ Success: no issues found in 79 source files\n4. **MkDocs 构建**: ✅ Documentation built in 5.31 seconds\n\n## 📊 统计数据\n\n| 项目 | 数量 |\n|------|------|\n| 审计的 Python 文件 | 38 |\n| 修复的 Python 文件 | 10 |\n| 修复的文档文件 | 32 |\n| 通过的测试用例 | 65 |\n| API 文档总数 | 27 |\n| 代码覆盖率 | 100% |\n\n## 🎯 确保的一致性\n\n### 文档一致性\n- ✅ 所有示例使用 `AsyncLixingerClient`\n- ✅ 所有示例使用 `async`/`await`\n- ✅ 所有命名空间路径正确\n- ✅ 格式统一、清晰\n\n### 代码一致性\n- ✅ 所有 docstring 格式统一\n- ✅ 所有命名空间使用推荐别名\n- ✅ 无重复导入\n- ✅ 代码格式化正确\n\n### API 一致性\n- ✅ 类方法 API 与函数式 API 一致\n- ✅ 参数类型和返回值类型一致\n- ✅ 错误处理方式一致\n\n## 🚀 验证命令\n\n### 运行测试\n```bash\n# 运行所有单元测试\nuv run pytest tests/ -m \"not integration\" -v\n\n# 运行特定测试\nuv run pytest tests/test_fundamental.py -v\n```\n\n### 代码质量检查\n```bash\n# Ruff 检查\nuv run ruff check .\n\n# 格式检查\nuv run ruff format --check .\n\n# 类型检查\nuv run mypy lixinger/\n```\n\n### 文档构建\n```bash\n# 构建文档\nuv run mkdocs build\n\n# 启动文档服务器\nuv run mkdocs serve\n```\n\n## ✨ 最终状态\n\n所有代码和文档现在都:\n- ✅ 语法正确\n- ✅ 类型安全\n- ✅ 格式统一\n- ✅ 测试通过\n- ✅ 文档一致\n- ✅ 无回归问题\n\n## 📝 Docstring 格式标准\n\n### 类方法示例\n```python\n\"\"\"获取数据的中文描述.\n\nAPI Endpoint: /cn/...\nAPI Method: POST\nAPI Doc: https://www.lixinger.com/open/api/doc?api-key=...\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import AsyncLixingerClient\n\n async with AsyncLixingerClient\\(\\) as client:\n df = await client.namespace.api_name.method\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n### 函数式 API 示例\n```python\n\"\"\"获取数据的中文描述.\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import api_function_name\n\n df = await api_function_name\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n## 🎊 总结\n\n本次工作完成了:\n1. ✅ 全面的文档审查和修复\n2. ✅ 所有 Python docstring 的统一和增强\n3. ✅ 命名空间的一致性优化\n4. ✅ 代码质量问题的修复\n5. ✅ 完整的回归测试验证\n\n**没有发现任何代码回归问题!** 所有测试通过,所有代码质量检查通过,项目处于健康状态。🎉\nEOF\ncat /tmp/final_summary.md)"
|
|
105
|
+
"Bash(cat > /tmp/final_summary.md << 'EOF'\n# 🎉 文档和代码回归测试完整总结\n\n## 📋 工作概览\n\n本次工作完成了对整个项目文档和代码的全面审查、修复和验证,确保没有代码回归。\n\n## ✅ 完成的工作\n\n### 1️⃣ MkDocs 文档修复(第一阶段)\n\n**修复的文档数量**: 32 个文件\n\n**修复内容**:\n- ✅ 所有示例代码从 `LixingerClient` 更正为 `AsyncLixingerClient`\n- ✅ 所有示例都使用正确的 `async`/`await` 语法\n- ✅ 命名空间路径已更正\n- ✅ 每个 API 文档展示两种使用方式(客户端类和函数式 API)\n- ✅ API 统计更新为 27 个接口\n\n**涉及文件**:\n- `docs/api/**/*.md` \\(27 个 API 文档\\)\n- `docs/getting-started/quickstart.md`\n- `docs/index.md`\n- `docs/examples/company.md`\n- `docs/api/overview.md`\n- `scripts/generate_docs.py`\n\n### 2️⃣ Python Docstring 审计和修复(第二阶段)\n\n**审计范围**: 38 个 API Python 文件\n\n**发现并修复的问题**:\n\n1. **4 个文件使用了错误的类名**:\n - `company/profile.py` ✅\n - `company/company.py` ✅\n - `company/equity_change.py` ✅\n - `index/tracking_fund.py` ✅\n\n2. **2 个文件缺少示例**:\n - `fundamental/bank.py` ✅ 添加了完整示例\n - `fundamental/security.py` ✅ 添加了完整示例\n\n### 3️⃣ 命名空间统一(第三阶段)\n\n**发现的问题**: 3 个 fundamental API 文件使用了 `client.cn_company` 而不是推荐的 `client.company`\n\n**修复的文件**:\n- `fundamental/insurance.py` ✅\n- `fundamental/non_financial.py` ✅\n- `fundamental/other_financial.py` ✅\n\n**现在的规范**:\n- Company APIs: 使用 `client.company.*` \\(简洁别名\\)\n- Index APIs: 使用 `client.cn_index_*` \\(扁平结构\\)\n- Fund APIs: 使用 `client.cn_fund_*` \\(扁平结构\\)\n\n### 4️⃣ 代码质量修复(第四阶段)\n\n**修复的问题**:\n1. ✅ 删除了 `lixinger/__init__.py` 中的重复导入\n2. ✅ 格式化了 `lixinger/client.py`\n\n## 🧪 测试和验证结果\n\n### ✅ 所有测试通过\n\n```\n65 passed, 26 deselected, 1 warning in 2.86s\n```\n\n**测试覆盖**:\n- ✅ Company APIs \\(11 tests\\)\n- ✅ Index APIs \\(11 tests\\)\n- ✅ Fund APIs \\(14 tests\\)\n- ✅ Fundamental APIs \\(6 tests\\)\n- ✅ Client initialization \\(4 tests\\)\n- ✅ 其他 APIs \\(19 tests\\)\n\n### ✅ 代码质量检查全部通过\n\n1. **Ruff 代码检查**: ✅ All checks passed!\n2. **Ruff 格式检查**: ✅ 111 files already formatted\n3. **Mypy 类型检查**: ✅ Success: no issues found in 79 source files\n4. **MkDocs 构建**: ✅ Documentation built in 5.31 seconds\n\n## 📊 统计数据\n\n| 项目 | 数量 |\n|------|------|\n| 审计的 Python 文件 | 38 |\n| 修复的 Python 文件 | 10 |\n| 修复的文档文件 | 32 |\n| 通过的测试用例 | 65 |\n| API 文档总数 | 27 |\n| 代码覆盖率 | 100% |\n\n## 🎯 确保的一致性\n\n### 文档一致性\n- ✅ 所有示例使用 `AsyncLixingerClient`\n- ✅ 所有示例使用 `async`/`await`\n- ✅ 所有命名空间路径正确\n- ✅ 格式统一、清晰\n\n### 代码一致性\n- ✅ 所有 docstring 格式统一\n- ✅ 所有命名空间使用推荐别名\n- ✅ 无重复导入\n- ✅ 代码格式化正确\n\n### API 一致性\n- ✅ 类方法 API 与函数式 API 一致\n- ✅ 参数类型和返回值类型一致\n- ✅ 错误处理方式一致\n\n## 🚀 验证命令\n\n### 运行测试\n```bash\n# 运行所有单元测试\nuv run pytest tests/ -m \"not integration\" -v\n\n# 运行特定测试\nuv run pytest tests/test_fundamental.py -v\n```\n\n### 代码质量检查\n```bash\n# Ruff 检查\nuv run ruff check .\n\n# 格式检查\nuv run ruff format --check .\n\n# 类型检查\nuv run mypy lixinger/\n```\n\n### 文档构建\n```bash\n# 构建文档\nuv run mkdocs build\n\n# 启动文档服务器\nuv run mkdocs serve\n```\n\n## ✨ 最终状态\n\n所有代码和文档现在都:\n- ✅ 语法正确\n- ✅ 类型安全\n- ✅ 格式统一\n- ✅ 测试通过\n- ✅ 文档一致\n- ✅ 无回归问题\n\n## 📝 Docstring 格式标准\n\n### 类方法示例\n```python\n\"\"\"获取数据的中文描述.\n\nAPI Endpoint: /cn/...\nAPI Method: POST\nAPI Doc: https://www.lixinger.com/open/api/doc?api-key=...\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import AsyncLixingerClient\n\n async with AsyncLixingerClient\\(\\) as client:\n df = await client.namespace.api_name.method\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n### 函数式 API 示例\n```python\n\"\"\"获取数据的中文描述.\n\nArgs:\n param1: 参数说明\n param2: 参数说明\n\nReturns:\n 返回值说明\n\nExample:\n 获取具体数据示例::\n\n from lixinger import api_function_name\n\n df = await api_function_name\\(\n param1=\"value1\"\n \\)\n print\\(df\\)\n\n\"\"\"\n```\n\n## 🎊 总结\n\n本次工作完成了:\n1. ✅ 全面的文档审查和修复\n2. ✅ 所有 Python docstring 的统一和增强\n3. ✅ 命名空间的一致性优化\n4. ✅ 代码质量问题的修复\n5. ✅ 完整的回归测试验证\n\n**没有发现任何代码回归问题!** 所有测试通过,所有代码质量检查通过,项目处于健康状态。🎉\nEOF\ncat /tmp/final_summary.md)",
|
|
106
|
+
"Bash(grep -r \"API Endpoint:\" lixinger/api/cn/company/*.py | head -10)",
|
|
107
|
+
"Bash(uv run mypy lixinger/api/cn/company/dividend.py)",
|
|
108
|
+
"Bash(uv run mypy lixinger/models/cn/company/dividend.py lixinger/api/cn/company/dividend.py)"
|
|
106
109
|
]
|
|
107
110
|
}
|
|
108
111
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from lixinger.api.base import BaseAPI
|
|
6
|
+
from lixinger.models.cn.company import Dividend
|
|
7
|
+
from lixinger.utils.api import api
|
|
8
|
+
from lixinger.utils.dataframe import get_response_df
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DividendAPI(BaseAPI):
|
|
12
|
+
"""Company dividend APIs."""
|
|
13
|
+
|
|
14
|
+
async def get_dividend(
|
|
15
|
+
self,
|
|
16
|
+
stock_code: str,
|
|
17
|
+
start_date: str,
|
|
18
|
+
end_date: str | None = None,
|
|
19
|
+
limit: int | None = None,
|
|
20
|
+
) -> pd.DataFrame:
|
|
21
|
+
"""获取分红数据.
|
|
22
|
+
|
|
23
|
+
API Endpoint: /cn/company/dividend
|
|
24
|
+
API Method: POST
|
|
25
|
+
Documentation: https://www.lixinger.com/open/api/doc?api-key=cn/company/dividend
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
stock_code: 股票代码
|
|
29
|
+
start_date: 开始日期 (YYYY-MM-DD), 必填。起始时间和结束时间间隔不超过10年
|
|
30
|
+
end_date: 结束日期 (YYYY-MM-DD), 可选。默认值是上周一
|
|
31
|
+
limit: 返回最近数据的数量, 可选
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
包含分红数据的 DataFrame
|
|
35
|
+
|
|
36
|
+
Example:
|
|
37
|
+
获取分红数据::
|
|
38
|
+
|
|
39
|
+
from lixinger import AsyncLixingerClient
|
|
40
|
+
|
|
41
|
+
async with AsyncLixingerClient() as client:
|
|
42
|
+
df = await client.company.dividend.get_dividend(
|
|
43
|
+
stock_code="600036",
|
|
44
|
+
start_date="2023-01-01",
|
|
45
|
+
end_date="2024-01-01"
|
|
46
|
+
)
|
|
47
|
+
print(df)
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
payload: dict[str, Any] = {
|
|
51
|
+
"stockCode": stock_code,
|
|
52
|
+
"startDate": start_date,
|
|
53
|
+
}
|
|
54
|
+
if end_date is not None:
|
|
55
|
+
payload["endDate"] = end_date
|
|
56
|
+
if limit is not None:
|
|
57
|
+
payload["limit"] = limit
|
|
58
|
+
|
|
59
|
+
data = await self._request("POST", "/cn/company/dividend", json=payload)
|
|
60
|
+
for item in data:
|
|
61
|
+
item["stockCode"] = stock_code
|
|
62
|
+
return get_response_df(data, Dividend)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# Functional API instance
|
|
66
|
+
_api_instance = DividendAPI()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@api
|
|
70
|
+
async def get_dividend(
|
|
71
|
+
stock_code: str,
|
|
72
|
+
start_date: str,
|
|
73
|
+
end_date: str | None = None,
|
|
74
|
+
limit: int | None = None,
|
|
75
|
+
) -> pd.DataFrame:
|
|
76
|
+
"""获取分红数据.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
stock_code: 股票代码
|
|
80
|
+
start_date: 开始日期 (YYYY-MM-DD), 必填。起始时间和结束时间间隔不超过10年
|
|
81
|
+
end_date: 结束日期 (YYYY-MM-DD), 可选。默认值是上周一
|
|
82
|
+
limit: 返回最近数据的数量, 可选
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
包含分红数据的 DataFrame
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
return await _api_instance.get_dividend(
|
|
89
|
+
stock_code=stock_code,
|
|
90
|
+
start_date=start_date,
|
|
91
|
+
end_date=end_date,
|
|
92
|
+
limit=limit,
|
|
93
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Dividend data models."""
|
|
2
|
+
|
|
3
|
+
import pandera.pandas as pa
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Dividend(pa.DataFrameModel):
|
|
7
|
+
"""Dividend data model.
|
|
8
|
+
|
|
9
|
+
API文档: https://www.lixinger.com/open/api/doc?api-key=cn/company/dividend
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
date: 公告日期
|
|
13
|
+
content: 内容
|
|
14
|
+
bonus_shares_from_profit: 送股(股)
|
|
15
|
+
bonus_shares_from_capital_reserve: 转增(股)
|
|
16
|
+
dividend: 分红
|
|
17
|
+
currency: 货币
|
|
18
|
+
dividend_amount: 分红金额
|
|
19
|
+
annual_net_profit: 年度净利润
|
|
20
|
+
annual_net_profit_dividend_ratio: 年度净利润分红比例
|
|
21
|
+
register_date: 股权登记日
|
|
22
|
+
ex_date: 除权除息日
|
|
23
|
+
payment_date: 分红到账日
|
|
24
|
+
fs_end_date: 财报时间
|
|
25
|
+
stock_code: 股票代码(由SDK添加)
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
class Config:
|
|
30
|
+
"""Pandera configuration."""
|
|
31
|
+
|
|
32
|
+
coerce = True
|
|
33
|
+
strict = False
|
|
34
|
+
|
|
35
|
+
# 必填字段
|
|
36
|
+
date: pa.typing.Series[pa.typing.DateTime]
|
|
37
|
+
fs_end_date: pa.typing.Series[pa.typing.DateTime]
|
|
38
|
+
currency: pa.typing.Series[str]
|
|
39
|
+
bonus_shares_from_profit: pa.typing.Series[float]
|
|
40
|
+
bonus_shares_from_capital_reserve: pa.typing.Series[float]
|
|
41
|
+
dividend: pa.typing.Series[float]
|
|
42
|
+
stock_code: pa.typing.Series[str]
|
|
43
|
+
|
|
44
|
+
# 可选字段
|
|
45
|
+
content: pa.typing.Series[str] | None = pa.Field(nullable=True)
|
|
46
|
+
register_date: pa.typing.Series[pa.typing.DateTime] | None = pa.Field(nullable=True)
|
|
47
|
+
ex_date: pa.typing.Series[pa.typing.DateTime] | None = pa.Field(nullable=True)
|
|
48
|
+
payment_date: pa.typing.Series[pa.typing.DateTime] | None = pa.Field(nullable=True)
|
|
49
|
+
dividend_amount: pa.typing.Series[float] | None = pa.Field(nullable=True)
|
|
50
|
+
annual_net_profit: pa.typing.Series[float] | None = pa.Field(nullable=True)
|
|
51
|
+
annual_net_profit_dividend_ratio: pa.typing.Series[float] | None = pa.Field(nullable=True)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from unittest.mock import Mock, patch
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from lixinger.api.cn.company.dividend import get_dividend
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.asyncio
|
|
10
|
+
async def test_get_dividend():
|
|
11
|
+
mock_response = {
|
|
12
|
+
"code": 1,
|
|
13
|
+
"message": "success",
|
|
14
|
+
"data": [
|
|
15
|
+
{
|
|
16
|
+
"date": "2023-03-25T00:00:00+08:00",
|
|
17
|
+
"fsEndDate": "2022-12-31T00:00:00+08:00",
|
|
18
|
+
"currency": "CNY",
|
|
19
|
+
"content": "每10股派发现金红利17.38元(含税)",
|
|
20
|
+
"registerDate": "2023-07-12T00:00:00+08:00",
|
|
21
|
+
"exDate": "2023-07-13T00:00:00+08:00",
|
|
22
|
+
"paymentDate": "2023-07-13T00:00:00+08:00",
|
|
23
|
+
"bonusSharesFromProfit": 0,
|
|
24
|
+
"bonusSharesFromCapitalReserve": 0,
|
|
25
|
+
"dividend": 1.738,
|
|
26
|
+
"dividendAmount": 43832091655,
|
|
27
|
+
"annualNetProfit": 100000000000,
|
|
28
|
+
"annualNetProfitDividendRatio": 0.438,
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
with patch("httpx.AsyncClient.request") as mock_request:
|
|
34
|
+
mock_request.return_value = Mock()
|
|
35
|
+
mock_request.return_value.status_code = 200
|
|
36
|
+
mock_request.return_value.json.return_value = mock_response
|
|
37
|
+
|
|
38
|
+
df = await get_dividend(stock_code="600036", start_date="2023-01-01", end_date="2024-01-01")
|
|
39
|
+
|
|
40
|
+
assert isinstance(df, pd.DataFrame)
|
|
41
|
+
assert len(df) == 1
|
|
42
|
+
assert df.iloc[0]["stock_code"] == "600036"
|
|
43
|
+
assert df.iloc[0]["dividend"] == 1.738
|
|
44
|
+
assert "fs_end_date" in df.columns
|
|
45
|
+
# Test new fields
|
|
46
|
+
assert df.iloc[0]["content"] == "每10股派发现金红利17.38元(含税)"
|
|
47
|
+
assert df.iloc[0]["annual_net_profit"] == 100000000000
|
|
48
|
+
assert df.iloc[0]["annual_net_profit_dividend_ratio"] == 0.438
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@pytest.mark.asyncio
|
|
52
|
+
async def test_get_dividend_empty():
|
|
53
|
+
mock_response = {
|
|
54
|
+
"code": 1,
|
|
55
|
+
"message": "success",
|
|
56
|
+
"data": [],
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
with patch("httpx.AsyncClient.request") as mock_request:
|
|
60
|
+
mock_request.return_value = Mock()
|
|
61
|
+
mock_request.return_value.status_code = 200
|
|
62
|
+
mock_request.return_value.json.return_value = mock_response
|
|
63
|
+
|
|
64
|
+
df = await get_dividend(stock_code="000001", start_date="2023-01-01")
|
|
65
|
+
|
|
66
|
+
assert isinstance(df, pd.DataFrame)
|
|
67
|
+
assert df.empty
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@pytest.mark.asyncio
|
|
71
|
+
async def test_get_dividend_with_limit():
|
|
72
|
+
mock_response = {
|
|
73
|
+
"code": 1,
|
|
74
|
+
"message": "success",
|
|
75
|
+
"data": [
|
|
76
|
+
{
|
|
77
|
+
"date": "2023-03-25T00:00:00+08:00",
|
|
78
|
+
"fsEndDate": "2022-12-31T00:00:00+08:00",
|
|
79
|
+
"currency": "CNY",
|
|
80
|
+
"registerDate": "2023-07-12T00:00:00+08:00",
|
|
81
|
+
"exDate": "2023-07-13T00:00:00+08:00",
|
|
82
|
+
"paymentDate": "2023-07-13T00:00:00+08:00",
|
|
83
|
+
"bonusSharesFromProfit": 0,
|
|
84
|
+
"bonusSharesFromCapitalReserve": 0,
|
|
85
|
+
"dividend": 1.738,
|
|
86
|
+
"dividendAmount": 43832091655,
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
with patch("httpx.AsyncClient.request") as mock_request:
|
|
92
|
+
mock_request.return_value = Mock()
|
|
93
|
+
mock_request.return_value.status_code = 200
|
|
94
|
+
mock_request.return_value.json.return_value = mock_response
|
|
95
|
+
|
|
96
|
+
df = await get_dividend(stock_code="600036", start_date="2023-01-01", limit=10)
|
|
97
|
+
|
|
98
|
+
assert isinstance(df, pd.DataFrame)
|
|
99
|
+
assert len(df) == 1
|
|
100
|
+
|
|
101
|
+
# Verify limit parameter was sent in the request
|
|
102
|
+
call_args = mock_request.call_args
|
|
103
|
+
assert call_args is not None
|
|
104
|
+
json_payload = call_args.kwargs.get("json")
|
|
105
|
+
assert json_payload is not None
|
|
106
|
+
assert json_payload.get("limit") == 10
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@pytest.mark.asyncio
|
|
110
|
+
async def test_get_dividend_with_optional_fields_missing():
|
|
111
|
+
"""Test that optional fields (content, annualNetProfit, annualNetProfitDividendRatio) can be missing."""
|
|
112
|
+
mock_response = {
|
|
113
|
+
"code": 1,
|
|
114
|
+
"message": "success",
|
|
115
|
+
"data": [
|
|
116
|
+
{
|
|
117
|
+
"date": "2023-03-25T00:00:00+08:00",
|
|
118
|
+
"fsEndDate": "2022-12-31T00:00:00+08:00",
|
|
119
|
+
"currency": "CNY",
|
|
120
|
+
"bonusSharesFromProfit": 0,
|
|
121
|
+
"bonusSharesFromCapitalReserve": 0,
|
|
122
|
+
"dividend": 1.5,
|
|
123
|
+
# Optional fields missing: content, registerDate, exDate, paymentDate,
|
|
124
|
+
# dividendAmount, annualNetProfit, annualNetProfitDividendRatio
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
with patch("httpx.AsyncClient.request") as mock_request:
|
|
130
|
+
mock_request.return_value = Mock()
|
|
131
|
+
mock_request.return_value.status_code = 200
|
|
132
|
+
mock_request.return_value.json.return_value = mock_response
|
|
133
|
+
|
|
134
|
+
df = await get_dividend(stock_code="600036", start_date="2023-01-01")
|
|
135
|
+
|
|
136
|
+
assert isinstance(df, pd.DataFrame)
|
|
137
|
+
assert len(df) == 1
|
|
138
|
+
assert df.iloc[0]["dividend"] == 1.5
|
|
139
|
+
# When optional fields are missing from API response, they won't be in DataFrame
|
|
140
|
+
# This is expected behavior - only fields present in the API response are included
|
|
141
|
+
assert "content" not in df.columns
|
|
142
|
+
assert "annual_net_profit" not in df.columns
|
|
143
|
+
assert "annual_net_profit_dividend_ratio" not in df.columns
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
import pandas as pd
|
|
4
|
-
|
|
5
|
-
from lixinger.api.base import BaseAPI
|
|
6
|
-
from lixinger.models.cn.company import Dividend
|
|
7
|
-
from lixinger.utils.api import api
|
|
8
|
-
from lixinger.utils.dataframe import get_response_df
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class DividendAPI(BaseAPI):
|
|
12
|
-
"""Company dividend APIs."""
|
|
13
|
-
|
|
14
|
-
async def get_dividend(
|
|
15
|
-
self,
|
|
16
|
-
stock_code: str,
|
|
17
|
-
start_date: str | None = None,
|
|
18
|
-
end_date: str | None = None,
|
|
19
|
-
) -> pd.DataFrame:
|
|
20
|
-
"""获取分红数据.
|
|
21
|
-
|
|
22
|
-
API Endpoint: /cn/company/dividend
|
|
23
|
-
API Method: POST
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
stock_code: 股票代码
|
|
27
|
-
start_date: 开始日期 (YYYY-MM-DD)
|
|
28
|
-
end_date: 结束日期 (YYYY-MM-DD)
|
|
29
|
-
|
|
30
|
-
"""
|
|
31
|
-
payload: dict[str, Any] = {
|
|
32
|
-
"stockCode": stock_code,
|
|
33
|
-
}
|
|
34
|
-
if start_date is not None:
|
|
35
|
-
payload["startDate"] = start_date
|
|
36
|
-
if end_date is not None:
|
|
37
|
-
payload["endDate"] = end_date
|
|
38
|
-
|
|
39
|
-
data = await self._request("POST", "/cn/company/dividend", json=payload)
|
|
40
|
-
for item in data:
|
|
41
|
-
item["stockCode"] = stock_code
|
|
42
|
-
return get_response_df(data, Dividend)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# Functional API instance
|
|
46
|
-
_api_instance = DividendAPI()
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@api
|
|
50
|
-
async def get_dividend(
|
|
51
|
-
stock_code: str,
|
|
52
|
-
start_date: str | None = None,
|
|
53
|
-
end_date: str | None = None,
|
|
54
|
-
) -> pd.DataFrame:
|
|
55
|
-
"""获取分红数据.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
stock_code: 股票代码
|
|
59
|
-
start_date: 开始日期 (YYYY-MM-DD)
|
|
60
|
-
end_date: 结束日期 (YYYY-MM-DD)
|
|
61
|
-
|
|
62
|
-
"""
|
|
63
|
-
return await _api_instance.get_dividend(
|
|
64
|
-
stock_code=stock_code,
|
|
65
|
-
start_date=start_date,
|
|
66
|
-
end_date=end_date,
|
|
67
|
-
)
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"""Dividend data models."""
|
|
2
|
-
|
|
3
|
-
import pandera.pandas as pa
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Dividend(pa.DataFrameModel):
|
|
7
|
-
"""Dividend data model."""
|
|
8
|
-
|
|
9
|
-
class Config:
|
|
10
|
-
"""Pandera configuration."""
|
|
11
|
-
|
|
12
|
-
coerce = True
|
|
13
|
-
strict = False
|
|
14
|
-
|
|
15
|
-
date: pa.typing.Series[pa.typing.DateTime]
|
|
16
|
-
fs_end_date: pa.typing.Series[pa.typing.DateTime]
|
|
17
|
-
currency: pa.typing.Series[str]
|
|
18
|
-
bonus_shares_from_profit: pa.typing.Series[float]
|
|
19
|
-
bonus_shares_from_capital_reserve: pa.typing.Series[float]
|
|
20
|
-
dividend: pa.typing.Series[float]
|
|
21
|
-
register_date: pa.typing.Series[pa.typing.DateTime] | None = pa.Field(nullable=True)
|
|
22
|
-
ex_date: pa.typing.Series[pa.typing.DateTime] | None = pa.Field(nullable=True)
|
|
23
|
-
payment_date: pa.typing.Series[pa.typing.DateTime] | None = pa.Field(nullable=True)
|
|
24
|
-
dividend_amount: pa.typing.Series[float] | None = pa.Field(nullable=True)
|
|
25
|
-
stock_code: pa.typing.Series[str]
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
from unittest.mock import Mock, patch
|
|
2
|
-
|
|
3
|
-
import pandas as pd
|
|
4
|
-
import pytest
|
|
5
|
-
|
|
6
|
-
from lixinger.api.cn.company.dividend import get_dividend
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@pytest.mark.asyncio
|
|
10
|
-
async def test_get_dividend():
|
|
11
|
-
mock_response = {
|
|
12
|
-
"code": 1,
|
|
13
|
-
"message": "success",
|
|
14
|
-
"data": [
|
|
15
|
-
{
|
|
16
|
-
"date": "2023-03-25T00:00:00+08:00",
|
|
17
|
-
"fsEndDate": "2022-12-31T00:00:00+08:00",
|
|
18
|
-
"currency": "CNY",
|
|
19
|
-
"registerDate": "2023-07-12T00:00:00+08:00",
|
|
20
|
-
"exDate": "2023-07-13T00:00:00+08:00",
|
|
21
|
-
"paymentDate": "2023-07-13T00:00:00+08:00",
|
|
22
|
-
"bonusSharesFromProfit": 0,
|
|
23
|
-
"bonusSharesFromCapitalReserve": 0,
|
|
24
|
-
"dividend": 1.738,
|
|
25
|
-
"dividendAmount": 43832091655,
|
|
26
|
-
}
|
|
27
|
-
],
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
with patch("httpx.AsyncClient.request") as mock_request:
|
|
31
|
-
mock_request.return_value = Mock()
|
|
32
|
-
mock_request.return_value.status_code = 200
|
|
33
|
-
mock_request.return_value.json.return_value = mock_response
|
|
34
|
-
|
|
35
|
-
df = await get_dividend(stock_code="600036", start_date="2023-01-01", end_date="2024-01-01")
|
|
36
|
-
|
|
37
|
-
assert isinstance(df, pd.DataFrame)
|
|
38
|
-
assert len(df) == 1
|
|
39
|
-
assert df.iloc[0]["stock_code"] == "600036"
|
|
40
|
-
assert df.iloc[0]["dividend"] == 1.738
|
|
41
|
-
assert "fs_end_date" in df.columns
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@pytest.mark.asyncio
|
|
45
|
-
async def test_get_dividend_empty():
|
|
46
|
-
mock_response = {
|
|
47
|
-
"code": 1,
|
|
48
|
-
"message": "success",
|
|
49
|
-
"data": [],
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
with patch("httpx.AsyncClient.request") as mock_request:
|
|
53
|
-
mock_request.return_value = Mock()
|
|
54
|
-
mock_request.return_value.status_code = 200
|
|
55
|
-
mock_request.return_value.json.return_value = mock_response
|
|
56
|
-
|
|
57
|
-
df = await get_dividend(stock_code="000001")
|
|
58
|
-
|
|
59
|
-
assert isinstance(df, pd.DataFrame)
|
|
60
|
-
assert df.empty
|
|
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
|
|
File without changes
|
{lixinger_python-0.3.0 → lixinger_python-0.3.1}/docs/api/company/fundamental/non_financial.md
RENAMED
|
File without changes
|
{lixinger_python-0.3.0 → lixinger_python-0.3.1}/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
|
|
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
|