)
如何開通基于 AI 打造的 A 股量化策略上三層策略骨架與代碼落地“AI量化”這四個字最近幾乎快被說爛了。但真有人問“那我到底該怎么從零開始搭一套能跑的AI量化策略”絕大多數(shù)人給出的答案要么是讓你去看機器學(xué)習(xí)課程要么是丟給你一個封裝好的黑盒框架跑完回測數(shù)據(jù)很好看真到實盤卻完全不是那么回事。這篇文章不講虛的我直接分享我拉通“AI A股量化”時踩出來的那條完整鏈路。今天先解決最核心的一件事先把三層策略骨架搭起來——信號層負(fù)責(zé)“買什么、賣什么”風(fēng)控層負(fù)責(zé)“買多少、多少止損”執(zhí)行層負(fù)責(zé)“成交清不清楚、滑點控制沒控制”最后附上能直接改的 Python 代碼。這篇主要面向兩類人一類是有一定 Python 基礎(chǔ)、想正經(jīng)入行量化但不知道第一行代碼寫哪的另一類是已經(jīng)手寫過簡單均線策略、但發(fā)現(xiàn)“加了一個AI模型之后就不知道怎么和原來那套交易邏輯拼起來”的朋友。看完你至少能搭出一個從“行情數(shù)據(jù)進”到“委托單出”的完整策略雛形跑通一次模擬盤閉環(huán)。1. 三層策略骨架先想清楚系統(tǒng)怎么解耦1.1 為什么我們最先搭骨架而不是先找模型很多人一上來就抱著“我要用深度學(xué)習(xí)預(yù)測股價”的心態(tài)開始寫代碼結(jié)果通常都在數(shù)據(jù)清洗階段就放棄了。我自己的教訓(xùn)是A股量化、特別是偏中低頻的策略真正的挑戰(zhàn)從來不是“模型不夠聰明”而是“當(dāng)一個信號產(chǎn)生時整個鏈路能不能干凈、及時、可控地把它變成一筆交易”。最早我寫策略所有邏輯堆在一個文件里拉數(shù)據(jù)、算因子、出信號、算倉位、模擬下單全揉在一起。初看挺爽改個參數(shù)重跑一遍也就幾分鐘。但問題很快暴露回測和模擬盤的邏輯混在一起模型一旦要換特征或者想對比兩套止損規(guī)則就得復(fù)制粘貼一大堆代碼改到后面自己都分不清哪段邏輯在生效。后來我把系統(tǒng)重新按三層拆開整個思路瞬間就清晰了信號層根據(jù)數(shù)據(jù)輸入輸出一個“看好/看淡/中性”的判斷以及對應(yīng)的置信度。風(fēng)控層拿到信號和當(dāng)前持倉輸出“今天實際要交易多少倉位、觸發(fā)什么條件必須撤”。執(zhí)行層根據(jù)風(fēng)控層的指令結(jié)合盤口和費用約束生成實際委托單。三層之間要數(shù)據(jù)流向下傳遞不反向依賴。因為只有把這三層徹底解耦你才能做到“換一個模型不換風(fēng)控、換一套風(fēng)控不動信號、改一個執(zhí)行參數(shù)不影響策略邏輯”。1.2 信號層解決“買什么、賣什么”信號層是整個策略的“大腦”它的輸入是行情、基本面、輿情、乃至盤口數(shù)據(jù)輸出是方向判斷和強度打分。注意這里的輸出不直接等同于買入或賣出它更像一個“分析師”只表達(dá)觀點不負(fù)責(zé)動手。為什么要把“觀點”和“決策”分開因為在實操中你會發(fā)現(xiàn)AI模型給出的原始輸出往往是很原始的數(shù)值比如某個分類概率、回歸預(yù)測的期望收益率。如果直接把這種數(shù)值拿去下單經(jīng)常會遇到“模型說漲2%結(jié)果倉位算出來占用了90%資金”的荒謬情況。所以信號層一般還要做一道“語義化”加工把模型的數(shù)值輸出映射成1看好、-1看淡、0觀望三檔同時附帶一個0到1的置信度供風(fēng)控層使用。我第一次搭信號層時犯過一個典型錯誤直接把 XGBoost 的分類概率當(dāng)信號概率大于0.5就買入概率小于0.5就賣出。看上去很合理但實際回測下來換手率極高手續(xù)費把收益全吃光了。后來我在信號到交易的中間加了一個“死區(qū)”dead zone概率在0.55到0.6之間統(tǒng)統(tǒng)觀望才把換手壓下來。這就是信號層存在的意義——它天然承擔(dān)了“過濾噪音”的責(zé)任。1.3 風(fēng)控層解決“買多少、什么時候撤離”風(fēng)控層是很多散戶寫策略時最不重視、但對長期收益影響最大的一層。它要回答三個問題第一給定信號的置信度當(dāng)前應(yīng)該下多少倉位第二持倉萬一走反什么價位必須止損第三整個賬戶凈值回撤到什么程度策略必須降杠桿甚至停擺。這一層設(shè)計得好不好直接決定策略的“存活率”。我見過不少剛?cè)胄械呐笥研盘柲P妥龅梅浅;ㄉ贚STM加注意力機制都用上了但倉位永遠(yuǎn)是單票滿倉止損從來不止結(jié)果一次極端行情就回到解放前。其實A股本身有漲跌停、T1、部分股票流動性一般等約束風(fēng)控層如果不能主動去適應(yīng)這些規(guī)則再聰明的信號也救不了賬戶。風(fēng)控層的一個核心思想是所有風(fēng)控規(guī)則必須獨立于當(dāng)前信號。你不能因為“這個信號特別強”就臨時跳過止損線那是情緒化交易的根源。我在代碼里實現(xiàn)風(fēng)控層的習(xí)慣是先讓所有規(guī)則“無腦執(zhí)行”哪怕空倉也要跑一遍風(fēng)控檢查邏輯——這樣能保證規(guī)則的完備性不會在極端行情下被漏掉。1.4 執(zhí)行層解決“以什么成本買到”執(zhí)行層是最容易被新手忽略、但同樣是最能體現(xiàn)系統(tǒng)是否“開通”了的一環(huán)。信號層說“可以買”、風(fēng)控層說“買3成倉位”執(zhí)行層要負(fù)責(zé)把它變成“明天開盤后以不超過XX價格買入XX股”這樣一條可落地的委托。A股的執(zhí)行約束非常多最小交易單位是100股科創(chuàng)板是200股起、之后按1股遞增、買入申報價不能超過漲停價、T1規(guī)則下當(dāng)天買進的股票當(dāng)天不能賣。這些細(xì)節(jié)如果不在執(zhí)行層處理好回測里利潤豐厚實盤一跑就各種廢單。所以完整的執(zhí)行層應(yīng)當(dāng)至少包含根據(jù)可用資金和最小交易單位計算真實買入數(shù)量根據(jù)當(dāng)前價和可容忍滑點計算限價根據(jù)T1規(guī)則判斷某只票是否真的“可賣”必要時把大單拆成小單避免對流動性不足的標(biāo)的造成沖擊。2. 數(shù)據(jù)準(zhǔn)備與AI信號生成讓模型先能“開口說話”2.1 數(shù)據(jù)源的接入與清洗三層骨架里信號層的第一步是拿到干凈的數(shù)據(jù)。對A股日線級策略來說最基礎(chǔ)的數(shù)據(jù)就是“OHLCV”開盤、最高、最低、收盤、成交量。國內(nèi)有很多開源數(shù)據(jù)接口數(shù)據(jù)質(zhì)量參差不齊我建議優(yōu)先選擇提供“前復(fù)權(quán)”數(shù)據(jù)的接口。原因很簡單如果股票發(fā)生過除權(quán)除息不復(fù)權(quán)的K線會出現(xiàn)向下的跳空缺口直接拿去算收益率特征會得到大量虛假的“暴跌”信號。用前復(fù)權(quán)數(shù)據(jù)處理歷史回測再用“不復(fù)權(quán)價格 除權(quán)除息日修正”來撮合模擬盤是業(yè)界基本打法。拿到數(shù)據(jù)后我一般還會做三層清洗剔除上市不足半年的次新股這些股上市初期波動異常很多因子會失真。剔除ST和長期停牌股它們流動性差、漲跌停規(guī)則特殊初期接入容易帶偏整體評估。對齊交易自然日把行情數(shù)據(jù)按交易日對齊非交易日的數(shù)據(jù)如果接口返回了直接丟棄。第一步的數(shù)據(jù)加載不用寫太多花活核心是把“日期索引 前復(fù)權(quán)價格 成交量”整理好供因子計算使用。import pandas as pd def load_daily_data(code, start2018-01-01, end2024-12-31): # 這里是一個典型的開源數(shù)據(jù)接口封裝示意實際使用時換成你的數(shù)據(jù)源即可 df get_daily_price(code, start_datestart, end_dateend, adjustqfq) df df[[date, open, high, low, close, volume]].copy() df[date] pd.to_datetime(df[date]) df df.set_index(date).sort_index() # 剔除停牌日成交量或成交額為0的行 df df[(df[volume] 0) (df[close] 0)] return df2.2 特征工程與標(biāo)簽構(gòu)造有了K線數(shù)據(jù)下一步是構(gòu)造特征。特征不用貪多我一開始只用了三組動量類過去5、10、20個交易日的累計收益率衡量趨勢強度。波動類近10、20日收益率標(biāo)準(zhǔn)差衡量不確定性。量價配合類近5日量能變化率和價格變化率的比值衡量放量上漲還是縮量下跌。這三組特征加起來不到10個足夠讓模型學(xué)出一些簡單的非線性關(guān)系。真正重要的是標(biāo)簽怎么構(gòu)造。我的經(jīng)驗是用“未來5個交易日收益率為正與否”作為二分類標(biāo)簽比“未來1日收益率方向”穩(wěn)定得多。5日窗口能過濾掉大量日內(nèi)噪音也更貼近A股投資者真實持有周期。標(biāo)簽構(gòu)造有一個最關(guān)鍵的細(xì)節(jié)防止未來函數(shù)泄漏。當(dāng)你用第T日的數(shù)據(jù)做特征去預(yù)測第T1到T5日的收益方向時標(biāo)簽里絕對不能包含第T日當(dāng)天收盤前無法獲得的信息。很多初學(xué)者在同一個DataFrame里既算特征又算標(biāo)簽忘記用shift把標(biāo)簽整體往后挪一天導(dǎo)致回測時模型“偷看”了未來數(shù)據(jù)。這類泄漏在實盤里根本無法復(fù)制屬于量化新手最容易踩的暗坑。def build_dataset(df): x df.copy() x[ret_1] x[close].pct_change() x[ret_5] x[close].pct_change(5) x[ret_10] x[close].pct_change(10) x[ret_20] x[close].pct_change(20) x[vol_10] x[ret_1].rolling(10).std() x[vol_20] x[ret_1].rolling(20).std() x[vol_ratio] x[volume] / x[volume].rolling(5).mean() x[price_vol_ratio] x[ret_5] / (x[vol_10] 1e-8) # 標(biāo)簽未來5日收益率是否為正。shift(-5) 表示取未來第5天的收益 x[future_ret] x[close].shift(-5) / x[close] - 1 x[label] (x[future_ret] 0).astype(int) # 特征必須在T日收盤時可得所以特征本身不需要shift # 但建模時要讓模型用T日特征預(yù)測T1T5的標(biāo)簽這里通過時序切分控制 return x.dropna()2.3 用XGBoost生成方向信號特征和標(biāo)簽準(zhǔn)備好之后模型選型我推薦先用 XGBoost。很多人覺得AI量化必須上深度學(xué)習(xí)其實中低頻表格數(shù)據(jù)場景樹模型往往更快、更穩(wěn)、更好解釋。我拿LSTM和XGBoost在同樣特征集上比過XGBoost的 AUC 普遍高一些而且調(diào)參成本低得多。訓(xùn)練時我用了一個非常重要的切分方式時間序列按順序切而不是隨機切。因為股價數(shù)據(jù)天然是時序的如果隨機把未來某一年數(shù)據(jù)混進訓(xùn)練集相當(dāng)于模型提前見到了“答案”。我的習(xí)慣是前70%做訓(xùn)練、中間15%做驗證、最后15%做測試驗證集用來調(diào)超參數(shù)和確定買入閾值測試集只在最后跑一次避免反復(fù)試出來的“看上去很美”的結(jié)果。from xgboost import XGBClassifier features [ret_1, ret_5, ret_10, ret_20, vol_10, vol_20, vol_ratio, price_vol_ratio] full build_dataset(load_daily_data(000001)) train_end int(len(full) * 0.7) valid_end int(len(full) * 0.85) x_train, y_train full.iloc[:train_end][features], full.iloc[:train_end][label] x_valid, y_valid full.iloc[train_end:valid_end][features], full.iloc[train_end:valid_end][label] x_test, y_test full.iloc[valid_end:][features], full.iloc[valid_end:][label] model XGBClassifier(max_depth3, n_estimators100, learning_rate0.05, subsample0.8, random_state42) model.fit(x_train, y_train)這里我特意把random_state固定。為什么A股行情是確定的但模型訓(xùn)練過程中存在隨機性如果你不固定隨機種子今天跑出一個結(jié)果、明天跑出另一個結(jié)果后面所有風(fēng)控參數(shù)調(diào)整都會變得毫無意義。固定隨機種子是最基本、也最容易被忽略的實驗紀(jì)律。2.4 從模型概率到交易信號模型輸出的是“未來5日上漲”的概率不能直接拿來下單。我的做法是把它轉(zhuǎn)換成一個帶死區(qū)的離散信號。具體來說在驗證集上跑出所有樣本的概率分布然后挑選兩個閾值當(dāng)概率大于等于0.62時給1看多概率小于等于0.42時給-1看空中間一律給0觀望。這兩個閾值不是拍腦袋定的而是讓驗證集的F1分?jǐn)?shù)盡量高、同時換手率盡量低。這一步本質(zhì)上是壓縮模型的自由度模型不必每一次都給出明確觀點一個“猶豫”的0信號能夠大幅減少無效交易帶來的摩擦成本。prob model.predict_proba(x_valid)[:, 1] k_threshold_high 0.62 # 得在驗證集上反復(fù)調(diào) k_threshold_low 0.42 signal pd.Series(0, indexx_valid.index) signal[prob k_threshold_high] 1 signal[prob k_threshold_low] -1這里也順帶說明一個我常被問到的問題為什么閾值設(shè)得這么不對稱因為A股有T1約束和做空限制沒有辦法直接做空所以“看空信號”更適合被解釋為“空倉等待”而不是“賣出做空”。這樣一來看空閾值可以設(shè)得保守一些只有模型非常有把握時才應(yīng)該清倉而看多閾值對應(yīng)的是可以入場的較強預(yù)期需要兼顧置信度和交易次數(shù)。3. 風(fēng)控與倉位管理保證策略的“活下去”3.1 倉位計算公式信號層輸出之后風(fēng)控層要接住。我最常用的倉位模型是基于“置信度縮放”的固定比例倉位先定一個單票最大倉位上限比如10%然后乘以信號置信度得到實際倉位。置信度我用的是模型概率與閾值之間的“距離”距離越大說明模型越有把握持倉可以略微加重距離小則只給底倉。舉個例子看多閾值為0.62當(dāng)前概率0.8距離是0.18那么倉位調(diào)整系數(shù)可以是1 0.18 * 2 1.36再乘上最大倉位10%得到約13.6%的倉位如果概率只有0.63距離很小那倉位就只有10%附近。這么做的好處是模型大部分時間不會滿配一旦行情超出預(yù)期賬戶還有加倉空間行情不及預(yù)期虧損頭寸也相對可控。def calc_position(max_weight, prob, threshold_high): distance max(prob - threshold_high, 0) scale 1 distance * 2.0 weight max_weight * min(scale, 1.5) return round(weight, 4)這里需要提醒一句任何單票倉位上限都不能超過賬戶可承受的單筆虧損閾值。如果你單票最多只能虧總資金的1%且止損位距離入場價5%那最大倉位就不能超過20%。倉位和止損是兩個天然綁在一起的旋鈕單獨擰一個都會出事。3.2 ATR止損與移動止損止損規(guī)則我在A股中低頻策略里最常用的是ATR止損。ATR平均真實波幅衡量的是個股近期的日內(nèi)真實波動范圍比固定百分比止損更能適應(yīng)不同波動率的股票。比如說你定了2倍ATR止損意思是從買入價向下2倍的日波幅才止損股票波動大就容忍多一點波動小就嚴(yán)格一點。實際計算ATR需要用到最高價、最低價和前一收盤價。計算方式不復(fù)雜關(guān)鍵是回測和實盤都要用同一套算法不能回測時用日線ATR、實盤時用5分鐘ATR邏輯全錯位。def calc_atr(df, period14): prev_close df[close].shift(1) tr np.maximum(df[high] - df[low], np.maximum(abs(df[high] - prev_close), abs(df[low] - prev_close))) return tr.rolling(period).mean()有了ATR止損價就是入場價 - 止損倍數(shù) * ATR。如果信號還沒失效但價格一路上漲我建議把止損失水平移到“入場后最高價 - 2倍ATR”這樣能鎖定利潤同時給趨勢足夠空間。我見過很多人設(shè)了止盈線一漲到目標(biāo)價就賣飛結(jié)果放著放著立刻翻倍了。移動止損比固定止盈更符合趨勢交易的邏輯。3.3 組合級回撤熔斷除了單票止損組合層面還得有一個總體的“熔斷機制”。我的規(guī)則很簡單如果賬戶凈值距離最近高點的回撤超過15%次日開始強制空倉5個交易日等情緒冷卻之后再重新開放交易?;爻芬坏┙咏?0%我再強制空倉10個交易日??諅}期間信號繼續(xù)記錄但不產(chǎn)生委托相當(dāng)于給策略一次“重新冷靜”的機會。這套規(guī)則的設(shè)計邏輯是當(dāng)策略連續(xù)虧損到一定幅度大概率是市場風(fēng)格發(fā)生了劇烈切換此時模型產(chǎn)出的信號可信度大幅下降。繼續(xù)硬扛只會讓虧損繼續(xù)放大不如干脆停下來觀察。風(fēng)控層里面回撤熔斷是最能避免“深度學(xué)習(xí)模型在某一年翻了車、卻把前三年利潤全部回吐”悲劇的防線。def check_drawdown(net_value, max_dd0.15): peak np.maximum.accumulate(net_value) dd net_value / peak - 1 if dd.iloc[-1] -max_dd: return {action: cut_all, reason: portfolio_drawdown} return {action: normal, reason: }回撤熔斷不是越多越好。我見過有人把閾值設(shè)成5%結(jié)果一年內(nèi)大部分時間都在空倉徹底錯過了所有反彈。閾值本身要和策略的波動特征匹配驗證集上最大回撤如果常年是12%那閾值就別放到10%如果策略最大回撤經(jīng)常18%那15%才是合理位置。4. 執(zhí)行層與回測驗證讓策略從紙面走向“模擬盤”4.1 從信號到委托單信號和倉位都算好之后執(zhí)行層要把“該買某只股票10%倉位”翻譯成“以什么價格、買多少股、哪一天能生效”。我處理A股模擬盤的經(jīng)驗是信號在第T日收盤后產(chǎn)生那么委托單最早只能掛第T1日。也就是說策略要有一個強制性的“次日生效”邏輯。千萬別在回測里用當(dāng)天的收盤價直接成交那是典型的未來函數(shù)。代碼里最簡單的處理是把信號整體shift(1)讓第T日算出來的目標(biāo)倉位第T1日才參與撮合。股數(shù)計算也要考慮A股的“一手100股”。先根據(jù)目標(biāo)市值算出理論股數(shù)再向下取整到100的倍數(shù)。資金不足時剩余資金寧可留著當(dāng)現(xiàn)金也不能為了滿倉去湊零股。def calc_share_count(target_value, current_price, lot_size100): raw_shares int(target_value / current_price / lot_size) * lot_size return max(raw_shares, 0)除此之外盤口約束必須硬性編碼。比如買入價不能高于漲停價賣出價不能低于跌停價如果當(dāng)前價已經(jīng)漲停意味著大概率買不進去這時候委托單要直接作廢不能假裝成交。4.2 回測引擎的搭建在回測層面我建議先把“向量化回測”跑通再做事件驅(qū)動回測。向量化回測適合快速驗證策略邏輯對不對它假設(shè)所有信號在同一時間點批量作用在所有股票上省去逐筆撮合的復(fù)雜度。比如你有20只股票每只股票每天都有倉位目標(biāo)直接按持倉市值變化計算組合凈值即可。向量化回測最大的優(yōu)點是快、清晰適合每天磨信號和倉位參數(shù)。但它的先天缺陷是忽略了沖擊成本和個股流動性差異所以回測凈值只能當(dāng)參考。等策略邏輯基本定型我會再寫一個按日循環(huán)的模擬盤腳本逐日根據(jù)信號下單成交價采用“次日開盤價 滑點估計”來模擬這才是真正接近實盤環(huán)境的驗證。position target_weight.shift(1) # T日信號T1日生效 ret daily_stock_ret 1 portfolio_ret (position * ret).sum(axis1) (1 - position.sum(axis1)) # 剩余現(xiàn)金部分無收益 net_value (1 portfolio_ret).cumprod()4.3 交易成本與滑點模擬盤里交易成本必須包含傭金、印花稅和滑點。傭金按成交金額的萬二到萬三估算買賣雙向都收印花稅只在賣出時收目前是千一滑點按買入價上浮0.1%、賣出價下浮0.1%估算。別小看這三個0.1%級別的數(shù)字中低頻策略一年的換手如果超過10倍成本合計就是總資金的3到5個點。很多回測里年化20%的策略扣完成本只剩10%這非?,F(xiàn)實。def estimate_trade_cost(buy_amount, sell_amount, commission_rate0.0003, stamp_tax0.001, slippage0.001): buy_cost buy_amount * (commission_rate slippage) sell_cost sell_amount * (commission_rate stamp_tax slippage) return buy_cost sell_cost4.4 評估指標(biāo)怎么讀最后回測結(jié)果不能只看“最終收益”。我最關(guān)注的指標(biāo)有三個年化收益、最大回撤、夏普比率。其中最大回撤決定了你的心理承受能力和加杠桿空間如果最大回撤30%說明策略和你的風(fēng)險偏好根本不匹配再高的年化也別碰。順便說一句勝率這個指標(biāo)很容易誤導(dǎo)人。我的經(jīng)驗是如果平均盈虧比能到1.5以上勝率只有40%的短線策略依然能賺錢如果勝率70%但盈虧比只有0.5長期下來大概率虧。所以回測報告里我會把“平均盈利/平均虧損”和“勝率”并列看缺一不可。def evaluate(net_value): annual_return net_value.iloc[-1] ** (252 / len(net_value)) - 1 daily_ret net_value.pct_change().dropna() sharpe daily_ret.mean() / daily_ret.std() * np.sqrt(252) max_dd (net_value / np.maximum.accumulate(net_value) - 1).min() return {annual_return: annual_return, sharpe: sharpe, max_drawdown: max_dd}5. 常見問題與排查技巧實錄5.1 未來函數(shù)的三個典型雷區(qū)這是量化新手最容易犯也最隱蔽的錯誤。我復(fù)盤自己踩過的雷總結(jié)出三個高頻雷區(qū)第一個標(biāo)簽泄漏。前面提過構(gòu)造未來收益標(biāo)簽時忘記整體后移導(dǎo)致模型提前學(xué)到了“未來信息”。判斷方法很簡單用訓(xùn)練好的模型在測試集上算AUC如果高到離譜比如超過0.75大概率有泄漏。第二個成交價用未來價。很多人回測時直接拿“當(dāng)日收盤價”買入但信號是收盤后才產(chǎn)生的實盤根本買不到當(dāng)天的收盤價。正確做法是信號T日出買入價至少是T1日的開盤價。第三個幸存者偏差。選股票池時如果直接用“當(dāng)前還在上市的股票”就相當(dāng)于剔除了過去幾年退市的股票?;販y結(jié)果看起來很好實際是漏掉了大量失敗案例。正確做法是用歷史某一天的成分股名單去回測那一天而不是用今天的名單覆蓋全部歷史。5.2 過擬合的識別AI量化里過擬合的典型表現(xiàn)是“訓(xùn)練集收益一片大好、驗證集收益斷崖下跌”。我的排查辦法是看驗證集和訓(xùn)練集的年化收益差如果差距超過50%或者直接由正轉(zhuǎn)負(fù)先別急著怪市場大概率是特征或者模型參數(shù)過擬合了。常用的緩解手段包括增加樣本內(nèi)時間跨度、減少特征數(shù)量、限制數(shù)模型深度XGBoost的max_depth別超過4、增大subsample隨機采樣比例、把連續(xù)型收益率標(biāo)簽改為排序型標(biāo)簽等。但最粗暴也有效的一招是驗證集指標(biāo)不達(dá)標(biāo)絕對不回測模型換參數(shù)。我之前就是因為太著急反復(fù)在測試集上調(diào)參最后測出來的結(jié)果完全失真。5.3 數(shù)據(jù)對齊與停牌處理A股停牌非常常見尤其重組停牌動輒一兩個月。如果回測時沒有對停牌做任何處理停牌期間持倉的每日收益可能是0看上去“回避了下跌”也可能“錯過了上漲”結(jié)果嚴(yán)重失真。我的處理方法是把停牌日的收益標(biāo)記為0同時在執(zhí)行層把停牌股票的委托單自動掛起直到復(fù)牌才繼續(xù)處理。數(shù)據(jù)對齊還有一個隱蔽問題不同數(shù)據(jù)源的交易日歷不一樣。有的接口會把節(jié)假日非交易日也保留有的會剔除。我統(tǒng)一的做法是把所有股票數(shù)據(jù)對齊到同一個交易日歷上以全市場成交量最大的那些股票的交易日作為基準(zhǔn)。我把這套三層骨架在模擬盤上完整跑通之后最大的體會是AI量化真正難的不是模型而是把模型輸出放到一個受控的交易鏈路里。信號層負(fù)責(zé)“聰明”風(fēng)控層負(fù)責(zé)“活著”執(zhí)行層負(fù)責(zé)“落地”只要這三層界限清晰后面模型哪怕?lián)Q成圖神經(jīng)網(wǎng)絡(luò)或者說加一個輿情因子都只是替換其中一塊積木而已。這篇是系列的上篇先把骨架和數(shù)據(jù)到信號這一段走通。后面有空我會單獨寫風(fēng)控參數(shù)那部分——尤其是ATR止損倍數(shù)怎么根據(jù)你交易頻率去調(diào)那又是一個能講一整篇的話題。