From 04c2be1d7fddb4d9e35f31fcc05de8c1d3e0a421 Mon Sep 17 00:00:00 2001 From: GitHub Date: Tue, 9 Jun 2026 18:21:25 +0800 Subject: [PATCH] fix(backtest): resolve mypy and ruff lint issues - dsl.py: use NDArray type annotations, fix None narrowing - cli.py: add type annotations, fix import sorting - strategy.py: fix UP038 isinstance, add noqa for I() method name - tests: fix E712 bool comparison assertions Co-Authored-By: Claude Opus 4.8 --- .claude/settings.local.json | 6 +- .../console-2026-06-05T10-12-13-252Z.log | 1 + .../page-2026-06-05T10-12-25-202Z.yml | 2169 +++++++++++++++++ docs/protocol-reverse-engineering.md | 144 ++ docs/protocol-unknown-fields.md | 384 +++ src/easy_tdx/backtest/cli.py | 7 +- src/easy_tdx/backtest/dsl.py | 14 +- src/easy_tdx/backtest/portfolio.py | 2 - src/easy_tdx/backtest/strategy.py | 6 +- tests/unit/test_backtest_orders.py | 4 - tests/unit/test_backtest_strategy.py | 16 +- 11 files changed, 2724 insertions(+), 29 deletions(-) create mode 100644 .playwright-mcp/console-2026-06-05T10-12-13-252Z.log create mode 100644 .playwright-mcp/page-2026-06-05T10-12-25-202Z.yml create mode 100644 docs/protocol-reverse-engineering.md create mode 100644 docs/protocol-unknown-fields.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 20d405f..8b64a01 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -72,7 +72,11 @@ "Bash(gh auth *)", "Bash(rm -rf easy_tdx.wiki)", "Bash(gh repo *)", - "Bash(gh api *)" + "Bash(gh api *)", + "Bash(mypy src/easy_tdx/backtest/types.py)", + "Bash(mypy tests/unit/test_backtest_types.py)", + "Bash(mypy src/easy_tdx/backtest/types.py tests/unit/test_backtest_types.py)", + "Bash(mypy *)" ] } } diff --git a/.playwright-mcp/console-2026-06-05T10-12-13-252Z.log b/.playwright-mcp/console-2026-06-05T10-12-13-252Z.log new file mode 100644 index 0000000..7c73b55 --- /dev/null +++ b/.playwright-mcp/console-2026-06-05T10-12-13-252Z.log @@ -0,0 +1 @@ +[ 12502ms] [ERROR] Failed to load resource: the server responded with a status of 503 () @ https://collector.github.com/github/collect:0 diff --git a/.playwright-mcp/page-2026-06-05T10-12-25-202Z.yml b/.playwright-mcp/page-2026-06-05T10-12-25-202Z.yml new file mode 100644 index 0000000..5365a6e --- /dev/null +++ b/.playwright-mcp/page-2026-06-05T10-12-25-202Z.yml @@ -0,0 +1,2169 @@ +- generic [ref=e2]: + - generic [ref=e3]: + - link "Skip to content" [ref=e4] [cursor=pointer]: + - /url: "#start-of-content" + - banner [ref=e6]: + - heading "Navigation Menu" [level=2] [ref=e7] + - generic [ref=e8]: + - link "Homepage" [ref=e10] [cursor=pointer]: + - /url: / + - img [ref=e11] + - generic [ref=e13]: + - navigation "Global" [ref=e16]: + - list [ref=e17]: + - listitem [ref=e18]: + - button "Platform" [ref=e20] [cursor=pointer]: + - text: Platform + - img [ref=e21] + - listitem [ref=e23]: + - button "Solutions" [ref=e25] [cursor=pointer]: + - text: Solutions + - img [ref=e26] + - listitem [ref=e28]: + - button "Resources" [ref=e30] [cursor=pointer]: + - text: Resources + - img [ref=e31] + - listitem [ref=e33]: + - button "Open Source" [ref=e35] [cursor=pointer]: + - text: Open Source + - img [ref=e36] + - listitem [ref=e38]: + - button "Enterprise" [ref=e40] [cursor=pointer]: + - text: Enterprise + - img [ref=e41] + - listitem [ref=e43]: + - link "Pricing" [ref=e44] [cursor=pointer]: + - /url: https://github.com/pricing + - generic [ref=e45]: Pricing + - generic [ref=e46]: + - button "Search or jump to…" [ref=e49] [cursor=pointer]: + - img [ref=e51] + - link "Sign in" [ref=e54] [cursor=pointer]: + - /url: /login?return_to=https%3A%2F%2Fgithub.com%2Fhandsomejustin%2Feasy_tdx + - link "Sign up" [ref=e55] [cursor=pointer]: + - /url: /signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=handsomejustin%2Feasy_tdx + - button "Appearance settings" [ref=e58] [cursor=pointer]: + - img + - main [ref=e62]: + - generic [ref=e63]: + - generic [ref=e64]: + - generic [ref=e66]: + - img [ref=e67] + - link "handsomejustin" [ref=e70] [cursor=pointer]: + - /url: /handsomejustin + - generic [ref=e71]: / + - strong [ref=e72]: + - link "easy_tdx" [ref=e73] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx + - generic [ref=e74]: Public + - generic [ref=e75]: + - list: + - listitem [ref=e76]: + - link "You must be signed in to change notification settings" [ref=e77] [cursor=pointer]: + - /url: /login?return_to=%2Fhandsomejustin%2Feasy_tdx + - img [ref=e78] + - text: Notifications + - listitem [ref=e80]: + - link "Fork 23" [ref=e81] [cursor=pointer]: + - /url: /login?return_to=%2Fhandsomejustin%2Feasy_tdx + - img [ref=e82] + - text: Fork + - generic "23" [ref=e84] + - listitem [ref=e85]: + - link "You must be signed in to star a repository" [ref=e87] [cursor=pointer]: + - /url: /login?return_to=%2Fhandsomejustin%2Feasy_tdx + - img [ref=e88] + - text: Star + - generic "61 users starred this repository" [ref=e90]: "61" + - navigation "Repository" [ref=e91]: + - list [ref=e92]: + - listitem [ref=e93]: + - link "Code" [ref=e94] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx + - img [ref=e95] + - generic [ref=e97]: Code + - listitem [ref=e98]: + - link "Pull requests" [ref=e99] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/pulls + - img [ref=e100] + - generic [ref=e102]: Pull requests + - listitem [ref=e103]: + - link "Actions" [ref=e104] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/actions + - img [ref=e105] + - generic [ref=e107]: Actions + - listitem [ref=e108]: + - link "Projects" [ref=e109] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/projects + - img [ref=e110] + - generic [ref=e112]: Projects + - listitem [ref=e113]: + - link "Security and quality" [ref=e114] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/security + - img [ref=e115] + - generic [ref=e117]: Security and quality + - listitem [ref=e118]: + - link "Insights" [ref=e119] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/pulse + - img [ref=e120] + - generic [ref=e122]: Insights + - generic [ref=e135]: + - heading "handsomejustin/easy_tdx" [level=1] [ref=e137] + - generic [ref=e138]: + - generic [ref=e141]: + - generic [ref=e142]: + - generic [ref=e143]: + - button "main branch" [ref=e145] [cursor=pointer]: + - generic [ref=e146]: + - generic [ref=e148]: + - img [ref=e150] + - generic [ref=e153]: main + - generic: + - img + - generic [ref=e154]: + - link "1 Branch" [ref=e155] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/branches + - generic [ref=e156]: + - generic: + - img + - generic [ref=e158]: + - strong [ref=e159]: "1" + - text: Branch + - link "11 Tags" [ref=e160] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tags + - generic [ref=e161]: + - generic: + - img + - generic [ref=e163]: + - strong [ref=e164]: "11" + - text: Tags + - generic [ref=e165]: + - generic [ref=e169]: + - img [ref=e171] + - combobox "Go to file" [ref=e173] + - button "Code" [ref=e174] [cursor=pointer]: + - generic [ref=e175]: + - generic: + - img + - generic [ref=e176]: Code + - generic: + - img + - generic [ref=e177]: + - generic [ref=e178]: + - heading "Folders and files" [level=2] [ref=e179] + - table "Folders and files" [ref=e180]: + - rowgroup: + - row "Name Last commit message Last commit date": + - columnheader "Name" + - columnheader "Last commit message": + - generic "Last commit message" + - columnheader "Last commit date": + - generic "Last commit date" + - rowgroup [ref=e181]: + - 'row "Latest commit handsomejustin commits by handsomejustin feat: add offline CLI commands and bump version to v1.5.0 Open commit details success Commit b17e984 · Jun 2, 20263 days ago History 57 Commits" [ref=e182]': + - 'cell "Latest commit handsomejustin commits by handsomejustin feat: add offline CLI commands and bump version to v1.5.0 Open commit details success Commit b17e984 · Jun 2, 20263 days ago History 57 Commits" [ref=e183]': + - generic [ref=e184]: + - heading "Latest commit" [level=2] [ref=e185] + - generic [ref=e186]: + - generic [ref=e188]: + - link "handsomejustin" [ref=e189] [cursor=pointer]: + - /url: /handsomejustin + - img "handsomejustin" [ref=e190] + - link "commits by handsomejustin" [ref=e191] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/commits?author=handsomejustin + - text: handsomejustin + - generic [ref=e192]: + - 'link "feat: add offline CLI commands and bump version to v1.5.0" [ref=e195] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/b17e98468b03cf73251b417f24142ad6f352c088 + - button "Open commit details" [ref=e196] [cursor=pointer]: + - img [ref=e197] + - button "success" [ref=e199] [cursor=pointer]: + - img [ref=e200] + - generic [ref=e202]: + - generic [ref=e204]: + - link "Commit b17e984" [ref=e205] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/commit/b17e98468b03cf73251b417f24142ad6f352c088 + - text: b17e984 + - text: · + - generic "Jun 2, 2026, 12:30 PM GMT+8" [ref=e206]: Jun 2, 20263 days ago + - generic [ref=e207]: + - heading "History" [level=2] [ref=e208] + - link "57 Commits" [ref=e209] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/commits/main/ + - generic [ref=e210]: + - generic: + - img + - generic [ref=e211]: 57 Commits + - 'row ".claude, (Directory) skill: add publish skill for PyPI release workflow May 26, 2026last week" [ref=e212]': + - cell ".claude, (Directory)" [ref=e213]: + - generic [ref=e214]: + - img [ref=e215] + - link ".claude, (Directory)" [ref=e220] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tree/main/.claude + - text: .claude + - 'cell "skill: add publish skill for PyPI release workflow" [ref=e221]': + - 'link "skill: add publish skill for PyPI release workflow" [ref=e224] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/2ec36e01bf9ddfe87a6dd13b677b1f1137929ca4 + - cell "May 26, 2026last week" [ref=e225]: + - generic [ref=e226]: May 26, 2026last week + - 'row ".github/workflows, (Directory) ci: disable sigstore attestations to fix 502 from rekor May 26, 2026last week" [ref=e227]': + - cell ".github/workflows, (Directory)" [ref=e228]: + - generic [ref=e229]: + - img [ref=e230] + - link ".github/workflows, (Directory)" [ref=e235] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tree/main/.github/workflows + - text: .github/workflows + - 'cell "ci: disable sigstore attestations to fix 502 from rekor" [ref=e236]': + - 'link "ci: disable sigstore attestations to fix 502 from rekor" [ref=e239] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/c825515ee61b63b67fc82fce68a798e8aee1947d + - cell "May 26, 2026last week" [ref=e240]: + - generic [ref=e241]: May 26, 2026last week + - 'row ".omc, (Directory) docs: update README to reflect merged datetime fields in DataFrame ou… May 22, 20262 weeks ago" [ref=e242]': + - cell ".omc, (Directory)" [ref=e243]: + - generic [ref=e244]: + - img [ref=e245] + - link ".omc, (Directory)" [ref=e250] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tree/main/.omc + - text: .omc + - 'cell "docs: update README to reflect merged datetime fields in DataFrame ou…" [ref=e251]': + - 'link "docs: update README to reflect merged datetime fields in DataFrame ou…" [ref=e254] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/d7547f7c4cc77039ed5f9ab30e5c2c3cb652bab4 + - cell "May 22, 20262 weeks ago" [ref=e255]: + - generic [ref=e256]: May 22, 20262 weeks ago + - 'row "docs, (Directory) feat: add BIAS_SIGNAL indicator (30-day bias with signal lines) May 28, 2026last week" [ref=e257]': + - cell "docs, (Directory)" [ref=e258]: + - generic [ref=e259]: + - img [ref=e260] + - link "docs, (Directory)" [ref=e265] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tree/main/docs + - text: docs + - 'cell "feat: add BIAS_SIGNAL indicator (30-day bias with signal lines)" [ref=e266]': + - 'link "feat: add BIAS_SIGNAL indicator (30-day bias with signal lines)" [ref=e269] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/4c5817f7b08703d7564731daac0ca33c912693e6 + - cell "May 28, 2026last week" [ref=e270]: + - generic [ref=e271]: May 28, 2026last week + - 'row "examples, (Directory) feat: add offline CLI commands and bump version to v1.5.0 Jun 2, 20263 days ago" [ref=e272]': + - cell "examples, (Directory)" [ref=e273]: + - generic [ref=e274]: + - img [ref=e275] + - link "examples, (Directory)" [ref=e280] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tree/main/examples + - text: examples + - 'cell "feat: add offline CLI commands and bump version to v1.5.0" [ref=e281]': + - 'link "feat: add offline CLI commands and bump version to v1.5.0" [ref=e284] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/b17e98468b03cf73251b417f24142ad6f352c088 + - cell "Jun 2, 20263 days ago" [ref=e285]: + - generic [ref=e286]: Jun 2, 20263 days ago + - 'row "scripts, (Directory) feat!: rename project from xmtdx to easy-tdx May 21, 20262 weeks ago" [ref=e287]': + - cell "scripts, (Directory)" [ref=e288]: + - generic [ref=e289]: + - img [ref=e290] + - link "scripts, (Directory)" [ref=e295] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tree/main/scripts + - text: scripts + - 'cell "feat!: rename project from xmtdx to easy-tdx" [ref=e296]': + - 'link "feat!: rename project from xmtdx to easy-tdx" [ref=e299] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/50491f9aae4953eeb7baedc8d707a1ae33da833d + - cell "May 21, 20262 weeks ago" [ref=e300]: + - generic [ref=e301]: May 21, 20262 weeks ago + - 'row "src/easy_tdx, (Directory) feat: add offline CLI commands and bump version to v1.5.0 Jun 2, 20263 days ago" [ref=e302]': + - cell "src/easy_tdx, (Directory)" [ref=e303]: + - generic [ref=e304]: + - img [ref=e305] + - link "src/easy_tdx, (Directory)" [ref=e310] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tree/main/src/easy_tdx + - text: src/easy_tdx + - 'cell "feat: add offline CLI commands and bump version to v1.5.0" [ref=e311]': + - 'link "feat: add offline CLI commands and bump version to v1.5.0" [ref=e314] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/b17e98468b03cf73251b417f24142ad6f352c088 + - cell "Jun 2, 20263 days ago" [ref=e315]: + - generic [ref=e316]: Jun 2, 20263 days ago + - 'row "tests, (Directory) feat: add technical indicator calculation (30 indicators via MyTT), b… May 28, 2026last week" [ref=e317]': + - cell "tests, (Directory)" [ref=e318]: + - generic [ref=e319]: + - img [ref=e320] + - link "tests, (Directory)" [ref=e325] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/tree/main/tests + - text: tests + - 'cell "feat: add technical indicator calculation (30 indicators via MyTT), b…" [ref=e326]': + - 'link "feat: add technical indicator calculation (30 indicators via MyTT), b…" [ref=e329] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/bcddf5a05205e730a6d0b5f747ffd6e387eb3ab5 + - cell "May 28, 2026last week" [ref=e330]: + - generic [ref=e331]: May 28, 2026last week + - 'row ".gitignore, (File) chore: remove uv.lock and add to .gitignore May 22, 20262 weeks ago" [ref=e332]': + - cell ".gitignore, (File)" [ref=e333]: + - generic [ref=e334]: + - img [ref=e335] + - link ".gitignore, (File)" [ref=e340] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/.gitignore + - text: .gitignore + - 'cell "chore: remove uv.lock and add to .gitignore" [ref=e341]': + - 'link "chore: remove uv.lock and add to .gitignore" [ref=e344] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/67a0415c38ef4c78ad720da5ccd3d3a1402a8d5f + - cell "May 22, 20262 weeks ago" [ref=e345]: + - generic [ref=e346]: May 22, 20262 weeks ago + - 'row "CLAUDE.md, (File) feat: merge datetime fields in DataFrame output, hide MinuteBar inter… May 22, 20262 weeks ago" [ref=e347]': + - cell "CLAUDE.md, (File)" [ref=e348]: + - generic [ref=e349]: + - img [ref=e350] + - link "CLAUDE.md, (File)" [ref=e355] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/CLAUDE.md + - text: CLAUDE.md + - 'cell "feat: merge datetime fields in DataFrame output, hide MinuteBar inter…" [ref=e356]': + - 'link "feat: merge datetime fields in DataFrame output, hide MinuteBar inter…" [ref=e359] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/02701952ca3ba153ae0eaf4c527c8f44f18023b1 + - cell "May 22, 20262 weeks ago" [ref=e360]: + - generic [ref=e361]: May 22, 20262 weeks ago + - 'row "LICENSE, (File) feat!: rename project from xmtdx to easy-tdx May 21, 20262 weeks ago" [ref=e362]': + - cell "LICENSE, (File)" [ref=e363]: + - generic [ref=e364]: + - img [ref=e365] + - link "LICENSE, (File)" [ref=e370] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/LICENSE + - text: LICENSE + - 'cell "feat!: rename project from xmtdx to easy-tdx" [ref=e371]': + - 'link "feat!: rename project from xmtdx to easy-tdx" [ref=e374] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/50491f9aae4953eeb7baedc8d707a1ae33da833d + - cell "May 21, 20262 weeks ago" [ref=e375]: + - generic [ref=e376]: May 21, 20262 weeks ago + - 'row "NOTICE, (File) feat!: rename project from xmtdx to easy-tdx May 21, 20262 weeks ago" [ref=e377]': + - cell "NOTICE, (File)" [ref=e378]: + - generic [ref=e379]: + - img [ref=e380] + - link "NOTICE, (File)" [ref=e385] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/NOTICE + - text: NOTICE + - 'cell "feat!: rename project from xmtdx to easy-tdx" [ref=e386]': + - 'link "feat!: rename project from xmtdx to easy-tdx" [ref=e389] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/50491f9aae4953eeb7baedc8d707a1ae33da833d + - cell "May 21, 20262 weeks ago" [ref=e390]: + - generic [ref=e391]: May 21, 20262 weeks ago + - 'row "README.md, (File) feat: add offline CLI commands and bump version to v1.5.0 Jun 2, 20263 days ago" [ref=e392]': + - cell "README.md, (File)" [ref=e393]: + - generic [ref=e394]: + - img [ref=e395] + - link "README.md, (File)" [ref=e400] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/README.md + - text: README.md + - 'cell "feat: add offline CLI commands and bump version to v1.5.0" [ref=e401]': + - 'link "feat: add offline CLI commands and bump version to v1.5.0" [ref=e404] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/b17e98468b03cf73251b417f24142ad6f352c088 + - cell "Jun 2, 20263 days ago" [ref=e405]: + - generic [ref=e406]: Jun 2, 20263 days ago + - 'row "pyproject.toml, (File) feat: add offline CLI commands and bump version to v1.5.0 Jun 2, 20263 days ago" [ref=e407]': + - cell "pyproject.toml, (File)" [ref=e408]: + - generic [ref=e409]: + - img [ref=e410] + - link "pyproject.toml, (File)" [ref=e415] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/pyproject.toml + - text: pyproject.toml + - 'cell "feat: add offline CLI commands and bump version to v1.5.0" [ref=e416]': + - 'link "feat: add offline CLI commands and bump version to v1.5.0" [ref=e419] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/commit/b17e98468b03cf73251b417f24142ad6f352c088 + - cell "Jun 2, 20263 days ago" [ref=e420]: + - generic [ref=e421]: Jun 2, 20263 days ago + - generic [ref=e423]: + - generic [ref=e424]: + - heading "Repository files navigation" [level=2] [ref=e425] + - navigation "Repository files" [ref=e426]: + - list [ref=e427]: + - listitem [ref=e428]: + - link "README" [ref=e429] [cursor=pointer]: + - /url: "#" + - img [ref=e431] + - generic [ref=e433]: README + - listitem [ref=e434]: + - link "License" [ref=e435] [cursor=pointer]: + - /url: "#" + - img [ref=e437] + - generic [ref=e439]: License + - button "Outline" [ref=e440] [cursor=pointer]: + - img [ref=e441] + - article [ref=e444]: + - generic [ref=e445]: + - heading "easy-tdx" [level=1] [ref=e446] + - 'link "Permalink: easy-tdx" [ref=e447] [cursor=pointer]': + - /url: "#easy-tdx" + - img [ref=e448] + - paragraph [ref=e450]: + - 'link "License: MIT" [ref=e451] [cursor=pointer]': + - /url: /handsomejustin/easy_tdx/blob/main/LICENSE + - 'img "License: MIT" [ref=e452]' + - link "PyPI" [ref=e453] [cursor=pointer]: + - /url: https://pypi.org/project/easy-tdx/ + - img "PyPI" [ref=e454] + - paragraph [ref=e455]: + - text: 通达信 TCP 行情协议客户端。支持 A 股、港股、美股、期货全市场;内置 + - code [ref=e456]: easy-tdx + - text: CLI 工具,默认 JSON 输出,天然适配 Claude Code、OpenClaw、Hermes 等 AI Agent 工具链。提供同步 + asyncio 双接口;strict mypy 通过;每一层编解码都有离线 fixture 测试覆盖。 + - generic [ref=e457]: + - heading "安装" [level=2] [ref=e458] + - 'link "Permalink: 安装" [ref=e459] [cursor=pointer]': + - /url: "#安装" + - img [ref=e460] + - generic [ref=e462]: + - generic [ref=e463]: pip install easy-tdx + - button "Copy code to clipboard" [ref=e465] [cursor=pointer]: + - img [ref=e466] + - paragraph [ref=e469]: + - text: 安装后自动注册 + - code [ref=e470]: easy-tdx + - text: CLI 命令: + - generic [ref=e471]: + - generic [ref=e472]: easy-tdx --help + - button "Copy code to clipboard" [ref=e474] [cursor=pointer]: + - img [ref=e475] + - paragraph [ref=e478]: 开发模式: + - generic [ref=e479]: + - generic [ref=e480]: + - text: pip install -e + - generic [ref=e481]: "\".[dev]\"" + - button "Copy code to clipboard" [ref=e483] [cursor=pointer]: + - img [ref=e484] + - generic [ref=e487]: + - heading "CLI 参考" [level=2] [ref=e488] + - 'link "Permalink: CLI 参考" [ref=e489] [cursor=pointer]': + - /url: "#cli-参考" + - img [ref=e490] + - paragraph [ref=e492]: + - code [ref=e493]: easy-tdx + - text: 默认输出 JSON(一行一条记录), + - code [ref=e494]: "--table" + - text: 切换表格, + - code [ref=e495]: "--output csv" + - text: 输出 CSV。 + - generic [ref=e496]: + - heading "基础" [level=3] [ref=e497] + - 'link "Permalink: 基础" [ref=e498] [cursor=pointer]': + - /url: "#基础" + - img [ref=e499] + - generic [ref=e501]: + - generic [ref=e502]: + - text: easy-tdx ping + - generic [ref=e503]: "# 服务器测速" + - text: easy-tdx version + - generic [ref=e504]: "# 版本号" + - button "Copy code to clipboard" [ref=e506] [cursor=pointer]: + - img [ref=e507] + - generic [ref=e510]: + - heading "行情" [level=3] [ref=e511] + - 'link "Permalink: 行情" [ref=e512] [cursor=pointer]': + - /url: "#行情" + - img [ref=e513] + - generic [ref=e515]: + - generic [ref=e516]: + - generic [ref=e517]: "# K 线" + - text: easy-tdx kline SZ 000001 --count 30 --table easy-tdx kline SH 600519 --period 5MIN --adjust QFQ + - generic [ref=e518]: "# 实时报价" + - text: easy-tdx quote + - generic [ref=e519]: "\"SZ 000001,SH 600519\"" + - text: "--table" + - generic [ref=e520]: "# 市场分类报价(按涨幅排序)" + - text: easy-tdx quote-list A --count 20 --table easy-tdx quote-list KCB --sort TOTAL_AMOUNT --order ASC easy-tdx quote-list CYB --count 50 + - button "Copy code to clipboard" [ref=e522] [cursor=pointer]: + - img [ref=e523] + - generic [ref=e526]: + - heading "分时 / 成交" [level=3] [ref=e527] + - 'link "Permalink: 分时 / 成交" [ref=e528] [cursor=pointer]': + - /url: "#分时--成交" + - img [ref=e529] + - generic [ref=e531]: + - generic [ref=e532]: easy-tdx tick SZ 000001 --table easy-tdx tick SH 600519 --days 5 easy-tdx tick SZ 000001 --date 20250115 easy-tdx transaction SZ 000001 --count 100 --table easy-tdx transaction SH 600519 --date 20250115 + - button "Copy code to clipboard" [ref=e534] [cursor=pointer]: + - img [ref=e535] + - generic [ref=e538]: + - heading "板块" [level=3] [ref=e539] + - 'link "Permalink: 板块" [ref=e540] [cursor=pointer]': + - /url: "#板块" + - img [ref=e541] + - generic [ref=e543]: + - generic [ref=e544]: + - text: easy-tdx board-list --type GN --table easy-tdx board-list --type HY --count 200 easy-tdx board-members 881001 --table easy-tdx belong-board SZ 000001 --table easy-tdx board-summary 881001 --table + - generic [ref=e545]: "# 板块汇总(成交额/主力净流入/涨跌家数)" + - text: easy-tdx board-summary 881001 --members --table + - generic [ref=e546]: "# 含成分股明细" + - text: easy-tdx board-ranking --type HY --top 10 --table + - generic [ref=e547]: "# 行业板块排行" + - text: easy-tdx board-ranking --type GN --sort-by amount + - generic [ref=e548]: "# 概念板块按成交额排行" + - button "Copy code to clipboard" [ref=e550] [cursor=pointer]: + - img [ref=e551] + - generic [ref=e554]: + - heading "资金 / 监控" [level=3] [ref=e555] + - 'link "Permalink: 资金 / 监控" [ref=e556] [cursor=pointer]': + - /url: "#资金--监控" + - img [ref=e557] + - generic [ref=e559]: + - generic [ref=e560]: easy-tdx capital-flow SH 600519 --table easy-tdx auction SZ 000001 --table easy-tdx unusual SH --count 100 --table easy-tdx market-stat --table easy-tdx server-info --table easy-tdx symbol-info SZ 000001 --table + - button "Copy code to clipboard" [ref=e562] [cursor=pointer]: + - img [ref=e563] + - generic [ref=e566]: + - heading "技术指标" [level=3] [ref=e567] + - 'link "Permalink: 技术指标" [ref=e568] [cursor=pointer]': + - /url: "#技术指标" + - img [ref=e569] + - generic [ref=e571]: + - generic [ref=e572]: + - text: easy-tdx indicator-list --table + - generic [ref=e573]: "# 列出所有可用指标" + - text: easy-tdx indicator MACD -m SH -c 600519 --table + - generic [ref=e574]: "# MACD" + - text: easy-tdx indicator KDJ -m SZ -c 000001 --table + - generic [ref=e575]: "# KDJ" + - text: easy-tdx indicator RSI -m SH -c 600519 --table + - generic [ref=e576]: "# RSI" + - text: easy-tdx indicator BOLL -m SH -c 600519 --table + - generic [ref=e577]: "# BOLL 布林带" + - text: easy-tdx indicator DMI -m SH -c 600519 --table + - generic [ref=e578]: "# DMI 动向指标" + - text: easy-tdx indicator ATR -m SH -c 600519 --table + - generic [ref=e579]: "# ATR 真实波幅" + - text: easy-tdx indicator WR -m SH -c 600519 --table + - generic [ref=e580]: "# WR 威廉指标" + - text: easy-tdx indicator CCI -m SH -c 600519 --table + - generic [ref=e581]: "# CCI 顺势指标" + - text: easy-tdx indicator BIAS -m SZ -c 000001 --table + - generic [ref=e582]: "# BIAS 乖离率" + - text: easy-tdx indicator BIAS_SIGNAL -m SH -c 600519 --table + - generic [ref=e583]: "# 30日乖离率信号" + - text: easy-tdx indicator OBV -m SZ -c 000001 --table + - generic [ref=e584]: "# OBV 能量潮" + - generic [ref=e585]: "# 多指标同时计算" + - text: easy-tdx indicator MACD,KDJ,RSI,BOLL -m SH -c 600519 --count 10 --table + - generic [ref=e586]: "# 自定义参数" + - text: easy-tdx indicator MACD -m SH -c 600519 --params SHORT=10,LONG=22 + - generic [ref=e587]: "# 分钟线指标" + - text: easy-tdx indicator MACD -m SH -c 600519 --period 5MIN --count 50 + - generic [ref=e588]: "# 仅输出指标值(不含 OHLCV)" + - text: easy-tdx indicator RSI -m SZ -c 000001 --no-ohlcv + - button "Copy code to clipboard" [ref=e590] [cursor=pointer]: + - img [ref=e591] + - generic [ref=e594]: + - heading "捉妖大师(重点)" [level=3] [ref=e595] + - 'link "Permalink: 捉妖大师(重点)" [ref=e596] [cursor=pointer]': + - /url: "#捉妖大师重点" + - img [ref=e597] + - paragraph [ref=e599]: 捉妖大师是多周期涨幅共振指标,通过 20/60/120 日涨幅及指数平滑判断短中长线趋势是否同向,用于筛选趋势刚启动的强势股。 + - generic [ref=e600]: + - generic [ref=e601]: + - text: easy-tdx indicator ZHUOYAO -m SH -c 600519 --count 30 --table + - generic [ref=e602]: "# 自定义周期参数" + - text: easy-tdx indicator ZHUOYAO -m SZ -c 000001 --params N1=90,N2=45,N3=15 + - generic [ref=e603]: "# 结合其他指标一起看" + - text: easy-tdx indicator ZHUOYAO,MACD,KDJ -m SH -c 600519 --count 20 --table + - button "Copy code to clipboard" [ref=e605] [cursor=pointer]: + - img [ref=e606] + - paragraph [ref=e609]: 输出列说明: + - table [ref=e611]: + - rowgroup [ref=e612]: + - row "列名 含义" [ref=e613]: + - columnheader "列名" [ref=e614] + - columnheader "含义" [ref=e615] + - rowgroup [ref=e616]: + - row "ZY_LONG 长线 — 120 日涨幅的 10 日指数平滑" [ref=e617]: + - cell "ZY_LONG" [ref=e618]: + - code [ref=e619]: ZY_LONG + - cell "长线 — 120 日涨幅的 10 日指数平滑" [ref=e620] + - row "ZY_MID 中线 — 60 日涨幅(%)" [ref=e621]: + - cell "ZY_MID" [ref=e622]: + - code [ref=e623]: ZY_MID + - cell "中线 — 60 日涨幅(%)" [ref=e624] + - row "ZY_SHORT 短线 — 20 日涨幅(%)" [ref=e625]: + - cell "ZY_SHORT" [ref=e626]: + - code [ref=e627]: ZY_SHORT + - cell "短线 — 20 日涨幅(%)" [ref=e628] + - row "ZY_TREND 趋势 — 中线的 10 日指数平滑" [ref=e629]: + - cell "ZY_TREND" [ref=e630]: + - code [ref=e631]: ZY_TREND + - cell "趋势 — 中线的 10 日指数平滑" [ref=e632] + - paragraph [ref=e633]: + - strong [ref=e634]: 核心信号: + - text: 四线全部 > 0 且短线 > 中线 > 长线 = 短中长趋势完全一致向上,是强势股特征。详见 + - link "捉妖大师指标详解" [ref=e635] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/docs/indicator-zhuoyao.md + - text: 。 + - generic [ref=e636]: + - heading "30日乖离率信号(重点)" [level=3] [ref=e637] + - 'link "Permalink: 30日乖离率信号(重点)" [ref=e638] [cursor=pointer]': + - /url: "#30日乖离率信号重点" + - img [ref=e639] + - paragraph [ref=e641]: 30日乖离率信号指标,在标准乖离率(BIAS)基础上叠加短/长信号线,通过三者位置关系判断趋势方向和转折点。源自通达信经典指标。 + - generic [ref=e642]: + - generic [ref=e643]: + - text: easy-tdx indicator BIAS_SIGNAL -m SH -c 600519 --count 60 --table + - generic [ref=e644]: "# 自定义周期参数" + - text: easy-tdx indicator BIAS_SIGNAL -m SZ -c 000001 --params P=5,M=20 + - generic [ref=e645]: "# 结合其他指标一起看" + - text: easy-tdx indicator BIAS_SIGNAL,MACD,KDJ -m SH -c 600519 --count 30 --table + - button "Copy code to clipboard" [ref=e647] [cursor=pointer]: + - img [ref=e648] + - paragraph [ref=e651]: 输出列说明: + - table [ref=e653]: + - rowgroup [ref=e654]: + - row "列名 含义" [ref=e655]: + - columnheader "列名" [ref=e656] + - columnheader "含义" [ref=e657] + - rowgroup [ref=e658]: + - row "BS_X M日乖离率 — 当前价格偏离30日均线的百分比" [ref=e659]: + - cell "BS_X" [ref=e660]: + - code [ref=e661]: BS_X + - cell "M日乖离率 — 当前价格偏离30日均线的百分比" [ref=e662] + - row "BS_SMA 短周期信号线 — 乖离率的 P 日均线,过滤短期噪音" [ref=e663]: + - cell "BS_SMA" [ref=e664]: + - code [ref=e665]: BS_SMA + - cell "短周期信号线 — 乖离率的 P 日均线,过滤短期噪音" [ref=e666] + - row "BS_LMA 长周期信号线 — 乖离率的 M 日均线,捕捉中期趋势方向" [ref=e667]: + - cell "BS_LMA" [ref=e668]: + - code [ref=e669]: BS_LMA + - cell "长周期信号线 — 乖离率的 M 日均线,捕捉中期趋势方向" [ref=e670] + - paragraph [ref=e671]: + - strong [ref=e672]: 核心信号: + - text: X > S_SMA 且 X_LMA 上升 = 多头确认(通达信红色);S_SMA > X 或 X_LMA 下降 = 空头预警(通达信绿色)。多空判断非对称设计——多头需两个条件同时满足,空头只需其一,偏向保守预警。详见 + - link "30日乖离率信号指标详解" [ref=e673] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/docs/indicator-bias-signal.md + - text: 。 + - generic [ref=e674]: + - generic [ref=e675]: "# Python API 用法 from easy_tdx import MacClient, Market with MacClient.from_best_host() as c: df = c.get_stock_kline_with_indicators( Market.SH, \"600519\", indicators=[\"BIAS_SIGNAL\"], count=60, ) # df 包含: datetime, open, close, high, low, vol, amount # + BS_X, BS_SMA, BS_LMA" + - button "Copy code to clipboard" [ref=e677] [cursor=pointer]: + - img [ref=e678] + - paragraph [ref=e681]: 支持 32 个指标:MACD, KDJ, RSI, BOLL, DMI, ATR, WR, CCI, BIAS, BIAS_SIGNAL, OBV, VR, EMV, MFI, BRAR, ASI, TRIX, DPO, MTM, ROC, EXPMA, BBI, PSY, DFMA, CR, KTN, XSII, MASS, TAQ, ZHUOYAO。 + - generic [ref=e682]: + - generic [ref=e683]: "# Python API 用法 from easy_tdx import MacClient, Market with MacClient.from_best_host() as c: df = c.get_stock_kline_with_indicators( Market.SH, \"600519\", indicators=[\"ZHUOYAO\"], count=30, ) # df 包含: datetime, open, close, high, low, vol, amount # + ZY_LONG, ZY_MID, ZY_SHORT, ZY_TREND" + - button "Copy code to clipboard" [ref=e685] [cursor=pointer]: + - img [ref=e686] + - paragraph [ref=e689]: 支持 32 个指标:MACD, KDJ, RSI, BOLL, DMI, ATR, WR, CCI, BIAS, BIAS_SIGNAL, OBV, VR, EMV, MFI, BRAR, ASI, TRIX, DPO, MTM, ROC, EXPMA, BBI, PSY, DFMA, CR, KTN, XSII, MASS, TAQ, ZHUOYAO。 + - generic [ref=e690]: + - heading "财务" [level=3] [ref=e691] + - 'link "Permalink: 财务" [ref=e692] [cursor=pointer]': + - /url: "#财务" + - img [ref=e693] + - generic [ref=e695]: + - generic [ref=e696]: + - text: easy-tdx f10 SH 600519 + - generic [ref=e697]: "# F10 公司信息" + - text: easy-tdx fund-flow SH 600519 + - generic [ref=e698]: "# 历史资金流向" + - button "Copy code to clipboard" [ref=e700] [cursor=pointer]: + - img [ref=e701] + - generic [ref=e704]: + - heading "扩展市场(港股/美股/期货)" [level=3] [ref=e705] + - 'link "Permalink: 扩展市场(港股/美股/期货)" [ref=e706] [cursor=pointer]': + - /url: "#扩展市场港股美股期货" + - img [ref=e707] + - generic [ref=e709]: + - generic [ref=e710]: + - text: easy-tdx ex markets + - generic [ref=e711]: "# 列出可用市场" + - text: easy-tdx ex kline HK_MAIN_BOARD 00700 --count 30 --table + - generic [ref=e712]: "# 港股 K 线" + - text: easy-tdx ex kline US_STOCK AAPL --table + - generic [ref=e713]: "# 美股 K 线" + - text: easy-tdx ex quote US_STOCK TSLA --table + - generic [ref=e714]: "# 美股报价" + - text: easy-tdx ex quote-list HK_MAIN_BOARD --table + - generic [ref=e715]: "# 港股商品列表" + - text: easy-tdx ex tick HK_MAIN_BOARD 00700 --table + - generic [ref=e716]: "# 港股分时" + - button "Copy code to clipboard" [ref=e718] [cursor=pointer]: + - img [ref=e719] + - generic [ref=e722]: + - heading "离线数据(无需网络)" [level=3] [ref=e723] + - 'link "Permalink: 离线数据(无需网络)" [ref=e724] [cursor=pointer]': + - /url: "#离线数据无需网络" + - img [ref=e725] + - paragraph [ref=e727]: 从本地通达信安装目录直接读取数据文件,无需网络连接: + - generic [ref=e728]: + - generic [ref=e729]: + - text: easy-tdx offline home + - generic [ref=e730]: "# 检测通达信安装目录" + - text: easy-tdx offline daily SH 600000 --count 10 --table + - generic [ref=e731]: "# A 股日线" + - text: easy-tdx offline min SZ 000001 --type lc5 --table + - generic [ref=e732]: "# 分钟线(5min/lc1/lc5)" + - text: easy-tdx offline ex-files --table + - generic [ref=e733]: "# 列出扩展市场可用文件" + - text: easy-tdx offline ex-daily 38#2_CPI --count 5 --table + - generic [ref=e734]: "# 扩展市场日线(期货/港股/外盘)" + - text: easy-tdx offline gbbq C:\new_jyplug\T0002\hq_cache\gbbq --table + - generic [ref=e735]: "# 股本变迁" + - text: easy-tdx offline financial C:\new_jyplug\vipdoc\fin\gpcw20260331.dat + - generic [ref=e736]: "# 历史财务" + - text: easy-tdx offline blocks C:\new_jyplug\T0002\blocknew --table + - generic [ref=e737]: "# 自定义板块" + - button "Copy code to clipboard" [ref=e739] [cursor=pointer]: + - img [ref=e740] + - generic [ref=e743]: + - heading "CLI 命令汇总" [level=2] [ref=e744] + - 'link "Permalink: CLI 命令汇总" [ref=e745] [cursor=pointer]': + - /url: "#cli-命令汇总" + - img [ref=e746] + - table [ref=e749]: + - rowgroup [ref=e750]: + - row "命令 说明" [ref=e751]: + - columnheader "命令" [ref=e752] + - columnheader "说明" [ref=e753] + - rowgroup [ref=e754]: + - row "ping 服务器延迟测速" [ref=e755]: + - cell "ping" [ref=e756]: + - code [ref=e757]: ping + - cell "服务器延迟测速" [ref=e758] + - row "version 版本号" [ref=e759]: + - cell "version" [ref=e760]: + - code [ref=e761]: version + - cell "版本号" [ref=e762] + - row "kline K 线(日/周/月/分钟,支持复权)" [ref=e763]: + - cell "kline" [ref=e764]: + - code [ref=e765]: kline + - cell "K 线(日/周/月/分钟,支持复权)" [ref=e766] + - row "quote 实时报价(单只/批量)" [ref=e767]: + - cell "quote" [ref=e768]: + - code [ref=e769]: quote + - cell "实时报价(单只/批量)" [ref=e770] + - row "quote-list 市场分类排序报价(A/SH/SZ/KCB/CYB)" [ref=e771]: + - cell "quote-list" [ref=e772]: + - code [ref=e773]: quote-list + - cell "市场分类排序报价(A/SH/SZ/KCB/CYB)" [ref=e774] + - row "tick 分时图(单日/多日/历史)" [ref=e775]: + - cell "tick" [ref=e776]: + - code [ref=e777]: tick + - cell "分时图(单日/多日/历史)" [ref=e778] + - row "transaction 逐笔成交" [ref=e779]: + - cell "transaction" [ref=e780]: + - code [ref=e781]: transaction + - cell "逐笔成交" [ref=e782] + - row "board-list 板块列表(行业/概念/风格)" [ref=e783]: + - cell "board-list" [ref=e784]: + - code [ref=e785]: board-list + - cell "板块列表(行业/概念/风格)" [ref=e786] + - row "board-members 板块成分股报价" [ref=e787]: + - cell "board-members" [ref=e788]: + - code [ref=e789]: board-members + - cell "板块成分股报价" [ref=e790] + - row "board-summary 板块汇总(成交额、主力净流入、涨跌家数)" [ref=e791]: + - cell "board-summary" [ref=e792]: + - code [ref=e793]: board-summary + - cell "板块汇总(成交额、主力净流入、涨跌家数)" [ref=e794] + - row "board-ranking 板块涨跌幅排行榜(行业/概念排行)" [ref=e795]: + - cell "board-ranking" [ref=e796]: + - code [ref=e797]: board-ranking + - cell "板块涨跌幅排行榜(行业/概念排行)" [ref=e798] + - row "belong-board 个股所属板块" [ref=e799]: + - cell "belong-board" [ref=e800]: + - code [ref=e801]: belong-board + - cell "个股所属板块" [ref=e802] + - row "capital-flow 资金流向" [ref=e803]: + - cell "capital-flow" [ref=e804]: + - code [ref=e805]: capital-flow + - cell "资金流向" [ref=e806] + - row "auction 集合竞价" [ref=e807]: + - cell "auction" [ref=e808]: + - code [ref=e809]: auction + - cell "集合竞价" [ref=e810] + - row "unusual 市场异动" [ref=e811]: + - cell "unusual" [ref=e812]: + - code [ref=e813]: unusual + - cell "市场异动" [ref=e814] + - row "market-stat 全市场涨跌统计" [ref=e815]: + - cell "market-stat" [ref=e816]: + - code [ref=e817]: market-stat + - cell "全市场涨跌统计" [ref=e818] + - row "server-info 服务器交易时段" [ref=e819]: + - cell "server-info" [ref=e820]: + - code [ref=e821]: server-info + - cell "服务器交易时段" [ref=e822] + - row "symbol-info 个股特征快照" [ref=e823]: + - cell "symbol-info" [ref=e824]: + - code [ref=e825]: symbol-info + - cell "个股特征快照" [ref=e826] + - row "indicator 技术指标计算(32 个:MACD/KDJ/RSI/BOLL/DMI/ATR...)" [ref=e827]: + - cell "indicator" [ref=e828]: + - code [ref=e829]: indicator + - cell "技术指标计算(32 个:MACD/KDJ/RSI/BOLL/DMI/ATR...)" [ref=e830] + - row "indicator-list 列出可用技术指标" [ref=e831]: + - cell "indicator-list" [ref=e832]: + - code [ref=e833]: indicator-list + - cell "列出可用技术指标" [ref=e834] + - row "f10 F10 公司信息" [ref=e835]: + - cell "f10" [ref=e836]: + - code [ref=e837]: f10 + - cell "F10 公司信息" [ref=e838] + - row "fund-flow 历史资金流向" [ref=e839]: + - cell "fund-flow" [ref=e840]: + - code [ref=e841]: fund-flow + - cell "历史资金流向" [ref=e842] + - row "ex kline 扩展市场 K 线" [ref=e843]: + - cell "ex kline" [ref=e844]: + - code [ref=e845]: ex kline + - cell "扩展市场 K 线" [ref=e846] + - row "ex quote 扩展市场报价" [ref=e847]: + - cell "ex quote" [ref=e848]: + - code [ref=e849]: ex quote + - cell "扩展市场报价" [ref=e850] + - row "ex quote-list 扩展市场商品列表" [ref=e851]: + - cell "ex quote-list" [ref=e852]: + - code [ref=e853]: ex quote-list + - cell "扩展市场商品列表" [ref=e854] + - row "ex tick 扩展市场分时" [ref=e855]: + - cell "ex tick" [ref=e856]: + - code [ref=e857]: ex tick + - cell "扩展市场分时" [ref=e858] + - row "ex markets 列出可用扩展市场" [ref=e859]: + - cell "ex markets" [ref=e860]: + - code [ref=e861]: ex markets + - cell "列出可用扩展市场" [ref=e862] + - row "offline home 检测通达信安装目录" [ref=e863]: + - cell "offline home" [ref=e864]: + - code [ref=e865]: offline home + - cell "检测通达信安装目录" [ref=e866] + - row "offline daily A 股日线(本地 .day 文件)" [ref=e867]: + - cell "offline daily" [ref=e868]: + - code [ref=e869]: offline daily + - cell "A 股日线(本地 .day 文件)" [ref=e870] + - row "offline min 分钟线(本地 .5/.lc1/.lc5 文件)" [ref=e871]: + - cell "offline min" [ref=e872]: + - code [ref=e873]: offline min + - cell "分钟线(本地 .5/.lc1/.lc5 文件)" [ref=e874] + - row "offline ex-files 列出扩展市场可用文件" [ref=e875]: + - cell "offline ex-files" [ref=e876]: + - code [ref=e877]: offline ex-files + - cell "列出扩展市场可用文件" [ref=e878] + - row "offline ex-daily 扩展市场日线(期货/港股/外盘)" [ref=e879]: + - cell "offline ex-daily" [ref=e880]: + - code [ref=e881]: offline ex-daily + - cell "扩展市场日线(期货/港股/外盘)" [ref=e882] + - row "offline gbbq 股本变迁数据" [ref=e883]: + - cell "offline gbbq" [ref=e884]: + - code [ref=e885]: offline gbbq + - cell "股本变迁数据" [ref=e886] + - row "offline financial 历史财务数据" [ref=e887]: + - cell "offline financial" [ref=e888]: + - code [ref=e889]: offline financial + - cell "历史财务数据" [ref=e890] + - row "offline blocks 自定义板块数据" [ref=e891]: + - cell "offline blocks" [ref=e892]: + - code [ref=e893]: offline blocks + - cell "自定义板块数据" [ref=e894] + - generic [ref=e895]: + - heading "Python API" [level=2] [ref=e896] + - 'link "Permalink: Python API" [ref=e897] [cursor=pointer]': + - /url: "#python-api" + - img [ref=e898] + - generic [ref=e900]: + - heading "连接管理" [level=3] [ref=e901] + - 'link "Permalink: 连接管理" [ref=e902] [cursor=pointer]': + - /url: "#连接管理" + - img [ref=e903] + - paragraph [ref=e905]: + - text: 所有客户端支持 + - code [ref=e906]: from_best_host() + - text: 自动选最低延迟服务器: + - generic [ref=e907]: + - generic [ref=e908]: "from easy_tdx import MacClient with MacClient.from_best_host() as c: df = c.get_stock_kline(...)" + - button "Copy code to clipboard" [ref=e910] [cursor=pointer]: + - img [ref=e911] + - table [ref=e915]: + - rowgroup [ref=e916]: + - row "客户端 端口 覆盖范围" [ref=e917]: + - columnheader "客户端" [ref=e918] + - columnheader "端口" [ref=e919] + - columnheader "覆盖范围" [ref=e920] + - rowgroup [ref=e921]: + - row "MacClient / AsyncMacClient 7709 A 股行情(MAC 协议,推荐)" [ref=e922]: + - cell "MacClient / AsyncMacClient" [ref=e923]: + - code [ref=e924]: MacClient + - text: / + - code [ref=e925]: AsyncMacClient + - cell "7709" [ref=e926] + - cell "A 股行情(MAC 协议,推荐)" [ref=e927] + - row "MacExClient / AsyncMacExClient 7727 港股/美股/期货(MAC 协议)" [ref=e928]: + - cell "MacExClient / AsyncMacExClient" [ref=e929]: + - code [ref=e930]: MacExClient + - text: / + - code [ref=e931]: AsyncMacExClient + - cell "7727" [ref=e932] + - cell "港股/美股/期货(MAC 协议)" [ref=e933] + - row "UnifiedTdxClient / AsyncUnifiedTdxClient 自动 A 股 + 扩展市场统一入口" [ref=e934]: + - cell "UnifiedTdxClient / AsyncUnifiedTdxClient" [ref=e935]: + - code [ref=e936]: UnifiedTdxClient + - text: / + - code [ref=e937]: AsyncUnifiedTdxClient + - cell "自动" [ref=e938] + - cell "A 股 + 扩展市场统一入口" [ref=e939] + - row "TdxClient / AsyncTdxClient 7709 A 股行情(标准协议)" [ref=e940]: + - cell "TdxClient / AsyncTdxClient" [ref=e941]: + - code [ref=e942]: TdxClient + - text: / + - code [ref=e943]: AsyncTdxClient + - cell "7709" [ref=e944] + - cell "A 股行情(标准协议)" [ref=e945] + - generic [ref=e946]: + - heading "MAC 协议(推荐)" [level=3] [ref=e947] + - 'link "Permalink: MAC 协议(推荐)" [ref=e948] [cursor=pointer]': + - /url: "#mac-协议推荐" + - img [ref=e949] + - generic [ref=e951]: + - heading "报价" [level=4] [ref=e952] + - 'link "Permalink: 报价" [ref=e953] [cursor=pointer]': + - /url: "#报价" + - img [ref=e954] + - generic [ref=e956]: + - generic [ref=e957]: "from easy_tdx import MacClient, Market, Category, SortType, SortOrder with MacClient.from_best_host() as c: # 批量报价(最多 80 只/次) df = c.get_stock_quotes([(Market.SH, \"600519\"), (Market.SZ, \"000858\")]) # 市场分类排序报价 df = c.get_stock_quotes_list( Category.A, count=20, sort_type=SortType.CHANGE_PCT, sort_order=SortOrder.DESC, )" + - button "Copy code to clipboard" [ref=e959] [cursor=pointer]: + - img [ref=e960] + - paragraph [ref=e963]: + - text: 返回列: + - code [ref=e964]: market, code, name + - text: + 动态字段( + - code [ref=e965]: pre_close, open, high, low, close, vol, amount, turnover, vol_ratio + - text: 等)。 + - generic [ref=e966]: + - heading "K 线(支持复权)" [level=4] [ref=e967] + - 'link "Permalink: K 线(支持复权)" [ref=e968] [cursor=pointer]': + - /url: "#k-线支持复权" + - img [ref=e969] + - generic [ref=e971]: + - generic [ref=e972]: "from easy_tdx import MacClient, Market, Period, Adjust with MacClient.from_best_host() as c: # 日K前复权 df = c.get_stock_kline(Market.SH, \"600519\", Period.DAILY, count=10, adjust=Adjust.QFQ) # 5分钟线 df = c.get_stock_kline(Market.SZ, \"000001\", Period.MIN_5, count=100)" + - button "Copy code to clipboard" [ref=e974] [cursor=pointer]: + - img [ref=e975] + - paragraph [ref=e978]: + - text: 返回列: + - code [ref=e979]: datetime, open, close, high, low, vol, amount + - text: 。 + - generic [ref=e980]: + - heading "技术指标" [level=4] [ref=e981] + - 'link "Permalink: 技术指标" [ref=e982] [cursor=pointer]': + - /url: "#技术指标-1" + - img [ref=e983] + - paragraph [ref=e985]: + - text: 自动获取 200+ 条历史数据预热 EMA,返回最后 + - code [ref=e986]: count + - text: 条带指标的结果: + - generic [ref=e987]: + - generic [ref=e988]: "from easy_tdx import MacClient, Market, Period, Adjust from easy_tdx.indicator import compute_indicators, list_indicators with MacClient.from_best_host() as c: # 便捷方法:获取 K 线 + 计算指标一步完成(默认前复权) df = c.get_stock_kline_with_indicators( Market.SH, \"600519\", indicators=[\"MACD\", \"KDJ\", \"RSI\", \"BOLL\"], count=30, ) # df 包含: datetime, open, close, high, low, vol, amount # + MACD_DIF, MACD_DEA, MACD_HIST, KDJ_K, KDJ_D, KDJ_J, RSI, # BOLL_UPPER, BOLL_MID, BOLL_LOWER # 自定义指标参数 df = c.get_stock_kline_with_indicators( Market.SH, \"600519\", indicators=[\"MACD\"], params={\"MACD\": {\"SHORT\": 10, \"LONG\": 22}}, ) # 独立使用:对已有 DataFrame 计算指标 raw = c.get_stock_kline(Market.SH, \"600519\", Period.DAILY, count=200, adjust=Adjust.QFQ) result = compute_indicators(raw, [\"ATR\", \"CCI\", \"WR\"], tail=30) # 查看所有可用指标 for info in list_indicators(): print(info[\"name\"], info[\"description\"], info[\"outputs\"])" + - button "Copy code to clipboard" [ref=e990] [cursor=pointer]: + - img [ref=e991] + - paragraph [ref=e994]: 支持 31 个技术指标: + - table [ref=e996]: + - rowgroup [ref=e997]: + - row "指标 输入 输出列" [ref=e998]: + - columnheader "指标" [ref=e999] + - columnheader "输入" [ref=e1000] + - columnheader "输出列" [ref=e1001] + - rowgroup [ref=e1002]: + - row "MACD close MACD_DIF, MACD_DEA, MACD_HIST" [ref=e1003]: + - cell "MACD" [ref=e1004] + - cell "close" [ref=e1005] + - cell "MACD_DIF, MACD_DEA, MACD_HIST" [ref=e1006] + - row "KDJ close, high, low KDJ_K, KDJ_D, KDJ_J" [ref=e1007]: + - cell "KDJ" [ref=e1008] + - cell "close, high, low" [ref=e1009] + - cell "KDJ_K, KDJ_D, KDJ_J" [ref=e1010] + - row "RSI close RSI" [ref=e1011]: + - cell "RSI" [ref=e1012] + - cell "close" [ref=e1013] + - cell "RSI" [ref=e1014] + - row "BOLL close BOLL_UPPER, BOLL_MID, BOLL_LOWER" [ref=e1015]: + - cell "BOLL" [ref=e1016] + - cell "close" [ref=e1017] + - cell "BOLL_UPPER, BOLL_MID, BOLL_LOWER" [ref=e1018] + - row "DMI close, high, low DMI_PDI, DMI_MDI, DMI_ADX, DMI_ADXR" [ref=e1019]: + - cell "DMI" [ref=e1020] + - cell "close, high, low" [ref=e1021] + - cell "DMI_PDI, DMI_MDI, DMI_ADX, DMI_ADXR" [ref=e1022] + - row "ATR close, high, low ATR" [ref=e1023]: + - cell "ATR" [ref=e1024] + - cell "close, high, low" [ref=e1025] + - cell "ATR" [ref=e1026] + - row "WR close, high, low WR1, WR2" [ref=e1027]: + - cell "WR" [ref=e1028] + - cell "close, high, low" [ref=e1029] + - cell "WR1, WR2" [ref=e1030] + - row "CCI close, high, low CCI" [ref=e1031]: + - cell "CCI" [ref=e1032] + - cell "close, high, low" [ref=e1033] + - cell "CCI" [ref=e1034] + - row "BIAS close BIAS1, BIAS2, BIAS3" [ref=e1035]: + - cell "BIAS" [ref=e1036] + - cell "close" [ref=e1037] + - cell "BIAS1, BIAS2, BIAS3" [ref=e1038] + - row "OBV close, vol OBV" [ref=e1039]: + - cell "OBV" [ref=e1040] + - cell "close, vol" [ref=e1041] + - cell "OBV" [ref=e1042] + - row "VR close, vol VR" [ref=e1043]: + - cell "VR" [ref=e1044] + - cell "close, vol" [ref=e1045] + - cell "VR" [ref=e1046] + - row "EMV high, low, vol EMV, EMV_MA" [ref=e1047]: + - cell "EMV" [ref=e1048] + - cell "high, low, vol" [ref=e1049] + - cell "EMV, EMV_MA" [ref=e1050] + - row "MFI close, high, low, vol MFI" [ref=e1051]: + - cell "MFI" [ref=e1052] + - cell "close, high, low, vol" [ref=e1053] + - cell "MFI" [ref=e1054] + - row "BRAR open, close, high, low AR, BR" [ref=e1055]: + - cell "BRAR" [ref=e1056] + - cell "open, close, high, low" [ref=e1057] + - cell "AR, BR" [ref=e1058] + - row "ASI open, close, high, low ASI, ASI_MA" [ref=e1059]: + - cell "ASI" [ref=e1060] + - cell "open, close, high, low" [ref=e1061] + - cell "ASI, ASI_MA" [ref=e1062] + - row "TRIX close TRIX, TRIX_MA" [ref=e1063]: + - cell "TRIX" [ref=e1064] + - cell "close" [ref=e1065] + - cell "TRIX, TRIX_MA" [ref=e1066] + - row "DPO close DPO, DPO_MA" [ref=e1067]: + - cell "DPO" [ref=e1068] + - cell "close" [ref=e1069] + - cell "DPO, DPO_MA" [ref=e1070] + - row "MTM close MTM, MTM_MA" [ref=e1071]: + - cell "MTM" [ref=e1072] + - cell "close" [ref=e1073] + - cell "MTM, MTM_MA" [ref=e1074] + - row "ROC close ROC, ROC_MA" [ref=e1075]: + - cell "ROC" [ref=e1076] + - cell "close" [ref=e1077] + - cell "ROC, ROC_MA" [ref=e1078] + - row "EXPMA close EXPMA_12, EXPMA_50" [ref=e1079]: + - cell "EXPMA" [ref=e1080] + - cell "close" [ref=e1081] + - cell "EXPMA_12, EXPMA_50" [ref=e1082] + - row "BBI close BBI" [ref=e1083]: + - cell "BBI" [ref=e1084] + - cell "close" [ref=e1085] + - cell "BBI" [ref=e1086] + - row "PSY close PSY, PSY_MA" [ref=e1087]: + - cell "PSY" [ref=e1088] + - cell "close" [ref=e1089] + - cell "PSY, PSY_MA" [ref=e1090] + - row "DFMA close DFMA_DIF, DFMA_DMA" [ref=e1091]: + - cell "DFMA" [ref=e1092] + - cell "close" [ref=e1093] + - cell "DFMA_DIF, DFMA_DMA" [ref=e1094] + - row "CR close, high, low CR" [ref=e1095]: + - cell "CR" [ref=e1096] + - cell "close, high, low" [ref=e1097] + - cell "CR" [ref=e1098] + - row "KTN close, high, low KTN_UPPER, KTN_MID, KTN_LOWER" [ref=e1099]: + - cell "KTN" [ref=e1100] + - cell "close, high, low" [ref=e1101] + - cell "KTN_UPPER, KTN_MID, KTN_LOWER" [ref=e1102] + - row "XSII close, high, low XSII_TD1, XSII_TD2, XSII_TD3, XSII_TD4" [ref=e1103]: + - cell "XSII" [ref=e1104] + - cell "close, high, low" [ref=e1105] + - cell "XSII_TD1, XSII_TD2, XSII_TD3, XSII_TD4" [ref=e1106] + - row "MASS high, low MASS, MASS_MA" [ref=e1107]: + - cell "MASS" [ref=e1108] + - cell "high, low" [ref=e1109] + - cell "MASS, MASS_MA" [ref=e1110] + - row "TAQ high, low TAQ_UP, TAQ_MID, TAQ_DOWN" [ref=e1111]: + - cell "TAQ" [ref=e1112] + - cell "high, low" [ref=e1113] + - cell "TAQ_UP, TAQ_MID, TAQ_DOWN" [ref=e1114] + - row "ZHUOYAO close ZY_LONG, ZY_MID, ZY_SHORT, ZY_TREND" [ref=e1115]: + - cell "ZHUOYAO" [ref=e1116] + - cell "close" [ref=e1117] + - cell "ZY_LONG, ZY_MID, ZY_SHORT, ZY_TREND" [ref=e1118] + - row "BIAS_SIGNAL close BS_X, BS_SMA, BS_LMA" [ref=e1119]: + - cell "BIAS_SIGNAL" [ref=e1120] + - cell "close" [ref=e1121] + - cell "BS_X, BS_SMA, BS_LMA" [ref=e1122] + - generic [ref=e1123]: + - heading "分时" [level=4] [ref=e1124] + - 'link "Permalink: 分时" [ref=e1125] [cursor=pointer]': + - /url: "#分时" + - img [ref=e1126] + - generic [ref=e1128]: + - generic [ref=e1129]: "with MacClient.from_best_host() as c: df = c.get_tick_chart(Market.SH, \"600519\") # 单日分时 df = c.get_tick_charts(Market.SH, \"600519\", days=3) # 多日分时(最多5天) df = c.get_chart_sampling(Market.SH, \"600519\") # 240点缩略采样" + - button "Copy code to clipboard" [ref=e1131] [cursor=pointer]: + - img [ref=e1132] + - generic [ref=e1135]: + - heading "逐笔成交" [level=4] [ref=e1136] + - 'link "Permalink: 逐笔成交" [ref=e1137] [cursor=pointer]': + - /url: "#逐笔成交" + - img [ref=e1138] + - generic [ref=e1140]: + - generic [ref=e1141]: "with MacClient.from_best_host() as c: df = c.get_transactions(Market.SH, \"600519\", count=100) df = c.get_transactions(Market.SH, \"600519\", count=100, date=20250115)" + - button "Copy code to clipboard" [ref=e1143] [cursor=pointer]: + - img [ref=e1144] + - generic [ref=e1147]: + - heading "板块" [level=4] [ref=e1148] + - 'link "Permalink: 板块" [ref=e1149] [cursor=pointer]': + - /url: "#板块-1" + - img [ref=e1150] + - generic [ref=e1152]: + - generic [ref=e1153]: "from easy_tdx import BoardType with MacClient.from_best_host() as c: df = c.get_board_list(BoardType.GN) # 概念板块 df = c.get_board_members(\"881001\", sort_type=SortType.CHANGE_PCT) df = c.get_belong_board(Market.SZ, \"000001\") # 个股所属板块 # 板块汇总:成交额、主力净流入、涨跌家数 summary = c.get_board_summary(\"881001\") # summary = { # \"member_count\": 82, # \"amount\": 5823456000.0, # 板块总成交额(元) # \"vol\": 412356789, # 板块总成交量(股) # \"main_net_amount\": -123456.0, # 当日主力净流入 # \"main_net_3d\": -567890.0, # 近3日主力净流入 # \"main_net_5d\": -234567.0, # 近5日主力净流入 # \"up_count\": 45, # \"down_count\": 37, # \"members\": DataFrame(...), # 成分股明细 # } # 板块涨跌幅排行榜 df = c.get_board_ranking(BoardType.HY, top_n=10, sort_by=\"change_pct\") df = c.get_board_ranking(BoardType.GN, top_n=20, sort_by=\"main_net_amount\") # 返回列:code, name, change_pct, amount, vol, main_net_amount, up_count, down_count, member_count" + - button "Copy code to clipboard" [ref=e1155] [cursor=pointer]: + - img [ref=e1156] + - generic [ref=e1159]: + - heading "资金流向" [level=4] [ref=e1160] + - 'link "Permalink: 资金流向" [ref=e1161] [cursor=pointer]': + - /url: "#资金流向" + - img [ref=e1162] + - generic [ref=e1164]: + - generic [ref=e1165]: "with MacClient.from_best_host() as c: df = c.get_capital_flow(Market.SH, \"600519\")" + - button "Copy code to clipboard" [ref=e1167] [cursor=pointer]: + - img [ref=e1168] + - paragraph [ref=e1171]: + - text: 返回列: + - code [ref=e1172]: date, main_in, main_out, main_net, small_in/out/net, mid_in/out/net, large_in/out/net + - text: 。 + - generic [ref=e1173]: + - heading "监控" [level=4] [ref=e1174] + - 'link "Permalink: 监控" [ref=e1175] [cursor=pointer]': + - /url: "#监控" + - img [ref=e1176] + - generic [ref=e1178]: + - generic [ref=e1179]: "with MacClient.from_best_host() as c: df = c.get_auction(Market.SH, \"600519\") # 集合竞价 df = c.get_unusual(Market.SH) # 市场异动 df = c.get_symbol_info(Market.SZ, \"000001\") # 个股特征快照 df = c.get_server_info() # 服务器交易时段" + - button "Copy code to clipboard" [ref=e1181] [cursor=pointer]: + - img [ref=e1182] + - generic [ref=e1185]: + - heading "扩展市场" [level=3] [ref=e1186] + - 'link "Permalink: 扩展市场" [ref=e1187] [cursor=pointer]': + - /url: "#扩展市场" + - img [ref=e1188] + - generic [ref=e1190]: + - generic [ref=e1191]: "from easy_tdx import MacExClient, ExMarket, Period with MacExClient.from_best_host() as c: count = c.goods_count(ExMarket.HK_MAIN_BOARD) df = c.goods_list(ExMarket.HK_MAIN_BOARD, start=0, count=50) df = c.goods_kline(ExMarket.US_STOCK, \"AAPL\", Period.DAILY, count=10) df = c.goods_quotes([(ExMarket.HK_MAIN_BOARD, \"00700\")]) df = c.goods_tick_chart(ExMarket.HK_MAIN_BOARD, \"00700\") df = c.goods_transaction(ExMarket.HK_MAIN_BOARD, \"00700\", count=100)" + - button "Copy code to clipboard" [ref=e1193] [cursor=pointer]: + - img [ref=e1194] + - generic [ref=e1197]: + - heading "统一客户端" [level=3] [ref=e1198] + - 'link "Permalink: 统一客户端" [ref=e1199] [cursor=pointer]': + - /url: "#统一客户端" + - img [ref=e1200] + - generic [ref=e1202]: + - generic [ref=e1203]: "from easy_tdx import UnifiedTdxClient, ExMarket, Market, Period with UnifiedTdxClient() as client: # A 股 -- 自动路由到 MacClient df = client.get_stock_kline(Market.SH, \"600519\", Period.DAILY, count=5) df = client.get_stock_quotes([(Market.SH, \"600519\")]) df = client.get_board_list() # 扩展市场 -- 自动路由到 MacExClient df = client.goods_kline(ExMarket.HK_MAIN_BOARD, \"00700\", Period.DAILY, count=5)" + - button "Copy code to clipboard" [ref=e1205] [cursor=pointer]: + - img [ref=e1206] + - generic [ref=e1209]: + - heading "标准协议" [level=3] [ref=e1210] + - 'link "Permalink: 标准协议" [ref=e1211] [cursor=pointer]': + - /url: "#标准协议" + - img [ref=e1212] + - generic [ref=e1214]: + - generic [ref=e1215]: "from easy_tdx import TdxClient, Market, KlineCategory with TdxClient.from_best_host() as c: count = c.get_security_count(Market.SH) stocks = c.get_security_list(Market.SH, start=0) quotes = c.get_security_quotes([(Market.SH, \"600000\"), (Market.SZ, \"000001\")]) bars = c.get_security_bars(Market.SZ, \"002176\", KlineCategory.DAY, 0, 100) minute = c.get_minute_time_data(Market.SH, \"600000\") trades = c.get_transaction_data(Market.SH, \"600000\", 0, 20) flow = c.get_fund_flow(Market.SH, \"600519\") blocks = c.get_block_info(\"block_gn.dat\") xdxr = c.get_xdxr_info(Market.SH, \"600519\") stat = c.get_market_stat()" + - button "Copy code to clipboard" [ref=e1217] [cursor=pointer]: + - img [ref=e1218] + - paragraph [ref=e1221]: + - code [ref=e1222]: AsyncTdxClient + - text: 提供对应的 + - code [ref=e1223]: async def + - text: 方法,接口一一对应。 + - generic [ref=e1224]: + - heading "SecurityQuote 字段说明" [level=3] [ref=e1225] + - 'link "Permalink: SecurityQuote 字段说明" [ref=e1226] [cursor=pointer]': + - /url: "#securityquote-字段说明" + - img [ref=e1227] + - paragraph [ref=e1229]: + - code [ref=e1230]: get_security_quotes() + - text: 返回的 DataFrame 包含以下特殊字段: + - table [ref=e1232]: + - rowgroup [ref=e1233]: + - row "字段 类型 说明" [ref=e1234]: + - columnheader "字段" [ref=e1235] + - columnheader "类型" [ref=e1236] + - columnheader "说明" [ref=e1237] + - rowgroup [ref=e1238]: + - row "trading_status int 交易状态标志。0x8020(32800) = 停牌,其余值表示正常交易或集合竞价" [ref=e1239]: + - cell "trading_status" [ref=e1240]: + - code [ref=e1241]: trading_status + - cell "int" [ref=e1242] + - cell "交易状态标志。0x8020(32800) = 停牌,其余值表示正常交易或集合竞价" [ref=e1243]: + - text: 交易状态标志。 + - code [ref=e1244]: "0x8020" + - text: (32800) = 停牌,其余值表示正常交易或集合竞价 + - row "open_amount float 集合竞价成交金额(元)。仅个股有效,指数该字段无意义" [ref=e1245]: + - cell "open_amount" [ref=e1246]: + - code [ref=e1247]: open_amount + - cell "float" [ref=e1248] + - cell "集合竞价成交金额(元)。仅个股有效,指数该字段无意义" [ref=e1249] + - row "server_time str 服务器时间,格式 HH:MM:SS.mmm" [ref=e1250]: + - cell "server_time" [ref=e1251]: + - code [ref=e1252]: server_time + - cell "str" [ref=e1253] + - cell "服务器时间,格式 HH:MM:SS.mmm" [ref=e1254]: + - text: 服务器时间,格式 + - code [ref=e1255]: HH:MM:SS.mmm + - 'row "unknown_2 int 指数: 集合竞价成交金额/100;个股: 舍入残差≈0" [ref=e1256]': + - cell "unknown_2" [ref=e1257]: + - code [ref=e1258]: unknown_2 + - cell "int" [ref=e1259] + - 'cell "指数: 集合竞价成交金额/100;个股: 舍入残差≈0" [ref=e1260]' + - 'row "unknown_3 int 个股: 集合竞价成交金额/100;指数: 负值/无意义" [ref=e1261]': + - cell "unknown_3" [ref=e1262]: + - code [ref=e1263]: unknown_3 + - cell "int" [ref=e1264] + - 'cell "个股: 集合竞价成交金额/100;指数: 负值/无意义" [ref=e1265]' + - row "unknown_5-8 int 保留字段,恒为 0" [ref=e1266]: + - cell "unknown_5-8" [ref=e1267]: + - code [ref=e1268]: unknown_5-8 + - cell "int" [ref=e1269] + - cell "保留字段,恒为 0" [ref=e1270] + - paragraph [ref=e1271]: 检测停牌: + - generic [ref=e1272]: + - generic [ref=e1273]: df = c.get_security_quotes([(Market.SH, "600000")]) is_suspended = df.iloc[0]["trading_status"] == 0x8020 + - button "Copy code to clipboard" [ref=e1275] [cursor=pointer]: + - img [ref=e1276] + - generic [ref=e1279]: + - heading "离线数据读取" [level=3] [ref=e1280] + - 'link "Permalink: 离线数据读取" [ref=e1281] [cursor=pointer]': + - /url: "#离线数据读取" + - img [ref=e1282] + - paragraph [ref=e1284]: 无需网络,从本地通达信安装目录直接读取: + - generic [ref=e1285]: + - generic [ref=e1286]: from easy_tdx.offline import detect_tdx_home, read_daily_bars, find_daily_bar_file from easy_tdx import Market home = detect_tdx_home() filepath = find_daily_bar_file(Market.SH, "600000") bars = read_daily_bars(filepath) + - button "Copy code to clipboard" [ref=e1288] [cursor=pointer]: + - img [ref=e1289] + - paragraph [ref=e1292]: 支持:日线、分钟线、扩展市场日线、板块、股本变迁、历史财务数据。 + - paragraph [ref=e1293]: v1.5.0 起可通过 CLI 直接使用: + - generic [ref=e1294]: + - generic [ref=e1295]: easy-tdx offline daily SH 600000 --count 10 --table easy-tdx offline ex-files --table easy-tdx offline ex-daily 29#A1801 --table + - button "Copy code to clipboard" [ref=e1297] [cursor=pointer]: + - img [ref=e1298] + - generic [ref=e1301]: + - heading "枚举参考" [level=2] [ref=e1302] + - 'link "Permalink: 枚举参考" [ref=e1303] [cursor=pointer]': + - /url: "#枚举参考" + - img [ref=e1304] + - generic [ref=e1306]: + - heading "Period(K 线周期)" [level=3] [ref=e1307] + - 'link "Permalink: Period(K 线周期)" [ref=e1308] [cursor=pointer]': + - /url: "#periodk-线周期" + - img [ref=e1309] + - table [ref=e1312]: + - rowgroup [ref=e1313]: + - row "值 名称 说明" [ref=e1314]: + - columnheader "值" [ref=e1315] + - columnheader "名称" [ref=e1316] + - columnheader "说明" [ref=e1317] + - rowgroup [ref=e1318]: + - row "7 MIN_1 1 分钟" [ref=e1319]: + - cell "7" [ref=e1320] + - cell "MIN_1" [ref=e1321]: + - code [ref=e1322]: MIN_1 + - cell "1 分钟" [ref=e1323] + - row "0 MIN_5 5 分钟" [ref=e1324]: + - cell "0" [ref=e1325] + - cell "MIN_5" [ref=e1326]: + - code [ref=e1327]: MIN_5 + - cell "5 分钟" [ref=e1328] + - row "1 MIN_15 15 分钟" [ref=e1329]: + - cell "1" [ref=e1330] + - cell "MIN_15" [ref=e1331]: + - code [ref=e1332]: MIN_15 + - cell "15 分钟" [ref=e1333] + - row "2 MIN_30 30 分钟" [ref=e1334]: + - cell "2" [ref=e1335] + - cell "MIN_30" [ref=e1336]: + - code [ref=e1337]: MIN_30 + - cell "30 分钟" [ref=e1338] + - row "3 MIN_60 60 分钟" [ref=e1339]: + - cell "3" [ref=e1340] + - cell "MIN_60" [ref=e1341]: + - code [ref=e1342]: MIN_60 + - cell "60 分钟" [ref=e1343] + - row "4 DAILY 日线" [ref=e1344]: + - cell "4" [ref=e1345] + - cell "DAILY" [ref=e1346]: + - code [ref=e1347]: DAILY + - cell "日线" [ref=e1348] + - row "5 WEEKLY 周线" [ref=e1349]: + - cell "5" [ref=e1350] + - cell "WEEKLY" [ref=e1351]: + - code [ref=e1352]: WEEKLY + - cell "周线" [ref=e1353] + - row "6 MONTHLY 月线" [ref=e1354]: + - cell "6" [ref=e1355] + - cell "MONTHLY" [ref=e1356]: + - code [ref=e1357]: MONTHLY + - cell "月线" [ref=e1358] + - row "10 QUARTERLY 季线" [ref=e1359]: + - cell "10" [ref=e1360] + - cell "QUARTERLY" [ref=e1361]: + - code [ref=e1362]: QUARTERLY + - cell "季线" [ref=e1363] + - row "11 YEARLY 年线" [ref=e1364]: + - cell "11" [ref=e1365] + - cell "YEARLY" [ref=e1366]: + - code [ref=e1367]: YEARLY + - cell "年线" [ref=e1368] + - generic [ref=e1369]: + - heading "Adjust(复权类型)" [level=3] [ref=e1370] + - 'link "Permalink: Adjust(复权类型)" [ref=e1371] [cursor=pointer]': + - /url: "#adjust复权类型" + - img [ref=e1372] + - table [ref=e1375]: + - rowgroup [ref=e1376]: + - row "值 名称 说明" [ref=e1377]: + - columnheader "值" [ref=e1378] + - columnheader "名称" [ref=e1379] + - columnheader "说明" [ref=e1380] + - rowgroup [ref=e1381]: + - row "0 NONE 不复权" [ref=e1382]: + - cell "0" [ref=e1383] + - cell "NONE" [ref=e1384]: + - code [ref=e1385]: NONE + - cell "不复权" [ref=e1386] + - row "1 QFQ 前复权" [ref=e1387]: + - cell "1" [ref=e1388] + - cell "QFQ" [ref=e1389]: + - code [ref=e1390]: QFQ + - cell "前复权" [ref=e1391] + - row "2 HFQ 后复权" [ref=e1392]: + - cell "2" [ref=e1393] + - cell "HFQ" [ref=e1394]: + - code [ref=e1395]: HFQ + - cell "后复权" [ref=e1396] + - generic [ref=e1397]: + - heading "Category(市场分类)" [level=3] [ref=e1398] + - 'link "Permalink: Category(市场分类)" [ref=e1399] [cursor=pointer]': + - /url: "#category市场分类" + - img [ref=e1400] + - table [ref=e1403]: + - rowgroup [ref=e1404]: + - row "值 名称 说明" [ref=e1405]: + - columnheader "值" [ref=e1406] + - columnheader "名称" [ref=e1407] + - columnheader "说明" [ref=e1408] + - rowgroup [ref=e1409]: + - row "0 SH 上证 A 股" [ref=e1410]: + - cell "0" [ref=e1411] + - cell "SH" [ref=e1412]: + - code [ref=e1413]: SH + - cell "上证 A 股" [ref=e1414] + - row "2 SZ 深证 A 股" [ref=e1415]: + - cell "2" [ref=e1416] + - cell "SZ" [ref=e1417]: + - code [ref=e1418]: SZ + - cell "深证 A 股" [ref=e1419] + - row "6 A 全部 A 股" [ref=e1420]: + - cell "6" [ref=e1421] + - cell "A" [ref=e1422]: + - code [ref=e1423]: A + - cell "全部 A 股" [ref=e1424] + - row "7 B B 股" [ref=e1425]: + - cell "7" [ref=e1426] + - cell "B" [ref=e1427]: + - code [ref=e1428]: B + - cell "B 股" [ref=e1429] + - row "8 KCB 科创板" [ref=e1430]: + - cell "8" [ref=e1431] + - cell "KCB" [ref=e1432]: + - code [ref=e1433]: KCB + - cell "科创板" [ref=e1434] + - row "12 BJ 北证 A 股" [ref=e1435]: + - cell "12" [ref=e1436] + - cell "BJ" [ref=e1437]: + - code [ref=e1438]: BJ + - cell "北证 A 股" [ref=e1439] + - row "14 CYB 创业板" [ref=e1440]: + - cell "14" [ref=e1441] + - cell "CYB" [ref=e1442]: + - code [ref=e1443]: CYB + - cell "创业板" [ref=e1444] + - generic [ref=e1445]: + - heading "BoardType(板块类型)" [level=3] [ref=e1446] + - 'link "Permalink: BoardType(板块类型)" [ref=e1447] [cursor=pointer]': + - /url: "#boardtype板块类型" + - img [ref=e1448] + - table [ref=e1451]: + - rowgroup [ref=e1452]: + - row "值 名称 说明" [ref=e1453]: + - columnheader "值" [ref=e1454] + - columnheader "名称" [ref=e1455] + - columnheader "说明" [ref=e1456] + - rowgroup [ref=e1457]: + - row "0 HY 行业一级" [ref=e1458]: + - cell "0" [ref=e1459] + - cell "HY" [ref=e1460]: + - code [ref=e1461]: HY + - cell "行业一级" [ref=e1462] + - row "1 HY2 行业二级" [ref=e1463]: + - cell "1" [ref=e1464] + - cell "HY2" [ref=e1465]: + - code [ref=e1466]: HY2 + - cell "行业二级" [ref=e1467] + - row "3 GN 概念" [ref=e1468]: + - cell "3" [ref=e1469] + - cell "GN" [ref=e1470]: + - code [ref=e1471]: GN + - cell "概念" [ref=e1472] + - row "4 FG 风格" [ref=e1473]: + - cell "4" [ref=e1474] + - cell "FG" [ref=e1475]: + - code [ref=e1476]: FG + - cell "风格" [ref=e1477] + - row "5 DQ 地区" [ref=e1478]: + - cell "5" [ref=e1479] + - cell "DQ" [ref=e1480]: + - code [ref=e1481]: DQ + - cell "地区" [ref=e1482] + - row "255 ALL 全部" [ref=e1483]: + - cell "255" [ref=e1484] + - cell "ALL" [ref=e1485]: + - code [ref=e1486]: ALL + - cell "全部" [ref=e1487] + - generic [ref=e1488]: + - heading "SortType(排序字段)" [level=3] [ref=e1489] + - 'link "Permalink: SortType(排序字段)" [ref=e1490] [cursor=pointer]': + - /url: "#sorttype排序字段" + - img [ref=e1491] + - table [ref=e1494]: + - rowgroup [ref=e1495]: + - row "名称 说明" [ref=e1496]: + - columnheader "名称" [ref=e1497] + - columnheader "说明" [ref=e1498] + - rowgroup [ref=e1499]: + - row "CODE 代码" [ref=e1500]: + - cell "CODE" [ref=e1501]: + - code [ref=e1502]: CODE + - cell "代码" [ref=e1503] + - row "PRICE 现价" [ref=e1504]: + - cell "PRICE" [ref=e1505]: + - code [ref=e1506]: PRICE + - cell "现价" [ref=e1507] + - row "CHANGE_PCT 涨幅%" [ref=e1508]: + - cell "CHANGE_PCT" [ref=e1509]: + - code [ref=e1510]: CHANGE_PCT + - cell "涨幅%" [ref=e1511] + - row "VOLUME 成交量" [ref=e1512]: + - cell "VOLUME" [ref=e1513]: + - code [ref=e1514]: VOLUME + - cell "成交量" [ref=e1515] + - row "TOTAL_AMOUNT 成交额" [ref=e1516]: + - cell "TOTAL_AMOUNT" [ref=e1517]: + - code [ref=e1518]: TOTAL_AMOUNT + - cell "成交额" [ref=e1519] + - row "TURNOVER_RATE 换手%" [ref=e1520]: + - cell "TURNOVER_RATE" [ref=e1521]: + - code [ref=e1522]: TURNOVER_RATE + - cell "换手%" [ref=e1523] + - row "MAIN_NET_AMOUNT 主力净额" [ref=e1524]: + - cell "MAIN_NET_AMOUNT" [ref=e1525]: + - code [ref=e1526]: MAIN_NET_AMOUNT + - cell "主力净额" [ref=e1527] + - generic [ref=e1528]: + - heading "ExMarket(扩展市场)" [level=3] [ref=e1529] + - 'link "Permalink: ExMarket(扩展市场)" [ref=e1530] [cursor=pointer]': + - /url: "#exmarket扩展市场" + - img [ref=e1531] + - table [ref=e1534]: + - rowgroup [ref=e1535]: + - row "值 名称 说明" [ref=e1536]: + - columnheader "值" [ref=e1537] + - columnheader "名称" [ref=e1538] + - columnheader "说明" [ref=e1539] + - rowgroup [ref=e1540]: + - row "28 ZZ_FUTURES 郑州商品" [ref=e1541]: + - cell "28" [ref=e1542] + - cell "ZZ_FUTURES" [ref=e1543]: + - code [ref=e1544]: ZZ_FUTURES + - cell "郑州商品" [ref=e1545] + - row "29 DL_FUTURES 大连商品" [ref=e1546]: + - cell "29" [ref=e1547] + - cell "DL_FUTURES" [ref=e1548]: + - code [ref=e1549]: DL_FUTURES + - cell "大连商品" [ref=e1550] + - row "30 SH_FUTURES 上海期货" [ref=e1551]: + - cell "30" [ref=e1552] + - cell "SH_FUTURES" [ref=e1553]: + - code [ref=e1554]: SH_FUTURES + - cell "上海期货" [ref=e1555] + - row "31 HK_MAIN_BOARD 香港主板" [ref=e1556]: + - cell "31" [ref=e1557] + - cell "HK_MAIN_BOARD" [ref=e1558]: + - code [ref=e1559]: HK_MAIN_BOARD + - cell "香港主板" [ref=e1560] + - row "47 CFFEX_FUTURES 中金所期货" [ref=e1561]: + - cell "47" [ref=e1562] + - cell "CFFEX_FUTURES" [ref=e1563]: + - code [ref=e1564]: CFFEX_FUTURES + - cell "中金所期货" [ref=e1565] + - row "48 HK_GEM 香港创业板" [ref=e1566]: + - cell "48" [ref=e1567] + - cell "HK_GEM" [ref=e1568]: + - code [ref=e1569]: HK_GEM + - cell "香港创业板" [ref=e1570] + - row "74 US_STOCK 美国股票" [ref=e1571]: + - cell "74" [ref=e1572] + - cell "US_STOCK" [ref=e1573]: + - code [ref=e1574]: US_STOCK + - cell "美国股票" [ref=e1575] + - generic [ref=e1576]: + - heading "Market(市场)" [level=3] [ref=e1577] + - 'link "Permalink: Market(市场)" [ref=e1578] [cursor=pointer]': + - /url: "#market市场" + - img [ref=e1579] + - table [ref=e1582]: + - rowgroup [ref=e1583]: + - row "值 名称 说明" [ref=e1584]: + - columnheader "值" [ref=e1585] + - columnheader "名称" [ref=e1586] + - columnheader "说明" [ref=e1587] + - rowgroup [ref=e1588]: + - row "0 SZ 深圳" [ref=e1589]: + - cell "0" [ref=e1590] + - cell "SZ" [ref=e1591]: + - code [ref=e1592]: SZ + - cell "深圳" [ref=e1593] + - row "1 SH 上海" [ref=e1594]: + - cell "1" [ref=e1595] + - cell "SH" [ref=e1596]: + - code [ref=e1597]: SH + - cell "上海" [ref=e1598] + - row "2 BJ 北京" [ref=e1599]: + - cell "2" [ref=e1600] + - cell "BJ" [ref=e1601]: + - code [ref=e1602]: BJ + - cell "北京" [ref=e1603] + - generic [ref=e1604]: + - heading "完整 API 列表" [level=2] [ref=e1605] + - 'link "Permalink: 完整 API 列表" [ref=e1606] [cursor=pointer]': + - /url: "#完整-api-列表" + - img [ref=e1607] + - generic [ref=e1609]: + - heading "MacClient / AsyncMacClient" [level=3] [ref=e1610] + - 'link "Permalink: MacClient / AsyncMacClient" [ref=e1611] [cursor=pointer]': + - /url: "#macclient--asyncmacclient" + - img [ref=e1612] + - table [ref=e1615]: + - rowgroup [ref=e1616]: + - row "方法 说明" [ref=e1617]: + - columnheader "方法" [ref=e1618] + - columnheader "说明" [ref=e1619] + - rowgroup [ref=e1620]: + - row "get_stock_quotes(stocks, fields) 批量实时报价" [ref=e1621]: + - cell "get_stock_quotes(stocks, fields)" [ref=e1622]: + - code [ref=e1623]: get_stock_quotes(stocks, fields) + - cell "批量实时报价" [ref=e1624] + - row "get_stock_quotes_list(category, ...) 市场分类排序报价" [ref=e1625]: + - cell "get_stock_quotes_list(category, ...)" [ref=e1626]: + - code [ref=e1627]: get_stock_quotes_list(category, ...) + - cell "市场分类排序报价" [ref=e1628] + - row "get_stock_kline(market, code, period, ...) K 线(支持复权)" [ref=e1629]: + - cell "get_stock_kline(market, code, period, ...)" [ref=e1630]: + - code [ref=e1631]: get_stock_kline(market, code, period, ...) + - cell "K 线(支持复权)" [ref=e1632] + - row "get_stock_kline_with_indicators(market, code, indicators, ...) K 线 + 技术指标" [ref=e1633]: + - cell "get_stock_kline_with_indicators(market, code, indicators, ...)" [ref=e1634]: + - code [ref=e1635]: get_stock_kline_with_indicators(market, code, indicators, ...) + - cell "K 线 + 技术指标" [ref=e1636] + - row "get_tick_chart(market, code, date) 单日分时图" [ref=e1637]: + - cell "get_tick_chart(market, code, date)" [ref=e1638]: + - code [ref=e1639]: get_tick_chart(market, code, date) + - cell "单日分时图" [ref=e1640] + - row "get_tick_charts(market, code, days) 多日分时图" [ref=e1641]: + - cell "get_tick_charts(market, code, days)" [ref=e1642]: + - code [ref=e1643]: get_tick_charts(market, code, days) + - cell "多日分时图" [ref=e1644] + - row "get_chart_sampling(market, code) 分时缩略采样" [ref=e1645]: + - cell "get_chart_sampling(market, code)" [ref=e1646]: + - code [ref=e1647]: get_chart_sampling(market, code) + - cell "分时缩略采样" [ref=e1648] + - row "get_transactions(market, code, ...) 逐笔成交" [ref=e1649]: + - cell "get_transactions(market, code, ...)" [ref=e1650]: + - code [ref=e1651]: get_transactions(market, code, ...) + - cell "逐笔成交" [ref=e1652] + - row "get_symbol_info(market, code) 个股特征快照" [ref=e1653]: + - cell "get_symbol_info(market, code)" [ref=e1654]: + - code [ref=e1655]: get_symbol_info(market, code) + - cell "个股特征快照" [ref=e1656] + - row "get_board_list(board_type, ...) 板块列表" [ref=e1657]: + - cell "get_board_list(board_type, ...)" [ref=e1658]: + - code [ref=e1659]: get_board_list(board_type, ...) + - cell "板块列表" [ref=e1660] + - row "get_board_members(board_symbol, ...) 板块成分股报价" [ref=e1661]: + - cell "get_board_members(board_symbol, ...)" [ref=e1662]: + - code [ref=e1663]: get_board_members(board_symbol, ...) + - cell "板块成分股报价" [ref=e1664] + - row "get_board_summary(board_symbol, ...) 板块汇总(成交额、主力净流入、涨跌家数)" [ref=e1665]: + - cell "get_board_summary(board_symbol, ...)" [ref=e1666]: + - code [ref=e1667]: get_board_summary(board_symbol, ...) + - cell "板块汇总(成交额、主力净流入、涨跌家数)" [ref=e1668] + - row "get_board_ranking(board_type, top_n, sort_by, ...) 板块涨跌幅排行榜(行业/概念排行)" [ref=e1669]: + - cell "get_board_ranking(board_type, top_n, sort_by, ...)" [ref=e1670]: + - code [ref=e1671]: get_board_ranking(board_type, top_n, sort_by, ...) + - cell "板块涨跌幅排行榜(行业/概念排行)" [ref=e1672] + - row "get_belong_board(market, code) 个股所属板块" [ref=e1673]: + - cell "get_belong_board(market, code)" [ref=e1674]: + - code [ref=e1675]: get_belong_board(market, code) + - cell "个股所属板块" [ref=e1676] + - row "get_capital_flow(market, code) 资金流向" [ref=e1677]: + - cell "get_capital_flow(market, code)" [ref=e1678]: + - code [ref=e1679]: get_capital_flow(market, code) + - cell "资金流向" [ref=e1680] + - row "get_auction(market, code) 集合竞价" [ref=e1681]: + - cell "get_auction(market, code)" [ref=e1682]: + - code [ref=e1683]: get_auction(market, code) + - cell "集合竞价" [ref=e1684] + - row "get_unusual(market, ...) 市场异动" [ref=e1685]: + - cell "get_unusual(market, ...)" [ref=e1686]: + - code [ref=e1687]: get_unusual(market, ...) + - cell "市场异动" [ref=e1688] + - row "get_server_info() 服务器交易时段" [ref=e1689]: + - cell "get_server_info()" [ref=e1690]: + - code [ref=e1691]: get_server_info() + - cell "服务器交易时段" [ref=e1692] + - row "get_kline_offset(offset, count) K 线偏移信息" [ref=e1693]: + - cell "get_kline_offset(offset, count)" [ref=e1694]: + - code [ref=e1695]: get_kline_offset(offset, count) + - cell "K 线偏移信息" [ref=e1696] + - row "get_goods_list(market, ...) 扩展市场商品列表" [ref=e1697]: + - cell "get_goods_list(market, ...)" [ref=e1698]: + - code [ref=e1699]: get_goods_list(market, ...) + - cell "扩展市场商品列表" [ref=e1700] + - generic [ref=e1701]: + - heading "MacExClient / AsyncMacExClient" [level=3] [ref=e1702] + - 'link "Permalink: MacExClient / AsyncMacExClient" [ref=e1703] [cursor=pointer]': + - /url: "#macexclient--asyncmacexclient" + - img [ref=e1704] + - table [ref=e1707]: + - rowgroup [ref=e1708]: + - row "方法 说明" [ref=e1709]: + - columnheader "方法" [ref=e1710] + - columnheader "说明" [ref=e1711] + - rowgroup [ref=e1712]: + - row "goods_count(market) 商品总数" [ref=e1713]: + - cell "goods_count(market)" [ref=e1714]: + - code [ref=e1715]: goods_count(market) + - cell "商品总数" [ref=e1716] + - row "goods_list(market, start, count) 商品列表" [ref=e1717]: + - cell "goods_list(market, start, count)" [ref=e1718]: + - code [ref=e1719]: goods_list(market, start, count) + - cell "商品列表" [ref=e1720] + - row "goods_quotes(stocks, fields) 批量报价" [ref=e1721]: + - cell "goods_quotes(stocks, fields)" [ref=e1722]: + - code [ref=e1723]: goods_quotes(stocks, fields) + - cell "批量报价" [ref=e1724] + - row "goods_quotes_list(market, ...) 市场分类报价列表" [ref=e1725]: + - cell "goods_quotes_list(market, ...)" [ref=e1726]: + - code [ref=e1727]: goods_quotes_list(market, ...) + - cell "市场分类报价列表" [ref=e1728] + - row "goods_kline(market, code, period, ...) K 线(支持复权)" [ref=e1729]: + - cell "goods_kline(market, code, period, ...)" [ref=e1730]: + - code [ref=e1731]: goods_kline(market, code, period, ...) + - cell "K 线(支持复权)" [ref=e1732] + - row "goods_tick_chart(market, code, ...) 分时图" [ref=e1733]: + - cell "goods_tick_chart(market, code, ...)" [ref=e1734]: + - code [ref=e1735]: goods_tick_chart(market, code, ...) + - cell "分时图" [ref=e1736] + - row "goods_chart_sampling(market, code) 分时缩略采样" [ref=e1737]: + - cell "goods_chart_sampling(market, code)" [ref=e1738]: + - code [ref=e1739]: goods_chart_sampling(market, code) + - cell "分时缩略采样" [ref=e1740] + - row "goods_transaction(market, code, ...) 逐笔成交" [ref=e1741]: + - cell "goods_transaction(market, code, ...)" [ref=e1742]: + - code [ref=e1743]: goods_transaction(market, code, ...) + - cell "逐笔成交" [ref=e1744] + - generic [ref=e1745]: + - heading "TdxClient / AsyncTdxClient" [level=3] [ref=e1746] + - 'link "Permalink: TdxClient / AsyncTdxClient" [ref=e1747] [cursor=pointer]': + - /url: "#tdxclient--asynctdxclient" + - img [ref=e1748] + - table [ref=e1751]: + - rowgroup [ref=e1752]: + - row "方法 说明" [ref=e1753]: + - columnheader "方法" [ref=e1754] + - columnheader "说明" [ref=e1755] + - rowgroup [ref=e1756]: + - row "get_security_count(market) 市场证券总数" [ref=e1757]: + - cell "get_security_count(market)" [ref=e1758]: + - code [ref=e1759]: get_security_count(market) + - cell "市场证券总数" [ref=e1760] + - row "get_security_list(market, start) 证券列表(分页)" [ref=e1761]: + - cell "get_security_list(market, start)" [ref=e1762]: + - code [ref=e1763]: get_security_list(market, start) + - cell "证券列表(分页)" [ref=e1764] + - row "get_security_list_all() 沪深 A 股完整列表(含行业)" [ref=e1765]: + - cell "get_security_list_all()" [ref=e1766]: + - code [ref=e1767]: get_security_list_all() + - cell "沪深 A 股完整列表(含行业)" [ref=e1768] + - row "get_security_quotes(stocks) 批量五档行情" [ref=e1769]: + - cell "get_security_quotes(stocks)" [ref=e1770]: + - code [ref=e1771]: get_security_quotes(stocks) + - cell "批量五档行情" [ref=e1772] + - row "get_security_bars(market, code, ...) 个股 K 线" [ref=e1773]: + - cell "get_security_bars(market, code, ...)" [ref=e1774]: + - code [ref=e1775]: get_security_bars(market, code, ...) + - cell "个股 K 线" [ref=e1776] + - row "get_index_bars(market, code, ...) 指数 K 线" [ref=e1777]: + - cell "get_index_bars(market, code, ...)" [ref=e1778]: + - code [ref=e1779]: get_index_bars(market, code, ...) + - cell "指数 K 线" [ref=e1780] + - row "get_minute_time_data(market, code) 今日分时" [ref=e1781]: + - cell "get_minute_time_data(market, code)" [ref=e1782]: + - code [ref=e1783]: get_minute_time_data(market, code) + - cell "今日分时" [ref=e1784] + - row "get_history_minute_time_data(market, code, date) 历史分时" [ref=e1785]: + - cell "get_history_minute_time_data(market, code, date)" [ref=e1786]: + - code [ref=e1787]: get_history_minute_time_data(market, code, date) + - cell "历史分时" [ref=e1788] + - row "get_transaction_data(market, code, ...) 当日逐笔成交" [ref=e1789]: + - cell "get_transaction_data(market, code, ...)" [ref=e1790]: + - code [ref=e1791]: get_transaction_data(market, code, ...) + - cell "当日逐笔成交" [ref=e1792] + - row "get_history_transaction_data(...) 历史逐笔成交" [ref=e1793]: + - cell "get_history_transaction_data(...)" [ref=e1794]: + - code [ref=e1795]: get_history_transaction_data(...) + - cell "历史逐笔成交" [ref=e1796] + - row "get_fund_flow(market, code) 当日资金流向" [ref=e1797]: + - cell "get_fund_flow(market, code)" [ref=e1798]: + - code [ref=e1799]: get_fund_flow(market, code) + - cell "当日资金流向" [ref=e1800] + - row "get_history_fund_flow(market, code, ...) 历史资金流向" [ref=e1801]: + - cell "get_history_fund_flow(market, code, ...)" [ref=e1802]: + - code [ref=e1803]: get_history_fund_flow(market, code, ...) + - cell "历史资金流向" [ref=e1804] + - row "get_xdxr_info(market, code) 除权除息历史" [ref=e1805]: + - cell "get_xdxr_info(market, code)" [ref=e1806]: + - code [ref=e1807]: get_xdxr_info(market, code) + - cell "除权除息历史" [ref=e1808] + - row "get_finance_info(market, code) 最新财务数据" [ref=e1809]: + - cell "get_finance_info(market, code)" [ref=e1810]: + - code [ref=e1811]: get_finance_info(market, code) + - cell "最新财务数据" [ref=e1812] + - row "get_company_info_category(market, code) 公司信息目录" [ref=e1813]: + - cell "get_company_info_category(market, code)" [ref=e1814]: + - code [ref=e1815]: get_company_info_category(market, code) + - cell "公司信息目录" [ref=e1816] + - row "get_company_info_content(...) 公司信息文本" [ref=e1817]: + - cell "get_company_info_content(...)" [ref=e1818]: + - code [ref=e1819]: get_company_info_content(...) + - cell "公司信息文本" [ref=e1820] + - row "get_block_info(filename) 板块信息" [ref=e1821]: + - cell "get_block_info(filename)" [ref=e1822]: + - code [ref=e1823]: get_block_info(filename) + - cell "板块信息" [ref=e1824] + - row "get_report_file(filename) 下载服务器文件" [ref=e1825]: + - cell "get_report_file(filename)" [ref=e1826]: + - code [ref=e1827]: get_report_file(filename) + - cell "下载服务器文件" [ref=e1828] + - row "get_market_stat() 全市场涨跌统计" [ref=e1829]: + - cell "get_market_stat()" [ref=e1830]: + - code [ref=e1831]: get_market_stat() + - cell "全市场涨跌统计" [ref=e1832] + - row "get_price_limits(market, code, name, pre_close) 涨跌停价" [ref=e1833]: + - cell "get_price_limits(market, code, name, pre_close)" [ref=e1834]: + - code [ref=e1835]: get_price_limits(market, code, name, pre_close) + - cell "涨跌停价" [ref=e1836] + - generic [ref=e1837]: + - heading "架构" [level=2] [ref=e1838] + - 'link "Permalink: 架构" [ref=e1839] [cursor=pointer]': + - /url: "#架构" + - img [ref=e1840] + - generic [ref=e1842]: + - code [ref=e1844]: "src/easy_tdx/ ├── client.py # TdxClient / AsyncTdxClient(标准协议) ├── unified.py # UnifiedTdxClient(统一入口) ├── config.py # 服务器地址、端口、超时配置 ├── indicator.py # 技术指标计算(32 个,基于 MyTT) ├── MyTT.py # 麦语言技术指标算法库 ├── mac/ │ ├── client.py # MacClient / AsyncMacClient(MAC 协议) │ ├── enums.py # Period, Adjust, Category, ExMarket, SortType, ... │ ├── models.py # MacBar, MacQuoteField, MacTick, BoardInfo, ... │ └── commands/ # MAC 命令(build_request + parse_response,无 IO) ├── ex/ │ ├── client.py # ExTdxClient / AsyncExTdxClient(标准协议扩展市场) │ ├── mac_client.py # MacExClient / AsyncMacExClient(MAC 协议扩展市场) │ └── transport/ # ExTdxConnection(端口 7727) ├── transport/ │ ├── sync.py # TdxConnection + ping_host / ping_all │ └── async_.py # AsyncTdxConnection(asyncio) ├── commands/ # 标准协议命令(无 IO) ├── codec/ # price / volume / datetime / frame / bitmap 编解码 ├── models/ # 纯 dataclass,无业务逻辑 ├── offline/ # 离线数据读取模块 └── cli/ # easy-tdx CLI(click)" + - button "Copy code to clipboard" [ref=e1846] [cursor=pointer]: + - img [ref=e1847] + - paragraph [ref=e1850]: commands 层不依赖 transport,可独立单测。 + - generic [ref=e1851]: + - heading "开发" [level=2] [ref=e1852] + - 'link "Permalink: 开发" [ref=e1853] [cursor=pointer]': + - /url: "#开发" + - img [ref=e1854] + - generic [ref=e1856]: + - generic [ref=e1857]: + - text: python -m pytest tests/unit/ -v + - generic [ref=e1858]: "# 单元测试(无需网络)" + - text: XMTDX_LIVE=1 python -m pytest tests/integration/ -v + - generic [ref=e1859]: "# 集成测试" + - text: mypy src/ + - generic [ref=e1860]: "# 类型检查" + - text: ruff check src/ tests/ + - generic [ref=e1861]: "# lint" + - text: ruff format --check src/ tests/ + - generic [ref=e1862]: "# format check" + - button "Copy code to clipboard" [ref=e1864] [cursor=pointer]: + - img [ref=e1865] + - generic [ref=e1868]: + - heading "致谢" [level=2] [ref=e1869] + - 'link "Permalink: 致谢" [ref=e1870] [cursor=pointer]': + - /url: "#致谢" + - img [ref=e1871] + - list [ref=e1873]: + - listitem [ref=e1874]: + - link "pytdx" [ref=e1875] [cursor=pointer]: + - /url: https://github.com/rainx/pytdx + - text: "-- 离线数据读取模块借鉴自 pytdx 项目,感谢 rainx 及所有贡献者" + - listitem [ref=e1876]: + - link "xmtdx" [ref=e1877] [cursor=pointer]: + - /url: https://github.com/minionszyw/xmtdx + - text: "-- 本项目初始原型" + - listitem [ref=e1878]: + - link "mootdx" [ref=e1879] [cursor=pointer]: + - /url: https://github.com/mootdx/mootdx + - text: "-- 工程化封装参考" + - listitem [ref=e1880]: + - link "MyTT" [ref=e1881] [cursor=pointer]: + - /url: https://github.com/mpquant/MyTT + - text: "-- 麦语言技术指标算法库,技术指标计算基于此实现" + - paragraph [ref=e1882]: + - text: 详见 + - link "NOTICE" [ref=e1883] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/NOTICE + - text: 和 + - link "LICENSE" [ref=e1884] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/LICENSE + - text: 。 + - generic [ref=e1885]: + - heading "Changelog" [level=2] [ref=e1886] + - 'link "Permalink: Changelog" [ref=e1887] [cursor=pointer]': + - /url: "#changelog" + - img [ref=e1888] + - generic [ref=e1890]: + - heading "1.5.0 (2026-06-02)" [level=3] [ref=e1891] + - 'link "Permalink: 1.5.0 (2026-06-02)" [ref=e1892] [cursor=pointer]': + - /url: "#150-2026-06-02" + - img [ref=e1893] + - paragraph [ref=e1895]: + - strong [ref=e1896]: 离线数据 CLI 命令 + - text: — 新增 + - code [ref=e1897]: offline + - text: 命令组,无需网络即可通过 CLI 读取本地通达信数据文件。 + - list [ref=e1898]: + - listitem [ref=e1899]: + - text: 新增 + - code [ref=e1900]: offline home + - text: :检测通达信安装目录 + - listitem [ref=e1901]: + - text: 新增 + - code [ref=e1902]: offline daily + - text: :A 股日线数据(.day 文件) + - listitem [ref=e1903]: + - text: 新增 + - code [ref=e1904]: offline min + - text: :分钟线数据(.5/.lc1/.lc5 文件, + - code [ref=e1905]: "--type" + - text: 指定格式) + - listitem [ref=e1906]: + - text: 新增 + - code [ref=e1907]: offline ex-files + - text: :列出扩展市场可用日线文件 + - listitem [ref=e1908]: + - text: 新增 + - code [ref=e1909]: offline ex-daily + - text: :扩展市场日线数据(期货/港股/外盘) + - listitem [ref=e1910]: + - text: 新增 + - code [ref=e1911]: offline gbbq + - text: :股本变迁数据 + - listitem [ref=e1912]: + - text: 新增 + - code [ref=e1913]: offline financial + - text: :历史财务数据 + - listitem [ref=e1914]: + - text: 新增 + - code [ref=e1915]: offline blocks + - text: :自定义板块数据 + - generic [ref=e1916]: + - heading "1.4.3 (2026-05-28)" [level=3] [ref=e1917] + - 'link "Permalink: 1.4.3 (2026-05-28)" [ref=e1918] [cursor=pointer]': + - /url: "#143-2026-05-28" + - img [ref=e1919] + - paragraph [ref=e1921]: + - strong [ref=e1922]: 30日乖离率信号指标 + - text: — 新增 BIAS_SIGNAL 指标,在标准乖离率基础上叠加短/长信号线,通过三者位置关系判断趋势方向和转折点。源自通达信经典指标。 + - list [ref=e1923]: + - listitem [ref=e1924]: + - text: 新增 + - code [ref=e1925]: BIAS_SIGNAL + - text: 指标:输出 BS_X/BS_SMA/BS_LMA 三条线 + - listitem [ref=e1926]: + - text: "CLI:" + - code [ref=e1927]: easy-tdx indicator BIAS_SIGNAL -m SH -c 600519 --table + - listitem [ref=e1928]: + - text: "Python API:" + - code [ref=e1929]: indicators=["BIAS_SIGNAL"] + - listitem [ref=e1930]: + - text: 详见 + - link "30日乖离率信号指标详解" [ref=e1931] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/docs/indicator-bias-signal.md + - generic [ref=e1932]: + - heading "1.4.2 (2026-05-28)" [level=3] [ref=e1933] + - 'link "Permalink: 1.4.2 (2026-05-28)" [ref=e1934] [cursor=pointer]': + - /url: "#142-2026-05-28" + - img [ref=e1935] + - paragraph [ref=e1937]: 修复 1.4.1 发布遗漏:MyTT.py 中 ZHUOYAO 函数定义未包含在 1.4.1 的 PyPI 包中。 + - generic [ref=e1938]: + - heading "1.4.1 (2026-05-28)" [level=3] [ref=e1939] + - 'link "Permalink: 1.4.1 (2026-05-28)" [ref=e1940] [cursor=pointer]': + - /url: "#141-2026-05-28" + - img [ref=e1941] + - paragraph [ref=e1943]: + - strong [ref=e1944]: 捉妖大师指标 + - text: — 新增 ZHUOYAO 多周期涨幅共振指标,通过 20/60/120 日涨幅及指数平滑判断短中长线趋势是否同向,用于筛选趋势刚启动的强势股。 + - list [ref=e1945]: + - listitem [ref=e1946]: + - text: 新增 + - code [ref=e1947]: ZHUOYAO + - text: 指标:输出 ZY_LONG/ZY_MID/ZY_SHORT/ZY_TREND 四条线 + - listitem [ref=e1948]: + - text: "CLI:" + - code [ref=e1949]: easy-tdx indicator ZHUOYAO -m SH -c 600519 --table + - listitem [ref=e1950]: + - text: "Python API:" + - code [ref=e1951]: indicators=["ZHUOYAO"] + - listitem [ref=e1952]: + - text: 详见 + - link "捉妖大师指标详解" [ref=e1953] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/blob/main/docs/indicator-zhuoyao.md + - generic [ref=e1954]: + - heading "1.4.0 (2026-05-28)" [level=3] [ref=e1955] + - 'link "Permalink: 1.4.0 (2026-05-28)" [ref=e1956] [cursor=pointer]': + - /url: "#140-2026-05-28" + - img [ref=e1957] + - paragraph [ref=e1959]: + - strong [ref=e1960]: 技术指标计算 + - text: — 集成 + - link "MyTT" [ref=e1961] [cursor=pointer]: + - /url: https://github.com/mpquant/MyTT + - text: 麦语言指标库,支持 30 个常用技术指标,一步获取 K 线 + 指标值。 + - list [ref=e1962]: + - listitem [ref=e1963]: + - text: 新增 + - code [ref=e1964]: indicator.py + - text: 核心模块:注册表驱动的指标调度, + - code [ref=e1965]: compute_indicators() + - text: 纯计算无 IO + - listitem [ref=e1966]: + - text: 新增 + - code [ref=e1967]: MacClient.get_stock_kline_with_indicators() + - text: / + - code [ref=e1968]: AsyncMacClient + - text: 同名方法 + - listitem [ref=e1969]: + - text: 新增 + - code [ref=e1970]: UnifiedTdxClient.get_stock_kline_with_indicators() + - text: / + - code [ref=e1971]: AsyncUnifiedTdxClient + - text: 同名方法 + - listitem [ref=e1972]: + - text: 新增 CLI 命令 + - code [ref=e1973]: easy-tdx indicator + - text: 和 + - code [ref=e1974]: easy-tdx indicator-list + - listitem [ref=e1975]: 自动获取 200+ 条历史数据预热 EMA,用户只需指定返回条数 + - listitem [ref=e1976]: 支持的指标:MACD, KDJ, RSI, BOLL, DMI, ATR, WR, CCI, BIAS, OBV, VR, EMV, MFI, BRAR, ASI, TRIX, DPO, MTM, ROC, EXPMA, BBI, PSY, DFMA, CR, KTN, XSII, MASS, TAQ + - generic [ref=e1977]: + - heading "1.3.1 (2025-05-15)" [level=3] [ref=e1978] + - 'link "Permalink: 1.3.1 (2025-05-15)" [ref=e1979] [cursor=pointer]': + - /url: "#131-2025-05-15" + - img [ref=e1980] + - list [ref=e1982]: + - listitem [ref=e1983]: + - text: 新增 + - code [ref=e1984]: board-summary + - text: 和 + - code [ref=e1985]: board-ranking + - text: CLI 命令 + - listitem [ref=e1986]: + - text: 新增 + - code [ref=e1987]: get_board_summary() + - text: 板块汇总(成交额、主力净流入、涨跌家数) + - listitem [ref=e1988]: + - text: 新增 + - code [ref=e1989]: get_board_ranking() + - text: 板块涨跌幅排行榜 + - generic [ref=e1990]: + - heading "1.3.0 (2025-05-12)" [level=3] [ref=e1991] + - 'link "Permalink: 1.3.0 (2025-05-12)" [ref=e1992] [cursor=pointer]': + - /url: "#130-2025-05-12" + - img [ref=e1993] + - list [ref=e1995]: + - listitem [ref=e1996]: + - text: 新增 MAC 协议客户端 + - code [ref=e1997]: MacClient + - text: / + - code [ref=e1998]: AsyncMacClient + - text: (端口 7709) + - listitem [ref=e1999]: + - text: 新增扩展市场客户端 + - code [ref=e2000]: MacExClient + - text: / + - code [ref=e2001]: AsyncMacExClient + - text: (端口 7727) + - listitem [ref=e2002]: + - text: 新增统一客户端 + - code [ref=e2003]: UnifiedTdxClient + - text: 自动路由 A 股 / 扩展市场 + - listitem [ref=e2004]: 新增板块、资金流向、集合竞价、异动、个股特征等数据接口 + - listitem [ref=e2005]: + - text: 新增 + - code [ref=e2006]: easy-tdx + - text: CLI 工具,默认 JSON 输出 + - generic [ref=e2007]: + - heading "1.2.1 (2025-04-20)" [level=3] [ref=e2008] + - 'link "Permalink: 1.2.1 (2025-04-20)" [ref=e2009] [cursor=pointer]': + - /url: "#121-2025-04-20" + - img [ref=e2010] + - list [ref=e2012]: + - listitem [ref=e2013]: 离线数据读取模块(日线、分钟线、板块、财务) + - listitem [ref=e2014]: 除权除息、股本变迁读取 + - generic [ref=e2015]: + - heading "1.0.0 (2025-03-01)" [level=3] [ref=e2016] + - 'link "Permalink: 1.0.0 (2025-03-01)" [ref=e2017] [cursor=pointer]': + - /url: "#100-2025-03-01" + - img [ref=e2018] + - list [ref=e2020]: + - listitem [ref=e2021]: 首个正式版本 + - listitem [ref=e2022]: TdxClient / AsyncTdxClient 标准协议客户端 + - listitem [ref=e2023]: K 线、实时报价、分时、逐笔成交、财务数据 + - generic [ref=e2027]: + - generic [ref=e2030]: + - heading "About" [level=2] [ref=e2031] + - paragraph [ref=e2032]: 通达信python SDK,支持在线获取数据及离线本地数据读取。全面优化接口。 + - heading "Topics" [level=3] [ref=e2033] + - generic [ref=e2035]: + - link "technical-analysis" [ref=e2036] [cursor=pointer]: + - /url: /topics/technical-analysis + - link "financial-data" [ref=e2037] [cursor=pointer]: + - /url: /topics/financial-data + - link "tdx" [ref=e2038] [cursor=pointer]: + - /url: /topics/tdx + - link "pytdx" [ref=e2039] [cursor=pointer]: + - /url: /topics/pytdx + - link "mootdx" [ref=e2040] [cursor=pointer]: + - /url: /topics/mootdx + - link "chinese-stock-market" [ref=e2041] [cursor=pointer]: + - /url: /topics/chinese-stock-market + - link "a-share-tdx" [ref=e2042] [cursor=pointer]: + - /url: /topics/a-share-tdx + - heading "Resources" [level=3] [ref=e2043] + - link "Readme" [ref=e2045] [cursor=pointer]: + - /url: "#readme-ov-file" + - img [ref=e2046] + - text: Readme + - heading "License" [level=3] [ref=e2048] + - link "View license" [ref=e2050] [cursor=pointer]: + - /url: "#License-1-ov-file" + - img [ref=e2051] + - text: View license + - link "Activity" [ref=e2054] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/activity + - img [ref=e2055] + - text: Activity + - heading "Stars" [level=3] [ref=e2057] + - link "61 stars" [ref=e2059] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/stargazers + - img [ref=e2060] + - strong [ref=e2062]: "61" + - text: stars + - heading "Watchers" [level=3] [ref=e2063] + - link "1 watching" [ref=e2065] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/watchers + - img [ref=e2066] + - strong [ref=e2068]: "1" + - text: watching + - heading "Forks" [level=3] [ref=e2069] + - link "23 forks" [ref=e2071] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/forks + - img [ref=e2072] + - strong [ref=e2074]: "23" + - text: forks + - link "Report repository" [ref=e2076] [cursor=pointer]: + - /url: /contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fhandsomejustin%2Feasy_tdx&report=handsomejustin+%28user%29 + - generic [ref=e2078]: + - heading "Releases 2" [level=2] [ref=e2079]: + - link "Releases 2" [ref=e2080] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/releases + - text: Releases + - generic "2" [ref=e2081] + - link "v1.5.0 离线数据 CLI 版 Latest Jun 2, 20263 days ago" [ref=e2082] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/releases/tag/v1.5.0 + - img [ref=e2083] + - generic [ref=e2085]: + - generic [ref=e2086]: + - generic [ref=e2087]: v1.5.0 离线数据 CLI 版 + - 'generic "Label: Latest" [ref=e2088]': Latest + - generic [ref=e2089]: Jun 2, 20263 days ago + - link "+ 1 release" [ref=e2091] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/releases + - generic [ref=e2093]: + - heading "Packages" [level=2] [ref=e2094]: + - link "Packages" [ref=e2095] [cursor=pointer]: + - /url: /users/handsomejustin/packages?repo_name=easy_tdx + - generic [ref=e2096]: No packages published + - generic [ref=e2098]: + - heading "Contributors 4" [level=2] [ref=e2099]: + - link "Contributors 4" [ref=e2100] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/graphs/contributors + - text: Contributors + - generic "4" [ref=e2101] + - list [ref=e2102]: + - listitem [ref=e2103]: + - link "@claude" [ref=e2104] [cursor=pointer]: + - /url: https://github.com/claude + - img "@claude" [ref=e2105] + - link "claude Claude" [ref=e2107] [cursor=pointer]: + - /url: https://github.com/claude + - strong [ref=e2108]: claude + - text: Claude + - listitem [ref=e2109]: + - link "@actions-user" [ref=e2110] [cursor=pointer]: + - /url: https://github.com/actions-user + - img "@actions-user" [ref=e2111] + - link "actions-user" [ref=e2113] [cursor=pointer]: + - /url: https://github.com/actions-user + - strong [ref=e2114]: actions-user + - listitem [ref=e2115]: + - link "@handsomejustin" [ref=e2116] [cursor=pointer]: + - /url: https://github.com/handsomejustin + - img "@handsomejustin" [ref=e2117] + - link "handsomejustin 毛利哥" [ref=e2119] [cursor=pointer]: + - /url: https://github.com/handsomejustin + - strong [ref=e2120]: handsomejustin + - text: 毛利哥 + - listitem [ref=e2121]: + - link "@minionszyw" [ref=e2122] [cursor=pointer]: + - /url: https://github.com/minionszyw + - img "@minionszyw" [ref=e2123] + - link "minionszyw" [ref=e2125] [cursor=pointer]: + - /url: https://github.com/minionszyw + - strong [ref=e2126]: minionszyw + - generic [ref=e2128]: + - heading "Languages" [level=2] [ref=e2129] + - list [ref=e2133]: + - listitem [ref=e2134]: + - link "Python 100.0%" [ref=e2135] [cursor=pointer]: + - /url: /handsomejustin/easy_tdx/search?l=python + - img [ref=e2136] + - generic [ref=e2138]: Python + - generic [ref=e2139]: 100.0% + - contentinfo [ref=e2141]: + - heading "Footer" [level=2] [ref=e2142] + - generic [ref=e2143]: + - generic [ref=e2144]: + - link "GitHub Homepage" [ref=e2145] [cursor=pointer]: + - /url: https://github.com + - img [ref=e2146] + - generic [ref=e2148]: © 2026 GitHub, Inc. + - navigation "Footer" [ref=e2149]: + - heading "Footer navigation" [level=3] [ref=e2150] + - list "Footer navigation" [ref=e2151]: + - listitem [ref=e2152]: + - link "Terms" [ref=e2153] [cursor=pointer]: + - /url: https://docs.github.com/site-policy/github-terms/github-terms-of-service + - listitem [ref=e2154]: + - link "Privacy" [ref=e2155] [cursor=pointer]: + - /url: https://docs.github.com/site-policy/privacy-policies/github-privacy-statement + - listitem [ref=e2156]: + - link "Security" [ref=e2157] [cursor=pointer]: + - /url: https://github.com/security + - listitem [ref=e2158]: + - link "Status" [ref=e2159] [cursor=pointer]: + - /url: https://www.githubstatus.com/ + - listitem [ref=e2160]: + - link "Community" [ref=e2161] [cursor=pointer]: + - /url: https://github.community/ + - listitem [ref=e2162]: + - link "Docs" [ref=e2163] [cursor=pointer]: + - /url: https://docs.github.com/ + - listitem [ref=e2164]: + - link "Contact" [ref=e2165] [cursor=pointer]: + - /url: https://support.github.com?tags=dotcom-footer + - listitem [ref=e2166]: + - button "Manage cookies" [ref=e2168] [cursor=pointer] + - listitem [ref=e2169]: + - button "Do not share my personal information" [ref=e2171] [cursor=pointer] \ No newline at end of file diff --git a/docs/protocol-reverse-engineering.md b/docs/protocol-reverse-engineering.md new file mode 100644 index 0000000..282ea23 --- /dev/null +++ b/docs/protocol-reverse-engineering.md @@ -0,0 +1,144 @@ +# TDX 协议逆向工程全景 + +本文记录通达信 (TDX) 私有二进制 TCP 协议的逆向研究过程,帮助理解 easy-tdx 项目中各层协议实现的设计原理。 + +## 第一层:抓包 — 发现帧结构 + +通达信客户端和服务器之间是裸 TCP(端口 `7709`),没有 HTTP 包装。研究者通过 Wireshark 抓包发现了一个固定的帧格式: + +``` +响应帧 = 16字节固定头 + 可变长度 body +``` + +`codec/frame.py` 记录了这个发现: + +``` +偏移 0: I (4字节) — 未知 +偏移 4: I (4字节) — 未知 +偏移 8: I (4字节) — 未知 +偏移 12: H (2字节) — zipsize(body 实际长度) +偏移 14: H (2字节) — unzipsize(解压后长度) +``` + +关键发现:**当 zipsize == unzipsize 时 body 未压缩,否则需要 zlib 解压**。这是通过对比抓包数据和 zlib 解压结果验证的。 + +## 第二层:握手 — 三条神秘命令 + +`commands/setup.py` 中的三条握手命令是硬编码的原始字节: + +```python +SETUP_CMD1: "0c0218930001030003000d0001" +SETUP_CMD2: "0c0218940001030003000d0002" +SETUP_CMD3: "0c031899000120002000db0f..." # 30字节,含GBK编码的"申银万国" +``` + +注释写得很清楚:"从 pytdx 源码移植,已在真实服务器验证"。这说明握手命令不是这个项目原创的,而是从开源项目 [pytdx](https://github.com/rainx/pytdx) 继承来的。pytdx 的作者 rainx 通过**逆向通达信 Windows 客户端**(用 IDA Pro 等反汇编工具)得到了这些字节序列。 + +第三条命令特别有意思,里面包含了 `d5d0c9ccd6a4a8af`,这是 GBK 编码的"申银万国"(一家券商名),说明这条握手命令里包含了**客户端标识信息**。 + +## 第三层:请求构造 — 猜解命令格式 + +每个命令的请求都是一个固定格式的二进制包。以 `security_list.py` 为例: + +```python +header = bytes.fromhex("0c0118640101060006005004") +payload = struct.pack("> 24) & 0xFF # 指数 +hleax = (ivol >> 16) & 0xFF # 高精度 +lheax = (ivol >> 8) & 0xFF # 中精度 +lleax = ivol & 0xFF # 低精度 +``` + +这个格式完全不是 IEEE 754,是通达信自创的。逆向方法:拿到已知成交量的 hex dump,用不同的拆分方式穷举,直到找到能还原正确数值的公式。 + +## 第六层:未知字段 — 逆向的痕迹 + +代码中大量保留了 `unknown_0` 到 `unknown_8` 的字段,这本身就是逆向过程的痕迹——解析出格式但不确定含义的字段。比如: + +- `unknown_0` 后来被发现是服务器时间戳("小时 + 百万分之一小时"编码) +- `unknown_1` 推测等于 `-price_raw` +- 指数 K 线比股票 K 线多 4 字节(上涨/下跌家数),是通过对比同一市场的指数和股票响应长度差异发现的 + +## 总结:逆向方法论 + +这个项目体现的逆向研究路线是: + +1. **抓包** (Wireshark) → 发现 TCP 帧结构、握手序列 +2. **反汇编** (IDA Pro) → 得到请求构造函数、编解码算法 +3. **黑盒验证** → 修改参数发请求,对比响应确认字段含义 +4. **差分分析** → 利用已知数据(如已知价格)反推编码公式 +5. **对比分析** → 指数 vs 股票、不同市场、不同周期的响应差异 +6. **开源传承** → pytdx 打下基础,easy-tdx 在此之上修复 bug 并重构 + +核心依赖是 **pytdx 项目**做的基础逆向工作(反汇编通达信客户端),easy-tdx 则是在已有协议知识上的高质量 Python 重写。 diff --git a/docs/protocol-unknown-fields.md b/docs/protocol-unknown-fields.md new file mode 100644 index 0000000..83b80be --- /dev/null +++ b/docs/protocol-unknown-fields.md @@ -0,0 +1,384 @@ +# TDX 协议未知字段逆向分析 + +本文档追踪 TDX 协议中尚未完全暴露的结构,作为持续逆向的参考。 + +## 一、实时行情 unknown 字段(security_quotes) + +`commands/security_quotes.py`,每只股票一条变长记录。 + +| 字段 | 编码 | 状态 | 含义 | +|------|------|------|------| +| unknown_0 | get_price | **已确认** | 服务器时间戳(小时+百万分之一小时),`_format_server_time()` 解码 | +| unknown_1 | get_price | **已确认** | **= -price_raw**(差分编码负基准值) | +| unknown_2 | get_price | **已确认** | **指数/板块**:集合竞价成交金额(`decoded * 100` = 元);**个股**:`= b_vol + s_vol - vol`(舍入残差,≈0) | +| unknown_3 | get_price | **已确认** | **个股**:集合竞价成交金额(`decoded * 100` = 元);**指数/板块**:无意义(负值) | +| unknown_4 | H (uint16) | **已确认** | **交易状态标志**:停牌=32800(0x8020);非停牌值结构已知(见下文) | +| unknown_5-8 | get_price | **已确认** | 恒为 0,保留字段 | + +### unknown_2 详细分析(已确认:指数集合竞价成交金额 / 个股舍入残差) + +**双重含义,取决于品种类型:** + +1. **指数/板块**:`IndexOpenAmount` — 集合竞价成交金额。`decoded * 100` = 元。 + - 上证指数(000001.SH):u2=125,967,040 → 开盘金额 ≈ 1,260 亿元 + - 深证成指(399001.SZ):u2=157,987,536 → 开盘金额 ≈ 1,580 亿元 + +2. **个股**:`= b_vol + s_vol - vol`(舍入残差)。 + - 验证方法:对 20 只股票逐一计算 `s_vol + b_vol - u2`,结果与 `vol` 精确匹配(20/20) + - 涨停时恒为 0(买量=总量,卖量=0);停牌时恒为 0(vol=0);正常股票范围 -25~55 + +来源:Go 实现 gotdx (quant1x/gotdx) 命名为 `IndexOpenAmount`,注释"指数有效-集合竞价成交金额=开盘成交金额"。 + +### unknown_3 详细分析(已确认:个股集合竞价成交金额) + +**unknown_3 = StockOpenAmount** — 个股集合竞价(9:15-9:25)成交金额。 + +公式:`开盘成交金额(元) = decoded_u3 * 100` +推导:`开盘成交量(手) = u3 * 100 / (open_price * 100) = u3 / open_price` + +验证数据: +| 股票 | u3 | 开盘金额(万元) | 开盘量(手) | 占总金额% | +|------|-----|--------------|-----------|----------| +| 平安银行(000001) | 73,598 | 736 | 6,840 | 0.81% | +| 京东方A(000725) | 4,825,923 | 48,259 | 832,056 | 1.66% | +| 贵州茅台(600519) | 754,092 | 7,541 | 595 | 0.71% | +| 比亚迪(002594) | 294,144 | 2,941 | 3,064 | 0.85% | + +合理性:开盘占比 0.22%~1.66%,符合 A 股集合竞价的典型比例。当日固定值(不随盘中变化)。 + +对指数/板块:u3 为负值,无实际意义。指数的开盘金额由 unknown_2 承载。 + +**排除历史假说**: +- 非换手率(R²=0.507) +- 非简单成交额衍生(amount/u3 比值变化 9 倍) +- 与 amount 高度相关(r=+0.95)因为活跃股的开盘金额与总金额正相关 + +来源:Go 实现 gotdx (quant1x/gotdx) 命名为 `StockOpenAmount`,注释"个股有效-集合竞价成交金额=开盘成交金额"。 + +### unknown_4 非停牌值分析 + +**已确认的结构特征**: + +| 条件 | u4 值 | 说明 | +|------|-------|------| +| 停牌 | 32800 (0x8020) | bit15=1,确认为停牌标志 | +| 指数 | 2 (0x0002) | 所有指数恒为 2 | +| 个股 | 598~6166 | 日内固定值(不随交易变化) | + +**字节结构**(个股非停牌值): +``` +u4 = hi_byte * 256 + lo_byte +hi_byte: 0~24, 23个唯一值,是 u4 的主变量(r=0.9992) +lo_byte: 仅 5 个可能值 → {2, 22, 86, 150, 214} + 低6位恒为 0x16=22, bit6-7 编码 0~3 四个级别 +``` + +lo_byte 详解: +| lo (hex) | 十进制 | bit7-6 | 含义推测 | +|----------|--------|--------|---------| +| 0x02 | 2 | - | 指数专用 | +| 0x16 | 22 | 00 | 个股级别0 | +| 0x56 | 86 | 01 | 个股级别1 | +| 0x96 | 150 | 10 | 个股级别2 | +| 0xD6 | 214 | 11 | 个股级别3 | + +**与行情指标的相关性**:与所有 MAC 标准字段弱相关(|r|<0.43),最高为 active2 (r=0.42)。 +hi_byte 与 active2(成交笔数) 中等相关,但不足以确认映射。 + +**推测**:通达信内部计算的日级分类/热度指标。lo_byte 编码股票分类属性,hi_byte 编码具体指标值。 +所有已知 TDX 实现(gotdx、pytdx、injoyai/tdx)均标记为"保留/未知",无权威解释。 + +### 附:MAC 协议 build_bitmap() Bug + +`codec/bitmap.py` 中 `build_bitmap()` 无法处理 bit 值 >= 128 的字段(如 BID_ASK_DIFF=0x8C), +会引发 OverflowError。这些字段应放入 4 字节控制区(位 128-159),但当前实现未处理这种分离。 + +## 二、证券列表 unknown 字段(security_list) + +`commands/security_list.py`,每条 29 字节记录: +``` +offset 0: 6s code +offset 6: H volunit +offset 8: 8s name (GBK) +offset 16: I _unknown1 ← 已确认:排序/分组字段 +offset 20: B decimal_point +offset 21: I pre_close_raw (实际是 IEEE float32,非通达信自定义浮点) +offset 25: I _unknown2 ← 已确认:私有时间戳/更新日期 +``` + +### _unknown1(已确认:排序/分组字段) + +拆分为两个 uint16 LE:`u1_lo`(offset 16) + `u1_hi`(offset 18)。 + +- **u1_hi** = 分组 ID,同组内的板块/指数共享相同的 u1_hi 值 +- **u1_lo** = 组内排序位置,与列表顺序单调递增 + +按品种统计: +- **SZ 主板**(000xxx):u1_hi ≈ 0,u1_lo 随列表顺序单调递增(630/630 非递减) +- **板块**(880xxx):u1_hi 有 27 个不同值(0~154),分组为约 9 个一簇 +- **SH 指数**(000xxx):u1_hi 范围 0~75,类似分组模式 +- **创业板**(300xxx):u1_hi ≈ 0,u1_lo 随列表顺序递增 + +不是浮点数,不是价格,不是简单计数器——是通达信内部的排序/分组标识。 + +### _unknown2(已确认:私有时间戳) + +大部分为 0,非零情况: +- SZ 主板:631/631 全部非零 +- SH 指数:20/200 非零 +- 板块:20/797 非零 +- 创业板:0/369 + +字节级分析(offset 25-28 = b25, b26, b27, b28): +- **b28 编码年份**:值 22~37 对应 2010~2025(公式:year = b28 + 1988) +- b26 在 SZ 主板中恒为 0x31(49),在 SH 指数中为 0x29~0x31 +- b27 范围 5~254,不是简单的月份或日序 +- 不是 IEEE float32,不是通达信自定义浮点,不是标准日期格式 + +推测:记录了某种更新/修改日期,但具体编码方式仍有部分未解。 + +### 重大发现:pre_close 实际是 IEEE float32 + +offset 21 的 pre_close_raw 一直被当作通达信自定义浮点编码(`_decode_volume`)。 +实际上它是 **标准 IEEE float32**。但 `_decode_volume()` 对价格范围(0.01~99999.99)的 +IEEE float32 位模式产生数学上相同的结果——纯属巧合,当前代码正确工作但原因理解有误。 + +pytdx 同样有此问题(也用 `get_volume` 解码此字段)。 + +## 三、其他待破解字段 + +### 3.1 响应帧头 16 字节(已确认) + +`codec/frame.py`:前 12 字节通过 gotdx 交叉验证已完全破解。 + +**字节级结构**(gotdx `StdResponseHeader`): + +| 偏移 | 大小 | 名称 | 含义 | +|------|------|------|------| +| 0-3 | uint32 | magic | 协议魔数,恒为 7654321 (0x0074CBB1) | +| 4 | uint8 | ZipFlag | bit4=1 表示 body 已压缩 (0x1C=压缩, 0x0C=未压缩) | +| 5-8 | uint32 | SeqID | 请求 bytes 1-4 的回显(命令标识匹配) | +| 9 | uint8 | 保留 | 观察到恒为 0x00 | +| 10-11 | uint16 | Method | 请求 bytes 10-11 的回显 | +| 12-13 | uint16 | ZipSize | body 压缩后字节数 | +| 14-15 | uint16 | UnZipSize | body 解压后字节数 | + +**验证数据**(3 次连接,setup + data 命令): +- magic 恒为 7654321(9/9 响应验证) +- ZipFlag bit4 与 zipsize≠unzipsize 完全一致(4/4 响应验证) +- SeqID 与请求 bytes 1-4 精确匹配(4/4 响应验证) +- Method 与请求 bytes 10-11 精确匹配(4/4 响应验证) + +**兼容说明**:代码使用 `struct "=128 字段的 bug + +子任务 B(流通股本交叉验证): +- **unknown_2 = b_vol + s_vol - vol**(20/20 精确匹配) +- unknown_3 不是换手率(R²=0.507) +- unknown_3 与成交额 R²=0.89,但不成固定比例 + +**2026-05-27 第四轮:穷举+交叉实现突破** + +穷举候选分析(95 只股票): +- 最高相关候选:cur_vol*price_raw(r=0.91),amount(r=0.89) +- 非线性变换排除幂次关系(线性最优 r=0.95) + +跨实现发现(gotdx/quant1x Go TDX 库): +- **unknown_2 = IndexOpenAmount**(指数集合竞价成交金额),个股时承载舍入残差 +- **unknown_3 = StockOpenAmount**(个股集合竞价成交金额),公式 `decoded * 100` = 元 +- 验证:平安银行开盘 736 万元/6,840 手(占总量 0.81%),贵州茅台开盘 7,541 万元/595 手(0.71%) +- 指数开盘金额:上证 1,260 亿、深证 1,580 亿,均合理 + +**2026-05-27 第四轮(续):unknown_4 非停牌值结构分析** + +跨实现调查(gotdx、pytdx、injoyai/tdx): +- 所有实现均命名为 ReversedBytes4,注释"保留/未知" +- gotdx 用 `Open==0` 判断停牌,不依赖 u4 + +结构发现(96 只活跃股票): +- u4 = hi*256 + lo,hi=主变量(r=0.9992),范围 0~24 +- lo 仅 5 值:{2(指数), 22(0x16), 86(0x56), 150(0x96), 214(0xD6)},低6位恒 0x16 +- u4 在日内固定不变 +- 与所有标准指标弱相关(最高 active2 r=0.42) +- **结论**:通达信内部日级分类指标,具体语义不明 + +### 7.2 证券列表 unknown 字段 + +**2026-05-27 第一轮:SH 市场基础统计** +- unknown1 99.9% 非零,自定义浮点解码为 0 +- unknown2 96% 为 0 + +**2026-05-27 第三轮:全品种深度分析** + +子任务 C(全品种分类分析): +- **unknown1 = 排序/分组字段**:u1_hi=分组ID, u1_lo=组内排序位置 +- **unknown2 = 私有时间戳**:b28 编码年份(year-1988),完整编码仍有部分未解 +- **重大发现:pre_close_raw 是 IEEE float32**(`_decode_volume` 恰好产生相同结果) + +### 7.3 响应帧头 16 字节 + +**2026-05-27:gotdx 交叉验证完全破解** + +gotdx `StdResponseHeader` 字节级结构对照: +- magic(4B)=7654321, ZipFlag(1B)=bit4压缩标志, SeqID(4B)=请求回显 +- 保留(1B)=0x00, Method(2B)=请求回显, ZipSize(2B), UnZipSize(2B) +- 9/9 响应验证通过(magic恒定、SeqID/Method精确匹配请求) + +代码更新:`codec/frame.py` 字段重命名为 `magic/seq_id/method`,docstring 更新完整字节结构。 + +### 7.4 分时数据 unknown_1 + +**2026-05-27:穷举分析后确认为"未确定"** + +假设穷举(多股票交叉验证): +- VWAP: r=0.006, 累计成交额: r=-0.029, delta_vwap: r=0.361 +- u1 范围与价格非线性质相关(茅台价格140x → u1范围300x) +- 所有已知实现(pytdx、gotdx、injoyai/tdx、xmtdx)均丢弃此字段 +- xmtdx 确认为 easy-tdx fork,注释"疑似均价"但无验证 +- **结论**:服务器内部指标,所有公开逆向实现均无法确认含义 + +### 7.5 跳过字节块 + +**2026-05-27:xdxr_info / fund_flow / block 分析** + +xdxr_info 9字节头部(fixture 验证): +- `01 00 01 36 30 30 30 30 30` = prefix(2B=1) + market(1B=SH) + code(6B="600000") +- 响应回显请求的 market+code,prefix 可能是类型标识 + +xdxr_info 每条1字节 padding: +- 87 条记录全部为 0x00,保留/对齐字节 + +fund_flow 9字节头部:同 xdxr_info 格式(prefix + market + code) + +block 384字节头部:gotdx 命名"头信息, 忽略",所有实现跳过 + +### 已知 Bug 清单 + +1. `codec/bitmap.py build_bitmap()` — bit>=128 字段溢出(不影响现有功能) +2. `commands/security_list.py` — pre_close 用 `_decode_volume` 而非 IEEE float32(结果正确但语义有误) diff --git a/src/easy_tdx/backtest/cli.py b/src/easy_tdx/backtest/cli.py index b5614eb..e32065b 100644 --- a/src/easy_tdx/backtest/cli.py +++ b/src/easy_tdx/backtest/cli.py @@ -3,8 +3,8 @@ from __future__ import annotations import importlib.util -import json from pathlib import Path +from typing import Any import click @@ -53,9 +53,9 @@ def backtest( easy-tdx backtest SZ 000001 --strategy-file my_strategy.py --indicators MACD,KDJ """ + from ..backtest.engine import BacktestEngine from ..cli.conn import get_mac_client from ..cli.parsers import parse_adjust, parse_market, parse_period - from ..backtest.engine import BacktestEngine from ..indicator import compute_indicators # 1. 加载策略 @@ -114,7 +114,6 @@ def _load_strategy( Returns: Strategy 子类 """ - from ..backtest.strategy import Strategy if strategy_file: return _load_strategy_from_file(strategy_file) @@ -174,7 +173,7 @@ def _load_strategy_from_file(path: str) -> type: return strategy_classes[0] -def _print_table(result) -> None: +def _print_table(result: Any) -> None: """以表格形式输出回测结果。""" perf = result.performance config = result.config diff --git a/src/easy_tdx/backtest/dsl.py b/src/easy_tdx/backtest/dsl.py index 38dd44a..d9bc5d4 100644 --- a/src/easy_tdx/backtest/dsl.py +++ b/src/easy_tdx/backtest/dsl.py @@ -10,6 +10,7 @@ from collections.abc import Callable from typing import Any import numpy as np +from numpy.typing import NDArray from .strategy import Strategy @@ -31,23 +32,24 @@ def dsl_strategy(func: Callable[..., Any]) -> type[Strategy]: class DSLStrategy(Strategy): _signal_func = staticmethod(func) - _buy_mask: np.ndarray | None = None - _sell_mask: np.ndarray | None = None + _buy_mask: NDArray[np.bool_] | None = None + _sell_mask: NDArray[np.bool_] | None = None def init(self) -> None: pass def next(self) -> None: - if self._buy_mask is None: + buy = self._buy_mask + sell = self._sell_mask + if buy is None or sell is None: return idx = self._bar_index - if idx < len(self._buy_mask) and self._buy_mask[idx]: + if idx < len(buy) and buy[idx]: self.buy(size=0) - elif idx < len(self._sell_mask) and self._sell_mask[idx]: + elif idx < len(sell) and sell[idx]: self.sell(size=0) DSLStrategy.__name__ = func.__name__ DSLStrategy.__qualname__ = func.__qualname__ - DSLStrategy._signal_func = func # type: ignore[attr-defined] return DSLStrategy diff --git a/src/easy_tdx/backtest/portfolio.py b/src/easy_tdx/backtest/portfolio.py index 4c67e1f..90d1e56 100644 --- a/src/easy_tdx/backtest/portfolio.py +++ b/src/easy_tdx/backtest/portfolio.py @@ -5,8 +5,6 @@ from __future__ import annotations -from typing import Any - import numpy as np import pandas as pd diff --git a/src/easy_tdx/backtest/strategy.py b/src/easy_tdx/backtest/strategy.py index be03e10..1872d19 100644 --- a/src/easy_tdx/backtest/strategy.py +++ b/src/easy_tdx/backtest/strategy.py @@ -100,7 +100,7 @@ class StrategyDataProxy: if col == "datetime": continue arr = df[col].to_numpy() - if len(arr) > 0 and isinstance(arr[0], (np.datetime64, pd.Timestamp)): + if len(arr) > 0 and isinstance(arr[0], np.datetime64 | pd.Timestamp): # datetime 列转为 int (YYYYMMDD) self._arrays[col] = _datetime_to_int(arr) else: @@ -250,7 +250,7 @@ class Strategy(ABC): # ── 指标注册 ─────────────────────────────────────────────────────────────── - def I( + def I( # noqa: E743 self, func: Callable[..., NDArray], *args: Any, **kwargs: Any ) -> NDArray: """注册指标。 @@ -441,7 +441,7 @@ def _datetime_to_int(arr: NDArray) -> NDArray: """ result = np.zeros(len(arr), dtype=np.float64) for i, val in enumerate(arr): - if isinstance(val, (np.datetime64, pd.Timestamp)): + if isinstance(val, np.datetime64 | pd.Timestamp): ts = pd.Timestamp(val) result[i] = float(ts.strftime("%Y%m%d")) else: diff --git a/tests/unit/test_backtest_orders.py b/tests/unit/test_backtest_orders.py index 76e8178..7aca070 100644 --- a/tests/unit/test_backtest_orders.py +++ b/tests/unit/test_backtest_orders.py @@ -2,15 +2,11 @@ from __future__ import annotations -import warnings - import pandas as pd -import pytest from easy_tdx.backtest.orders import OrderSimulator from easy_tdx.backtest.types import Signal - # ── Test Fixtures ───────────────────────────────────────────────────────────── diff --git a/tests/unit/test_backtest_strategy.py b/tests/unit/test_backtest_strategy.py index 6ba14b7..bde0e52 100644 --- a/tests/unit/test_backtest_strategy.py +++ b/tests/unit/test_backtest_strategy.py @@ -12,8 +12,6 @@ from easy_tdx.backtest.strategy import ( _SeriesAccessor, crossover, ) -from easy_tdx.backtest.types import Signal - # ── 辅助函数 ───────────────────────────────────────────────────────────────────── @@ -186,12 +184,12 @@ class TestCrossover: mask = crossover(a, b) # 索引 3 处:a[2]=3 <= b[2]=3, a[3]=4 > b[3]=2 → 金叉 - assert mask[3] == True + assert mask[3] # 其他位置无金叉 - assert mask[0] == False - assert mask[1] == False - assert mask[2] == False - assert mask[4] == False + assert not mask[0] + assert not mask[1] + assert not mask[2] + assert not mask[4] def test_crossover_false_no_cross(self) -> None: """测试无金叉情况(a 全在 b 下方)。""" @@ -208,7 +206,7 @@ class TestCrossover: b = pd.Series([5, 4, 3, 2, 1]) mask = crossover(a, b) - assert mask[3] == True + assert mask[3] def test_crossover_with_accessor(self) -> None: """测试接受 _SeriesAccessor 参数。""" @@ -218,7 +216,7 @@ class TestCrossover: acc_b = _SeriesAccessor(arr_b, bar_index=4) mask = crossover(acc_a, acc_b) - assert mask[3] == True + assert mask[3] # ── TestStrategyBase ──────────────────────────────────────────────────────────────