社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  机器学习算法

【东吴金工于明明团队】深度学习系列之四:从人工写因子到AI写因子:LLM-MCTS驱动的可解释因子迭代框架

东吴金工与产品研究 • 1 月前 • 140 次点击  



本报告围绕“人工写因子”向“AI挖因子”的范式升级,构建LLM-MCTS可解释因子迭代框架。MCTS负责在公式或代码搜索树中进行选择、扩展、评测和回传,LLM负责生成金融假说、给出可执行表达式或Python函数、解释机制并审查数据合法性。相比一次性让模型写公式,该框架把候选生成、周度RankIC/IR评测、样本内选择、样本外检验和经验库沉淀组织成闭环,可覆盖日频Seed改造、低频Seed池批量挖掘和高频分钟行为挖掘。


在日频Seed定向改造中,我们以29个低频价量原始因子为起点,对每个Seed保留迭代过程、候选池和样本内外表现。结果显示,候选池层面25/29个Seed至少搜索到过样本外优于原始Seed的候选,说明LLM-MCTS并非只是在原因子附近做机械组合,而是能够围绕波动、反转、成交确认、区间状态等逻辑提出增量结构。样本内正式候选以优于原始Seed为准,样本外仅用于验证,从而避免用样本外倒推选因子。


在低频Seed池批量挖掘中,我们进一步放松“必须贴近单个Seed ”的约束,以12个根节点机制作为起点进行批量搜索。样本内生成的173个因子优于对应原始Seed,143个同时实现样本内和样本外优于原始Seed,占样本内有效候选的82.7%。双优候选去重后包含123个公式,并沉淀58个可复用经验或工具。稳定性和差异性方面,双优候选之间的全局绝对相关性整体偏低,均值0.2604、中位数0.2148、90%分位数0.5529,绝对相关性大于0.8的比例仅1.88%、大于0.9的比例仅0.71%,说明搜索结果没有坍缩为少数同质信号。


该框架亦可以用在高频分钟因子挖掘,给定原始的经验因子作为Seed,经验函数作为LLM生成新因子的思路参考,利用LLM-MCTS搜索框架,可以得到更高质量的高频因子。其中“高量脉冲次数”因子表现最突出,样本内/样本外RankIC为0.0839/0.0744,样本内/样本外ICIR为1.140/0.770,RankIC保留率0.89;成交量高脉冲收益波动、成交额加权实现波动、尾盘相对开盘振幅等代表因子样本外RankIC亦达到0.0627至0.0647,验证框架可从日频公式扩展到分钟级交易行为机制


风险提示:

  1. 模型失效风险。本研究基于历史数据和统计规律构建因子,历史表现不代表未来收益。当市场结构、投资者行为、流动性环境或监管政策发生变化时,量价因子可能衰减甚至失效,导致组合表现不及预期。
  2. 过拟合风险。本文采用自动化方法进行因子挖掘,未来市场变化可能导致因子泛化能力下降。
  3. 数据质量风险。因子研究依赖行情、成交量、估值及收益标签等数据。数据缺失、异常、复权处理差异以及不同评测口径、股票池和样本区间设置,均可能影响研究结论。
  4. 大语言模型生成风险。大语言模型生成的因子逻辑、代码及工具函数可能存在理解偏差或实现错误。实际应用前,仍需对代码实现、数据处理及评测流程进行独立验证。
  5. 交易成本与流动性风险。 回测结果未必能够完全反映实盘环境。冲击成本、滑点、税费、涨跌停及成交不足等因素可能侵蚀策略收益,实际表现可能低于历史测算结果。





01

大语言模型时代的因子研究范式变革

1.1 传统因子研究面临效率与结果的双重瓶颈

因子挖掘是量化投资研究的核心环节,其本质是在海量市场信息中寻找能够预测未来收益或风险的有效信号。长期以来,因子研究主要依赖人工构建、机器学习建模以及自动化公式搜索等技术路径。尽管这些方法在不同阶段推动了量化研究的发展,但随着市场有效性的不断提升和数据维度的快速扩张,传统因子研究范式逐渐暴露出效率与结果两方面的瓶颈。


首先,人工因子构建仍然是当前主流机构最广泛采用的研究方式。研究员通常基于金融理论、市场经验或经济学逻辑提出研究假设,再通过数据验证形成具体因子表达式。例如,价值因子、动量因子、分析师预期因子等经典因子均源于此类研究范式。该方法具有较强的经济学解释能力,研究结果容易被投资经理理解和应用。然而,其核心问题在于高度依赖研究员的专业经验和领域知识,研究过程通常遵循“提出假设—构建因子—回测验证—迭代优化”的人工循环模式。面对数千个基础字段、上百种算子以及不断扩展的数据来源,人工探索能够覆盖的搜索空间极其有限,导致研究效率较低,并容易受到研究员认知边界和路径依赖的影响。


其次,以深度学习为代表的数据驱动方法试图通过神经网络自动学习市场规律。相比传统因子模型,神经网络能够处理高维、非线性特征,并自动挖掘复杂的变量交互关系,在预测能力上具有明显优势。然而,深度模型通常以隐藏层参数的形式存储信息,其预测逻辑难以映射为明确的金融含义。所以虽然神经网络能够生成具有较强预测能力的信号,但其“黑箱”特征限制了其在实际投研场景中的广泛应用。


第三类方法是以遗传规划(Genetic Programming)、强化学习(Reinforcement Learning)等为代表的自动公式搜索技术。这类方法通过预设算子库和搜索空间,利用进化算法或策略优化机制自动生成候选因子表达式,并依据回测结果不断迭代优化。从理论上看,该方法能够突破人工研究的搜索边界,实现更大规模的因子探索。然而,在实际应用中,搜索效率和表达式质量始终是其核心挑战。一方面,金融因子空间呈指数级增长,搜索过程往往需要消耗大量计算资源;另一方面,算法容易生成结构复杂、嵌套层数过深的表达式,虽然样本内表现优异,但往往存在过拟合风险,且难以进行经济学解释和实际应用。


