)
簡介面向量化研究與金融工程從業(yè)者的專題報告圍繞如何借助ChatGPT從高頻價量數(shù)據(jù)中挖掘選股因子展開兼顧大語言模型原理、提示工程與策略回測。內(nèi)容先比較Transformer與LSTM的權重分配差異解釋Scaling Law與RLHF的三階段訓練再給出角色、任務、指令式提示模板及思維鏈提示方法實戰(zhàn)部分覆蓋周頻變異系數(shù)因子、日頻買賣盤力量因子以及用賣盤力量因子構(gòu)建中證1000指數(shù)增強策略并討論代碼生成與因子衰減風險。資源包共1個PDF文件約2.21MB便于集中閱讀與檢索。已有1359人學習適合希望把大模型用于因子研究、提示設計與策略驗證的讀者參考。1. 從一句「給我一個高頻選股因子」說起18 頁研報拆出了什么把 ChatGPT 當成因子生成器最常見的翻車方式是對著對話框敲一句「給我一個高頻選股因子」然后拿到一段看著像那么回事、跑起來全是 NaN 的回答。這份 18 頁的 Alpha 掘金系列第五篇做的正是把這件事從玄學拉回工程它記錄了從 Transformer 底座、提示工程寫法到周頻變異系數(shù)因子、高頻買賣盤力量因子再到中證 1000 指數(shù)增強策略的完整鏈路中間夾著 IC 表、多空凈值、調(diào)倉價格約定和手續(xù)費假設。適合三類人手里有 tick 數(shù)據(jù)但不知道怎么讓模型幫忙想因子的人、想復現(xiàn)一條從提示到策略的完整鏈路的人、以及被模型代碼坑過一次、想搞清楚邊界在哪的人。下面按「底座—提示—因子—策略—坑—驗證」的順序拆。2. 模型底座與提示工程自注意力、RLHF 三步和三段式提示怎么串起來這一章講的是「為什么這套模型值得你花時間去調(diào)提示而不是隨手問兩句就放棄」。很多人跳過原理直接問因子結(jié)果得到的回答永遠是反轉(zhuǎn)因子、動量因子這類教科書貨色然后得出結(jié)論「大模型不行」。問題往往不在模型而在你沒有給它足夠的結(jié)構(gòu)約束。理解它的底座和訓練方式才知道約束該加在哪一層。2.1 LSTM 的兩個硬傷與自注意力補的是什么研報里對傳統(tǒng) LSTM 的評價很直接兩大缺陷一是模型對文本中不同的詞無法區(qū)分重要程度沒法讓某些詞比其他的權重更高二是對長距離信息不能有效提取和記憶導致大量信息丟失。放到因子研究場景里這兩個缺陷的后果很具體——當你用一段話描述「過去 5 個交易日、收盤價與成交量的變異系數(shù)、取前十檔委托量」時LSTM 很難判斷「前十檔」這個詞比「過去」更關鍵也很難把句子開頭限定的「僅使用委托價和委托量」帶到句子末尾的公式上。Transformer 的引入解決了這件事核心是自注意力機制Self-attention mechanism通過跟蹤序列數(shù)據(jù)中的關系來學習上下文給輸入數(shù)據(jù)的不同部分賦予不同權重。這個機制對使用者的實際含義是你在提示里寫下的每一個限定條件理論上都會被模型按權重分配注意力。所以提示不是寫得越長越好而是要把關鍵約束放在能被高權重捕捉的位置——字段名、單位、數(shù)據(jù)范圍、計算公式這些要比客套話重要得多。對比項LSTM 處理提示文本Transformer 處理提示文本對寫提示的啟示詞權重各詞權重趨同按相關性分配權重關鍵約束要寫具體名詞別寫形容詞長距離依賴句尾容易丟句首條件跨句子保留條件限定條件可前置也可重復一次數(shù)據(jù)規(guī)模參數(shù)與數(shù)據(jù)承載有限可吃更大數(shù)據(jù)集模型「見過」的研報越多越容易照搬落到可執(zhí)行的一步寫因子提示時把數(shù)據(jù)字段用清單形式列出來而不是混在自然語言里。比如不要寫「用高頻的委托數(shù)據(jù)算一個因子」而是寫「可用字段為買一至買十價、買一至買十量、賣一至賣十價、賣一至賣十量共 40 列快照頻率 3 秒」。字段名一旦明確模型給出的公式才有落地的可能否則它只能給你「order_volume」這種在你表里根本不存在的列名。2.2 Scaling Law 與 RLHF 三步模型為什么愛說「聽起來對」的話研報把模型智能水平的來源歸到兩點參數(shù)數(shù)量提升帶來的涌現(xiàn)現(xiàn)象Scaling Law以及加入 RLHF人類反饋的強化學習帶來的對人類偏好理解的提升。參數(shù)演進這條線可以看得很清楚2018 年 6 月的 GPT-1 參數(shù)約 1.17 億2019 年 2 月的 GPT-2 到 15 億GPT-3 高達 1750 億2023 年 3 月的 GPT-4 把文本輸入拓展到圖片理解能力也顯著提升。這條線對使用者的意義不是「越大越好」而是模型見過的研報、論文、代碼越多它越傾向于復述已有的成熟因子這也是為什么不做約束時它只會給你反轉(zhuǎn)和動量。RLHF 的訓練分三步每一步都值得使用者留意。第一步從大量包含人類真實意圖的指令集合中采樣由 40 名標注人員對指令進行標注標注完成后對模型做微調(diào)。第二步再次從指令集采樣作為輸入讓模型給出多個不同結(jié)果由標注員對這些輸出的好壞順序做標注再用排序結(jié)果訓練一個打分模型Reward Model使輸出更貼近人類最需要的答案。第三步從指令集采樣新指令作為輸入根據(jù)打分模型進一步優(yōu)化輸出結(jié)合打分模型訓練得到最終模型。訓練步驟做的事對使用者的實際影響應對手法指令微調(diào)40 名標注員標注指令微調(diào)模型模型學會了「聽話」的格式提示要給明確格式要求如「只輸出公式和字段說明」排序訓練 Reward Model對多個輸出排序訓練打分模型模型偏向人類覺得「專業(yè)」的表達別被術語唬住逐個字段核對是否存在用 RM 優(yōu)化輸出按打分模型繼續(xù)優(yōu)化回答更流暢但可能犧牲可執(zhí)行性要求給出可運行的偽代碼并自行驗證這也解釋了研報里反復提到的一個現(xiàn)象模型在部分情況下可能回答錯誤不符合用戶需求與認知并影響判斷。Reward Model 優(yōu)化的是「人類覺得好」不是「代碼能跑」。我一般會把它當成一個知識面很廣但從不看你的數(shù)據(jù)庫 schema 的實習生——思路可以采納字段和口徑必須自己過一遍。2.3 三段式提示公式與思維鏈把「要個因子」問成可執(zhí)行規(guī)格研報給的標準提示公式是三個元素角色模型在文本生成任務中應扮演的角色、任務對需要生成的內(nèi)容做清晰簡潔的敘述、指令生成文本時應遵循的指令。一般形式為「作為一個【角色】按照這些指示生成【任務】【指令】」。最基礎的例子是客服場景「作為一名【客服人員】請生成【客戶詢問的回復】【這些回復應當專業(yè)、準確、簡潔】」。這個公式真正有用的地方在【角色】和【指令】兩處的加碼。研報里的做法是角色從「量化研究員」升級成「資深的量化研究員」指令從一句空話升級成三條硬約束——「該因子必須具有原創(chuàng)性、具有較強的邏輯支撐、且因子也應當有出色的業(yè)績表現(xiàn)」。再往下走一步把因子類別、構(gòu)建方式、使用數(shù)據(jù)也一并限定模型給出的東西才開始接近可測狀態(tài)。示例中模型不僅正確使用了逐筆成交數(shù)據(jù)里的字段還按提示要求給出了用計算均值做降頻的操作。# 三段式提示模板因子版可直接照抄改寫 角色你是一名有 5 年經(jīng)驗的 A 股量化研究員熟悉 Level-2 逐筆委托與 3 秒快照數(shù)據(jù)。 任務構(gòu)造一個用于中證 1000 成分股的選股因子輸出因子名稱、經(jīng)濟邏輯、計算公式、所需字段、降頻方式。 指令 1. 數(shù)據(jù)范圍僅限委托價與委托量不得使用成交額、財務數(shù)據(jù)、輿情數(shù)據(jù) 2. 因子必須在橫截面上可比若量綱不一致必須給出標準化步驟 3. 給出日頻與周頻兩種聚合口徑并說明哪種更可能保持有效性 4. 只輸出公式與字段說明不要輸出無法執(zhí)行的偽代碼。這段模板的關鍵改動有三處把角色從泛化身份收窄到具體數(shù)據(jù)環(huán)境把數(shù)據(jù)邊界寫成白名單而不是黑名單把輸出格式鎖死。參數(shù)上可以調(diào)的只有第 1 條的白名單范圍和第 3 條的頻率口徑其余部分建議固定下來方便多次生成后橫向比較。思維鏈提示Chain-of-Thought Prompting解決的是另一類問題。研報用 IC 指標的缺陷做了一次壓力測試兩個因子 IC 值分別為 0.22 和 0.25但 A 因子雖然 IC 較低、多頭表現(xiàn)較好B 因子 IC 較高、多頭組卻表現(xiàn)最差——按 IC 選因子會得到與實際相反的結(jié)果。直接問模型「怎么改進 IC 指標」它給不出切中要害的答案改用分步引導后模型先提出「每組內(nèi)分別計算 IC 值再求均值」被指出邏輯漏洞后才給出「計算加權平均 IC反映不同組對整體 IC 的貢獻」再提示 A 股存在做空限制模型最終給出「給做多組賦予更高權重」。這條鏈的價值不在結(jié)論而在流程復雜問題上不要一次性問結(jié)果要拆成「現(xiàn)象描述—初步方案—指出漏洞—補充約束—收斂」五步。研報也提醒模型處理實際問題時仍存在「生搬硬套」的現(xiàn)象需要不斷提示糾正。你把漏洞指出來它才會改你不指它就當沒這回事。3. 周頻變異系數(shù)因子5 日滾動口徑下的四張 IC 表與一個反直覺結(jié)果這是整份研報里最容易復現(xiàn)的一段因為只用日頻量價數(shù)據(jù)。它的價值也不在因子本身多強——多頭超額只有 2.75%——而在于它完整展示了一條「提示產(chǎn)出因子 → 構(gòu)造 → 測試 → 判斷能不能用」的鏈路以及一個很多人會誤讀的結(jié)果IC 顯著不等于策略能賺錢。3.1 四個公式與 5 日滾動口徑的實際寫法研報里模型給出的原始思路是在收盤價和成交量兩個領域分別計算變異系數(shù)再相乘得到綜合選股因子用來衡量股票的波動性和流動性。研究者在此基礎上做了一次變形把兩者相除得到新的變異系數(shù)因子。四個口徑分別是LI σ_price / μ_price價格變異系數(shù)VLI σ_vol / μ_vol成交量變異系數(shù)LIxVLI LI × VLI乘積因子LI2VLI LI / VLI比值因子數(shù)據(jù)口徑是日頻量價取過去 5 天的價格和成交量變異系數(shù)進行計算測試區(qū)間 2016 年至 2022 年 8 月股票池為中證 1000 指數(shù)成份股周度調(diào)倉每周初開盤價買入、每周最后一個交易日收盤價賣出。import numpy as np import pandas as pd def cv_factor(df, price_colclose, vol_colvolume, window5): df: 單只股票的日頻數(shù)據(jù)必須含 trade_date / close / volume按日期升序 window: 滾動窗口研報口徑為 5 個交易日 返回: 含 LI / VLI / LIxVLI / LI2VLI 四列 g df.sort_values(trade_date).copy() roll g[price_col].rolling(window, min_periodswindow) # ddof0 與研報的總體標準差口徑一致改成 1 會讓小樣本窗口的因子值整體偏大 li roll.std(ddof0) / roll.mean() vroll g[vol_col].rolling(window, min_periodswindow) vli vroll.std(ddof0) / vroll.mean() out pd.DataFrame({ trade_date: g[trade_date].values, LI: li.values, VLI: vli.values, }) out[LIxVLI] out[LI] * out[VLI] # 除零保護停牌或極端縮量時 VLI 可能為 0直接除會得到 inf 污染整個截面 out[LI2VLI] out[LI] / out[VLI].replace(0, np.nan) return out參數(shù)上有三個地方值得說清楚。window5是研報設定改大之后因子會更平滑但衰減更慢做周頻調(diào)倉時窗口和調(diào)倉周期最好錯開否則會出現(xiàn)「用本周數(shù)據(jù)算本周信號」的隱性問題。min_periodswindow保證前 4 天不出值避免半窗口因子混進截面。ddof0是總體標準差樣本量只有 5 時用ddof1會讓因子值系統(tǒng)性偏大約 12%雖然對排序影響有限但和研報數(shù)值對不上時先查這里。3.2 面板對齊與調(diào)倉價格未來函數(shù)最容易藏在這三步單只股票算完只是第一步真正容易翻車的是把幾千只股票拼成截面、再和周度調(diào)倉對齊。研報的約定是每周初開盤價買入、每周最后一個交易日收盤價賣出這意味著周一開盤用的信號必須完全來自上周五收盤之前的數(shù)據(jù)。落到代碼上有三個動作先在日頻上算因子再取每周最后一個交易日的因子值作為下周信號最后把信號整體往后移一期。# 1) 日頻因子 - 每周最后一個交易日的快照此時該周數(shù)據(jù)已全部可得 factor_weekly (factor_daily .set_index(trade_date) .groupby(symbol) .resample(W-FRI).last() .reset_index()) # 2) 關鍵一步信號后移一期周一開盤只能看到上周五的信號 factor_weekly[signal] (factor_weekly .groupby(symbol)[LI2VLI] .shift(1)) # 3) 交易價格周一開盤買入當周最后交易日收盤賣出 px price_daily.set_index(trade_date) buy_px px.groupby(symbol)[open].resample(W-MON).first() sell_px px.groupby(symbol)[close].resample(W-FRI).last()resample(W-FRI)取的是每周最后一個交易日遇到節(jié)假日會自動落到前一個交易日這一點比手寫「周五」安全。shift(1)是按股票分組的漏掉groupby會讓信號串到別的股票上這是我自己踩過的坑——回測收益突然變得好得離譜查了兩天才發(fā)現(xiàn)是跨股票錯位。買賣價格分開取而不是統(tǒng)一用收盤價是因為研報明確用了周初開盤買、周末收盤賣這兩個價格之間的差異在高波動周能吃掉一多半超額。3.3 IC 表和凈值表放在一起看才知道因子能不能用研報給出的 IC 結(jié)果是這樣的LI 均值 -5.36%T 統(tǒng)計量 -8.07VLI 均值 -2.79%T 值 -7.53LIxVLI 均值 -5.29%T 值 -10.74LI2VLI 均值 -3.11%T 值 -4.69。四個因子的 T 值絕對值全部大于 2按常規(guī)標準都算顯著。研報的解釋是價格和成交量的波動率均為越低越好基本符合低波動異象。但把多空組合指標擺上來故事就變味了因子多空年化收益多空波動率夏普最大回撤多頭年化超額LI8.35%16.42%0.5131.43%-1.09%VLI8.40%9.75%0.8620.04%2.75%LIxVLI8.89%12.46%0.7127.58%0.74%LI2VLI2.06%15.87%0.1335.14%0.74%除 LI2VLI 外其余因子的多空曲線走勢較為平穩(wěn)多空年化收益在 8% 出頭看著還行。但真正要關注的是多頭組合年化超額——LI 是 -1.09%最好的 VLI 也只有 2.75%多頭夏普 0.17。研報的結(jié)論很克制因子 IC 指標整體表現(xiàn)較好但多頭表現(xiàn)欠佳因子單調(diào)性整體不夠明顯難以成功構(gòu)建投資策略。這里有個特別容易被誤讀的點。IC 為負、T 值顯著只說明「因子值越低、未來收益越高」這個排序關系在全截面上成立它衡量的是整條排序曲線的相關性而多頭超額只看最上面那一組的絕對表現(xiàn)。一個因子完全可能在全截面上排得很準但最頂端那一組的超額被交易成本、行業(yè)分布、市值暴露吃得干干凈凈。A 股不能做空多空凈值曲線再漂亮拿不到多頭那一端就等于沒有。所以看到「IC 顯著」四個字先別高興把多頭超額那一列單獨拉出來看這一條對后面高頻因子同樣適用。4. 高頻買賣盤力量因子3 秒快照前十檔到中證 1000 增強的 7.17%周頻因子那一節(jié)的結(jié)論偏負面但它的存在意義是給高頻因子做對照。研報選高頻的理由寫得很清楚利用高頻數(shù)據(jù)構(gòu)建選股因子是當前市場關注度較高的領域擁擠度相對較低且此類數(shù)據(jù)所能挖掘到的因子往往與傳統(tǒng)因子有一定獨立性。換句話說這條路的性價比在「獨立性」上不在「更容易」上。4.1 從委托價與委托量到 BSForce 的公式推導研報對模型限定了數(shù)據(jù)使用范圍——只能結(jié)合高頻數(shù)據(jù)里獨有的委托量和委托價并要求因子有一定原創(chuàng)性。經(jīng)過引導后模型給出的是買賣盤力量因子。原始公式直接用量乘以價差但研究者發(fā)現(xiàn)邏輯上有問題不做標準化的話高價股的因子值會天然大于低價股橫截面上根本不可比于是做了修正BForce BVol × (1 ? price_bid / price)SForce SVol × (price_ask / price ? 1)BSForce (BForce ? SForce) / (BForce SForce)其中 BVol 和 SVol 分別代表買盤和賣盤的委托量price_bid 和 price_ask 是委托價price 作為基準價。分母的 BForce SForce 讓因子落在 [-1, 1] 區(qū)間這正是橫截面可比的關鍵。import numpy as np import pandas as pd BID_PX [fbid_px{i} for i in range(1, 11)] # 買一至買十價 BID_VOL [fbid_vol{i} for i in range(1, 11)] # 買一至買十量 ASK_PX [fask_px{i} for i in range(1, 11)] ASK_VOL [fask_vol{i} for i in range(1, 11)] def snapshot_force(df): df: 某只股票某個交易日的 3 秒快照需含上述 40 列 返回: 該日每一條快照的 BForce / SForce單位與委托量一致 bid_px df[BID_PX].to_numpy(dtypefloat64) bid_vol df[BID_VOL].to_numpy(dtypefloat64) ask_px df[ASK_PX].to_numpy(dtypefloat64) ask_vol df[ASK_VOL].to_numpy(dtypefloat64) # 基準價用買一賣一中間價避免用最新成交價時把買賣價差算成因子的一部分 mid (bid_px[:, 0] ask_px[:, 0]) / 2.0 b_force bid_vol * (1.0 - bid_px / mid[:, None]) s_force ask_vol * (ask_px / mid[:, None] - 1.0) # 十檔求和研報口徑是對前十檔分別求值后聚合 return pd.DataFrame({ BForce: b_force.sum(axis1), SForce: s_force.sum(axis1), })三個參數(shù)細節(jié)。第一基準價研報公式里寫的是 price實操中用中間價更穩(wěn)直接用最新成交價會把買賣價差混進因子導致因子的一部分收益來自價差而不是力量失衡。第二十檔求和還是求均值研報原文是「分別求出前十檔的買入委托價、買入委托量和賣出委托價、賣出委托量最終每個交易日求出均值」實測下來求和與均值對排序結(jié)果影響不大但求和會讓因子值的量綱隨股票規(guī)模大幅波動我在截面回歸前一般會再做一次去極值和標準化。第三mid[:, None]這個廣播維度不要寫錯寫反了會得到 40×40 的矩陣跑得慢還不報錯。4.2 tick 清洗與日頻聚合這四類快照必須剔掉把逐條快照聚合成日頻因子中間隔著清洗這一步。常見的四類要剔除集合競價時段的快照十檔委托往往不全且沒有連續(xù)撮合、漲跌停板上的快照買盤或賣盤會掛出天量直接污染當日均值、停牌與長時間無更新的快照重復值會把均值往一邊拽、以及買一價或賣一價缺失的快照。def daily_force(snapshots): snapshots: 單只股票單日的全量快照已按時間升序 s snapshots.copy() # 剔除集合競價只保留連續(xù)競價時段 s s[(s[time] 09:30:00) (s[time] 14:57:00)] # 剔除漲跌停用當日漲跌停價判斷買一價等于漲停價即封板 s s[s[bid_px1] s[limit_up]] s s[s[ask_px1] s[limit_down]] # 剔除缺檔快照 s s.dropna(subset[bid_px1, ask_px1]) f snapshot_force(s) daily f.mean() # 當天所有快照求均值得到日頻因子 daily[BSForce] (daily[BForce] - daily[SForce]) / \ (daily[BForce] daily[SForce]) return daily研報的做法是對每只股票每天 3 秒快照數(shù)據(jù)分別求前十檔的委托價、委托量和委托價均值最終每個交易日求出均值得到買盤力量、賣盤力量和買賣盤力量差異因子。這里有個隱含假設日內(nèi)快照的算術平均能代表當天的力量水平。如果你發(fā)現(xiàn)因子在震蕩市里表現(xiàn)明顯變差可以試試改成分時段加權或取尾盤 30 分鐘均值本質(zhì)是在處理「日內(nèi)信息分布不均勻」這件事。4.3 日頻測試結(jié)果與衰減速度夏普 4.51 為什么不能直接用日頻測試區(qū)間是 2016 年 1 月至 2022 年 8 月股票池為中證 1000 指數(shù)成份股以次日開盤價作為買入價格。IC 結(jié)果BForce 均值 -0.24%T 值 -0.61SForce 均值 -1.02%T 值 -2.87BSForce 均值 1.13%T 值 7.00。買賣盤力量差異因子的顯著性明顯高于單邊因子。因子多空年化收益多空波動率夏普最大回撤多頭年化超額BForce18.74%19.47%0.9635.25%11.17%SForce4.06%18.88%0.2238.71%6.57%BSForce37.00%8.21%4.514.88%17.29%BSForce 的多空夏普 4.51、最大回撤 4.88%這個組合在所有測試里是最漂亮的。但研報緊接著給了一句關鍵判斷日頻調(diào)倉的成本過高對實際投資的盈利水平影響較大難以獲得實際收益而且 BSForce 衰減速度過快在第二天基本已經(jīng)失效。于是只把買盤力量和賣盤力量因子降到周頻測試在中證 1000 成份股上每周第一個交易日開盤價成交。降頻之后的結(jié)果明顯下來了BForce 多頭年化超額 9.77%SForce 10.20%雖然整體多空單調(diào)性一般但多頭組合表現(xiàn)尚可。研報最終選了相對表現(xiàn)更好的賣盤力量因子來構(gòu)建中證 1000 指數(shù)增強策略在單邊千分之二的手續(xù)費率下年化超額收益率 7.17%信息比率 0.57。這條鏈路里最值得記住的是「衰減」這兩個字。BSForce 的日頻夏普 4.51 是真的但它依賴的是買賣盤失衡在次日開盤前的短暫定價偏差一旦把調(diào)倉頻率降到周頻、或者把費率提到千二收益就會被交易成本和信號失效兩頭夾擊。高頻因子的夏普要打兩個折扣一個是換手率折扣一個是衰減折扣。研報的處理方式很務實——不硬扛日頻直接降頻看還剩多少剩下的那部分才是能裝進產(chǎn)品的。4.4 指數(shù)增強的落地7.17% 超額背后有哪些約束用賣盤力量因子做中證 1000 增強年化超額 7.17%、IR 0.57這個數(shù)字在單邊千二費率下不算驚艷但對一個依賴高頻委托數(shù)據(jù)的單因子策略來說已經(jīng)是可用的起點。落地時有幾個約束必須明確寫進流程否則回測和實盤的差距會比這 7.17% 大得多。環(huán)節(jié)需要固定的口徑常見錯誤股票池中證 1000 成分股按調(diào)倉日前一交易日名單用當前成分股回溯引入幸存者偏差權重約束個股相對基準的主動權重上限、行業(yè)中性只做市值加權行業(yè)暴露吃掉超額換手控制單期換手上限、緩沖帶因子排名小幅變動就全額調(diào)倉費率吞掉收益費率假設單邊千分之二含印花稅與沖擊成本用萬分之一估算回測虛高我在復現(xiàn)這類策略時習慣先把費率調(diào)到單邊千分之三跑一遍如果超額還剩一半以上才認為這個因子有實用價值。研報給的是千二這是一個偏樂觀但不離譜的假設真實沖擊成本取決于你的資金規(guī)模和下單方式小資金可以更樂觀大資金必須往下打折。5. 避坑排查因子挖掘鏈路上五類翻車現(xiàn)場這一章是我認為整份研報最該反復看的部分——不是因為它寫了什么而是因為它沒寫、但你在復現(xiàn)時一定會撞上的東西。下面五條按「現(xiàn)象 → 原因 → 解決」展開每一條都對應研報里的某個具體口徑。第一條因子公式完全照抄多空凈值卻是一條水平線?,F(xiàn)象是代碼不報錯、因子值也有但分組收益全為 0 或者完全隨機。原因通常出在價格口徑上研報的委托價是快照里的買一賣一而很多人拿到的是逐筆成交的成交價兩者差一個買賣價差而這個價差恰恰是因子收益的主要來源另一個常見原因是復權——用未復權價算 LI 和 VLI除權日當天價格跳空會讓變異系數(shù)瞬間翻倍這個異常值會污染整個截面。解決方式是把字段映射表先寫出來逐列核對單位手還是股、時點快照時間戳還是交易所推送時間、復權方式前復權還是后復權再動手算因子。我一般會在算因子前先跑一遍數(shù)據(jù)體檢每一天的截面股票數(shù)、缺失率、因子值的 1% 和 99% 分位這三項里任何一項異常都說明數(shù)據(jù)沒對齊。第二條IC 顯著為正多頭組卻跑輸基準?,F(xiàn)象和第三章周頻因子完全一致T 值大于 2多空曲線平穩(wěn)向上但把空頭那一半去掉剩下的多頭超額是負的。原因是 IC 衡量的是整條排序曲線的秩相關它對中間段和空頭段同樣敏感而實際組合只能買多頭。解決方式是在看 IC 的同時強制看三個數(shù)多頭組年化超額、多頭組夏普、以及分組收益的單調(diào)性。研報里 LI 因子多空年化 8.35%、多頭超額 -1.09%就是典型的「空頭貢獻全部收益」。如果多頭超額為負而多空為正這個因子在 A 股基本沒有獨立使用價值只能作為多因子的對沖腿或者風險因子。第三條回測收益高得離譜一查是未來函數(shù)?,F(xiàn)象是年化收益 50% 以上、最大回撤個位數(shù)、夏普超過 3。原因幾乎總是信號和交易時點錯位常見的三種用當日收盤價算因子、當日收盤價買入用周頻resample之后忘記shift導致周一用了本周五的數(shù)據(jù)以及在截面標準化時用了全樣本均值而不是滾動窗口把未來信息漏進了歷史。解決方式是做一次「時間機器測試」——把回測的結(jié)束日期往前挪一年重跑如果曲線形狀大幅變化說明有前視再做一個「隨機信號對照」用同分布的隨機數(shù)替代因子值跑同樣的流程正常應該得到接近 0 的超額如果隨機信號也能跑出正超額說明流程里有系統(tǒng)性的泄漏。第四條照抄模型給的代碼運行報列名錯誤?,F(xiàn)象是KeyError或者跑出來的因子全是 NaN。原因是模型生成的代碼用的是通用列名close、volume、bid_price而你的表里可能是last_px、total_vol、bp1或者模型默認了「買一到買十」的列順序而你的數(shù)據(jù)是「賣一到賣十在前」。研報里也提到模型針對常用的量化研究所需框架和函數(shù)能較準確地給出結(jié)果但使用時需要注意代碼細節(jié)確保符合實際需求對模型給的代碼做微調(diào)可以大幅提升研究效率。解決方式很樸素讓模型先輸出字段映射表再輸出代碼拿到代碼后第一件事不是跑而是把每個df[...]里的列名對著自己的 schema 過一遍。我現(xiàn)在的習慣是在提示末尾固定加一句「代碼中所有列名必須來自我給出的字段清單不得自創(chuàng)」。第五條因子第二天就失效但沒人測過衰減曲線。現(xiàn)象是日頻回測夏普 4.51改成周頻調(diào)倉后收益腰斬實盤更差。原因是這類委托量因子捕捉的是極短周期的供需失衡研報明確寫了 BSForce 在第二天基本已經(jīng)失效只有 BForce 和 SForce 降頻后還能保留 9.77% 和 10.20% 的多頭超額。解決方式是在因子測試階段就加一張衰減表分別用 T1、T2、T3、T5 的收益算 IC看 IC 衰減到一半需要幾天。如果半衰期只有 1 天這個因子就只能做日內(nèi)或 T1任何周頻組合都是在賭如果半衰期超過 5 天才值得考慮降頻使用。這張表的成本很低但能省掉后面幾個月的無效優(yōu)化。6. 進階驗證把模型給的代碼壓進一條可復跑的研究流水線模型給的代碼能跑通只是及格線能復跑、能對照、能證偽才算過關。我在這類項目上固定跑三步驗證每一步都設了通過標準任何一步不過就不往下走。驗證步驟具體做法通過標準不通過怎么辦隨機因子對照用同分布隨機數(shù)替換因子值跑完整流程多頭超額在 ±1% 內(nèi)查信號對齊、查費率、查分組邏輯衰減曲線用 T1 到 T5 收益分別算 IC半衰期覆蓋目標調(diào)倉周期縮短調(diào)倉周期或換因子費率敏感性單邊費率從萬五到千三各跑一遍千三下超額仍為正加換手約束或降低調(diào)倉頻率隨機因子對照這一步最容易被跳過但它能抓出 90% 的流程性錯誤。研報里 BSForce 的多空夏普 4.51 看著誘人我用隨機信號跑同樣流程時曾得到過 0.8 的夏普一查是分組時用了未來一期的行業(yè)分類——這類錯誤不會報錯只會讓你的因子看起來特別好。第二個習慣是給每個因子寫一行「墓志銘」數(shù)據(jù)來源、構(gòu)造公式、測試區(qū)間、股票池、調(diào)倉頻率、費率假設、多頭超額、半衰期八個字段一張表。研報里的四個變異系數(shù)因子和三個力量因子我全部按這個格式記了一份后來發(fā)現(xiàn)真正能進組合的只有兩個其余的在第二步衰減曲線就掛了。沒有這張表三個月后你連自己測過什么都沒印象。第三個是模型輸出的歸檔。每次讓模型生成因子把完整提示、原始回答、你改了什么、改完的測試結(jié)果一起存下來。研報里那次思維鏈糾偏用了五輪提示才收斂到「給做多組更高權重」這個糾偏過程本身就是資產(chǎn)——下次遇到類似問題可以直接從第三輪開始問不用從零磨。說個自己的教訓。早期復現(xiàn)高頻因子時我看到 BSForce 日頻夏普 4.51 就直接上了周頻組合結(jié)果實盤第一周就發(fā)現(xiàn)換手率高得離譜千二費率吃掉了大部分超額回頭才去補衰減曲線和費率敏感性兩張表。從那以后我每次拿到一個新因子不管夏普多漂亮都強制先走一遍「隨機對照—衰減曲線—費率敏感性」這三步一步都不跳。希望幫到你。本文還有配套的精品資源點擊獲取