Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NL2QuantStrategy

Natural Language → Executable Quant Strategy Code

NL2QuantStrategy 是一个基于结构化 DSL 的量化策略翻译流水线,用于将自然语言量化策略描述转换为可执行的 Python / pandas 信号代码。

把中文选股问句(比如“收盘价的5日均线大于阈值0.01时买入”)翻译成可以直接运行的 pandas 信号代码。翻译过程不是直接让 LLM 生成代码,而是先抽成一份结构化 DSL 契约,再确定性渲染——以此换取可复现、低幻觉、可审计

这类问句的句式风格,参考了同花顺问财这类中文自然语言选股平台的问题域。仓库内不含、也未改写任何第三方平台的真实问句、作者或翻译对偶——所有问句与数值都是独立创作的合成数据(data_origin=synthetic),不是真实策略,也不是市场事实。

Overview

输入:中文策略问句(自然语言)
        ↓
输出:def signal(df: pd.DataFrame) -> pd.Series 形式的 pandas 信号代码

120 条合成问句走完“切分子句 → 抽成 DSL 契约 → 渲染成 Python”的同一条流水线,每一条的结果都是确定、可复现的。整个项目由四个小模块组成:parser(问句→契约)、codegen(契约→代码)、schema(契约校验)、future_leak(前视检测)。

Motivation

为什么不用直接让 LLM 翻译? 这是本项目的核心问题。

LLM 直接生成策略代码的痛点是不可控:

Natural Language
      |
      v
   Python Code      ← 每次调用都可能不同,可能编造不存在的函数
      |
      v
   unpredictable

本仓库的做法是在中间插入一层结构化表示:

Natural Language
      |
      v
   Structured DSL   ← 可校验、可审计的中间契约
      |
      v
   Validated Code Generation
      |
      v
   Executable Signal
维度 结构化翻译(本仓库) 直接让 LLM 翻译
可复现性 同一问句永远产出同一份代码,规则固定、逐字节可复现 同一问句多次调用,可能每次代码都不一样
幻觉 低:不认识的函数或运算符直接报 NotImplementedError,绝不瞎编 可能编造不存在的函数、字段名或逻辑
行为一致 代码永远操作同一套数据形态(close/open/high/low/vol/amount…),换数据源不用改翻译逻辑 输出风格飘忽,下游处理困难
可审计 每一步都有中间产物(子句、AST、DSL 契约)可以检查 只有黑盒输出,难以追溯

结构化翻译牺牲了一点灵活度,换来的是可靠:遇到没见过的写法宁可跳过(fail-closed),也不输出一个猜出来的结果。

Architecture

flowchart TD
    Q["中文策略问句"] --> S["parser.split_clauses<br/>按 且/并且/同时/以及 切分子句"]
    S --> P["parser.parse_clause<br/>识别价格字段 / DSL 函数 / 比较运算符 / 窗口 / 阈值"]
    P --> C["expected_ast + expected_filters<br/>DSL 契约(schema.SyntheticTranslationRecord)"]
    C --> R["codegen.render_python<br/>def signal(df) -> pd.Series 源码"]
    C --> F["future_leak.detect_future_leak_query<br/>fail-closed 黑名单命中列表"]
    R --> OUT["可执行 pandas 信号"]
    F --> OUT2["检测报告"]
Loading

四个模块各自独立、可单独替换:

  • parser.py:教学骨架解析器,只演示“切分子句 → 识别函数 → 比较运算符 → 窗口/阈值”最小链路;
  • codegen.py:遇到未知函数与未知比较运算符一律 NotImplementedError,宁可失败不猜;
  • future_leak.py:20 条正则黑名单,对问句或子句做保守扫描,可独立使用;
  • schema.py:不满足 data_origin=synthetic 等不变量直接抛 ValueError

Features

  • 结构化 DSL 中间表示:问句先解析成 expected_ast + expected_filters 契约,再做代码渲染;
  • fail-closed 渲染:未知函数、未知运算符一律拒绝(NotImplementedError),不输出猜出来的结果;
  • 前视检测:20 条正则黑名单识别未来函数/未来财务/同日成交等违规模式,故意构造的违规样本只作检测器正例;
  • 数据契约校验:每条记录强制 data_origin=synthetic、字段一致性校验;
  • 确定性可复现:合成数据由固定种子 20260816 生成,逐字节可复现。

Quick Example

拿一条合成问句走完全流程:

问句:若示例股票A的收盘价的5日均线大于阈值0.01,则下一交易日开盘买入并持有5日。

第 1 步:切分子句

from strategy_translation.parser import split_clauses

split_clauses("若示例股票A的收盘价的5日均线大于阈值0.01,则下一交易日开盘买入并持有5日。")
# ['若示例股票A的收盘价的5日均线大于阈值0.01,则下一交易日开盘买入并持有5日。']

整句是一个子句(“则”不是切分符,只有“且/并且/同时/以及”会切分;执行短语由数据契约里的 EXECUTION_PHRASES 处理,不进入解析器)。

第 2 步:解析成 DSL 契约

from strategy_translation.parser import parse_clause

parse_clause("若示例股票A的收盘价的5日均线大于阈值0.01,则下一交易日开盘买入并持有5日。")
# AtomicClause(function='ma', args=(5,), price_field='close', comparison_operator='gt', threshold=0.01)