1.2 LLM写因子的能力与瓶颈

近年来,大语言模型(Large Language Model,LLM)的快速发展为因子研究带来了新的可能。在前期报告《深度学习系列之一:AI重塑量化,基于大语言模型驱动的因子改进与情绪Alpha挖掘》中,我们已经验证,大语言模型具备较强的金融逻辑推理能力,能够围绕已有因子进行逻辑改写、结构增强和新因子构造,并在部分场景下获得较好的实证效果。这说明,LLM并不只是代码补全工具,它已经能够阅读因子表达式,理解背后的金融含义,并从价格行为、成交量变化、情绪冲击和交易拥挤等角度提出新的构造思路。


相比传统自动搜索方法,LLM能够利用其预训练知识直接生成具备金融逻辑的因子假设和表达式,从而显著降低因子构建成本。同时,由于生成过程以自然语言推理为基础,因子通常具备较好的可解释性。然而,当前直接利用LLM生成因子的研究仍然存在明显局限。一方面,模型生成过程缺乏系统性的搜索机制,容易停留在已有知识和常见模式附近;另一方面,缺少基于实验结果的持续反馈与迭代优化流程,难以形成“假设生成—验证评估—修正优化”的闭环研究体系。因此,虽然LLM提高了因子生成效率,但尚未从根本上解决因子发现过程中的系统性探索问题。


总体来看,当前主流因子研究方法均存在不同程度的局限:人工研究具备较强解释性但效率不足;深度学习预测能力较强但缺乏透明性;遗传规划和强化学习能够扩大搜索范围但成本较高且结果复杂;大语言模型提升了研究效率但缺少严谨的反馈闭环。如何同时兼顾研究效率、因子质量、经济学解释性以及持续迭代能力,已成为当前量化因子研究领域亟待解决的重要问题。


1.3 兼顾可解释性和持续迭代能力的LLM-MCTS模型

为了解决之前提到的问题,Zhao, Lee, Hsu 2023年在《Large Language Models as Commonsense Knowledge for Large-Scale Task Planning》中较早提出了LLM既作为世界状态变化的常识性判断(commonsense world model),也作为启发式策略(heuristic policy),引导MCTS做任务规划,得出LLM不只可以当作直接生成动作的policy,也可以作为一种常识世界模型嵌入搜索算法中;LLM+MCTS通常比单独MCTS或单独LLM policy 更强的结论。Shi, Duan ,Li 2025年《Navigating the Alpha Jungle: An LLM-Powered MCTS Framework for Formulaic Factor Mining》提出了一种LLM-Powered MCTS的公式化Alpha因子挖掘框架,将因子生成问题建模为一棵公式搜索树:每个节点代表一个候选Alpha公式,MCTS负责在搜索树中选择具有潜力的节点继续扩展,LLM则根据已有公式、历史改造路径和多维回测反馈生成新的逻辑假说与公式表达。该方法的重要特点是并不直接让LLM一次性生成因子,而是先由LLM提出面向特定评价维度的改造建议(refinement suggestion)或Alpha画像(alpha portrait),再将其转化为可计算的公式,从而在搜索效率、经济解释和公式质量之间取得平衡。


不过,原文方法仍存在若干可进一步改进之处。首先,原文更侧重于从较大的公式空间中自动挖掘一组Alpha因子,并通过组合模型或下游预测模型验证整体效果,但对于“给定一个已有因子,如何在保留其经济逻辑的基础上生成一个更优替代公式”这一类实际因子研究问题,讨论相对不足。其次,原文的多维评价主要服务于Alpha Zoo的整体扩展,候选因子与初始因子的关系、逻辑继承、度量替换和适用场景并未被系统化记录,导致其在复现到具体因子改造任务时,仍需要额外的人工作业来判断新公式是否真正延续或改进了原始因子的经济含义。再次,原文虽然强调样本外验证和搜索效率,但在实际因子迭代中,如何区分“严格样本内选型结果”和“候选池中样本外表现更优的潜在结果”,以及如何围绕单个原因子进行IS/OOS稳定性诊断,仍有进一步细化空间。


基于上述问题,本文在原文LLM-MCTS思路的基础上,面向已有低频价量因子的定向改造场景进行了本地化扩展。本文不再从空白公式空间中泛化挖掘Alpha集合,而是以已有的29个低频价量因子作为根节点,逐个构建MCTS搜索树;在每次扩展时,要求LLM显式输出候选公式的逻辑假说、公式实现逻辑、预期方向、与原因子的关系、适用市场状态、潜在风险和组件解释,从而将“因子生成”转化为“可解释的因子逻辑改造”。在评价层面,本文以样本内和样本外周度RankIC、RankIR为核心指标,并同时保留严格样本内选型结果与候选池最优诊断结果,使得方法既能遵守样本外不反选的严谨原则,也能识别候选池中具有进一步研究价值的潜在优质公式。由此,本文尝试将原文偏通用的Alpha挖掘框架,推进为一个更适合低频价量因子复现、改造、诊断和迭代研究的工程化方法。


02

LLM驱动的MCTS:符合逻辑的因子迭代


2.1 MCTS模型可以提高搜索效率

MCTS的英文全称是Monte Carlo Tree Search,中文通常译为“蒙特卡洛树搜索”。它是一类序贯决策搜索方法:把一个复杂问题表示成一棵树,树上的节点代表当前状态,边代表可执行动作;算法在有限预算下不断重复“选择、扩展、评估、回传”,逐步把计算资源集中到更有希望的分支,同时保留对未充分探索分支的试探。


