当前位置: 首页 > news >正文

程序员量化交易实战 09:从 K 线到第一个可解释因子信号

第 8 篇把原始 K 线清洗成了统一的CleanMarketBar。现在可以写因子了。

这里先不追求复杂。第一组因子只做四件事:日收益、短均线、长均线、动量和波动率。它们足够简单,也足够暴露量化工程的几个关键问题:窗口、缺失值、信号解释和测试边界。

因子不是神秘公式

因子可以先理解成“把原始数据变成策略能消费的特征”。

比如:

  • 收盘价连续上涨,动量可能为正。
  • 短均线高于长均线,趋势可能偏强。
  • 波动率太高,即使上涨也可能需要谨慎。

这些判断都不是保证收益的规则。它们只是把行情数据变成更容易比较的工程对象。

几个常见名词先放在这里,后面文章会反复用到:

名词在本文里的含义
K 线每个交易日的开盘、最高、最低、收盘、成交量等行情记录
因子从行情、财务或其他数据里加工出来的特征,例如动量、波动率、估值
信号因子经过规则解释后的动作提示,例如观察、买入观察、风险观察
窗口计算指标时回看多少个交易日,例如 5 日均线、20 日动量
年化把日频指标按一年约 252 个交易日换算,方便不同周期比较

常见因子大致可以分成几类:动量因子看“过去一段时间是不是在涨”,反转因子看“短期是否过度下跌或上涨”,波动率因子看“价格摆动是否过大”,成交量或换手因子看“市场参与是否活跃”,估值和质量因子则更多依赖财务数据。第 9 篇先做动量、均线和波动率,是因为它们只依赖日线行情,最容易和第 8 篇的数据清洗结果接上。

先定义因子点

第 9 章新增app/factors.py,核心对象是FactorPoint

@dataclass(frozen=True) class FactorPoint: symbol: str trade_date: date close: float return_1d: float | None ma_short: float | None ma_long: float | None momentum: float | None volatility: float | None signal: str

这里故意允许None。窗口不够时,均线、动量、波动率都不应该硬算。很多回测 bug 就来自“前几天数据不够,代码却填了 0”。

均线要显式处理窗口

短均线和长均线用同一个函数:

def simple_moving_average(values: list[float], window: int) -> list[float | None]: if window <= 0: raise ValueError("window must be positive") out: list[float | None] = [] running = 0.0 for index, value in enumerate(values): running += value if index >= window: running -= values[index - window] out.append(round(running / window, 6) if index + 1 >= window else None) return out

这段代码没有 pandas,便于读者直接理解窗口计算过程。真实生产里可以换成更高效的向量化实现,但语义要保持一致。

收益率和波动率

日收益率从第二天开始才有:

def daily_returns(values: list[float]) -> list[float | None]: out: list[float | None] = [None] for previous, current in zip(values, values[1:], strict=False): out.append(round(current / previous - 1, 6) if previous else None) return out

波动率用滚动窗口,最后乘以 252 做年化:

variance = sum((value - mean) ** 2 for value in sample) / (len(sample) - 1) out.append(round(math.sqrt(variance * 252), 6))

这里不是为了预测未来,只是给后续策略一个风险感知输入。

从因子到信号

build_factor_points()会把每一天标成三类信号:

if ma_short[index] > ma_long[index] and momentum > 0 and vol[index] < 0.45: signal = "buy_watch" elif momentum < -0.08 or vol[index] >= 0.65: signal = "risk_watch" else: signal = "observe"

这不是交易圣杯。它只是一个明确、可解释、可测试的第一版信号。

我更关心的是工程性质:信号为什么出现,能不能复现,边界条件能不能测。如果这三个问题回答不了,策略复杂度越高越危险。

和前后章节联动运行

现在主线仓库里补了一个可运行示例,用同一批样例日线把第 9-12 篇串起来:

git clone https://github.com/ax2/zi-quant-platform.git cd zi-quant-platform uv sync --extra dev uv run python -m scripts.chapter_examples factor-backtest --source sample

这条命令会先输出第 9 篇的因子结果,再继续跑第 10 篇最小回测、第 11 篇组合回测和第 12 篇指标。下面是第 9 篇对应的真实运行截图:

截图里000001.SZ最近 5 个交易日都给出buy_watch。原因可以直接从字段读出来:短均线高于长均线,20 日动量为正,年化波动率低于当前阈值。这就是“可解释信号”的最低要求:不只是输出一个动作,还能说明它为什么出现。

测试信号比测试收益更重要

第 9 章的测试里有两个关键场景。

稳定上行应该给出buy_watch

closes = [10 + index * 0.1 for index in range(40)] points = build_factor_points(_bars(closes), short_window=5, long_window=20, volatility_window=5) assert points[-1].signal == "buy_watch"

