mirror of
https://ghfast.top/https://github.com/aeroxw/easy-tdx.git
synced 2026-09-12 14:34:15 +08:00
release: v1.8.1 - single-source version, batch backtest detail output
- Consolidate version to pyproject.toml as single source of truth - __init__.py, cli/__init__.py, docs/conf.py all read dynamically - run_all_strategies.py now shows best strategy full trade details - Update README changelog for 1.8.1 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b5b5d0dc5b
commit
b44636207b
@@ -78,7 +78,8 @@
|
|||||||
"Bash(mypy src/easy_tdx/backtest/types.py tests/unit/test_backtest_types.py)",
|
"Bash(mypy src/easy_tdx/backtest/types.py tests/unit/test_backtest_types.py)",
|
||||||
"Bash(mypy *)",
|
"Bash(mypy *)",
|
||||||
"Bash(git diff *)",
|
"Bash(git diff *)",
|
||||||
"Bash(echo \"exit: $?\")"
|
"Bash(echo \"exit: $?\")",
|
||||||
|
"Bash(where easy-tdx *)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1081,6 +1081,14 @@ ruff format --check src/ tests/ # format check
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### 1.8.1 (2026-06-09)
|
||||||
|
|
||||||
|
**回测增强** — 批量策略对比脚本新增最佳策略完整交易明细输出;版本号统一为单一来源(`pyproject.toml`)。
|
||||||
|
|
||||||
|
- `run_all_strategies.py` 排名结束后自动输出最佳策略的绩效概要 + 最近 10 笔交易记录
|
||||||
|
- 修复 `turtle_breakout` 策略 `TAQ()` 返回 3 值但只解包 2 个的 bug
|
||||||
|
- 版本号统一:`pyproject.toml` 为唯一来源,`__init__.py` / `cli/__init__.py` / `docs/conf.py` 均动态读取
|
||||||
|
|
||||||
### 1.8.0 (2026-06-09)
|
### 1.8.0 (2026-06-09)
|
||||||
|
|
||||||
**回测引擎** — 内置向量回测引擎,支持自定义策略回测和全策略批量对比。
|
**回测引擎** — 内置向量回测引擎,支持自定义策略回测和全策略批量对比。
|
||||||
|
|||||||
+9
-1
@@ -3,8 +3,16 @@ project = "easy-tdx"
|
|||||||
copyright = "2025, Justin Gu"
|
copyright = "2025, Justin Gu"
|
||||||
author = "Justin Gu"
|
author = "Justin Gu"
|
||||||
|
|
||||||
|
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
release = "1.8.0"
|
# Read from package metadata to keep single source of truth (pyproject.toml)
|
||||||
|
def _get_version() -> str:
|
||||||
|
from importlib.metadata import version
|
||||||
|
|
||||||
|
return version("easy-tdx")
|
||||||
|
|
||||||
|
|
||||||
|
release = _get_version()
|
||||||
|
|
||||||
# -- Extensions ---------------------------------------------------------------
|
# -- Extensions ---------------------------------------------------------------
|
||||||
extensions = [
|
extensions = [
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "easy-tdx"
|
name = "easy-tdx"
|
||||||
version = "1.8.0"
|
version = "1.8.1"
|
||||||
description = "通达信 TCP 协议行情数据客户端,支持在线行情、离线数据读取与写入同步"
|
description = "通达信 TCP 协议行情数据客户端,支持在线行情、离线数据读取与写入同步"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
# 确保 easy_tdx 可导入
|
# 确保 easy_tdx 可导入
|
||||||
sys.path.insert(0, str(Path(__file__).parent / "src"))
|
sys.path.insert(0, str(Path(__file__).parent / "src"))
|
||||||
@@ -75,6 +76,7 @@ def run_all(
|
|||||||
|
|
||||||
# 3. 逐个运行策略
|
# 3. 逐个运行策略
|
||||||
results: list[dict] = []
|
results: list[dict] = []
|
||||||
|
backtest_results: dict[str, Any] = {} # strategy_name -> BacktestResult
|
||||||
|
|
||||||
for sf in strategy_files:
|
for sf in strategy_files:
|
||||||
strategy_name = sf.stem
|
strategy_name = sf.stem
|
||||||
@@ -132,6 +134,7 @@ def run_all(
|
|||||||
"profit_factor": perf.get("profit_factor", 0),
|
"profit_factor": perf.get("profit_factor", 0),
|
||||||
"volatility": perf.get("volatility", 0),
|
"volatility": perf.get("volatility", 0),
|
||||||
})
|
})
|
||||||
|
backtest_results[strategy_name] = result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
elapsed = time.perf_counter() - t0
|
elapsed = time.perf_counter() - t0
|
||||||
click.echo(f" 错误 ({elapsed:.1f}s): {e}")
|
click.echo(f" 错误 ({elapsed:.1f}s): {e}")
|
||||||
@@ -220,6 +223,45 @@ def run_all(
|
|||||||
f"{r['sharpe']:>8.2f} {ret_dd_ratio:>10.2f} {r['win_rate']:>7.1%}"
|
f"{r['sharpe']:>8.2f} {ret_dd_ratio:>10.2f} {r['win_rate']:>7.1%}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 最佳策略完整交易明细
|
||||||
|
best_name = valid[0]["strategy"]
|
||||||
|
if best_name in backtest_results:
|
||||||
|
bt = backtest_results[best_name]
|
||||||
|
bp = bt.performance
|
||||||
|
bc = bt.config
|
||||||
|
|
||||||
|
click.echo("\n" + "=" * 80)
|
||||||
|
click.echo(f"[DETAIL] 最佳策略交易明细: {best_name}")
|
||||||
|
click.echo("=" * 80)
|
||||||
|
|
||||||
|
click.echo("=== 回测绩效概要 ===")
|
||||||
|
click.echo(f"总收益率: {bp.get('total_return', 0):.2%}")
|
||||||
|
click.echo(f"年化收益: {bp.get('annual_return', 0):.2%}")
|
||||||
|
click.echo(f"最大回撤: {bp.get('max_drawdown', 0):.2%}")
|
||||||
|
click.echo(f"夏普比率: {bp.get('sharpe', 0):.2f}")
|
||||||
|
click.echo(f"胜率: {bp.get('win_rate', 0):.2%}")
|
||||||
|
click.echo(f"交易次数: {bp.get('total_trades', 0)}")
|
||||||
|
click.echo()
|
||||||
|
click.echo("=== 配置参数 ===")
|
||||||
|
click.echo(f"初始资金: {bc.get('cash', 0):.2f}")
|
||||||
|
click.echo(f"佣金率: {bc.get('commission', 0):.4f}")
|
||||||
|
click.echo(f"成交规则: {bc.get('execution', 'next_open')}")
|
||||||
|
click.echo()
|
||||||
|
|
||||||
|
if not bt.trades.empty:
|
||||||
|
click.echo("=== 最近交易记录 ===")
|
||||||
|
recent_trades = bt.trades.tail(10)
|
||||||
|
for _, trade in recent_trades.iterrows():
|
||||||
|
direction = "买入" if trade["direction"] == "BUY" else "卖出"
|
||||||
|
status = "拒绝" if trade["rejected"] else "成交"
|
||||||
|
click.echo(
|
||||||
|
f" [{trade['datetime']}] {direction} "
|
||||||
|
f"数量={trade['size']:.0f} 价格={trade['price']:.2f} "
|
||||||
|
f"盈亏={trade['pnl']:.2f} [{status}]"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
click.echo("无交易记录")
|
||||||
|
|
||||||
# 报告错误
|
# 报告错误
|
||||||
if errored:
|
if errored:
|
||||||
click.echo("\n[!] 以下策略运行失败:")
|
click.echo("\n[!] 以下策略运行失败:")
|
||||||
|
|||||||
@@ -107,4 +107,11 @@ __all__ = [
|
|||||||
"save_best_ex_host",
|
"save_best_ex_host",
|
||||||
]
|
]
|
||||||
|
|
||||||
__version__ = "1.8.0"
|
|
||||||
|
def _get_version() -> str:
|
||||||
|
from importlib.metadata import version
|
||||||
|
|
||||||
|
return version("easy-tdx")
|
||||||
|
|
||||||
|
|
||||||
|
__version__ = _get_version()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from ..backtest.cli import backtest
|
|||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
@click.version_option(version="1.8.0", prog_name="easy-tdx")
|
@click.version_option(version=__import__("importlib.metadata", fromlist=["version"]).version("easy-tdx"), prog_name="easy-tdx")
|
||||||
def cli() -> None:
|
def cli() -> None:
|
||||||
"""easy-tdx -- 通达信行情数据 CLI(默认 JSON 输出,适合 Agent 使用)。
|
"""easy-tdx -- 通达信行情数据 CLI(默认 JSON 输出,适合 Agent 使用)。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user