从方法论上看,MCTS适合处理“搜索空间很大、每一步选择会影响后续空间、单次评估代价较高、又不能完全依赖贪心”的问题。它最早广泛应用于棋类和博弈决策,例如围棋中每一步落子都会形成新的局面树;在本项目中,MCTS被移植到公式因子挖掘里,每个节点代表一条已经生成并评测过的因子公式。


公式化因子挖掘的难点在于组合空间呈爆炸式增长。以低频价量因子为例,一个因子可以由open、high、low、close、volume、amount等字段构造;可以选择Mean、Std、Corr、If、Sign等算子;还可以调整窗口、嵌套层数、方向、条件过滤和交互方式。即使只开放几十个算子和少量窗口,候选公式数量也会远超可穷举范围。

另一个难点是不能只选择当前分数最高的候选继续扩展。某个候选在第一轮表现最好,并不代表围绕它继续加深一定最优;相反,一个当前分数略低但结构更有延展性的分支,可能在后续生成更强的子公式。MCTS方法通过UCT机制在“利用已知高分分支”和“探索访问较少分支”之间平衡,避免搜索过早收敛到局部最优。


本项目还面临评测成本约束。每个候选公式都要在股票池上计算因子值、对齐未来收益、按周度计算截面RankIC和RankIR,并额外评估覆盖率、换手、与已有候选的相关性、公式复杂度等指标。因此MCTS的作用不是替代回测,而是决定有限的回测预算应该优先投向哪条搜索路径。


可见MCTS主要解决三个问题:第一,把公式生成过程组织成可追踪的搜索树;第二,用reward和UCT决定下一轮扩展哪个节点;第三,把每轮候选的真实评测结果回传到树上,使后续搜索既参考历史最优表现,也保留必要的探索空间。


2.2 MCTS模型具体流程

MCTS的方法论可以概括为“用树记录已探索路径,用评分决定下一步扩展方向”。在本文的因子挖掘任务中,根节点是输入的原始因子,子节点是由LLM或模板生成并完成评测的候选公式,父子关系表示候选公式从哪一个已有公式改写而来。这样,公式生成不再是一次性枚举,而是被组织成一棵可以复盘、可以回传反馈的搜索树。


一次MCTS迭代包含“选择、扩展、评测、回传”四个动作:选择阶段根据当前搜索树确定要扩展的节点;扩展阶段围绕该节点生成若干候选公式;评测阶段用真实行情数据计算候选因子的IC、IR、覆盖率、换手和相关性;回传阶段把候选得分沿父链写回搜索树,更新各节点的访问次数和历史最优奖励。



在上述闭环中,候选公式先由评测函数转化为reward,再由搜索树结构转化为UCT。二者承担不同职责:reward衡量“某个公式本身好不好”,UCT衡量“下一轮是否还应该继续沿这个节点探索”。


本文MCTS搜索使用mcts_reward_score作为回传奖励。它不是单一IC排序,而是把预测强度、稳定性、覆盖率、换手友好度、候选多样性和过拟合惩罚合成为一个搜索阶段分数:




完成reward回传后,MCTS在选择阶段使用UCT对子节点排序。UCT由“利用项”和“探索项”两部分组成:利用项是该分支历史上找到过的最好reward,探索项则由父节点访问次数和当前节点访问次数共同决定。




除了在已有子节点之间向下选择,代码还加入virtual expansion判断,用来决定是继续沿最优子节点挖深,还是停留在当前节点横向扩宽。这里的关键不是给某个候选因子重新打分,而是在搜索树上比较两种动作:第一,沿当前节点下已经存在的最优child继续往深处走;第二,暂时不进入child,而是在当前节点上再生成一批新的兄弟候选。



virtual_score可以理解为“当前节点继续横向扩宽的机会价值”。其中best_reward代表当前节点所在分支已经证明过的最好结果,说明这个节点附近确实有价值;后面的virtual_expansion_weight/(1+expansions)是额外给当前节点的一点探索补贴。节点扩展次数越多,expansions越大,这个补贴越小,表示系统已经给过该节点足够多横向尝试机会,后续更倾向于沿已有高UCT子节点向下挖深或切换分支。


因此,virtual_score的判断逻辑可以用一句话概括:如果“当前节点再试一批新候选”的机会价值不低于“最优子节点继续向下挖”的价值,就停在当前节点继续扩宽;否则进入UCT最高的子节点继续深挖。它本质上是在控制搜索树的形状,避免搜索树一开始就变成一条很深但很窄的链。




因此,MCTS在本文中的作用不是替代因子评测,而是管理有限搜索预算:LLM负责提出候选公式,evaluate_alpha负责把候选转化为reward,MCTS再用UCT、virtual expansion和回传机制决定下一轮应当横向扩宽、纵向挖深,还是切换到新的兄弟分支。


2.3 LLM-MCTS模型运作逻辑

在本文框架中,LLM-MCTS不是简单地把大语言模型接到搜索树后面,而是把MCTS的搜索控制能力与LLM的语义生成能力拆成两个层次。MCTS负责决定“下一轮扩展哪个节点”,LLM负责回答“围绕这个节点,哪些公式改写在金融逻辑上值得尝试”。因此,LLM-MCTS的核心不是让LLM直接给出最终因子,而是让LLM成为MCTS扩展动作的生成器和逻辑审查器。



从流程上看,加入LLM前后的MCTS主干并没有改变:系统仍然从Seed初始化开始,经过节点选择、候选扩展、样本内评测、reward回传和下一轮搜索,最后进入样本内外复评验证。也就是说,MCTS仍然是整个框架的控制层,负责管理搜索树、分配搜索预算和决定路径切换。