持续下行应该给出risk_watch

closes = [20 - index * 0.2 for index in range(40)] points = build_factor_points(_bars(closes), short_window=5, long_window=20, volatility_window=5) assert points[-1].signal == "risk_watch"

这类测试不证明策略能赚钱,但能证明代码没有把趋势方向、窗口边界和风险阈值写反。

本篇实战任务

拉取第 9 章代码:

git clone https://github.com/ax2/zi-quant-platform.git cd zi-quant-platform git checkout chapter-09 uv sync --extra dev uv run pytest

只跑因子测试:

uv run pytest tests/test_factors.py

第 9 章全量测试通过:164 passed,仍只有既有 FastAPI deprecation warning。

本章更新与代码仓库

本章更新内容:

  • 新增app/factors.py
  • 实现日收益、短均线、长均线、动量、年化波动率和三类信号。
  • 新增tests/test_factors.py,覆盖窗口边界、上涨信号和风险信号。
  • 在当前主线补充scripts.chapter_examples factor-backtest联动示例,可真实运行第 9-12 篇代码链路。
  • 补充因子、信号、窗口、年化等常见名词解释。

代码仓库:

https://github.com/ax2/zi-quant-platform

本章代码:

git clone https://github.com/ax2/zi-quant-platform.git cd zi-quant-platform git checkout chapter-09 uv sync --extra dev uv run pytest tests/test_factors.py

本篇小结

因子不是为了把数学公式堆上去,而是把行情数据转成可解释、可测试、可复现的中间层。

第 9 篇完成了第一版因子信号。下一篇我们把信号接进最小回测循环,看它如何变成买入、卖出、现金、持仓和权益曲线。

http://www.jsqmd.com/news/1061109/

相关文章:

  • 2026 青岛装修公司口碑盘点:靠谱家装品牌实力参考 - 装修新知
  • TerraScope:首个像素级地理空间理解的视觉语言模型
  • 合肥腾飞学校 2026 招生简章|热门专业、学费、招生计划一次整理 - 辛云教育资讯
  • 2026年10款靠谱论文降AIGC工具亲测:规范定稿实战对比实用指南
  • Moonlight TV终极指南:在LG webOS电视上实现完美NVIDIA GameStream游戏串流体验
  • 代码异味与安全漏洞的混合智能检测与修复
  • 南京视频号代运营服务机构实力排行盘点 - 起跑123
  • 2026年众智商学院SCMP四模块五模块六模块费用怎么核对?前期缴费和考试节点说明 - 众智商学院官方
  • 江苏连云港叛逆学校具体地址在哪?2026 最新收费标准一览 - 小途xt
  • 2026年苏州手表回收门店排行榜top5 实时名表大盘高折扣变现门店推荐 - 名奢变现站
  • 2026广州黄金回收避雷指南:看完再出手,少亏上千块 - 奢侈品回收评测
  • 2026年贵阳防雷检测服务商深度评测:甲级资质机构如何守护建筑安全 - 企业名录优选推荐
  • 海口黄金回收别踩坑,避开偷秤乱扣费,正规靠谱门店整理 - 奢侈品回收评测
  • NXP KL2x系列MCU超低功耗与USB集成设计实战指南
  • 【无人机巡检】无人机桥梁检查覆盖路径规划Matlab仿真
  • 致远OA V8.1 SP2安全加固实战:从Nmap扫描到分层防护
  • 2026济南历下回收店翡翠回收|七家持证机构排位与避坑实测 - 沉迷学习28
  • 2026重庆钻石回收TOP7实测榜单|本地靠谱钻饰变现商家测评 - 名奢变现站
  • 怪物猎人世界终极辅助工具:HunterPie完整使用手册
  • 终极指南:5分钟免费解锁英雄联盟国服全皮肤体验
  • DeepSeek-R1在llama.cpp中的GPU加速真相与生产级调优
  • 2026日照海边性价比高的酒店精选:出行住宿实用指南 - 谁都没有我好看
  • 网盘直链下载助手终极指南:5分钟告别限速困扰,解锁高速下载新姿势
  • Terraform import 实战:将现有 DigitalOcean 资源纳入 IaC 管理
  • NSK LA25EL 超高刚度直线导轨技术详解
  • 2026年上海英国本科申请材料辅导哪家专业:五家优选深度解析 - 科技焦点
  • 科普大牌珠宝变现要点,经典款与冷门系列二手回收保值差异详解 - 奢品小当家
  • Seedance 2.0不是独立产品,而是即梦平台的AI视频引擎
  • 视频投票怎么做?2026支持批量导入选手的免费小程序测评 - 微信投票小程序
  • LangChain / LangGraph、MCP、Harness Engineer 与 Claude Code 的对应关系 - 若