solidrock-quant 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. solidrock/__init__.py +53 -0
  2. solidrock/agent/__init__.py +5 -0
  3. solidrock/agent/errors.py +95 -0
  4. solidrock/agent/mcp_server.py +224 -0
  5. solidrock/agent/skills/backtest-workflow.md +75 -0
  6. solidrock/agent/skills/data-update-workflow.md +46 -0
  7. solidrock/agent/skills/experiment-comparison-workflow.md +46 -0
  8. solidrock/agent/tools.py +638 -0
  9. solidrock/agent/validation.py +205 -0
  10. solidrock/backtest/__init__.py +21 -0
  11. solidrock/backtest/config.py +51 -0
  12. solidrock/backtest/context.py +158 -0
  13. solidrock/backtest/costs.py +137 -0
  14. solidrock/backtest/engine.py +562 -0
  15. solidrock/backtest/matching.py +285 -0
  16. solidrock/backtest/portfolio.py +209 -0
  17. solidrock/backtest/vectorized.py +109 -0
  18. solidrock/cli/__init__.py +5 -0
  19. solidrock/cli/main.py +560 -0
  20. solidrock/config.py +47 -0
  21. solidrock/data/__init__.py +36 -0
  22. solidrock/data/calendar.py +106 -0
  23. solidrock/data/futures.py +157 -0
  24. solidrock/data/quality.py +163 -0
  25. solidrock/data/schema.py +196 -0
  26. solidrock/data/sources/__init__.py +27 -0
  27. solidrock/data/sources/akshare_source.py +642 -0
  28. solidrock/data/sources/baostock_source.py +259 -0
  29. solidrock/data/sources/base.py +206 -0
  30. solidrock/data/sources/registry.py +53 -0
  31. solidrock/data/sources/tushare_source.py +290 -0
  32. solidrock/data/store.py +407 -0
  33. solidrock/data/symbols.py +170 -0
  34. solidrock/experiments/__init__.py +5 -0
  35. solidrock/experiments/tracker.py +149 -0
  36. solidrock/factors/__init__.py +24 -0
  37. solidrock/factors/analysis.py +284 -0
  38. solidrock/factors/base.py +120 -0
  39. solidrock/factors/processing.py +71 -0
  40. solidrock/factors/report.py +83 -0
  41. solidrock/report/__init__.py +15 -0
  42. solidrock/report/json_report.py +55 -0
  43. solidrock/report/markdown.py +99 -0
  44. solidrock/report/metrics.py +156 -0
  45. solidrock/risk/__init__.py +5 -0
  46. solidrock/risk/checks.py +56 -0
  47. solidrock/strategy/__init__.py +5 -0
  48. solidrock/strategy/base.py +59 -0
  49. solidrock/strategy/loader.py +50 -0
  50. solidrock/utils/__init__.py +5 -0
  51. solidrock/utils/loader.py +53 -0
  52. solidrock_quant-0.2.0.dist-info/METADATA +195 -0
  53. solidrock_quant-0.2.0.dist-info/RECORD +56 -0
  54. solidrock_quant-0.2.0.dist-info/WHEEL +4 -0
  55. solidrock_quant-0.2.0.dist-info/entry_points.txt +2 -0
  56. solidrock_quant-0.2.0.dist-info/licenses/LICENSE +201 -0