真正发生变化的是扩展动作的生成方式。没有LLM时,MCTS的扩展通常依赖固定模板、随机扰动或预设算子组合;这些方法能够持续产生候选公式,但容易出现机械堆叠、金融逻辑弱、解释依赖事后补充的问题。加入LLM后,每一次扩展都变成“带语义约束的候选生成”:LLM会读取父节点公式、root逻辑、当前评测弱项、历史路径和可用算子边界,生成带有假说、方向、适用场景、风险和组件解释的新公式。


同时,LLM的加入并不意味着模型决策权转移给大语言模型。候选公式仍必须通过逻辑审查、公式解析、合法性过滤和真实数据评测;审查不通过的候选不会进入MCTS树,评测不佳的候选也不会因为文字解释好而被保留。换言之,LLM改变的是“候选从哪里来、是否具备金融假说”,MCTS保留的是“下一步往哪里搜、哪些结果可以回传”的决策权。



因此,LLM-MCTS与没有LLM的MCTS并不是两套完全不同的搜索框架,而是在同一套MCTS控制层上替换并增强了“扩展器”。没有LLM时,扩展器更像算子模板库;加入LLM后,扩展器变成能够理解父节点经济含义、识别评测弱项、提出逻辑假说并输出候选公式的研究代理。



从信息流看,MCTS给LLM的不是一个空白任务,而是带约束的上下文:父节点公式、root大逻辑、当前RankIC/RankIR、最弱维度、历史搜索路径、已高频出现结构和可用算子边界。LLM返回给MCTS的也不是单个答案,而是一组可被解析、可被审查、可被回测的候选动作。随后,数据评测层把这些动作转化为mcts_reward_score、absRankIC、absRankIR、coverage、turnover、diversity、overfit等指标,MCTS再据此更新搜索树。


因此,LLM-MCTS的运作逻辑可以概括为三层闭环:第一层是MCTS控制层,负责选择、回传和路径切换;第二层是LLM生成与审查层,负责把金融逻辑转化为候选公式;第三层是数据评测层,负责用真实历史数据检验候选是否有效。三层共同作用,使因子挖掘既不是纯粹的黑箱生成,也不是机械模板枚举,而是一个由金融假说、搜索控制和实证反馈共同驱动的迭代过程。


03

日频价量因子的迭代挖掘

本部分围绕29个日频低频量价Seed因子的LLM-MCTS迭代结果展开。实验数据为A股日频行情数据,输入字段主要包括open、high、low、close、vwap、volume、amount等量价变量;每个Seed单独作为MCTS根节点,LLM在当前节点公式、父路径、评测反馈和可用算子约束下生成候选公式,MCTS根据reward、UCT与回传结果决定后续搜索方向。后文先介绍原始Seed与算子体系,再以vstd20案例展示前两层搜索过程,最后汇总29个因子的整体改进效果。

评测口径方面,样本内区间为2019-01-01至2023-12-31,样本外区间为2024-01-01至2026-05-27;收益标签为未来5个交易日close-to-close收益,RankIC/RankIR按周度截面计算。Stage1在样本内进行LLM-MCTS搜索,股票池采用按成交额分层抽样(5组、随机种子42,主批次抽样比例20%),以降低搜索成本;Stage2将候选放回全市场,在样本内复评并在样本外验证。



3.1 原始因子与算子介绍

本文以29个Alpha158风格低频量价Seed为起点,在给定的算子和变量中进行LLM-MCTS搜索。Seed提供初始经济假说,算子定义可改写的公式空间,大语言模型提供改进的候选因子和负责逻辑约束,从而保证候选因子可计算、可复现、可解释。


数据层面,实验仅使用日频量价字段,包括开盘价,收盘价,最高/最低价,成交均价,成交价和成交额,不引入行业、基本面、分析师预期等基本面信息,所以可以认为是低频的价量信息。



原始Seed的窗口统一为20个交易日,即公式中的%d在本实验中均取20。统一窗口有助于比较不同公式结构的改进效果,也使样本内外IC、IR的差异更多反映因子逻辑本身。



算子体系覆盖滞后、滚动统计、回归相关、条件判断、成交加权、真实波幅和分域处理等类型。LLM只能在这些算子内提出候选公式,MCTS再根据回测反馈选择扩展方向,因此搜索空间既保持开放性,也受到金融逻辑和代码语法的共同约束。



3.2 LLM-MCTS搜索案例

本节以vstd20为例展示LLM-MCTS的实际迭代过程。该Seed的原始公式为Std($volume,%d)/($volume+1e-12),其中%d=20,含义是用过去20日成交量标准差刻画成交量波动,再用当日成交量做归一化。它描述的是成交活跃度的不稳定性,但由于分母依赖当日成交量,容易受到单日放量或缩量扰动。


因此,vstd20的优化不是脱离原始逻辑重新造因子,而是围绕“成交量不稳定、资金流冲击、量价确认、分域标准化”逐步展开。LLM负责提出符合该逻辑的候选公式和经济解释,MCTS负责根据真实评测分数与UCT机制决定继续深挖哪条路径。



整个搜索过程可以概括为“选择、扩展、评测、回传”。选择阶段由MCTS根据UCT选择当前最值得扩展的节点;扩展阶段由LLM根据Seed逻辑、历史路径和允许算子提出候选;评测阶段计算RankIC、RankIR、覆盖率、换手、多样性和过拟合惩罚;回传阶段更新节点visits与best_reward,影响下一轮搜索。



具体到数值计算,MCTS使用mcts_reward衡量单个候选本身的质量,再用UCT决定下一轮从哪个节点继续扩展。reward是候选的静态评测分数,UCT是在reward基础上加入访问次数惩罚后的路径选择分数。两者的区别在于:reward回答“这个公式好不好”,UCT回答“下一步还要不要继续沿这条路径试”。



第一层优化从root开始。此时搜索树没有子节点,MCTS必然选择root扩展;LLM收到原始公式后,围绕成交量不稳定这一主线生成5条方向:分母稳健化、价量同步、单位成交量冲击、成交确认和分域标准化。其中vstd2mean将分母从当日成交量改为20日均量,保留原逻辑但显著提升稳定性,因此成为第一层胜出分支。