问句被抽成:5 日均线(ma)作用于收盘价(close),比较符是大于(gt),阈值 0.01。

第 3 步:渲染成 pandas 代码

PYTHONPATH=src python3 -m strategy_translation.codegen \
  --query "若示例股票A的收盘价的5日均线大于阈值0.01,则下一交易日开盘买入并持有5日。"

输出:

# 问句:若示例股票A的收盘价的5日均线大于阈值0.01,则下一交易日开盘买入并持有5日。
import pandas as pd
from typing import Any


def signal(df: pd.DataFrame) -> pd.Series:
    mask = df["close"].rolling(5).mean() > 0.01
    return mask

第 4 步(可选):前视检测

如果问句里混进了未来信息,检测器会命中黑名单:

from strategy_translation.future_leak import detect_future_leak_query

detect_future_leak_query("若示例股票A的收盘价大于阈值0.01且依据未来财务数据,则下一交易日开盘买入。")
# ['future_financial']

这类故意构造的违规样本只用于展示检测器,标记为不可准入,不会进入任何可复现的收益结论。

Installation

需要 Python 3.11+。运行时依赖为空(dependencies=[]),测试依赖只有 pytest>=8([test] 可选组)。

pip install -e .
# 之后可直接用 strategy-translation-generate / strategy-translation-codegen 两个命令

Usage

所有命令也可以用 PYTHONPATH=src 前缀运行(未 pip install -e . 时的形态):

# 1. 生成 120 条合成数据(固定种子 20260816,逐字节可复现)
PYTHONPATH=src python3 -m strategy_translation.generate --output-dir data

# 2. 单条翻译:问句 → pandas 信号代码
PYTHONPATH=src python3 -m strategy_translation.codegen \
  --query "收盘价的5日均线大于等于阈值0.01"

# 3. 批量翻译:每条可渲染的记录写一个 .py 文件
#    (需要先执行第 1 步生成 data/synthetic_translation_queries.jsonl)
PYTHONPATH=src python3 -m strategy_translation.codegen \
  --input data/synthetic_translation_queries.jsonl --output-dir examples

# 4. 跑全量测试
PYTHONPATH=src python3 -m pytest -q

Dataset

data/ 下的逐行数据默认不随仓库分发,由 generate 命令用固定种子 20260816 确定性生成,逐字节可复现:

文件 内容
synthetic_translation_queries.jsonl 120 行:合成中文问句、粗粒度 expected_astexpected_filterslookahead_label
synthetic_translation_coverage.csv 同一份数据的扁平 CSV,嵌套结构紧凑 JSON 序列化,120 行 + 表头

每条记录的元数据契约见 schema.SyntheticTranslationRecord,硬约束:

  • data_origin=syntheticrights_status=self_createdrelease_status=local_preview
  • strategy_family ∈ 11 类家族;
  • lookahead_label ∈ {none, future_financial, ambiguous_price_basis, same_day_fill};
  • functionexpected_ast.function 必须一致;expected_ast 必须含 argsprice

合成样本里故意保留 future_financial / ambiguous_price_basis / same_day_fill 三类违规样本,用作 future_leak 黑名单的正例——它们不能进入任何可复现的收益结论。

Design Philosophy

  • fail-closed:遇到没见过的写法宁可跳过,也不输出一个猜出来的结果。批量模式下 120 条中约 64 条可渲染,剩下 56 条因为 function=wma/or/and/not/rank/percentile/...operator=extreme 触发跳过——跳过不是 bug,是 fail-closed 边界本身
  • 可复现优先:固定种子、确定性渲染、逐字节可复现;
  • 可审计:每一步都有中间产物(子句、AST、DSL 契约)可以检查;
  • 研究纪律:T 日可知信息 → T+1 成交;故意构造的违规样本只作检测器负例,标记为不可准入。

Current Scope

当前支持:

  • 移动平均类:ma / ema / wmawma 未实现渲染,触发 fail-closed);
  • 价格与量字段:close / open / high / low / vol / amount / change / pct_chg
  • 参考与窗口函数:ref / sum / std / llv / hhv / count / cross 等;
  • 比较运算符:gt / gte / lt / lte / eq

解析器是有意保持的教学骨架:不处理否定、嵌套、指代消解。更细的字段说明、模块设计动机与 fail-closed 边界见 docs/methodology.md

Roadmap

以下为规划方向(尚未实现):

  • 扩展 DSL 函数库与运算符覆盖,缩小 fail-closed 跳过面;
  • 接入 LLM 作为“问句 → 契约”阶段的辅助解析,保留契约校验与渲染的确定性;
  • 增加回测与评估模块,形成“翻译 → 验证”闭环;
  • 支持更多语言与句式(否定、嵌套、指代消解)。

License

本仓库的代码与合成数据采用 MIT 许可证,全文见 LICENSE。 This repository is intended for research and educational purposes only and does not constitute investment advice. 仅作为学习参考,不构成任何投资建议。 版权行:Copyright (c) 2026 NL2QuantStrategy contributors

About

基于结构化 DSL 流程,将自然语言量化策略自动转换为可执行 Python 交易信号。Translate natural language quantitative strategies into executable Python trading signals with a structured DSL pipeline.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages