本文档由Gemini 2.5 pro生成。读者可以参考输入的prompt来得到更详细的介绍。
KalmanStockV1\scripts\feature_analysis\run_factor_backtest_gemini.py KalmanStockV1\scripts\feature_analysis\run_factors_parallel_gemini.py KalmanStockV1\scripts\feature_analysis\factor_analysis_gemini.ipynb KalmanStockV1\config\config_features.py
KalmanStockV1\config\config.py
KalmanStockV1\src\feature_engineer\data_loader_gemini.py KalmanStockV1\src\feature_engineer\feature_filter_gemini.py KalmanStockV1\src\feature_engineer\strategy_gemini.py KalmanStockV1\src\feature_engineer\pipeline.py KalmanStockV1\src\feature_engineer\factor_scoring_gemini.py
通读我这个项目中“特征工程”这个功能,这里是涉及到的脚本。请写一个详细的、面对小白的readme文档(markdown),介绍:
- 什么是特征工程,我在这里做了什么。
- 整个特征工程的workflow是怎样的,先从哪一步开始做起,下一步转到哪里,会读取什么、做了怎样的处理、怎样的计算、怎样的缓存、测试结果会怎样记录……等等。附:至少要教会小白读者“应该先运行哪个脚本,然后结果会跑到哪里,然后再运行哪个脚本”
- 介绍脚本丰富且具有可拓展性、可调配参数做实验的功能,并且教会小白可以通过修改哪里的代码、怎么修改来实现这些功能。比如说如果要设计新的特征可以怎么加、在哪里可以选择特征组合进行测试、在哪里可以控制权重、可以怎么设置因子的硬性过滤、可以怎么设置各种阈值、各种回测的模式。
- 总结我的交易策略。这是一个金融性比较浓的项目,希望你能好总结其中的交易流程和逻辑。可以介绍必要的金融知识,以及回测模拟是怎样的一个金融场景的(T+1的买卖策略、因子要在收盘后才暴露才能得到信号、如何设置了止盈止损、凯利公式、落袋为安策略、资金分配……等等)
- 教会新手可以通过它怎样做实验,并且指出下一步开发的方向和可能性
以markdown格式,放在srcipts/feature_analysis文件夹下
补充:你还可以让它画TD图来展示整个特征工程的workflow。我没写,后面补充了
运行的脚本是以_gemini结尾的
运行之前,先检查你有没有parquet文件的数据。没有的话,先去运行fetch_data_parquet.py脚本,下载数据。它一定是跑得通的。跑不通的话,你检查你的config.py文件是不是最新的。
已经是傻瓜式教程了,学不懂建议回炉重造。
在量化金融领域,特征工程是将原始、杂乱的市场数据(如股票的开盘价、收盘价、成交量)转化为能够预测未来股价走势的、有意义的信号(即“特征”或“因子”)的过程。
想象一下,你是一位侦探,原始数据是零散的线索。单独看“昨天股价上涨了1%”这条线索可能意义不大。但如果你通过特征工程,将它与“成交量放大”、“市场整体情绪积极”等线索结合,可能会得到一个强有力的信号:“这只股票明天有较大概率继续上涨”。
这个将线索转化为信号的过程,就是特征工程。我们在这里做的,就是构建一个强大的“信号加工厂”。
本项目构建了一个完整的、从数据处理到策略回测的特征工程流水线。具体来说:
- 自动化因子计算:我们建立了一个可扩展的“因子工厂” (
engineering.py),能够自动计算数十种在学术界和业界被证明有效的因子,涵盖动量 (Momentum)、反转 (Reversal)、波动率 (Volatility)、交易量和市场情绪等多个维度。 - 因子合成与评分:我们将多个独立的因子通过加权融合,最终合成为一个综合性的
score。这个分数代表了我们对一只股票未来表现的最终判断,分数越高,我们越看好它。 - 高度逼真的回测引擎:我们创建了一个专业的交易模拟器 (
run_factor_backtest_gemini.py),它不仅能根据我们的score进行买卖,还严格遵守了现实世界的交易规则(如T+1制度),并内置了多种风险管理模块(如止盈止损、凯利公式等)。 - 灵活的实验平台:整个系统被设计成一个大型的“实验平台”。你可以像科学家一样,通过修改配置文件,轻松地组合不同的因子、调整它们的权重、设置过滤条件,然后一键运行回测,验证你的想法。
理解整个系统如何运转至关重要。下面是“一步一步”的指南,告诉你数据是如何被处理、计算并最终生成回测报告的。
(这是一个流程图占位符,你可以根据下面的描述绘制一个流程图)
graph TD
A[原始数据 .csv/.parquet] --> B[data_loader_gemini.py];
C[大盘指数数据] --> B;
B --> D{缓存检查};
D -- 缓存存在 --> E[加载缓存 .pkl];
D -- 缓存不存在 --> F[engineering.py];
F -- 计算特征 --> G[生成全量特征数据];
G --> H[缓存至 data/processed_feat/];
H --> E;
E --> I[输出: 带特征的DataFrame];
subgraph "1. 数据准备与加载"
A
C
B
D
E
F
G
H
I
end
I --> J[run_factor_backtest_gemini.py];
subgraph "2. 配置参数"
K[factor_weights];
M[feature_filters];
N[回测风控参数];
end
K --> L;
M --> L;
N --> L;
subgraph "3. 策略执行与回测"
J -- 读取配置 --> L[GeminiFactorBacktestConfig];
L --> P[feature_filter_gemini.py];
P --> Q[factor_scoring_gemini.py];
Q --> R[strategy_gemini.py];
R --> S{回测循环};
S --> T[交易策略模块];
T --> U[应用各类策略];
end
subgraph "4. 结果输出"
S --> V[输出至 /output];
V --> W[净值曲线 .png];
V --> X[回测报告 .json];
V --> Y[交易日志 .csv];
end
subgraph "5. 可拓展模块"
Z1[engineering.py] --> F;
end
整个工作流围绕着核心回测脚本 run_factor_backtest_gemini.py (单文件测试) 和 run_factors_parallel_gemini.py (并行地产生因子) 展开。当你运行它们时,背后会发生以下事情:
第 1 步:加载原始数据 (data_loader_gemini.py)
- 读取:脚本首先会从
data/目录下读取指定的股票数据文件(.csv或.parquet格式)。 - 注入大盘数据:为了计算
Alpha、Beta等与市场相关的因子,脚本会自动读取预先准备好的大盘指数数据,并将其合并到个股数据中。 - 计算与缓存:
- 它会调用“因子工厂” (
engineering.py),对数据进行全面的特征计算。 - 为了节省时间,计算好的全量特征数据会被缓存到
data/processed_feat/目录下,命名为[股票代码]_gemini_raw.pkl。下次你再运行同一只股票时,它会直接读取缓存,跳过重复计算,极大提升效率。
- 它会调用“因子工厂” (
第 2 步:因子筛选 (feature_filter_gemini.py)
- 在对股票进行打分排名之前,系统会首先进行一轮“硬性筛选”。
- 你可以预先在配置文件中设置一些基本门槛,例如“过去20天的日均换手率不能低于0.5%”或者“市值不能小于50亿”。
- 只有满足这些硬性条件的股票,才有资格进入下一步的打分环节。这一步能有效过滤掉不符合你策略偏好的“垃圾样本”。
第 3 步:因子打分 (factor_scoring_gemini.py)
- 标准化:由于不同因子的量纲和分布千差万别(例如市盈率可能上百,而换手率可能是小数),直接相加没有意义。因此,系统会先对所有因子进行Z-Score标准化或者根据排名取rank(这是可以调的超参数),让它们都处于一个可比较的水平。
- 加权求和:根据你在配置文件中为每个因子设定的权重 (weights),系统会将标准化后的因子值进行加权求和,得到最终的
score。 - 信号对齐:这是非常关键的一步!为了防止“偷看未来”,我们今天(T日)收盘后计算出的
score,只能用来指导明天(T+1日)的交易。脚本通过shift(1)操作,将T日的信号延迟到T+1日才生效,确保了回测的公平性。
第 4 步:回测模拟 (run_factor_backtest_gemini.py)
- 每日循环:回测引擎会按交易日一天天模拟。
- 排名与选股:在每个交易日,引擎会根据当天的
aligned_score对所有股票进行排名,挑选出分数最高、排名最靠前的几只股票作为备选买入对象。 - 执行交易:
- 卖出:检查持仓股票是否触发了止盈、止损或其他卖出条件。
- 买入:在排名靠前的备选股中,根据资金管理策略(如凯利公式或等权分配)计算买入数量,并执行买入。
- 记录结果:每一笔交易、每一天的资产变化都会被详细记录下来。
第 5 步:结果产出
- 运行哪个脚本? 对于初学者,建议直接运行
scripts/feature_analysis/run_factors_parallel_gemini.py,它会处理data/目录下的所有股票数据。 - 结果在哪里? 运行结束后,所有的回测结果,包括:
[股票代码]_backtest_results.json: 详细的回测性能指标(年化收益、夏普比率、最大回撤等)。作者备注:其实更重要的是,这个文件会记录每次运行时候的超参数!!!!!!!具体是,会记录my_cfg的内容。所以你修改参数、加参数,最好在执行脚本的地方,修改my_cfg的内容,这样它们就会被记录下来了可以复现。[股票代码]_backtest_nav.png: 清晰的净值曲线图。[股票代码]_trade_logs.csv: 每一笔详细的交易记录。 都会被保存在feature_test/文件夹下。你只需要去这个文件夹查看结果,就能直观地评估你策略的优劣。
本框架最大的亮点在于其高度的可拓展性和可配置性。你几乎可以通过修改一个文件——config/config_features.py——来控制整个策略的所有核心环节。作者人工备注:config/config_features.py里面的是默认参数,还可以在执行脚本处,找到my_cfg修改,改的方法是一模一样的。
- 打开
src/feature_engineer/engineering.py。 - 编写函数:在文件里,模仿现有函数的写法,添加一个你自己的因子计算函数。例如:
def calculate_my_new_ratio(df): # 假设你想计算 (最高价-最低价) / 成交量 df['feat_my_price_vol_ratio'] = (df['high'] - df['low']) / (df['volume'] + 1e-6) return df
- 注册因子:在文件底部的
FeatureRegistry中,将你的新函数注册进去。做完这两步,系统就会在运行时自动计算你新添加的因子了!class FeatureRegistry: # ... (已有内容) GROUP_MY_FEATURES = [ (calculate_my_new_ratio, 'my_features') ] ALL_FEATURE_GROUPS = ( GROUP_1_MOMENTUM + # ... (已有内容) GROUP_MY_FEATURES # <-- 把你的新组加在这里 )
- 打开
config/config_features.py。 - 找到
GeminiFactorBacktestConfig类中的FACTOR_WEIGHTS字典。class GeminiFactorBacktestConfig: # ... FACTOR_WEIGHTS: Dict[str, float] = { # --- 动量类 --- "feat_mom_abs_ret_20d": 1.0, "feat_mom_abs_ret_60d": 0.5, "feat_volatility_20d": -0.2, # 注意:可以给负权重的 # ... }
- 实验:
- 调整权重:直接修改数字即可。例如,你认为20日动量更重要,可以把
1.0改成1.5。 - 关闭因子:如果你想暂时禁用某个因子,只需将其权重设置为
0。 - 反转因子:如果你认为某个因子是反向指标(值越小越好),只需给它一个负权重。
- 调整权重:直接修改数字即可。例如,你认为20日动量更重要,可以把
- 同样在
config/config_features.py中。 - 单因子过滤:修改
feature_filters。例如,你只想选择20日动量为正的股票:feature_filters: Dict[str, dict] = { "feat_mom_abs_ret_20d": {"min": 0.0, "operator": ">"} }
- 组合条件过滤:修改
composite_filters。例如,你要求股票必须同时满足“60日动量为正”和“信息离散度大于0.7”:composite_filters: List[dict] = [ { "name": "强势上涨股", "conditions": [ ("feat_mom_resid_60d", ">=", 0), ("feat_mom_info_discreteness", ">=", 0.7), ], "require_all": True # True 代表 AND 逻辑 } ]
- 打开
config/config_features.py。 - 找到
GeminiFactorBacktestConfig类。class GeminiFactorBacktestConfig: # ... stop_loss_pct: float = -0.05 # 硬止损百分比 take_profit_pct: float = 0.10 # 止盈百分比 max_hold_days: int = 20 # 单只股票最长持有天数 max_positions: int = 5 # 同时最多持有几只股票
GeminiFactorBacktestConfig 类就是一个巨大的“策略参数控制台”,你可以调整:
stop_loss_pct: 硬止损百分比 (例如-0.05代表亏损5%就卖出)。take_profit_pct: 止盈百分比。max_hold_days: 单只股票最长持有天数。max_positions: 同时最多持有几只股票。min_score_threshold: 综合score的最低门槛,低于此分数的股票即使排名靠前也不买。
这是一个金融专业性较强的项目,理解其背后的交易逻辑是关键。
我们的回测引擎严格模拟了中国A股市场的T+1交易制度。
- 什么是T+1? 简单说,你今天买入的股票,最早要到明天才能卖出。这杜绝了“当天买入,发现不对,立刻止损”的可能性,对策略的稳健性提出了更高要求。
- 代码如何实现? 在回测循环中,我们用
pos['entry_date'] == today这行代码来检查。如果一只股票的买入日期是今天,那么在今天的“卖出环节”它会被自动跳过,从而完美实现了T+1的限制。 - 信号的延迟性:如前所述,所有因子的计算都基于当天收盘后的数据。这意味着我们最早只能在第二天开盘时根据这个信号进行交易。
align_signals函数确保了这一点,让回测杜绝了“未来函数”的作弊行为。
假设回测进行到某一天,引擎会严格按照以下顺序执行操作:
-
早盘卖出 (Open Phase):
- 检查所有昨天及以前买入的持仓股。
- 如果某只股票处于亏损状态,并且其昨日排名已经大幅下滑(例如掉到所有股票的后50%),那么我们认为它已经失去了上涨动能,会以今日开盘价果断卖出,这被称为“排名止损”。
-
盘中买入 (Entry Phase):
- 筛选:选出当天
score排名最高的N只股票。 - 风控:剔除掉那些已经持仓的、以及开盘就“一字涨停”买不进去的股票。
- 资金分配:
- 凯利公式 (
use_kelly):如果启用,系统会根据历史的胜率和盈亏比,计算出一个理论上最优的仓位比例,用于本次买入。这是一种动态的、旨在最大化长期复利增长的资金管理方法。作者备注:我还没有测试凯利公式的可行性,因为这个公式的脚本还没完善好。我认为效果不会好 - 等权分配:如果禁用凯利公式,则将可用资金平均分配给待买入的几只股票。
- 凯利公式 (
- 执行买入:以当日开盘价(或未来可拓展的日内均价)模拟买入,并扣除手续费。作者备注:这玩意儿比较难搞,将来的工作。我先留一个接口,别启用
- 筛选:选出当天
-
尾盘卖出 (Close Phase):
- 再次检查所有昨天及以前买入的持仓股。
- 止盈止损:判断股价是否触及了预设的
TAKE_PROFIT_PCT(止盈线) 或STOP_LOSS_PCT(止损线)。 - 移动止损:判断股价是否从“持仓期间的最高点”回撤了特定幅度。
- 时间止损:持仓时间是否超过了
MAX_HOLD_DAYS。 - 如果触发了以上任何一个条件,则以当日收盘价卖出。
-
落袋为安 (
pocket_enabled):- 这是一个非常专业的风控策略。当你的总资产的盈利部分超过一个阈值时(例如,初始100万,现在总资产120万,盈利超过初始资金的15%),系统会自动将一部分利润“提取”出来,不再用于后续的交易。
- 这模拟了现实中的投资者会将部分利润转出账户的行为,使得回测的净值曲线更平滑、更保守,有效控制风险。作者备注:这个功能似乎在csv记录文件中没有体现,没有记录落袋金额是多少。但是只要开启它脚本自身是会执行该策略的。你可以增加一些记录。
对于新手,我们建议从简单实验开始,逐步建立感觉。
-
第一步:调整因子权重
- 目标:验证单个因子的有效性。
- 操作:
- 打开
config/config_features.py。 - 在
FACTOR_WEIGHTS中,将除一个因子外的所有其他因子权重都设置为0。例如,只保留"feat_mom_abs_ret_20d": 1.0。 - 运行
scripts/feature_analysis/run_factors_parallel_gemini.py。 - 去
output/文件夹下查看结果。这个单因子的策略表现如何? - 重复此过程,测试每一个你感兴趣的因子。
- 作者备注:你也可以通过把一些行给注释掉来实现“禁用”某个因子。例如:
my_cfg = config_features.GeminiFactorBacktestConfig( selected_features = [ # --- 基础技术指标 (Basic) --- 'feat_tech_ma20', 'feat_tech_ma60', 'feat_tech_bias_20', # --- 动量类特征 (Momentum Group) --- # 1. 残差与去噪 'feat_mom_resid_60d', # 残差动量 'feat_mom_alpha_60d', # 特质动量 'feat_mom_jump_filtered', # 反转过滤动量 'feat_mom_freq_resid', # 频率残差 # 2. 路径与形态 'feat_mom_slope_r2', # 稳态斜率动量 'feat_mom_info_discreteness', # 信息离散度 (ID) # 'feat_mom_sharpe', # 夏普动量 'feat_mom_vol_contraction', # 波动率收缩 # 'feat_mom_hurst', # Hurst 指数 (趋势持续性) # 3. 微观与资金 'feat_mom_overnight', # 隔夜动量 'feat_mom_vwb', # 成交量加权突破 去掉它之后,大差不差嘛 回撤变差了点 可以留着 # 'feat_mom_cgo', # CGO 获利盘比例 # 4. 边界条件 # 'feat_mom_dist_high', # 距离52周高点 'feat_mom_accumulation', # 累积买盘强度 # --- 反转类特征 (Reversion Group) --- # 1. 价格反转 # 'feat_rev_ret_5d', # 5日反转 动量策略加入它之后,收益直接由正转负 权重怎么改都没用 # 'feat_rev_ret_10d', # 10日反转 # 'feat_rev_ret_20d', # 20日反转 # 'feat_rev_max_ret_20d', # 极值效应 (MAX) # 'feat_rev_min_ret_5d', # 恐慌反转 (Min Ret) # 2. 技术指标反转 # 'feat_rev_bias_20d', # 均线乖离 20 # 'feat_rev_bias_60d', # 均线乖离 60 # 'feat_rev_boll_pos', # 布林带位置 # 'feat_rev_rsi_14', # RSI (反转视角) # 3. 流动性与量价 # 'feat_rev_turn_ratio', # 换手率比率 # 'feat_rev_turn_shock_ret', # 换手率突变冲击 # 'feat_rev_amihud', # Amihud 非流动性 emmm 把它去掉后,收益率直接变成负数。嗯,先检查它有没有未来函数。如果没有,说明它很牛! # 'feat_rev_cpv', # CPV 量价相关性 # 4. 结构与日内 # 'feat_rev_clv', # CLV 收盘位置 # 'feat_rev_rsrs_std', # RSRS 斜率标准化 # 'feat_rev_overnight', # 隔夜反转 (取反) # 5. 基本面反转 (依赖原始数据是否存在) # 'feat_rev_peTTM_bias', # PE 估值回归 # 'feat_rev_pbMRQ_bias', # PB 估值回归 # d'feat_rev_psTTM_bias', # PS 估值回归 # 'feat_rev_pcfNcfTTM_bias', # PCF 估值回归 ] )
- 打开
-
第二步:组合有效因子
- 目标:尝试构建一个简单的多因子模型。
- 操作:
- 从第一步中,挑出几个表现最好的单因子。
- 在
FACTOR_WEIGHTS中,为这几个因子设置一个非零权重(初始可以都设为1.0)。 - 再次运行回测,看看组合后的效果是否比任何一个单因子都好。
-
第三步:加入过滤条件和风控
- 目标:优化策略的风险控制。
- 操作:
- 在你的有效因子组合基础上,尝试在
config_features.py中加入feature_filters。例如,增加一个波动率过滤,要求feat_volatility_20d必须小于某个值。 - 调整
stop_loss_pct和take_profit_pct,观察它们对夏普比率和最大回撤的影响。 - 运行回测,比较结果。你的策略是不是变得更稳健了?
- 在你的有效因子组合基础上,尝试在
本框架已经非常强大,但量化的世界永无止境。以下是一些可以探索的进阶方向:
- 开发更复杂的因子:深入研究学术文献,实现一些更前沿的因子,如另类数据因子、基于机器学习的预测因子等。
- 动态因子权重:目前的因子权重是固定的。一个进阶方向是,让模型(例如一个简单的线性回归或更复杂的
LightGBM模型)根据不同的市场状态 (Market Regime) 自动学习并调整每个因子的权重。作者备注:这是AI的废话。后面的事情我早在做了 - 精细化择时:目前买卖主要发生在开盘或收盘。可以引入日内高频数据,研究更精细的交易执行算法,以求获得更好的成交价格。作者备注:这是一个很有挑战性的方向。难度会有点大。我预留了一个接口。这将是我们中级阶段需要做的
- 参数优化:
config_features.py中有大量参数。可以利用网格搜索 (Grid Search) 或贝叶斯优化等方法,系统性地寻找最优的参数组合。作者备注:调参数,加参数,八仙过海各显神通啦。注意加参数最好在config_features.py中注册,在执行代码中引用。
希望这份文档能帮助你开启激动人心的量化交易之旅。祝实验顺利!
下图清晰地展示了从数据输入到结果输出的完整流程,并标注了各个环节中可供您实验和调整的关键模块与参数位置。
graph TD
subgraph "1. 数据准备与加载"
A[原始数据 .csv/.parquet] --> B(data_loader_gemini.py);
C[大盘指数数据] --> B;
B --> D{"缓存检查"};
D -- 缓存存在 --> E[加载缓存 .pkl];
D -- 缓存不存在 --> F(engineering.py);
F -- 计算所有特征 --> G[生成全量特征数据];
G --> H(缓存至 data/processed/);
H --> E;
E --> I[输出: 带全量特征的DataFrame];
end
subgraph "2. 策略执行与回测"
I --> J(run_factor_backtest_gemini.py);
subgraph "实验参数配置区 (config/config_features.py)"
K["factor_weights: Dict[str, float]<br>调整因子权重"] --.-> L;
M["feature_filters / composite_filters<br>设置硬性过滤条件"] --.-> L;
N["stop_loss_pct, take_profit_pct, max_hold_days...<br>调整回测风控参数"] --.-> L;
end
J -- "读取配置" --> L(GeminiFactorBacktestConfig);
subgraph "回测引擎内部流程"
L --> P(feature_filter_gemini.py<br>硬性条件筛选);
P --> Q(factor_scoring_gemini.py<br>因子标准化与加权打分);
Q --> R(strategy_gemini.py<br>信号对齐 T -> T+1);
R --> S{回测循环 (逐日模拟)};
S -- "买入/卖出决策" --> T(交易策略模块);
T -- "应用" --> U["止盈/止損/排名/时间/凯利公式/落袋为安等"];
end
end
subgraph "3. 结果输出"
S --> V(输出至 /output);
V --> W[净值曲线 .png];
V --> X[回测报告 .json];
V --> Y[交易日志 .csv];
end
subgraph "A. 可拓展模块"
Z1(engineering.py<br><b>可在此处添加新因子</b>) -- "拓展" --> F;
end
style A fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#f9f,stroke:#333,stroke-width:2px
style K fill:#bbf,stroke:#333,stroke-width:2px
style M fill:#bbf,stroke:#333,stroke-width:2px
style N fill:#bbf,stroke:#333,stroke-width:2px
style Z1 fill:#9f9,stroke:#333,stroke-width:2px