以第一层胜出的vstd2mean为例,它的absRankIC=0.0437、absRankIR=0.5879。虽然absRankIC仍略低于0.05的目标中心,但已远高于原始seed;同时该公式覆盖率高、过拟合惩罚低、与已有有效候选不重复,因此reward达到第一层最高。




第二层优化不再从原始Seed出发,而是沿vstd2mean继续扩展。LLM在“成交量变异系数更稳健”这一局部结论上继续提出5个候选:价量相关交互、成交额变异系数、成交额分域标准化、隔夜跳空尺度和价格波动压缩。这一层展示了LLM的核心作用:它不是随机拼接算子,而是沿已验证的节点逻辑继续提出可解释的经济假说。




第二层中amount_cv的absRankIC=0.0491、absRankIR=0.6490,已经显示出很强的候选价值;但它与vstd2mean同属“变异系数”结构,diversity_score只有0.0249,因此搜索阶段reward被多样性项压低。相比之下,vol_cv×price_volume_corr的IC/IR略弱,但多样性更高,reward反而略高。这说明Stage1的MCTS并非只按IC/IR排序,而是在有效性、稳定性和候选差异度之间做平衡。



以第二层的vol_cv×PVCorr为例,其公式逻辑是“成交量变异系数×价量相关性”。它试图回答:成交量本身不稳定时,如果这种不稳定还伴随价格同步变化,是否意味着更强的交易冲击或情绪扰动。这个候选的absRankIC=0.0489,已经接近0.05的目标中心;但由于它与已有候选相关性较高,diversity_score只有0.3292。




第二轮结束后,vstd2mean分支已经被访问6次,探索项下降;其他第一层兄弟分支仍只访问1次,探索项较高。因此下一轮UCT不再选择当前best_reward最高的vstd2mean,而是转向vol_price_sync。这是MCTS相比贪心搜索最关键的差异:它会利用高分路径,但不会让搜索过早坍缩到单一结构。



需要注意,第二轮结束后的下一步选择发生在root层。虽然vol_cv×PVCorr在vstd2mean分支内部仍有较高节点内UCT,但MCTS必须先在root的第一层子节点之间做选择。此时vstd2mean整个分支已被访问6次,root层探索项被压低;vol_price_sync只访问1次,探索项显著更高,因此成为第三轮最终选中的扩展分支。



从最终样本外结果看,LLM在第二层提出的amount_cv方向被证明非常重要。它保留“标准差/均值”的变异系数结构,但将成交量替换为成交额,使因子从“股数成交不稳定”转为“资金规模进出不稳定”。最终代表性公式为-1*Div(Std($amount,%d),Add(Mean($amount,%d),1e-12)),样本外absRankIC提升至0.0549,absRankIR提升至0.8104,明显优于原始seed。


因此,vstd20案例展示了本文框架的完整分工:LLM提供可解释的候选方向和逻辑假说,MCTS用真实评测结果管理搜索路径,diversity与UCT防止候选过度集中,最终再通过样本外验证筛选真正稳健的改进因子。


3.3 因子优化整体效果

本节从两个互补口径评估LLM-MCTS对29个日频价量Seed的整体优化效果。第一类是正式选择口径:仅根据样本内评价选择最终因子,再观察样本外表现,因而更接近真实研究流程下的可复现结论。第二类是候选池诊断口径:统计搜索过程中已经通过样本内保留条件的候选,在样本外是否存在更优解,用于衡量搜索空间中是否被LLM-MCTS挖掘出具有外推潜力的方向。


从正式选择口径看,29个Seed的最终入选因子在样本内全部优于原因子,其中19个在样本外仍优于原因子,说明该框架能够较稳定地把原始单一价量定义改造成更强的表达式。这一结果提示:样本内最优并不必然等于样本外最优,后续应进一步加强稳健性筛选、复杂度惩罚和跨样本一致性约束。


从候选池诊断口径看,564个样本内保留候选中,有425个候选在样本外也优于其对应Seed;以每个Seed的样本外最优候选观察,29个Seed均能找到样本外优于原因子的候选,其中9个Seed存在达到OOS目标线的候选。该结果说明LLM-MCTS的生成与搜索过程确实扩大了有效因子空间,但也说明最终选择规则仍需要在“不使用样本外信息”的约束下更好地识别这些稳健方向。



下表展示部分Seed的代表性候选表现,其中OOS absIC和OOS absIR分别衡量样本外周度RankIC的绝对强度和稳定性,OOS提升则表示该候选相对原因子在样本外的增量。该表的含义是:即使最终入选仍应坚持“样本内选择、样本外只验证”,所有的Seed均搜索到样本内外均显著优于Seed的因子。



3.4 优秀案例:从表达式到金融逻辑

本节选取std20、cntn20与rank20三个Seed。三个案例分别代表波动率改造、下跌频率逻辑重构、价格位置反转增强三类路径。它们的共同特征是:改进表达式不是简单堆叠算子,而是在LLM给出的金融假说约束下,对原始Seed的信息维度、成交确认方式或反转条件进行结构化替换。


std20:从收盘价波动率到成交确认的真实波幅


原因子刻画收盘价标准差相对价格水平,主要描述close-to-close维度的价格波动强弱。它的优点是定义简单,但只使用收盘价序列,容易遗漏日内最高价、最低价和隔夜跳空带来的真实波动。改进因子把波动率代理从“收盘价标准差”替换为“成交量加权真实波幅”,同时沿用原因子的负号方向,使因子继续表达低波动/波动冲击控制逻辑,而不是转向价格均值回复或动量逻辑。


原因子公式:


-1*Std($close,%d)/$close


改进后公式:


