mirror of
https://ghfast.top/https://github.com/aeroxw/easy-tdx.git
synced 2026-09-12 15:44:15 +08:00
release: v1.11.5 — scipy 依赖声明 + 文档同步 + 工程化清理
- pyproject: 新增 science 可选依赖组(scipy),dev 纳入 scipy;版本号 1.11.5 - factor/analysis: spearman 分支加 scipy 软依赖保护,缺失时友好报错 - mac/client: 板块排行吞异常处补 logger.debug - CLAUDE.md: 架构章节补全 mac/ex/unified/portfolio/factor/offline/screen 子包 - .gitignore: 补全 .coverage、signals.json - README: 补 1.11.5 changelog
This commit is contained in:
@@ -16,3 +16,7 @@ venv/
|
||||
uv.lock
|
||||
docs/_build/
|
||||
FK/
|
||||
|
||||
# 测试覆盖率与运行时产物
|
||||
.coverage
|
||||
signals.json
|
||||
|
||||
@@ -23,7 +23,18 @@ ruff format --check src/ tests/
|
||||
|
||||
```
|
||||
src/easy_tdx/
|
||||
├── client.py # TdxClient / AsyncTdxClient(高层 API)
|
||||
├── client.py # TdxClient / AsyncTdxClient(Windows 通达信协议高层 API)
|
||||
├── mac/ # macOS 通达信协议(独立命令/编解码/握手)
|
||||
│ ├── client.py # MacClient / AsyncMacClient(mac 行情高层 API)
|
||||
│ ├── commands/ # mac 协议命令(SymbolQuotesCmd / BoardMembersQuotesCmd 等)
|
||||
│ ├── enums.py # Category / SortType / FilterType / BoardType / Period / Adjust
|
||||
│ └── models.py # MacQuoteField / MacTickChart 等 dataclass
|
||||
├── ex/ # 扩展行情协议(ExTdx)+ macOS 扩展(MacEx)
|
||||
│ ├── client.py # ExTdxClient / AsyncExTdxClient
|
||||
│ ├── mac_client.py # MacExClient / AsyncMacExClient(goods_* 系列方法)
|
||||
│ ├── commands/ # 扩展协议命令
|
||||
│ └── models.py # ExMarketInfo / ExInstrumentInfo 等
|
||||
├── unified.py # UnifiedTdxClient / AsyncUnifiedTdxClient(聚合 mac + mac_ex 的门面)
|
||||
├── chanlun/ # 缠论技术分析模块(独立于 transport,纯计算)
|
||||
│ ├── analyser.py # ChanlunAnalyser 主入口(接收 DataFrame)
|
||||
│ ├── types.py # 数据结构(Kline/CLKline/FX/BI/XD/ZS/MMD/BC)
|
||||
@@ -39,27 +50,41 @@ src/easy_tdx/
|
||||
│ ├── beichi.py # 背驰判断(笔/盘整/趋势)
|
||||
│ └── multi_level.py # 多级别联立分析
|
||||
├── transport/
|
||||
│ ├── sync.py # TdxConnection(socket)+ ping_host / ping_all
|
||||
│ ├── sync.py # TdxConnection(socket)+ ping_host / ping_all / ping_mac_all
|
||||
│ └── async_.py # AsyncTdxConnection(asyncio)
|
||||
├── commands/ # 每条命令:build_request() + parse_response(),无 IO
|
||||
├── codec/ # price / volume / datetime / frame 编解码
|
||||
├── codec/ # price / volume / datetime / frame / financial / bitmap 编解码
|
||||
├── backtest/ # 回测引擎
|
||||
│ ├── engine.py # BacktestEngine(止损/止盈执行/缠论自动桥接)
|
||||
│ ├── strategy.py # Strategy 基类(向量化 datetime)
|
||||
│ ├── orders.py # OrderSimulator(SL/TP 同 bar 执行)
|
||||
│ ├── execution.py # 可插拔执行模型(Immediate/TWAP/VWAP/Limit)
|
||||
│ ├── slippage.py # 滑点模型(Fixed/Percent/Volume/Volatility)
|
||||
│ ├── performance.py # PerformanceAnalyzer(FIFO 真实持仓天数)
|
||||
│ ├── portfolio_engine.py # 多标的组合回测
|
||||
│ └── combo.py # 多因子组合回测
|
||||
│ ├── portfolio.py / portfolio_engine.py # 多标的组合回测
|
||||
│ ├── combo.py # 多因子组合回测
|
||||
│ ├── attribution.py # Brinson / 因子 / 成本归因
|
||||
│ └── dsl.py # 策略 DSL 解析
|
||||
├── portfolio/ # 组合层
|
||||
│ ├── optimizer.py # 权重优化(mean_variance 可选 scipy,缺失回退等权)
|
||||
│ └── ... # risk / rebalance 等
|
||||
├── factor/ # 因子分析
|
||||
│ ├── analysis.py # FactorAnalyzer(compute_ic 用 spearman,可选 scipy → pip install easy-tdx[science])
|
||||
│ ├── engine.py / base.py / transform.py
|
||||
│ └── builtin/ # 内置因子
|
||||
├── screen/
|
||||
│ └── scanner.py # SignalScanner(并发扫描/增量缓存)
|
||||
│ ├── scanner.py # SignalScanner(并发扫描/增量缓存)
|
||||
│ └── ranker.py # 排序/打分
|
||||
├── realtime/
|
||||
│ └── engine.py # EventBus + RealtimeStrategy(asyncio 事件驱动)
|
||||
├── cli/
|
||||
│ └── cmd_chanlun.py # easy-tdx chanlun CLI 命令
|
||||
├── offline/ # 离线数据读写(daily_bar / min_bar / gbbq / history_financial 等)
|
||||
├── indicator.py / MyTT.py # 技术指标(MyTT 为第三方库移植,命名沿袭惯例)
|
||||
├── config.py # 主机/端口/超时配置 + best_host 持久化
|
||||
├── cli/ # easy-tdx CLI(click);cmd_chanlun / cmd_backtest / cmd_offline / cmd_factor 等
|
||||
└── models/ # 纯 dataclass,无业务逻辑
|
||||
```
|
||||
|
||||
commands 层不依赖 transport,可独立单测。修改 codec 或 commands 时不需要网络。
|
||||
四套 client 关系:`client.py`(Windows 标准)、`mac/client.py`(macOS)、`ex/client.py`(扩展)、`ex/mac_client.py`(macOS 扩展);每套均提供 sync + async 镜像。`unified.py` 是 mac + mac_ex 的门面。commands 层不依赖 transport,可独立单测。修改 codec 或 commands 时不需要网络。
|
||||
|
||||
## 协议编解码注意事项
|
||||
|
||||
|
||||
@@ -1511,6 +1511,24 @@ ruff format --check src/ tests/ # format check
|
||||
|
||||
## Changelog
|
||||
|
||||
### 1.11.5 (2026-06-13)
|
||||
|
||||
**稳定性与代码质量修复** — 全项目代码审计 + 一个潜伏的 ping 崩溃 bug 修复。
|
||||
|
||||
**Bug 修复**:
|
||||
- 修复 `easy-tdx ping` 在非交易时间(服务器握手阶段关闭连接)整个命令崩溃的问题。根因:`ping_host` 仅捕获 `OSError`,但握手期 `_recv_exact_sock` 抛出的 `TdxConnectionError`(继承自 `TdxError(Exception)` 而非 `OSError`)逃出捕获,经 `ping_all` 的 `fut.result()` 重新抛出,导致单台服务器不可用就拖垮整条测速命令。修复后符合 docstring 承诺"不可达服务器不包含在结果中",并加防御层让 `ping_all` 对异常 future 容错跳过。
|
||||
- 修复回测 `OrderSimulator._find_bar_index` 把 DataFrame 的 index label 当位置索引用的隐患。当传入 df 的 index 非默认 RangeIndex 时,`idxmax()` 返回的 label 与 `iloc[]` 期望的位置不一致,可能导致撮合取错 K 线。改用 `to_numpy().argmax()` 取真实位置。
|
||||
|
||||
**依赖与工程化**:
|
||||
- scipy 隐式硬依赖声明:`factor/analysis.py` 的 Rank IC(spearman)通过 pandas lazy import scipy,干净环境必报 `ModuleNotFoundError`。新增 `science` 可选依赖组(`pip install easy-tdx[science]`),并在 spearman 分支加 try-import 友好报错(复用 `optimizer.py` 现有模式)。
|
||||
- `mac/client.py` 板块 N 日涨跌幅排行中静默吞异常的 `except Exception: continue` 补上 `logger.debug` 日志,便于排查。
|
||||
- `.gitignore` 补全 `.coverage`、`signals.json`。
|
||||
|
||||
**文档**:
|
||||
- `CLAUDE.md` 架构章节更新:补全 `mac/`、`ex/`、`unified.py`、`portfolio/`、`factor/`、`offline/`、`screen/` 等子包,说明四套 client(Windows/macOS/扩展/macOS扩展)的 sync+async 镜像关系。
|
||||
|
||||
**测试**:564 passed, 0 failed(+8 新增:2 ping 容错回归、2 非连续 index 回归、4 既有覆盖增强)
|
||||
|
||||
### 1.11.1 (2026-06-12)
|
||||
|
||||
**量化因子引擎 + 组合管理 + 高级回测增强** — 三大新模块,补齐从因子研究到组合执行的完整量化链路。
|
||||
|
||||
+3
-2
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "easy-tdx"
|
||||
version = "1.11.1"
|
||||
version = "1.11.5"
|
||||
description = "通达信 TCP 协议行情数据客户端,支持在线行情、离线数据读取与写入同步"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
@@ -14,7 +14,8 @@ dependencies = ["pandas>=2.0", "tzdata>=2024.1", "click>=8.0"]
|
||||
easy-tdx = "easy_tdx.cli:cli" # cli/__init__.py exposes the click group
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "pytest-cov", "mypy>=1.9", "ruff>=0.4"]
|
||||
dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "pytest-cov", "mypy>=1.9", "ruff>=0.4", "scipy>=1.10"]
|
||||
science = ["scipy>=1.10"]
|
||||
web = ["fastapi>=0.110", "uvicorn[standard]>=0.29"]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
|
||||
@@ -56,6 +56,12 @@ class FactorAnalyzer:
|
||||
ic_values.append(np.nan)
|
||||
continue
|
||||
if method == "spearman":
|
||||
try:
|
||||
import scipy # type: ignore[import-untyped] # noqa: F401 # pandas spearman lazy import
|
||||
except ImportError as e:
|
||||
raise ImportError(
|
||||
"Rank IC (spearman) 需要 scipy,请执行 `pip install easy-tdx[science]`"
|
||||
) from e
|
||||
corr = valid[self._factor_col].corr(valid[self._return_col], method="spearman")
|
||||
else:
|
||||
corr = valid[self._factor_col].corr(valid[self._return_col], method="pearson")
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
from dataclasses import asdict
|
||||
from types import TracebackType
|
||||
@@ -48,6 +49,8 @@ _RETRY_DELAYS = (0.1, 0.5, 1.0, 2.0)
|
||||
_KLINE_PAGE_SIZE = 700
|
||||
_BOARD_MEMBERS_PAGE_SIZE = 80
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _convert_board_code(board_symbol: str) -> int:
|
||||
"""将用户可见的板块代码转换为服务器协议代码。
|
||||
@@ -815,6 +818,7 @@ class MacClient:
|
||||
adjust=Adjust.NONE,
|
||||
)
|
||||
except Exception:
|
||||
_logger.debug("板块 %s K线获取失败,跳过", board_code, exc_info=True)
|
||||
continue
|
||||
|
||||
if kline_df.empty or len(kline_df) < 2:
|
||||
@@ -1642,6 +1646,7 @@ class AsyncMacClient:
|
||||
adjust=Adjust.NONE,
|
||||
)
|
||||
except Exception:
|
||||
_logger.debug("板块 %s K线获取失败,跳过", board_code, exc_info=True)
|
||||
continue
|
||||
|
||||
if kline_df.empty or len(kline_df) < 2:
|
||||
|
||||
Reference in New Issue
Block a user