solidrock/__init__.py ADDED
@@ -0,0 +1,53 @@
1
+ """SolidRockQuant · 磐石智擎 — Agent 原生的量化研究与回测框架.
2
+
3
+ 数据层快速上手::
4
+
5
+ from solidrock import DataStore, parse_symbol
6
+ from solidrock.data.sources import create_source
7
+
8
+ src = create_source("akshare")
9
+ store = DataStore(".solidrock")
10
+ df = src.fetch_bars(["000001.SZ", "600519.SH"], start="2024-01-01")
11
+ store.update_bars(df, source="akshare")
12
+
13
+ 回测快速上手::
14
+
15
+ from solidrock import BacktestConfig, BacktestEngine, Strategy
16
+
17
+ class MyStrategy(Strategy):
18
+ ...
19
+
20
+ result = BacktestEngine(MyStrategy, BacktestConfig(start="2024-01-01", end="2025-12-31"),
21
+ DataStore(".solidrock")).run()
22
+ print(result.metrics["sharpe"])
23
+ """
24
+
25
+ from solidrock.agent.errors import ErrorCode, SolidRockError
26
+ from solidrock.backtest import BacktestConfig, BacktestEngine, BacktestResult, Context
27
+ from solidrock.config import Settings, get_settings
28
+ from solidrock.data.store import DataStore
29
+ from solidrock.data.symbols import AssetType, Symbol, parse_symbol
30
+ from solidrock.factors import Factor, FactorData, analyze_factor
31
+ from solidrock.strategy.base import Strategy
32
+
33
+ __version__ = "0.2.0"
34
+
35
+ __all__ = [
36
+ "AssetType",
37
+ "BacktestConfig",
38
+ "BacktestEngine",
39
+ "BacktestResult",
40
+ "Context",
41
+ "DataStore",
42
+ "ErrorCode",
43
+ "Factor",
44
+ "FactorData",
45
+ "Settings",
46
+ "SolidRockError",
47
+ "Strategy",
48
+ "Symbol",
49
+ "__version__",
50
+ "analyze_factor",
51
+ "get_settings",
52
+ "parse_symbol",
53
+ ]
@@ -0,0 +1,5 @@
1
+ """Agent 接口层:MCP Server、错误规范、技能文件."""
2
+
3
+ from solidrock.agent.errors import ErrorCode, SolidRockError, err
4
+
5
+ __all__ = ["ErrorCode", "SolidRockError", "err"]
@@ -0,0 +1,95 @@
1
+ """错误体系:稳定错误码 + 修复建议(hint)规范.
2
+
3
+ 全库统一抛出 :class:`SolidRockError`。每条错误必须携带:
4
+
5
+ - ``code``:稳定的枚举错误码,Agent 依赖它做分支判断;只能追加,不能改名或删除;
6
+ - ``message``:人读描述;
7
+ - ``hint``:**可执行**的修复建议,Agent 依赖它自纠错,这是"Agent 友好"的硬性要求。
8
+
9
+ 示例::
10
+
11
+ raise err(
12
+ ErrorCode.SYMBOL_NOT_FOUND,
13
+ f"代码 {raw} 在数据源中不存在",
14
+ hint="先调用 search_instruments 确认符号;股票代码需带交易所后缀,如 000001.SZ",
15
+ )
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from enum import Enum
21
+ from typing import Any
22
+
23
+
24
+ class ErrorCode(str, Enum):
25
+ """稳定错误码(对外契约,只追加不修改)。"""
26
+
27
+ # --- 请求与符号 ---
28
+ SYMBOL_INVALID = "SYMBOL_INVALID" # 符号格式非法
29
+ SYMBOL_NOT_FOUND = "SYMBOL_NOT_FOUND" # 格式合法但数据源查无此标的
30
+ PARAM_INVALID = "PARAM_INVALID" # 参数非法(日期区间倒置等)
31
+
32
+ # --- 数据源 ---
33
+ SOURCE_NOT_REGISTERED = "SOURCE_NOT_REGISTERED" # 未注册的数据源名
34
+ SOURCE_UNAVAILABLE = "SOURCE_UNAVAILABLE" # 依赖库未安装或网络不可达
35
+ SOURCE_AUTH_FAILED = "SOURCE_AUTH_FAILED" # 鉴权失败(token 缺失/无效/积分不足)
36
+ SOURCE_REQUEST_FAILED = "SOURCE_REQUEST_FAILED" # 请求失败(限流/超时/接口变动)
37
+ CAPABILITY_NOT_SUPPORTED = "CAPABILITY_NOT_SUPPORTED" # 数据源不具备该能力
38
+
39
+ # --- 本地数据 ---
40
+ NO_DATA = "NO_DATA" # 本地无数据,需要先更新
41
+ DATA_FORMAT_INVALID = "DATA_FORMAT_INVALID" # 数据不符合标准 schema
42
+ SNAPSHOT_NOT_FOUND = "SNAPSHOT_NOT_FOUND"
43
+ SNAPSHOT_EXISTS = "SNAPSHOT_EXISTS"
44
+ SNAPSHOT_READ_ONLY = "SNAPSHOT_READ_ONLY" # 快照是只读副本
45
+
46
+ # --- 策略校验(M3+ 回测/Agent 层使用) ---
47
+ STRATEGY_INVALID = "STRATEGY_INVALID"
48
+ LOOKAHEAD_SUSPECTED = "LOOKAHEAD_SUSPECTED"
49
+
50
+ # --- 其他 ---
51
+ INTERNAL_ERROR = "INTERNAL_ERROR" # 未预期的框架错误(应附复现步骤报 issue)
52
+
53
+
54
+ class SolidRockError(Exception):
55
+ """框架内所有受检错误的基类。"""
56
+
57
+ def __init__(
58
+ self,
59
+ code: ErrorCode,
60
+ message: str,
61
+ *,
62
+ hint: str | None = None,
63
+ details: dict[str, Any] | None = None,
64
+ ) -> None:
65
+ super().__init__(message)
66
+ self.code = code
67
+ self.message = message
68
+ self.hint = hint
69
+ self.details = details or {}
70
+
71
+ def to_dict(self) -> dict[str, Any]:
72
+ """输出 MCP 信封中的 ``error`` 段(见 docs/design.md §8.2)。"""
73
+ out: dict[str, Any] = {"code": self.code.value, "message": self.message}
74
+ if self.hint:
75
+ out["hint"] = self.hint
76
+ if self.details:
77
+ out["details"] = self.details
78
+ return out
79
+
80
+ def __str__(self) -> str:
81
+ text = f"[{self.code.value}] {self.message}"
82
+ if self.hint:
83
+ text += f"\nhint: {self.hint}"
84
+ return text
85
+
86
+
87
+ def err(
88
+ code: ErrorCode,
89
+ message: str,
90
+ *,
91
+ hint: str | None = None,
92
+ details: dict[str, Any] | None = None,
93
+ ) -> SolidRockError:
94
+ """便捷构造函数。"""
95
+ return SolidRockError(code, message, hint=hint, details=details)
@@ -0,0 +1,224 @@
1
+ """MCP Server(FastMCP,stdio 传输).
2
+
3
+ 接入 Claude Desktop / Claude Code 等 LLM 客户端::
4
+
5
+ # .mcp.json
6
+ {"mcpServers": {"solidrock": {"command": "srq", "args": ["mcp", "serve"]}}}
7
+
8
+ 所有工具返回 JSON 字符串(统一信封,见 tools.py)。工具的 docstring 即
9
+ LLM 看到的使用说明,必须自包含、带单位与示例。
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Any
15
+
16
+ from solidrock import __version__
17
+ from solidrock.agent.errors import ErrorCode, err
18
+
19
+
20
+ def build_server() -> Any:
21
+ """构建 MCP Server 实例(兼容 mcp 1.x FastMCP 与 2.x MCPServer)."""
22
+ try: # mcp 2.x
23
+ from mcp.server.mcpserver import MCPServer as _Server
24
+ except ImportError:
25
+ try: # mcp 1.x(fastmcp 已在 2.x 改名,此处兼容旧版)
26
+ from mcp.server.fastmcp import FastMCP as _Server # type: ignore[attr-defined, no-redef]
27
+ except ImportError as exc:
28
+ raise err(
29
+ ErrorCode.SOURCE_UNAVAILABLE,
30
+ "MCP 扩展未安装",
31
+ hint="pip install 'solidrock-quant[mcp]' 或 pip install mcp",
32
+ ) from exc
33
+
34
+ from solidrock.agent import tools as t
35
+
36
+ mcp = _Server(
37
+ "solidrock",
38
+ instructions=(
39
+ "SolidRockQuant:A股/期货量化研究与回测框架。"
40
+ "典型研究闭环:get_data_overview → fetch_bars(补数据) → 编写策略文件 → "
41
+ "validate_strategy → run_backtest → compare_experiments 迭代改进。"
42
+ f"当前版本 {__version__}。"
43
+ ),
44
+ )
45
+
46
+ @mcp.tool()
47
+ def get_data_overview() -> str:
48
+ """查看本地数据总览:已缓存的行情(符号数/行数/日期范围)、交易日历、快照、实验数量。
49
+
50
+ 开始任何研究前先调用它了解本地有什么数据。返回 JSON 信封。
51
+ """
52
+ return t.tool_get_data_overview()
53
+
54
+ @mcp.tool()
55
+ def data_health(symbols: list[str] | None = None, jump_threshold: float = 0.2) -> str:
56
+ """数据体检:缺失交易日、OHLC 异常、复权因子缺失、单日大幅波动。
57
+
58
+ symbols 缺省检查全部本地标的。回测前建议跑一次,避免坏数据污染结论。
59
+ """
60
+ return t.tool_data_health(symbols=symbols, jump_threshold=jump_threshold)
61
+
62
+ @mcp.tool()
63
+ def list_data_sources() -> str:
64
+ """列出可用数据源(akshare/tushare 等)及其能力与可用性。"""
65
+ return t.tool_list_data_sources()
66
+
67
+ @mcp.tool()
68
+ def search_instruments(query: str, limit: int = 20) -> str:
69
+ """按代码或名称搜索标的。
70
+
71
+ 示例:query="510300" 找沪深300ETF;query="贵州茅台" 找 600519.SH。
72
+ 股票符号格式:<6位代码>.<SZ|SH|BJ>,指数/ETF 同理,期货为 <品种><月份>.<交易所>。
73
+ """
74
+ return t.tool_search_instruments(query=query, limit=limit)
75
+
76
+ @mcp.tool()
77
+ def fetch_bars(
78
+ symbols: list[str] | str,
79
+ start: str | None = None,
80
+ end: str | None = None,
81
+ source: str | None = None,
82
+ freq: str = "1d",
83
+ ) -> str:
84
+ """拉取/更新行情到本地(增量幂等)。
85
+
86
+ symbols 为统一符号或其列表,如 ["000001.SZ", "510300.SH"];
87
+ start/end 格式 YYYY-MM-DD(建议显式给 start);freq:1d(默认)/
88
+ 1m / 5m(分钟线无复权因子,仅供研究,事件回测用日线)。
89
+ """
90
+ return t.tool_fetch_bars(symbols=symbols, start=start, end=end, source=source, freq=freq)
91
+
92
+ @mcp.tool()
93
+ def get_trading_calendar(
94
+ start: str | None = None,
95
+ end: str | None = None,
96
+ update: bool = False,
97
+ ) -> str:
98
+ """查询交易日历(update=True 时先从数据源刷新)。"""
99
+ return t.tool_get_trading_calendar(start=start, end=end, update=update)
100
+
101
+ @mcp.tool()
102
+ def validate_strategy(strategy_file: str) -> str:
103
+ """策略代码静态检查:语法、前视偏差(shift(-n)/bfill)、Context API 误用。
104
+
105
+ 回测前必调用(run_backtest 内部也会自动调用)。strategy_file 为策略
106
+ .py 文件的绝对路径。返回 issues 列表(severity: error/warning)。
107
+ """
108
+ return t.tool_validate_strategy(strategy_file=strategy_file)
109
+
110
+ @mcp.tool()
111
+ def run_backtest(
112
+ strategy_file: str,
113
+ start: str,
114
+ end: str,
115
+ params: dict[str, Any] | None = None,
116
+ benchmark: str | None = "000300.SH",
117
+ execution: str = "next_open",
118
+ initial_cash: float = 1_000_000.0,
119
+ name: str | None = None,
120
+ ) -> str:
121
+ """运行回测(自动静态校验 + 结果自动留痕)。
122
+
123
+ strategy_file:策略文件绝对路径(内含一个 Strategy 子类);
124
+ params:策略参数覆盖,如 {"fast": 10};
125
+ execution:next_open(默认,防前视)| same_close(仅快速研究);
126
+ benchmark 传 null 关闭基准对比。返回核心指标 + 产物目录
127
+ (report.md/result.json/trades.csv/nav.csv)。
128
+ """
129
+ return t.tool_run_backtest(
130
+ strategy_file=strategy_file,
131
+ start=start,
132
+ end=end,
133
+ params=params,
134
+ benchmark=benchmark,
135
+ execution=execution,
136
+ initial_cash=initial_cash,
137
+ name=name,
138
+ )
139
+
140
+ @mcp.tool()
141
+ def list_experiments(kind: str | None = None, limit: int = 20) -> str:
142
+ """列出最近的实验(kind: backtest/factor,默认全部)。"""
143
+ return t.tool_list_experiments(kind=kind, limit=limit)
144
+
145
+ @mcp.tool()
146
+ def get_experiment(run_id: str) -> str:
147
+ """查看单个实验的完整配置、指标与产物路径。"""
148
+ return t.tool_get_experiment(run_id=run_id)
149
+
150
+ @mcp.tool()
151
+ def compare_experiments(run_ids: list[str]) -> str:
152
+ """并排对比多个实验的核心指标(至少 2 个 run_id,来自 list_experiments)。"""
153
+ return t.tool_compare_experiments(run_ids=run_ids)
154
+
155
+ @mcp.tool()
156
+ def run_factor_analysis(
157
+ factor_file: str,
158
+ universe: list[str],
159
+ start: str,
160
+ end: str,
161
+ params: dict[str, Any] | None = None,
162
+ quantiles: int = 5,
163
+ fwd_period: int = 1,
164
+ name: str | None = None,
165
+ ) -> str:
166
+ """运行因子分析:RankIC + 分层回测(自动留痕)。
167
+
168
+ factor_file:因子文件绝对路径(内含一个 Factor 子类,compute 返回
169
+ index=date/columns=symbol 的宽表);universe 为股票池符号列表(建议
170
+ 50 只以上,截面太少 IC 不可信);quantiles 分层数;fwd_period 前瞻
171
+ 收益期。解读:|IC均值|>0.03 且 ICIR>0.5 才值得继续;层间单调性比
172
+ 多空收益更重要。
173
+ """
174
+ return t.tool_run_factor_analysis(
175
+ factor_file=factor_file,
176
+ universe=universe,
177
+ start=start,
178
+ end=end,
179
+ params=params,
180
+ quantiles=quantiles,
181
+ fwd_period=fwd_period,
182
+ name=name,
183
+ )
184
+
185
+ @mcp.tool()
186
+ def run_vectorized_backtest(
187
+ factor_file: str,
188
+ universe: list[str],
189
+ start: str,
190
+ end: str,
191
+ params: dict[str, Any] | None = None,
192
+ top: float = 0.2,
193
+ bottom: float = 0.2,
194
+ fee_rate: float = 1.5e-4,
195
+ name: str | None = None,
196
+ ) -> str:
197
+ """向量化因子筛选:做多头部分位、做空尾部分位的组合净值(秒级)。
198
+
199
+ 适合批量扫参数的快速迭代;逐日再平衡、收盘成交、单一费率,
200
+ 结论仅用于相对比较,最终结论用 run_backtest 事件引擎复核。
201
+ """
202
+ return t.tool_run_vectorized_backtest(
203
+ factor_file=factor_file,
204
+ universe=universe,
205
+ start=start,
206
+ end=end,
207
+ params=params,
208
+ top=top,
209
+ bottom=bottom,
210
+ fee_rate=fee_rate,
211
+ name=name,
212
+ )
213
+
214
+ return mcp
215
+
216
+
217
+ def main() -> None:
218
+ """stdio 入口(srq mcp serve)。"""
219
+ server = build_server()
220
+ server.run() # stdio
221
+
222
+
223
+ if __name__ == "__main__":
224
+ main()
@@ -0,0 +1,75 @@
1
+ # SKILL: 回测研究流程
2
+
3
+ 目标:让 Agent 独立完成"检查数据 → 写策略 → 校验 → 回测 → 读结果 → 迭代"的完整闭环。
4
+
5
+ ## 0. 前置认知
6
+
7
+ - 所有 MCP 工具返回 **JSON 信封**:`status`("ok"/"error") + `data` + `artifacts`(文件路径) + `error.{code,message,hint}`。
8
+ - 出错时先读 `error.hint` 并按它行动,不要盲目重试相同参数。
9
+ - 符号格式:`000001.SZ` / `600519.SH` / `000300.SH`(指数) / `510300.SH`(ETF) / `RB2505.SHFE`(期货) / `RB.SHFE`(主连)。
10
+ - 引擎默认 `next_open` 执行(收盘信号次日开盘成交,防前视);不要为了"更好的回测收益"改用 `same_close`。
11
+
12
+ ## 1. 检查本地数据
13
+
14
+ 调用 `get_data_overview`,确认:
15
+ 1. 回测区间内的交易日历已覆盖(否则 `get_trading_calendar` 传 `update=true`);
16
+ 2. 目标标的日线已缓存且区间覆盖"回测起点往前 250 个交易日"(策略 warmup);
17
+ 缺数据 → `fetch_bars(symbols=[...], start=<回测起点-365天>, end=今天)`。
18
+
19
+ ## 2. 编写策略文件
20
+
21
+ 在项目工作区写一个 `.py` 文件(内含**一个** Strategy 子类):
22
+
23
+ ```python
24
+ from solidrock import Context, Strategy
25
+
26
+
27
+ class MyStrategy(Strategy):
28
+ params = {"symbol": "510300.SH", "fast": 5, "slow": 20}
29
+
30
+ def setup(self, ctx: Context) -> None:
31
+ ctx.universe = [str(self.params["symbol"])] # 必须设置
32
+
33
+ def on_signal(self, ctx: Context) -> None: # 每个交易日收盘后调用
34
+ symbol = str(self.params["symbol"])
35
+ close = ctx.history(symbol, int(self.params["slow"]) + 1, fields="close")[symbol]
36
+ window = close.iloc[-int(self.params["slow"]) :]
37
+ if window.isna().any() or len(window) < int(self.params["slow"]):
38
+ return # 数据不足(warmup 期/停牌)直接跳过
39
+ target = 1.0 if window.iloc[-int(self.params["fast"]) :].mean() > window.mean() else 0.0
40
+ ctx.order_target_percent(symbol, target)
41
+ ```
42
+
43
+ 可用 API(只有这些,幻觉调用会被静态检查拦截):
44
+ - 下单:`ctx.order(sym, qty)`、`ctx.order_value(sym, value)`、`ctx.order_target_percent(sym, pct)`、`ctx.order_target_value(sym, value)`、`ctx.cancel_all()`
45
+ - 数据:`ctx.history(symbols, n, fields="close")`(宽表 DataFrame,含当日 bar)、`ctx.position(sym)`
46
+ - 查询:`ctx.portfolio`(cash/positions/total_value)、`ctx.now`、`ctx.params`
47
+ - 其他:`ctx.log(msg)`
48
+
49
+ 硬性规则:
50
+ - **只能用截至当前 bar 的数据**(`shift(-n)`、`bfill` 会被拦截);
51
+ - 参数全部通过 `self.params` 声明与读取,方便对比实验;
52
+ - 仓位目标用 `order_target_percent`,不要手写股数对齐逻辑(引擎处理整手/T+1/资金约束)。
53
+
54
+ ## 3. 校验并回测
55
+
56
+ 1. `validate_strategy(strategy_file=<绝对路径>)` — 有 error 必须先修;
57
+ 2. `run_backtest(strategy_file=<绝对路径>, start="YYYY-MM-DD", end="YYYY-MM-DD", params={...}, name="<可辨识的实验名>")`;
58
+ 3. 读返回的 `metrics`(核心:annual_return / sharpe / max_drawdown / trade_win_rate / annual_turnover / excess_annual_return)与 `rejection_counts`。
59
+
60
+ ## 4. 迭代
61
+
62
+ - `list_experiments` → `compare_experiments(run_ids=[...])` 横向对比;
63
+ - 每次改动只动一个变量(一个参数或一处逻辑),实验名带上改动点(如 "双均线-fast10");
64
+ - 警惕过拟合:参数扫描得到的"最优"参数要换区间/换标的验证;
65
+ - 交易胜率低但盈亏比高是趋势策略常态,单看胜率会误判。
66
+
67
+ ## 5. 常见错误码
68
+
69
+ | code | 含义 | 处置 |
70
+ |------|------|------|
71
+ | NO_DATA | 本地无数据/区间无交易日 | fetch_bars 补数据或修正区间 |
72
+ | SYMBOL_INVALID | 符号格式错 | 用 search_instruments 确认 |
73
+ | LOOKAHEAD_SUSPECTED | 疑似前视 | 按行号修复,不要绕过 |
74
+ | STRATEGY_INVALID | 语法/API 误用 | 按 issues 修复 |
75
+ | WEIGHT_CAP | 触发仓位上限 | 正常风控行为;若目标仓位>上限属策略设计问题 |
@@ -0,0 +1,46 @@
1
+ # SKILL: 数据更新流程
2
+
3
+ 目标:让 Agent 正确地把行情数据落到本地并保证可复现。
4
+
5
+ ## 决策树
6
+
7
+ 1. `get_data_overview` 看现有数据;
8
+ 2. 需要新数据 → `fetch_bars`;
9
+ 3. 做实验前 → 创建数据快照(`srq data snapshot create <tag>`,或提醒用户执行)。
10
+
11
+ ## fetch_bars 用法
12
+
13
+ ```
14
+ fetch_bars(symbols=["000001.SZ", "510300.SH"], start="2023-01-01", end="2026-09-08")
15
+ ```
16
+
17
+ - **增量幂等**:重复调用只补缺口,不产生重复行;
18
+ - **start 建议显式给**:不传时走增量续拉(本地无数据则从 1990 年全量拉,慢);
19
+ - **回测 prep**:回测起点往前留 ≥250 个交易日(warmup),即 start ≈ 回测起点 - 15 个月;
20
+ - 返回摘要含每个符号在本地库中的总行数与覆盖区间;
21
+ - 复权因子自动获取(东财主通道失败自动切新浪)。
22
+
23
+ ## 交易日历
24
+
25
+ ```
26
+ get_trading_calendar(update=true) # 首次使用/年末更新
27
+ ```
28
+ 回测引擎依赖日历切分交易日;日历缺失时报 NO_DATA 并提示更新。
29
+
30
+ ## 数据快照(可复现的关键)
31
+
32
+ 数据每天都会变(新 bar、复权因子修正)。严肃实验前创建快照:
33
+
34
+ ```
35
+ srq data snapshot create snap-20260908 # CLI 命令,近零拷贝
36
+ ```
37
+
38
+ - 快照只读;回测结果会记录所用快照名,复现实验 = 指定同一快照;
39
+ - 不要往快照里写数据(会被拒绝)。
40
+
41
+ ## 数据口径备忘
42
+
43
+ - 价格:**原始价 + 复权因子**(不做前复权落库),hfq = close × adj_factor;
44
+ - volume 单位:手(股票与期货均如此);amount 单位:元;
45
+ - pre_close 为除权后口径(与交易所一致);
46
+ - 指数/期货 adj_factor 恒为 1;新浪回退通道的 ETF 因子为 NaN。
@@ -0,0 +1,46 @@
1
+ # SKILL: 实验对比与策略迭代
2
+
3
+ 目标:让 Agent 用实验追踪做有依据的策略改进,而不是凭印象改参数。
4
+
5
+ ## 核心循环
6
+
7
+ ```
8
+ list_experiments(limit=20)
9
+ → 挑出同策略不同参数(或不同策略同区间)的 run_id
10
+ → compare_experiments(run_ids=[...])
11
+ → 读差异 → 形成假设 → 只改一个变量 → run_backtest → 回到开头
12
+ ```
13
+
14
+ ## 怎么读对比表
15
+
16
+ 指标列含义与陷阱:
17
+
18
+ | 指标 | 含义 | 陷阱 |
19
+ |------|------|------|
20
+ | annual_return | 年化收益(几何) | 短区间年化会被放大 |
21
+ | sharpe | 年化收益/年化波动 | 收益平稳的策略才可信;<0.5 基本不可用 |
22
+ | max_drawdown | 最大回撤 | 必须结合年化看(卡玛 = 年化/\|回撤\|) |
23
+ | trade_win_rate | 平仓交易胜率 | 趋势策略 30-40% 是常态,别拿它否决策略 |
24
+ | profit_factor | 总盈利/总亏损 | >1.3 才有继续优化的价值 |
25
+ | annual_turnover | 年化换手 | 高换手 + 低超额 = 费用吃掉收益 |
26
+ | excess_annual_return | 相对基准年化 | 评估策略的最终标准 |
27
+
28
+ ## 实验纪律
29
+
30
+ 1. **单变量原则**:两次实验只差一个参数/一处逻辑,否则对比无意义;
31
+ 2. **实验命名带信息**:`双均线-fast10` 优于 `test2`;
32
+ 3. **控制数据版本**:对比的实验应基于同一数据快照(get_experiment 看 data_snapshot);
33
+ 4. **防过拟合**:
34
+ - 同一组参数换 2-3 个不重叠区间验证;
35
+ - 换 1-2 个同类标的验证;
36
+ - 参数敏感性:最优参数附近的邻居参数表现不应断崖式变差;
37
+ 5. **费用意识**:A股双边成本约 0.15%(佣金+印花税+过户+滑点),策略年换手 1000% 意味着每年先亏 1.5%。
38
+
39
+ ## 产物引用
40
+
41
+ 每次实验的完整数据在 `get_experiment(run_id).artifacts_dir` 下:
42
+ - `result.json`:完整指标、逐日净值、全部成交与拒单(机器读);
43
+ - `report.md`:人读报告;
44
+ - `trades.csv` / `nav.csv`:明细。
45
+
46
+ 需要逐笔分析时直接读这些文件,不要试图让工具返回大表。