-1*EMA(Greater($high-$low,Greater(Abs($high-Ref($close,1)),Abs($low-Ref($close,1))))*$volume,%d)/EMA($volume,%d)/$close


因子可以先化简成:-[EMA(TrueRange*volume,d)/EMA(volume,d)]/close,即“取负后的成交量加权真实波幅占价格比例”。


其中,TrueRange=max(high-low,abs(high-Ref(close,1)),abs(low-Ref(close,1)))。high-low捕捉日内振幅;abs(high-昨日收盘价)和abs(low-昨日收盘价)捕捉隔夜跳空后最高价、最低价相对前收盘的冲击。三者取最大值后,因子不再只看收盘点位,而是尽量覆盖日内波动和隔夜缺口。


TrueRange*volume表示“有成交量参与的真实波动”。如果某天真实波幅很大但成交量很低,其权重不会被过度放大;如果大波幅同时伴随高成交量,则更可能代表真实资金冲击或市场分歧。


EMA(TrueRange*volume,d)/EMA(volume,d)是最近d日成交量加权平均真实波幅,用EMA强调近期状态,并通过除以EMA(volume,d)消除原始成交量规模差异。最后再除以close,是为了把绝对波幅转成相对价格尺度,便于不同价格水平股票之间横截面比较。


公式前面的-1保留了原因子方向:因子值越高,通常代表成交量加权真实波幅相对价格越低;因子值越低,则代表近期出现放量大波动、隔夜缺口或日内冲击更强。这里的核心不是“放量超跌”,而是用更完整的真实波幅替代收盘价标准差,并用成交量确认波动是否具有交易意义。


综合来看,该改进因子可以理解为“成交确认后的低真实波幅因子”。它保留了std20的波动率大逻辑,但把单一收盘价波动扩展为包含日内区间、隔夜跳空和成交参与度的真实波幅度量,因此比原始Std(close,d)/close更贴近市场实际承受的价格冲击。



从机制上看,std20的改进重点是把“收盘价标准差”替换为“成交量加权真实波幅”。LLM在这里提出的是波动率度量升级假说,MCTS通过样本内外评测确认该真实波幅代理是否比原始close-to-close波动更有效。



cntn20:从下跌天数到成交量加权负乖离


原因子只统计过去窗口内下跌日占比,核心信息是“下跌发生了多少次”。这种定义容易把无量阴跌、正常回调和真实资金压力混在一起,也无法区分轻微下跌与深度折价。改进因子把下跌频率逻辑重构为“成交量加权的负乖离”:价格相对均线越低、且下跌位置成交量越高,因子值越高。因此,该路径不是简单增加一个成交量项,而是把原来的计数型信号升级为强度型、资金确认型的均值回复信号。


原因子公式:


