系統(tǒng):從免費(fèi)數(shù)據(jù)到策略驗(yàn)證的完整實(shí)踐)
你有沒(méi)有過(guò)這樣的經(jīng)歷——想學(xué)量化交易但一看到那些動(dòng)輒幾千上萬(wàn)的付費(fèi)數(shù)據(jù)源、復(fù)雜的回測(cè)框架和云服務(wù)器賬單就覺(jué)得門檻太高還沒(méi)開(kāi)始就想放棄了或者你已經(jīng)用Excel手動(dòng)算過(guò)幾次策略但每次想調(diào)整參數(shù)、測(cè)試不同周期都得重新整理數(shù)據(jù)、重寫公式過(guò)程繁瑣到讓人失去耐心我最初接觸量化時(shí)也卡在這個(gè)階段。直到后來(lái)想明白一件事量化回測(cè)的核心不是尋找“圣杯”策略而是搭建一個(gè)能讓你快速驗(yàn)證想法、迭代策略的“實(shí)驗(yàn)環(huán)境”。這個(gè)環(huán)境必須足夠輕量、免費(fèi)、可控讓你能把精力集中在策略邏輯本身而不是浪費(fèi)在配置環(huán)境和解決依賴上。今天要聊的就是如何用完全免費(fèi)的工具和開(kāi)源庫(kù)在你自己電腦上搭建一套“雙擊即看”的量化回測(cè)系統(tǒng)。這套系統(tǒng)的所有數(shù)據(jù)都來(lái)自免費(fèi)且穩(wěn)定的接口所有代碼都是可運(yùn)行、可修改的Python源碼。它不追求覆蓋所有復(fù)雜場(chǎng)景但足以讓你跑通從數(shù)據(jù)獲取、策略編寫、回測(cè)分析到可視化展示的完整鏈路。更重要的是它能幫你建立起對(duì)量化工作流最直觀的認(rèn)知數(shù)據(jù)怎么來(lái)、策略怎么寫、回測(cè)怎么跑、結(jié)果怎么看。1. 為什么“免費(fèi)”和“雙擊即看”對(duì)量化入門如此重要在深入代碼之前我們需要先達(dá)成一個(gè)共識(shí)對(duì)于量化入門者而言第一個(gè)系統(tǒng)的核心價(jià)值是“降低啟動(dòng)摩擦力”而不是“提供生產(chǎn)級(jí)性能”。很多人一開(kāi)始就陷入誤區(qū)去研究那些需要復(fù)雜配置、商業(yè)許可、高頻數(shù)據(jù)處理的專業(yè)框架。結(jié)果往往是環(huán)境還沒(méi)配好熱情就已經(jīng)耗盡了。這就像學(xué)開(kāi)車你應(yīng)該先找輛能開(kāi)動(dòng)的教練車熟悉方向盤和油門而不是直接去研究F1賽車的空氣動(dòng)力學(xué)。一個(gè)理想的入門級(jí)回測(cè)系統(tǒng)應(yīng)該滿足三個(gè)最低要求零成本啟動(dòng)不需要為數(shù)據(jù)、軟件或云資源付費(fèi)。環(huán)境簡(jiǎn)單最好能用最普及的工具如Python和最常見(jiàn)的庫(kù)避免冷門依賴。流程閉環(huán)從數(shù)據(jù)到策略再到圖表整個(gè)鏈路能在一個(gè)腳本或簡(jiǎn)單工程里跑通形成正反饋?!半p擊即看”正是這種理念的體現(xiàn)。它意味著你拿到源碼后只需要最基礎(chǔ)的Python環(huán)境運(yùn)行一個(gè)腳本就能看到從數(shù)據(jù)下載、回測(cè)計(jì)算到圖表輸出的全過(guò)程。這種即時(shí)反饋是保持學(xué)習(xí)動(dòng)力的關(guān)鍵。那么數(shù)據(jù)從哪里來(lái)這就是我們接下來(lái)要解決的核心問(wèn)題。2. 數(shù)據(jù)源選型為什么是akshare和baostock數(shù)據(jù)是量化的基石。對(duì)于免費(fèi)系統(tǒng)數(shù)據(jù)源的選擇直接決定了系統(tǒng)的可行性和穩(wěn)定性。我們的核心訴求是免費(fèi)、穩(wěn)定、易獲取、覆蓋A股主要數(shù)據(jù)。經(jīng)過(guò)對(duì)比和長(zhǎng)期使用我選擇了兩個(gè)開(kāi)源庫(kù)作為數(shù)據(jù)支柱akshare和baostock。這不是說(shuō)它們完美無(wú)缺而是在免費(fèi)、中文友好和功能覆蓋上達(dá)到了一個(gè)很好的平衡。2.1 akshare你的“量化數(shù)據(jù)瑞士軍刀”如果你只能用一句話記住akshare那就是它試圖用統(tǒng)一的接口聚合大量散落在各處的免費(fèi)金融數(shù)據(jù)源。它的設(shè)計(jì)思路很直接——為每一個(gè)數(shù)據(jù)需求如股票日線、財(cái)務(wù)報(bào)表、宏觀經(jīng)濟(jì)、新聞?shì)浨樘峁┮粋€(gè)對(duì)應(yīng)的函數(shù)。你不需要關(guān)心數(shù)據(jù)具體來(lái)自哪個(gè)網(wǎng)站也不需要寫爬蟲去解析HTML調(diào)用函數(shù)就能拿到結(jié)構(gòu)化的DataFrame。它的核心優(yōu)勢(shì)覆蓋面極廣從股票、基金、期貨、期權(quán)到宏觀經(jīng)濟(jì)、行業(yè)分類、新聞事件甚至社交媒體情緒數(shù)據(jù)幾乎涵蓋了量化研究可能用到的所有免費(fèi)數(shù)據(jù)維度。接口統(tǒng)一無(wú)論什么數(shù)據(jù)返回的基本都是Pandas DataFrame大大降低了后續(xù)數(shù)據(jù)處理的復(fù)雜度。社區(qū)活躍作為一個(gè)開(kāi)源項(xiàng)目它持續(xù)更新能較快地適應(yīng)一些數(shù)據(jù)源接口的變化。需要注意的邊界穩(wěn)定性依賴上游akshare本身不生產(chǎn)數(shù)據(jù)它是數(shù)據(jù)的“搬運(yùn)工”。如果某個(gè)原始網(wǎng)站改版或限制訪問(wèn)對(duì)應(yīng)的接口可能會(huì)暫時(shí)失效。這是所有免費(fèi)數(shù)據(jù)源都要面對(duì)的風(fēng)險(xiǎn)。不適合高頻場(chǎng)景它的數(shù)據(jù)更新頻率通常是日級(jí)或分鐘級(jí)有限且調(diào)用時(shí)有網(wǎng)絡(luò)請(qǐng)求無(wú)法用于需要Tick級(jí)數(shù)據(jù)或極低延遲的高頻交易研究。需要處理網(wǎng)絡(luò)環(huán)境由于需要訪問(wèn)外部網(wǎng)站在某些網(wǎng)絡(luò)環(huán)境下可能需要配置。對(duì)于入門回測(cè)akshare在日線數(shù)據(jù)、基本面數(shù)據(jù)、板塊數(shù)據(jù)的獲取上完全夠用。它的價(jià)值在于讓你擺脫“找數(shù)據(jù)”的瑣碎快速進(jìn)入“用數(shù)據(jù)”的階段。2.2 baostock專注而穩(wěn)定的A股歷史數(shù)據(jù)服務(wù)如果說(shuō)akshare是“廣”那么baostock就是“專”。它由深圳證券交易所旗下公司運(yùn)營(yíng)專注于提供A股歷史行情數(shù)據(jù)。它的核心優(yōu)勢(shì)數(shù)據(jù)質(zhì)量相對(duì)規(guī)整作為官方背景的服務(wù)其提供的股票日/周/月線、復(fù)權(quán)因子等數(shù)據(jù)格式統(tǒng)一歷史數(shù)據(jù)完整度較好。接口穩(wěn)定采用登錄-查詢-退出的客戶端模式連接相對(duì)穩(wěn)定提供了Python、R等多種語(yǔ)言的API。免費(fèi)提供復(fù)權(quán)數(shù)據(jù)計(jì)算回測(cè)收益時(shí)復(fù)權(quán)價(jià)格至關(guān)重要。baostock直接提供了前復(fù)權(quán)、后復(fù)權(quán)價(jià)格省去了自己計(jì)算的麻煩。需要注意的邊界數(shù)據(jù)范圍聚焦A股主要就是滬深京市的股票、指數(shù)數(shù)據(jù)不覆蓋港股、美股或其他資產(chǎn)。非實(shí)時(shí)數(shù)據(jù)同樣適用于歷史回測(cè)而非實(shí)盤交易。需要登錄使用前需要調(diào)用login()函數(shù)進(jìn)行登錄免費(fèi)注冊(cè)即可。在實(shí)際搭建中我通常會(huì)以baostock作為日線行情數(shù)據(jù)的主數(shù)據(jù)源因?yàn)樗€(wěn)定、規(guī)整。同時(shí)用akshare作為補(bǔ)充獲取基本面指標(biāo)、板塊分類、資金流向等維度數(shù)據(jù)用于豐富策略邏輯。2.3 數(shù)據(jù)獲取的通用流程與避坑指南無(wú)論使用哪個(gè)庫(kù)數(shù)據(jù)獲取的代碼模式是相似的但有幾個(gè)關(guān)鍵點(diǎn)決定了后續(xù)流程是否順暢先定義時(shí)間范圍和標(biāo)的不要一上來(lái)就下載全部數(shù)據(jù)。先明確你要測(cè)試的策略時(shí)間段和股票池例如2020-2023年的滬深300成分股。處理復(fù)權(quán)這是回測(cè)準(zhǔn)確性的生命線。股價(jià)會(huì)因?yàn)榉旨t、送股而產(chǎn)生缺口必須使用復(fù)權(quán)價(jià)格進(jìn)行計(jì)算否則收益計(jì)算會(huì)嚴(yán)重失真。baostock的query_history_k_data函數(shù)可以直接指定adjustflag參數(shù)2為前復(fù)權(quán)3為后復(fù)權(quán)。如果使用其他未提供復(fù)權(quán)價(jià)的數(shù)據(jù)源務(wù)必獲取復(fù)權(quán)因子并自行計(jì)算。統(tǒng)一數(shù)據(jù)格式確保從不同接口獲取的數(shù)據(jù)其日期列名如‘date’、價(jià)格列名如‘close’是統(tǒng)一的并轉(zhuǎn)換為datetime類型和float類型方便后續(xù)合并與計(jì)算。本地化存儲(chǔ)不要每次回測(cè)都重新下載數(shù)據(jù)。將下載好的數(shù)據(jù)以CSV或Parquet格式保存到本地并建立簡(jiǎn)單的版本管理如按下載日期命名文件夾。這能極大提升回測(cè)效率也是對(duì)數(shù)據(jù)源不穩(wěn)定的一種緩沖。# 示例使用baostock獲取單只股票前復(fù)權(quán)日線數(shù)據(jù)并保存 import baostock as bs import pandas as pd # 登錄 lg bs.login() # 顯示登錄返回信息 print(login respond error_code:lg.error_code) print(login respond error_msg:lg.error_msg) # 獲取滬深300成分股列表示例實(shí)際可從akshare獲取更全面的列表 stock_list [sh.600000, sz.000001] # 示例股票代碼 all_data [] for code in stock_list: rs bs.query_history_k_data_plus(code, date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,peTTM,pbMRQ,psTTM,pcfNcfTTM,isST, start_date2020-01-01, end_date2023-12-31, frequencyd, adjustflag2) # adjustflag2 前復(fù)權(quán) # 將數(shù)據(jù)轉(zhuǎn)換為DataFrame data_list [] while (rs.error_code 0) rs.next(): data_list.append(rs.get_row_data()) df pd.DataFrame(data_list, columnsrs.fields) df[date] pd.to_datetime(df[date]) # 將數(shù)值列轉(zhuǎn)換為float for col in [open, high, low, close, volume, pctChg]: df[col] pd.to_numeric(df[col], errorscoerce) all_data.append(df) # 退出 bs.logout() # 合并并保存 if all_data: combined_df pd.concat(all_data, ignore_indexTrue) combined_df.to_csv(./data/stock_daily_data.csv, indexFalse) print(f數(shù)據(jù)已保存共{len(combined_df)}行)注意在實(shí)際項(xiàng)目中你需要添加更完善的錯(cuò)誤處理如網(wǎng)絡(luò)重試、進(jìn)度提示以及將不同股票的數(shù)據(jù)分開(kāi)存儲(chǔ)以便增量更新。3. 構(gòu)建核心回測(cè)引擎從簡(jiǎn)單的“向量化回測(cè)”開(kāi)始有了數(shù)據(jù)下一步就是讓策略在歷史數(shù)據(jù)上“跑”起來(lái)這就是回測(cè)。對(duì)于入門者我強(qiáng)烈建議從向量化回測(cè)開(kāi)始而不是一上來(lái)就模仿實(shí)盤的事件驅(qū)動(dòng)回測(cè)。為什么向量化回測(cè)的核心思想是將整個(gè)時(shí)間序列數(shù)據(jù)如每日收盤價(jià)看作一個(gè)向量數(shù)組策略信號(hào)和交易邏輯也通過(guò)向量數(shù)組運(yùn)算來(lái)表達(dá)。它一次性對(duì)整個(gè)歷史周期進(jìn)行計(jì)算思路更貼近數(shù)據(jù)分析。事件驅(qū)動(dòng)回測(cè)則模擬真實(shí)交易逐個(gè)處理“時(shí)間點(diǎn)”上的事件如開(kāi)盤、收盤、訂單更貼近實(shí)盤但復(fù)雜度也高得多。對(duì)于大多數(shù)基于日線數(shù)據(jù)的初級(jí)策略如均線交叉、動(dòng)量、突破向量化回測(cè)完全夠用且代碼直觀易于調(diào)試和理解。它能快速回答“這個(gè)想法歷史上有沒(méi)有效”這個(gè)核心問(wèn)題。3.1 一個(gè)最簡(jiǎn)單的雙均線策略回測(cè)示例讓我們用代碼實(shí)現(xiàn)一個(gè)經(jīng)典的雙均線策略金叉買入死叉賣出并計(jì)算其收益。假設(shè)我們已經(jīng)有了包含date,code,close列的DataFramedf并且已經(jīng)按date排序。import pandas as pd import numpy as np def vectorized_backtest(df, short_window5, long_window20): 簡(jiǎn)單的向量化雙均線策略回測(cè) :param df: 包含日期、代碼、收盤價(jià)的數(shù)據(jù)框單只股票 :param short_window: 短期均線周期 :param long_window: 長(zhǎng)期均線周期 :return: 添加了信號(hào)和持倉(cāng)的df以及累計(jì)收益率 # 計(jì)算均線 df[SMA_short] df[close].rolling(windowshort_window).mean() df[SMA_long] df[close].rolling(windowlong_window).mean() # 生成交易信號(hào)1為買入金叉-1為賣出死叉0為持有 # 金叉短期均線上穿長(zhǎng)期均線 df[signal] 0 df.loc[df[SMA_short] df[SMA_long], signal] 1 df.loc[df[SMA_short] df[SMA_long], signal] -1 # 為了得到準(zhǔn)確的交叉點(diǎn)我們計(jì)算信號(hào)的變化點(diǎn)從1變-1或從-1變1 df[position] df[signal].replace(0, methodffill).shift(1).fillna(0) # position1表示持有股票position0表示持有現(xiàn)金 # 計(jì)算每日收益率股價(jià)漲跌幅 df[returns] df[close].pct_change() # 計(jì)算策略每日收益率當(dāng)持倉(cāng)為1時(shí)獲得市場(chǎng)收益為0時(shí)收益為0忽略利息 df[strategy_returns] df[position] * df[returns] # 計(jì)算累計(jì)收益 df[cumulative_market_returns] (1 df[returns]).cumprod() df[cumulative_strategy_returns] (1 df[strategy_returns]).cumprod() return df # 假設(shè)df是某只股票的數(shù)據(jù) # df pd.read_csv(your_stock_data.csv) # df[date] pd.to_datetime(df[date]) # df df.sort_values(date).reset_index(dropTrue) # 運(yùn)行回測(cè) # result_df vectorized_backtest(df) # print(result_df[[date, close, SMA_short, SMA_long, position, cumulative_strategy_returns]].tail())這段代碼雖然簡(jiǎn)單但包含了向量化回測(cè)的所有關(guān)鍵要素?cái)?shù)據(jù)準(zhǔn)備確保數(shù)據(jù)按時(shí)間排序。指標(biāo)計(jì)算在整列數(shù)據(jù)上滾動(dòng)計(jì)算均線。信號(hào)生成通過(guò)向量比較產(chǎn)生買賣信號(hào)。持倉(cāng)管理將信號(hào)轉(zhuǎn)化為持倉(cāng)狀態(tài)這里用了前向填充和滯后一期避免未來(lái)函數(shù)。收益計(jì)算根據(jù)持倉(cāng)計(jì)算策略每日和累計(jì)收益。3.2 必須警惕的“未來(lái)函數(shù)”陷阱在編寫信號(hào)邏輯時(shí)未來(lái)函數(shù)是最大的坑。它指的是在時(shí)間點(diǎn)t使用了t時(shí)刻之后才能獲得的信息。在回測(cè)中這會(huì)導(dǎo)致結(jié)果嚴(yán)重虛高因?yàn)椴呗浴邦A(yù)知”了未來(lái)。如何避免嚴(yán)格使用.shift()當(dāng)你用t時(shí)刻的數(shù)據(jù)生成信號(hào)并決定在t1時(shí)刻交易時(shí)在計(jì)算收益時(shí)一定要用df[position].shift(1)來(lái)對(duì)齊。上面的示例已經(jīng)體現(xiàn)了這一點(diǎn)。仔細(xì)檢查指標(biāo)計(jì)算例如計(jì)算t日的20日均線理論上應(yīng)該使用t-19日到t日的數(shù)據(jù)。pandas的rolling().mean()默認(rèn)是包含當(dāng)前行的這在回測(cè)中是允許的因?yàn)槭毡P后即可計(jì)算。但要確保沒(méi)有用到t1日的數(shù)據(jù)?;販y(cè)時(shí)點(diǎn)模擬在腦海中模擬在每個(gè)交易日收盤后我根據(jù)截至當(dāng)天的所有歷史數(shù)據(jù)能做出什么交易決策這個(gè)決策只能在下一個(gè)交易日?qǐng)?zhí)行。3.3 從單只股票到股票池向量化思維的延伸上面的例子是針對(duì)單只股票的。對(duì)于一個(gè)多股票的策略如行業(yè)輪動(dòng)、選股向量化回測(cè)依然高效。核心思路是將數(shù)據(jù)構(gòu)造成一個(gè)以日期為索引、股票代碼為列的多維DataFrame或Panel雖然Panel已棄用但可以用多層索引的DataFrame。對(duì)所有股票同時(shí)計(jì)算指標(biāo)、生成信號(hào)。在每一天根據(jù)信號(hào)對(duì)所有股票進(jìn)行排序、篩選決定持倉(cāng)組合。計(jì)算整個(gè)股票池的日度組合收益。這部分的代碼會(huì)復(fù)雜一些需要熟練使用pandas的groupby、pivot、unstack等操作。但邏輯內(nèi)核不變避免循環(huán)用數(shù)組向量運(yùn)算代替。4. 績(jī)效分析與可視化讓結(jié)果自己“說(shuō)話”回測(cè)跑出曲線只是第一步更重要的是解讀。一個(gè)策略光看最終收益率是遠(yuǎn)遠(yuǎn)不夠的必須從多個(gè)維度評(píng)估其表現(xiàn)和風(fēng)險(xiǎn)。4.1 必須計(jì)算的幾個(gè)核心績(jī)效指標(biāo)年化收益率將總收益率換算成年均水平便于比較。total_days len(result_df) years total_days / 252.0 # 假設(shè)一年252個(gè)交易日 cum_ret result_df[cumulative_strategy_returns].iloc[-1] annual_return (cum_ret ** (1/years)) - 1年化波動(dòng)率衡量策略收益的波動(dòng)程度即風(fēng)險(xiǎn)。daily_returns result_df[strategy_returns] annual_volatility daily_returns.std() * np.sqrt(252)夏普比率最常用的風(fēng)險(xiǎn)調(diào)整后收益指標(biāo)。表示每承受一單位風(fēng)險(xiǎn)能獲得多少超額回報(bào)。通常假設(shè)無(wú)風(fēng)險(xiǎn)利率為0。sharpe_ratio annual_return / annual_volatility最大回撤策略從前期高點(diǎn)跌到最低點(diǎn)的最大跌幅。這是衡量策略下行風(fēng)險(xiǎn)和投資者心理承受能力的關(guān)鍵指標(biāo)。cumulative result_df[cumulative_strategy_returns] running_max cumulative.expanding().max() drawdown (cumulative - running_max) / running_max max_drawdown drawdown.min()勝率盈利交易次數(shù)占總交易次數(shù)的比例。盈虧比平均盈利與平均虧損的比值。4.2 用可視化建立直觀認(rèn)知數(shù)字是抽象的圖表是直觀的。至少生成三張圖策略凈值 vs 基準(zhǔn)凈值曲線這是最重要的圖。將你的策略累計(jì)收益和某個(gè)基準(zhǔn)如滬深300指數(shù)的累計(jì)收益畫在一起直觀對(duì)比。import matplotlib.pyplot as plt plt.figure(figsize(12,6)) plt.plot(result_df[date], result_df[cumulative_strategy_returns], labelStrategy) plt.plot(result_df[date], result_df[cumulative_market_returns], labelBenchmark (Buy Hold)) plt.title(Strategy vs Benchmark Cumulative Returns) plt.xlabel(Date) plt.ylabel(Cumulative Returns) plt.legend() plt.grid(True) plt.show()回撤曲線圖展示策略歷史上每一次回撤的深度和持續(xù)時(shí)間。plt.figure(figsize(12,4)) plt.fill_between(result_df[date], drawdown, 0, drawdown 0, colorred, alpha0.3) plt.plot(result_df[date], drawdown, colorred, linewidth1) plt.title(Strategy Drawdown) plt.xlabel(Date) plt.ylabel(Drawdown) plt.grid(True) plt.show()月度收益熱力圖分析策略收益的季節(jié)性或月度效應(yīng)。# 將日收益數(shù)據(jù)重采樣為月收益 result_df[year_month] result_df[date].dt.to_period(M) monthly_returns result_df.groupby(year_month)[strategy_returns].apply(lambda x: (1x).prod()-1) # 將月度收益轉(zhuǎn)換為數(shù)據(jù)透視表格式用于熱力圖 # ... (此處略去數(shù)據(jù)重塑代碼) # 使用seaborn繪制熱力圖4.3 可視化不是裝飾是分析工具不要為了好看而畫圖。每張圖都應(yīng)該能回答一個(gè)具體問(wèn)題凈值曲線我的策略長(zhǎng)期是否跑贏了簡(jiǎn)單持有它在牛熊市的表現(xiàn)如何回撤圖我最大可能虧多少錢回撤持續(xù)了多久我能否承受月度熱力圖我的策略在某些月份是否持續(xù)失效是否有季節(jié)性規(guī)律通過(guò)圖表發(fā)現(xiàn)的問(wèn)題要回頭去檢查策略邏輯、參數(shù)或者思考市場(chǎng)環(huán)境的變化。這是一個(gè)不斷迭代的過(guò)程。5. 從“能跑”到“好用”工程化與迭代的思考當(dāng)你成功運(yùn)行了第一個(gè)回測(cè)看到了第一條凈值曲線后這個(gè)“雙擊即看”的系統(tǒng)就完成了它的啟蒙使命。接下來(lái)你需要思考如何讓它從一個(gè)腳本進(jìn)化成一個(gè)“好用”的工具以支持更復(fù)雜的策略迭代。5.1 模塊化設(shè)計(jì)讓代碼可維護(hù)最初的腳本可能把所有功能都寫在一個(gè)文件里。隨著策略變復(fù)雜你需要拆分data_fetcher.py負(fù)責(zé)從akshare、baostock獲取數(shù)據(jù)并保存到本地?cái)?shù)據(jù)庫(kù)或文件。strategy.py定義策略類包含信號(hào)生成的核心邏輯。backtest_engine.py包含回測(cè)引擎負(fù)責(zé)運(yùn)行策略、計(jì)算持倉(cāng)和收益。performance.py負(fù)責(zé)計(jì)算夏普比率、最大回撤等指標(biāo)。plotting.py負(fù)責(zé)所有可視化功能。config.py集中管理參數(shù)如股票池、回測(cè)周期、策略參數(shù)等。main.py主程序串聯(lián)整個(gè)流程。這樣當(dāng)你需要測(cè)試一個(gè)新策略時(shí)只需要修改或新建一個(gè)strategy.py其他模塊可以復(fù)用。5.2 參數(shù)優(yōu)化與過(guò)擬合陷阱當(dāng)你發(fā)現(xiàn)一個(gè)策略有效時(shí)很自然地會(huì)想“如果調(diào)整一下均線周期結(jié)果會(huì)不會(huì)更好”于是開(kāi)始嘗試不同的參數(shù)組合。這就是參數(shù)優(yōu)化。一個(gè)簡(jiǎn)單的網(wǎng)格搜索示例def optimize_parameters(df): results [] for short in range(5, 20, 5): for long in range(20, 100, 20): if short long: continue result_df vectorized_backtest(df, short, long) # 計(jì)算績(jī)效指標(biāo)如年化夏普 # ... sharpe calculate_sharpe(result_df) results.append({short: short, long: long, sharpe: sharpe}) return pd.DataFrame(results)但是必須極度警惕過(guò)擬合過(guò)擬合是指策略在歷史數(shù)據(jù)上表現(xiàn)極好僅僅是因?yàn)樗『谩坝涀 绷四嵌螝v史的噪聲而非抓住了有效規(guī)律導(dǎo)致在未來(lái)實(shí)盤中失效。如何規(guī)避樣本外測(cè)試將歷史數(shù)據(jù)分為兩段訓(xùn)練集用于優(yōu)化參數(shù)和測(cè)試集用于驗(yàn)證結(jié)果。絕對(duì)不能用測(cè)試集的數(shù)據(jù)做任何參數(shù)優(yōu)化。交叉驗(yàn)證將數(shù)據(jù)分成多段輪流用其中一部分測(cè)試觀察策略在不同時(shí)段是否穩(wěn)定。保持參數(shù)簡(jiǎn)單不要使用過(guò)多的參數(shù)或過(guò)于復(fù)雜的規(guī)則。一個(gè)需要幾十個(gè)參數(shù)才能“工作”的策略大概率是過(guò)擬合的。邏輯優(yōu)先于曲線策略的核心理念應(yīng)該有經(jīng)濟(jì)學(xué)或行為金融學(xué)的邏輯支撐而不是純粹的數(shù)據(jù)挖掘。問(wèn)問(wèn)自己這個(gè)策略為什么應(yīng)該賺錢它的邏輯在未來(lái)還會(huì)成立嗎5.3 理解免費(fèi)系統(tǒng)的邊界規(guī)劃下一步我們搭建的這套免費(fèi)系統(tǒng)其邊界非常清晰適用個(gè)人學(xué)習(xí)、策略思路驗(yàn)證、基于日/周線數(shù)據(jù)的低頻策略研究。不適用高頻交易、實(shí)盤交易缺乏實(shí)時(shí)數(shù)據(jù)、訂單執(zhí)行、風(fēng)控模塊、需要極端精確的計(jì)算如考慮滑點(diǎn)、手續(xù)費(fèi)、沖擊成本。當(dāng)你用這個(gè)系統(tǒng)驗(yàn)證了一個(gè)有潛力的想法后下一步的進(jìn)階路徑可能是引入更精細(xì)的成本模型在回測(cè)中加入手續(xù)費(fèi)、印花稅、滑點(diǎn)假設(shè)成交價(jià)與預(yù)期價(jià)的偏差。探索更專業(yè)的回測(cè)框架如Zipline,Backtrader,PyAlgoTrade等。它們提供了更嚴(yán)謹(jǐn)?shù)氖录?qū)動(dòng)模型、更豐富的訂單類型和風(fēng)險(xiǎn)控制模塊。但學(xué)習(xí)成本也更高。連接模擬交易使用一些券商提供的模擬交易API在實(shí)時(shí)的模擬環(huán)境中測(cè)試策略感受市場(chǎng)的微觀結(jié)構(gòu)。學(xué)習(xí)風(fēng)險(xiǎn)管理如何設(shè)置止損、如何控制倉(cāng)位、如何分散投資這些是比尋找“圣杯”策略更重要的事。最終這套免費(fèi)系統(tǒng)的最大價(jià)值不是給你一個(gè)賺錢的策略而是給你一個(gè)完整的、可觸摸的量化認(rèn)知框架。你知道了數(shù)據(jù)從哪來(lái)、怎么處理知道了策略怎么寫、怎么回測(cè)知道了績(jī)效怎么看、怎么評(píng)價(jià)。你親手走通了從想法到驗(yàn)證的完整閉環(huán)。這個(gè)過(guò)程中培養(yǎng)的數(shù)據(jù)處理能力、邏輯思維能力和對(duì)市場(chǎng)的理解遠(yuǎn)比某一段漂亮的回測(cè)曲線更有價(jià)值。所以不要停留在僅僅運(yùn)行一遍源碼。去修改它用你自己的策略想法替換掉雙均線去擴(kuò)展它嘗試加入基本面指標(biāo)去質(zhì)疑它思考這個(gè)策略的弱點(diǎn)在哪里。這個(gè)系統(tǒng)是你的實(shí)驗(yàn)室而最好的學(xué)習(xí)永遠(yuǎn)發(fā)生在你親自動(dòng)手實(shí)驗(yàn)的時(shí)候。