Mean($close


改进后公式:


Div(EMA(Mul(Sub(Mean($close,%d),$close),$volume),%d),EMA($volume,%d))


因子可以先化简成:EMA((Mean(close,d)-close)*volume,d)/EMA(volume,d),即最近d日“成交量加权的价格负乖离”。


其中,Mean(close,d)-close衡量当前价格低于近期价格中枢的幅度;该项为正,说明价格处在均线下方,折价越深数值越大。乘以volume后,只有伴随较高成交量的负乖离才会被显著放大;再除以EMA(volume,d),则把原始成交量规模归一化为成交量加权的平均偏离。


高因子值通常对应:价格明显低于近期均线,且这种低位偏离发生在成交量较高的阶段。它可以理解为“放量低位折价”或“有交易确认的超跌状态”,隐含逻辑是恐慌抛压、流动性冲击或资金换手后,价格存在向均值回归的可能。


低因子值或负值通常对应:价格接近或高于近期均线,或者低位偏离缺乏成交量确认。相比原始cntn20只看下跌天数,改进因子更强调“跌得有多深、是否有量、是否持续”,因此更容易过滤无量噪声和普通技术性回调。



从机制上看,cntn20的改进重点是把“下跌次数”转换成“放量负乖离强度”。LLM在这里提出的是有资金参与的超跌反转假说,MCTS则用样本内外RankIC/IR验证该假说是否真正优于原始计数逻辑。



rank20:从价格时序排名到放量反转确认


原因子用收盘价在过去窗口内的时序排名刻画相对位置,本质上是价格位置反转信号:价格越低,未来越期待均值回复。但单纯排名只描述“低不低”,并不区分低位是否伴随成交量、是否代表真实资金冲击。改进因子把价格位置信号改写为成交量加权的价格偏离,并进一步乘以当日相对成交量,强调“放量确认的低位偏离”。


原因子公式:


-1*Rank($close,%d)


改进后公式:


Mul(Mul(-1,Div(EMA(Mul(Sub($close,Mean($close,%d)),$volume),%d),EMA($volume,%d))),Div($volume,Mean($volume,%d)))


因子可以先化简成:-[EMA((close-Mean(close,d))*volume,d)/EMA(volume,d)]*[volume/Mean(volume,d)],即“取反后的成交量加权价格偏离”乘以“当日成交量放大倍数”。


其中,close-Mean(close,d)衡量收盘价相对近期价格中枢的偏离:为正表示价格高于均线,为负表示价格低于均线。乘以volume并用EMA平滑后,再除以EMA(volume,d),得到最近一段时间的成交量加权平均偏离。


公式前面的负号把方向调整为反转逻辑:如果价格在有成交量参与的情况下低于均线,原始偏离为负,取反后因子值变高。最后的volume/Mean(volume,d)是当日量能确认项,当日越放量,低位偏离或高位过热的信号越被放大。


高因子值通常对应:近期价格低于均线,低位偏离有成交量参与,且当日成交量也明显高于自身均量。这可以理解为“放量超跌”状态,可能反映短期过度反应、恐慌交易或抛压释放后的均值回复机会。

低因子值或负值通常对应:价格在放量状态下高于均线,反转视角下更像短期过热。相比原始rank20只用价格排序,改进因子同时引入偏离幅度、历史成交确认和当日成交确认,因而更强调低位信号的质量而不是单纯低位本身。



从机制上看,rank20的改进重点是把“价格处于低位”进一步约束为“放量确认的低位”。这一处理保留了原Seed的反转大逻辑,同时用成交量强度提高信号信噪比,使低位排名不再等同于无条件买入信号。




04

批量低频因子挖掘:不再拘泥于Seed的金融逻辑

本节将因子研究从“给定Seed后做局部改造”推进到“以若干低频价量机制为根节点的批量挖掘”。前文实验更像是在已有因子附近寻找更好的表达式;本节则把Seed作为搜索入口和基准,允许LLM在量价、波动、流动性、跳空、日内位置等机制之间提出新的组合假说,再由MCTS用样本内评测结果决定继续深挖哪些分支。


4.1 从Seed改造到Seed池挖掘

批量挖掘实验使用12个根节点覆盖主要低频价量研究入口。每个根节点都先计算原因子表现,再在同一评价框架下生成、筛选和复评候选因子。这样既能比较“新因子是否超过原始根节点”,也能观察不同根节点是否反复导向相似的有效机制。



4.2 模型参数与前文实验的区别

本节保留前文的核心评测口径:样本内为2019-01-01至2023-12-31,样本外为2024-01-01至2026-05-27,预测周期为5个交易日的收益率,并使用周度RankIC、RankIR作为主要指标。主要变化在搜索目标、LLM约束和搜索深度:第3章的因子改进部分强调不偏离原Seed的大逻辑,本节强调在低频价量域内发现可复用的新机制。



4.3 最终效果

从最终挖掘到的因子结果来看,批量挖掘并不是只在单个Seed附近做微调。总共有173个候选因子在样本内优于原始Seed;进一步看样本外验证,其中143个仍优于对应Seed,说明搜索得到的有效表达并非完全依赖样本内拟合。



从相关性结果看,样本内外均优于Seed的候选整体同质化程度较低。123个唯一公式形成7503对两两组合,abs相关均值仅为0.2604,中位数为0.2148;低于0.4的组合占77.1%,高于0.8的组合仅1.88%。这说明本轮搜索并非只重复发现少数相近公式,而是在真实波幅、成交参与、价量同步等机制下形成了较分散的候选池。





整体而言,升级后的批量挖掘模式体现出两点优势:第一,多个Seed可以共同探索低频价量空间,最终并非只改进单个原始因子,而是识别出真实波幅、放量冲击、成交额不稳定、量价同步/背离等可复用机制;第二,LLM生成的概念算子在通过解析、审查和复评后进入经验库,使后续搜索不必每次从原始算子重新组合,而可以复用已经验证过的结构组件。



05

高频因子的迭代挖掘

与前文低频价量实验不同,高频版的候选因子表达形式不再是公式字符串,而是一份可运行的Python因子代码,输入为分钟级Open、High、Low、Close、Volume、Amount,输出日度因子宽表,再用统一的IS/OOS口径评测。

因此,高频实验的重点不是把一个日频Seed做局部变形,而是让LLM在日内状态、分时结构、成交量脉冲、价格路径和微观波动等空间中提出候选机制,再由代码校验和全市场评测决定是否保留。


5.1 高频因子挖掘的LLM-MCTS流程设计

跟低频因子挖掘流程稍有不同。由于高频因子部分返回的是代码,为了提升效率,本部分先把多个Seed、经验库和分钟函数说明输入给LLM,由LLM在日内状态、分时结构、成交量脉冲、价格路径和微观波动等空间中提出候选机制;随后由脚本批量运行并在样本内外复评,最后把有效机制写回经验库,并允许下一轮迭代时继续复用。



高频挖掘的Seed候选覆盖分钟振幅、价格偏离、收益波动和成交量状态四类,属于人工根据逻辑挖掘出的高频因子。



5.2 因子挖掘结果与代表性候选

截至当前高频实验,候选池共形成30个可评测高频因子,覆盖尾盘压力、多机制候选、日内实现波动率、分钟振幅、价格偏离、收益波动和成交量状态等方向。下表展示目前表现较好的7个代表因子,样本内外rankIC均表现十分优秀,且样本外相对于样本内衰减较低。



高频因子的挖掘模型返回的是因子计算的代码。如seedtxt_vol_up_num的逻辑是先定义成交量高位状态,再统计状态从非高位切换到高位的次数。这个处理把连续放量区间视为一次事件,避免简单把连续高量分钟重复计数。


vol = read_year_vars(data_root, int(year), ("Volume",),   stock_pool=stock_pool)["Volume"]
   vol_up = get_up_space(vol)
   vol_up_num = vol_up * (vol_up.shift(1) != 1)
   factor = daily_sum(vol_up_num)


seedtxt_vol_up_ret_std不直接看全日收益波动,而是只看高量状态下的分钟收益波动。如果高量分钟本身伴随剧烈价格跳动,说明交易冲击或短期分歧更强;方向调整后,低高量收益波动对应更高未来收益。


data = read_year_vars(data_root,   int(year), ("Close", "Volume"), stock_pool=stock_pool)
   ret =   data["Close"].groupby(data["Close"].index.normalize()).pct_change()
   vol_up_ret = ret * get_up_space(data["Volume"])
   factor = daily_std(vol_up_ret)


hf_rv_volume_weighted是成交额加权的日内实现波动率。它不是平均看每一分钟,而是让成交额占比高的分钟获得更高权重,因此更强调真实资金参与较多时产生的价格波动。


data = read_year_vars(data_root, int(year), ("Close",   "Amount"), stock_pool=stock_pool)
   close = data["Close"]
   amount = data["Amount"].where(data["Amount"] > 0)
   minute_ret = close.groupby(close.index.normalize()).pct_change()
   day_amount_for_minute = daily_sum(amount).reindex(amount.index.normalize())
   day_amount_for_minute.index = amount.index
   amount_share = safe_divide(amount, day_amount_for_minute)
   factor = np.sqrt(daily_sum(minute_ret * minute_ret * amount_share))


5.3 高量脉冲次数机制的经验解释

经验总结部分提到“高量脉冲次数是当前最强机制”,不是指它在经济上已经被证明为唯一正确解释,而是指在当前30个可评测高频候选中,seedtxt_vol_up_num同时取得最高的样本内RankIC和最高的样本外RankIC:IS RankIC为0.0839,OOS RankIC为0.0744,因此模型会总结高因子的可能成功之处。


seedtxt_vol_up_num因子代码调用了get_up_space(Volume)函数。get_up_space的作用是对每只股票、每个交易日分别计算当日分钟成交量的均值和标准差,当某一分钟成交量高于“当日均值+1倍标准差”时标记为1,否则记为空值。随后seedtxt_vol_up_num并不把所有高量分钟相加,而是用vol_up.shift(1)!=1找到每一段连续高量区间的第一个分钟,再按日加总。


# one_minute_factor_process.py
   up_limit = df.groupby(df.index.date).mean() + df.groupby(df.index.date).std()
   up_limit = up_limit.reindex(df.index, method="ffill")
   up_space = (df > up_limit).replace(False, np.nan).replace(True, 1)

   # seedtxt_vol_up_num.py
   vol_up = get_up_space(Volume)
   pulse_start = vol_up * (vol_up.shift(1) != 1)
   factor = daily_sum(pulse_start)


这个结果带来的“感悟”主要有三层。第一,高频数据里有价值的信息未必只在价格波动大小上,也可能在交易状态的切换次数上。成交量从正常状态突然进入高位状态,往往代表市场注意力、资金参与或流动性需求发生变化;连续高量区间只记一次,可以把它理解为一次异常交易事件,而不是把同一次事件重复放大。


第二,脉冲次数比简单的高量分钟收益更稳。seedtxt_vol_up_ret_std也很强,但它需要同时依赖高量状态和价格收益波动,噪声更高;seedtxt_vol_up_num只识别高量事件出现的次数,先抓状态,再看预测效果,因此在样本外保留率上更稳。


第三,这个机制给后续LLM-MCTS迭代提供了更明确的方向:后面LLM可以围绕“高量事件”继续展开,例如高量脉冲占全天分钟数的比例、早盘/午后/尾盘脉冲分布、高量脉冲后的价格方向、脉冲对应分钟的AMP/RV/VWAP偏离等。这就是把单个强因子的表现转化为经验库的过程。




06

风险提示

模型失效风险。本研究基于历史数据和统计规律构建因子,历史表现不代表未来收益。当市场结构、投资者行为、流动性环境或监管政策发生变化时,量价因子可能衰减甚至失效,导致组合表现不及预期。

过拟合风险。本文采用自动化方法进行因子挖掘,未来市场变化可能导致因子泛化能力下降。

数据质量风险。因子研究依赖行情、成交量、估值及收益标签等数据。数据缺失、异常、复权处理差异以及不同评测口径、股票池和样本区间设置,均可能影响研究结论。

大语言模型生成风险。大语言模型生成的因子逻辑、代码及工具函数可能存在理解偏差或实现错误。实际应用前,仍需对代码实现、数据处理及评测流程进行独立验证。

交易成本与流动性风险。回测结果未必能够完全反映实盘环境。冲击成本、滑点、税费、涨跌停及成交不足等因素可能侵蚀策略收益,实际表现可能低于历史测算结果。


本文源自报告《深度学习系列之四:从人工写因子到AI写因子:LLM-MCTS驱动的可解释因子迭代框架

报告时间:2026年6月23

发布报告机构:东吴证券研究所

报告作者:于明明 S0600525120002


    本公众订阅号(微信号:ymm_quant)由东吴证券研究所金融工程团队设立,系本研究团队研究成果发布的唯一订阅号。

    本公众号所载的信息仅面向专业投资机构,仅供在新媒体背景下研究观点的及时交流。

    本订阅号不是东吴证券研究所金融工程团队研究报告的发布平台,所载内容均来自于东吴证券研究所已正式发布的研究报告或对已发布报告进行的跟踪与解读,如需了解详细的报告内容或研究信息,请具体参见东吴证券研究所已发布的完整报告。

    本订阅号所载内容不构成对具体证券在具体价位、具体时点、具体市场表现的判断或投资建议,不能够等同于指导具体投资的操作性意见。本订阅号所载内容仅供参考之用,接收人不应单纯依靠本资料的信息而取代自身的独立判断,应自主做出投资决策并自行承担风险。东吴证券研究所及本研究团队不对任何因使用本订阅号所载任何内容所引致或可能引致的损失承担任何责任。

   本订阅号对所载内容保留一切法律权利。订阅人对本订阅号发布的所有内容(包括文字、图片、影像等)未经书面许可,禁止复制、转载;经授权进行复制、转载的,需注明出处为“东吴证券研究所”,且不得对本订阅号所截内容进行任何有悖原意的引用、删节或修改。

特别声明

    《证券期货投资者适当性管理办法》、《证券经营机构投资者适当性管理实施指引(试行)》于2017年7月1日起正式实施。通过新媒体形式制作的本订阅号推送信息仅面向东吴证券客户中的专业投资者,请勿在未经授权前进行任何形式的转发。若您非东吴证券客户中的专业投资者,为保证服务质量、控制投资风险,请取消关注本订阅号,请勿订阅、接收或使用本订阅号中的任何推送信息。因本订阅号难以设置访问权限,若给您造成不便,烦请谅解!感谢您给予的理解和配合。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/198072