更新日誌
2.2.13 (2026-10-16)
Fixed
FinlabDataFrame.corrwith(axis=1)計算逐日股票相關係數時,不再把非定值資料或自身相關錯算為 0;保留缺值與常數的 pandas 處理、混合 DataFrame 輸入,以及一般 FinLab 日期運算。曾用此結果研究因子的用戶,請升級並重新執行相關計算。(Issue #436、PR #437)
2.2.12 (2026-10-16)
Fixed
-
報告快照、HTML 匯出與上傳沿用回測已保存的資料狀態,不再重複請求更新資訊或計算整張表的雜湊,減少雲端研究定稿的等待;歷史回測沒有待更新來源時,不再顯示建議交易時間。績效與持股數值不變。(Issue #431、PR #432)
-
HTML 持股報告的進場日期改為與進場價對應的成交日,另列訊號日;沒有待執行換股時不顯示已過期的預定日期,其他市場與舊報表仍保留有效排程,並更新分析版面。回測計算不變。(PR #430)
-
sim()遇到零列或零個股票欄位的部位表時,改在回測前提示如何對齊股票欄位與大盤日期序列,不再出現 pandas 索引錯誤;明確全零的現金部位仍可回測。(Issue #423、PR #424) -
groupby_category().groups、indices與ngroups保留 pandas 原生分組資訊,不同產業成員數不再報錯,成員數相同時也不再誤轉成 DataFrame;產業聚合與揭露日期對齊不變。(Issue #420、PR #421) -
韓國、日本、香港與英國股票及基金市場的回測改讀現有還原價格表,修正預設回測找不到資料集的錯誤;費用、稅率與歷史資料不變。(Issue #418、PR #419)
-
回測從非交易日的月、週或自訂換股日期開始時,保留原本可能被跳過的第一期持倉;受影響策略的交易與績效可能改變,後續換股與下一交易日成交規則不變。(Issue #416、PR #417)
-
data.get()遇到已連線但沒有回應的資料授權、下載或版本查詢時,較早結束等待並保留原有重試;下載逾時以每次讀取的無回應時間計算,仍允許持續傳輸的大檔案完成。資料與快取規則不變。(Issue #414、PR #415) -
一般與日期範圍
data.get(..., save_to_storage=False)改為在下載前報錯,並提示先呼叫data.set_storage(data.CacheStorage())、移除舊參數;不再警告後仍寫入磁碟。分時與歷史版本讀取仍支援該參數。(Issue #411、PR #412) -
雲端唯讀資料若已帶有發布時的驗證雜湊,回測資料狀態檢查會沿用它,不再重算整張表;雜湊不符時仍不視為已確認,可修改的快取與舊資料維持原有驗證。(Issue #433、PR #434)
2.2.11 (2026-10-13)
Changed
-
回測報告儀表板更新為 Studio 新版分析與持股頁,包含績效時間軸、年度色帶與白話策略體檢;回測計算與資料數值不變。
-
季報布林條件與日資料對齊、
&/|/^運算及布林遮罩篩選改用整張陣列處理,減少美股全市場選股的逐欄成本。運算結果、揭露前未知值與公開輸出的型別維持不變。(Issue #404、PR #405)
Fixed
-
唯讀環境中,登入憑證更新成功但無法寫回磁碟快取時,
python -m finlab ai與data.get()現在會沿用記憶體中的新憑證繼續執行,不再因快取寫入失敗而中斷;同一行程共用新憑證,下次啟動再更新。初次登入與環境變數登入的行為不變。(Issue #408、PR #409) -
Python 3.10 安裝
finlab[qlib]時使用仍提供相容 wheel 的 TA-Lib 版本,避免因新版 TA-Lib 不再提供 Python 3.10 wheel 而轉為編譯、缺少系統函式庫時安裝失敗。Python 3.11 以上的相依選擇不變。
Documentation
industry_rank()文件更正台股分類來源為櫃買中心產業價值鏈資訊平台,說明預設使用大類、多分類排名取平均,以及目前分類快照套用所有日期、並非歷史時點分類;rank()範例明確使用橫向排名。函式與資料行為不變。(Issue #406、PR #407)
2.2.10 (2026-10-10)
Added
data.get()下載到排程外改寫的新版本時,會提示資料集、修正時間、異常紀錄連結與as_of=回溯寫法;更新快取後重讀及日期範圍讀取不重複提示。提示使用既有版本索引,不新增每次呼叫的網路查詢;手動補入新日期也可能提示。資料數值未因這項功能變動,歷史版本的保留期限與存取權限仍適用。(Issue #400、PR #402)
Fixed
-
finlab.ml.feature.combine()現在會對 MultiIndex 特徵套用resample,單獨使用或混合寬表特徵時都與原有重採樣日期對齊,不再忽略週/月頻設定或產生整欄空值。字串W沿用週日日期;需要每週最後交易日請傳入明確的日期索引,標籤也傳入相同的resample。未指定resample的標籤period仍指交易日。(Issue #397、PR #399)行為變更 結果可能改變
2.2.9 (2026-10-10)
Changed
sim()遇到下市持股時不再發出DelistedHoldingWarning,finlab.backtest.delisting.DelistedHoldingWarning類別也一併移除。下市持股的出場方式與之後不再買入的規則都不變。匯入這個類別或以它過濾警告的程式,請刪除相關寫法。(Issue #390、PR #395)
Added
python -m finlab cloud deploy與cloud schedule set新增--frequency(daily、weekly、monthly、custom)、--days-of-week、--day-of-month與--cron,雲端排程可設定每週、每月或自訂 cron 執行。時間一律為台北時間,當月沒有的日期會跳過,不會自動避開休市日;原本的指令行為不變,cloud schedule list/get會顯示已儲存的頻率。(PR #386)
Fixed
-
美股等未定義預先讀取資料的市場(例如
USMarket、USFundMarket),sim()讀取價格、指數與公司資料時原本略過資料版本檢查,歷史資料修正後仍沿用舊的本機快取,可能與自己用data.get()取得的新資料混用。現在所有市場的回測都與data.get()一樣檢查資料版本;同一次sim()/sim_batch()再讀到同一份快取時共用確認結果,不重複查詢或下載。台股回測,以及資料沒有修正時的結果不變。(Issue #391、PR #392) -
finlab.portfolio.Portfolio的子策略起始日或換股日不同時,position會把只有部分子策略有部位的日期整列清成 0。現在各子策略的部位對齊到所有換股日,沿用該子策略最近一次的目標,開始前以現金計,清倉的股票不再沿用舊持股;creturn照舊只計算共同期間。(Issue #384、PR #385)行為變更 結果可能改變
-
macOS Apple Silicon 上,
finlab.ml.qlib的DNNModel、TabnetModel、SFMModel因 sklearn 與 PyTorch 各載入一份 OpenMP 而在訓練或建立時程序中止,先匯入 torch 時則換成LGBModel中止。現在 macOS arm64 預設以單執行緒訓練,八個模型都能完成訓練與預測,但速度較慢;其他平台不變。另外get_models()補上SFMModel,單一模型建立失敗時只略過該模型;已安裝 PyTorch 時不再誤報缺少 PyTorch;TabnetModel的驗證分數納入最後不足一個批次的資料並依筆數加權,驗證集小於一個批次時不再失敗。(Issue #387、PR #388)行為變更 結果可能改變
2.2.8 (2026-10-09)
Fixed
verify_strategy()的策略函式若回傳持倉 DataFrame 或其他非 Report 值,現在會拋出指出實際型別、並附上sim(..., upload=False)正確寫法的TypeError,不再只顯示缺少trades屬性。回傳 Report 的正常用法與驗證結果不變。(Issue #381、PR #382)
2.2.7 (2026-10-09)
Changed
-
免費帳號下載的資料改存在資料快取資料夾內的
free子資料夾,同一台電腦的 Python 程式與 Jupyter kernel 共用,不再每次執行都重新下載。雲端資料沒有更新時直接讀取本機快取,不下載、不扣每日下載額度;雲端有新檔時重新下載一次。付費帳號不讀取free子資料夾;資料夾無法寫入時照舊只存在記憶體。資料內容不變。(PR #376) -
資料名稱不含冒號的大型完整資料表重新發布後,若雲端提供該表的變動檔,
data.get()只下載有變動的日期,並與本機快取合併;合併結果與正式資料表的雜湊相符才採用,否則照原本方式整份下載。沒有變動檔或使用免費帳號時,行為與先前相同。資料內容不變。(PR #378) -
data.indicator()固定使用市場價格計算,傳入high=、low=、close=、open=、volume=或data=等自訂價格時仍會報錯;錯誤訊息改為說明這點,並附上以talib.abstract逐檔計算的寫法。參數名稱打錯時的錯誤訊息不變。(Issue #350、PR #356)
Added
-
sim()與hold_until()的stop_loss、take_profit除了數字,也接受以日期為索引、股票為欄位的 DataFrame,讓每檔股票每天使用不同的停損停利門檻,例如 ATR 倍數停損。每根 K 棒採用該日或之前最近一筆門檻,touched_exit=True的盤中觸價只採用前一根 K 棒(含)以前的門檻,不使用當天才算得出的值;每格門檻的效果與相同數字一致,NaN、第一筆日期之前與 DataFrame 沒有的股票當天不停損停利。使用 DataFrame 時report.stop_loss/report.take_profit為None,停損停利出場仍記錄在report.actions。trail_stop、trail_stop_activation仍只接受數字;停損停利參數傳入 Series、陣列等不支援的型別時,會在回測前拋出指出參數名稱與替代寫法的TypeError,不再出現 pandas 的布林判斷錯誤。數字門檻的回測結果不變。(Issue #358、PR #359、#361) -
新增
finlab.backtest.metrics_from_nav():傳入其他回測框架或自訂帳本產生的日頻淨值 Series,即可用與sim()相同的口徑計算年化報酬、夏普值、最大回撤等淨值績效。淨值須已扣除交易成本並排除入出金的影響;本函式不產生 Report、交易明細、持倉或委託。(PR #367)
Fixed
-
sim()的resample傳入 DataFrame、Series、DatetimeIndex 或日期清單(例如以月營收公布日換股)時,resample_offset原本會被靜默忽略;現在會依指定位移每個換股日,報表的下一次換股日也套用相同位移。同時使用這兩個參數的策略,換股日期與回測結果會改變;字串resample的行為不變。(Issue #362、PR #363)雲端排程會隨本次執行環境升級生效,不需要自行升級。自行執行的用戶請升級套件並重新啟動 Python/Jupyter kernel,再重新確認使用自訂換股日期與
resample_offset的策略結果。行為變更 結果可能改變
-
sim()的回測授權連線中斷時,會在 3 秒後重試一次,請求也加上 30 秒逾時,不再因單次連線中斷讓整個回測失敗,或在對方沒有回應時一直等待;兩次都失敗時,錯誤訊息會提示檢查網路後重新執行sim()。(Issue #368、PR #369) -
本機資料快取放在唯讀資料夾(例如唯讀掛載的資料夾)時,
data.get()讀取快取不再因無法建立或開啟.lock檔而拋出LocalDataReadError;寫入快取仍需要可寫入的資料夾。(Issue #372、PR #373) -
使用 pandas 2 時,含空值的布林持倉(例如布林 DataFrame 經
.shift()後)傳入sim()不再印出Downcasting object dtype arrays on .fillna的FutureWarning;空值仍視為不持有,回測結果不變。(Issue #364、PR #365) -
下單的
show_alerting_stocks()會加上處置股/警示股警告標題與注意事項;沒有待下單股票在處置股或信用警示名單中時,也會顯示確認訊息,不再沒有任何輸出。(PR #357)
2.2.6 (2026-10-05)
Fixed
-
修正雲端排程使用唯讀資料快取時,
data.get()因無法更新快取版本時間而失敗的問題;現在會沿用既有的快取內容。資料數值與回測計算方式不變。(Issue #344、PR #346) -
Google Cloud Functions、Cloud Run service/job 與 AWS Lambda 的預設資料快取改放系統暫存目錄。其他環境的使用者目錄不可寫時,也會退回暫存目錄,避免匯入套件或呼叫
data.get()失敗。可寫的本機目錄、Colab 與自行指定的FileStorage(path)行為不變。(Issue #344、PR #347)
2.2.5 (2026-10-05)
Changed
-
持有空單的策略在兩次換股之間有持股停損出場時,
report.weights會放大其餘空單的權重,以此建立的Position.from_report()實單會多放空。現在其餘空單維持原本權重,與回測實際持有的部位一致:例如 5 檔空單各 -0.2,其中 1 檔停損後,其餘 4 檔由 -0.25 改回 -0.2。只做多的策略不受影響,回測損益與交易紀錄不變。(Issue #229、PR #338)雲端排程會隨本次執行環境升級生效,不需要自行升級。自行執行的用戶請升級套件並重新啟動 Python/Jupyter kernel,下單前先確認實單目標。
行為變更
-
資料修正後,預設的
data.get()/data.gets()最慢約 5 分鐘就會取得修正後的資料,不必等下一次排程更新,也不必使用force_download=True。本機快取已是最新時不需連線確認;排程時間已過、資料尚未更新的期間,改為每 5 分鐘最多確認一次,不再每次呼叫都多一次線上查詢。已回傳的 DataFrame 仍是當時的快照,要使用修正後的資料請重新呼叫。import finlab也不再於背景查詢資料更新時間。(Issue #304、PR #336)
Added
-
新增
data.describe(),不下載資料就能查詢資料表或欄位的說明、欄位清單、所屬市場與類別及更新排程,與data.search()共用目錄快取。查無的名稱會拋出KeyError。(Issue #88、PR #313) -
新增環境變數
FINLAB_MAX_DOWNLOAD_WORKERS,設定data.get()/data.gets()同時下載的數量:預設 8,設為 1 時依序下載,適合限制執行緒數的環境。另新增data.free_memory(),釋放已讀取資料占用的記憶體,下次讀取會從本機快取載入;自己仍持有的 DataFrame 不會被釋放,請先del不再使用的變數。(Issue #119、PR #337) -
finlab ai新增--history [N]列出最近的提問(預設 10 則)、--show <提問ID>讀取指定提問與所有回覆(包含事後追加的處理進度),以及--json輸出,方便自己的程式或 AI agent 讀取。(Issue #328、PR #329)
Fixed
-
使用 pandas 3 時,價格中間有缺值的股票,缺值後第一天的報酬會被漏算,影響
position.weight.inverse_volatility()、risk_parity()、correlation()、target_volatility()、drawdown_control()算出的權重、event_study()的個股與大盤報酬,以及Position.from_weight()使用槓桿時的保證金分配。現在會先沿用缺值前的價格再計算報酬,結果與 pandas 2 相同。使用 pandas 2 的用戶不受影響。(Issue #330、PR #331)結果可能改變
-
python -m finlab cloud deploy --help與 CLI 文件把小型方案(tiers)的規格誤寫成 2 GiB 記憶體、120 秒逾時,已更正為 1 CPU、4 GiB、300 秒。實際執行規格不變。(Issue #332、PR #333)
Documentation
- 新增 版本升級與重現:整理 2.0.19 起各版會改變選股、回測或實單目標的條件與遷移寫法,附可下載的升級前後對照案例,並說明如何鎖住執行環境、保存資料版本與回測設定。另提供 JSON/Atom 版本影響清單,可用程式篩出會影響自己策略的變更。(Issue #334、PR #335)
2.2.4 (2026-10-04)
Changed
- 撤回 2.2.3 的排程外歷史修正快取檢查,避免每次預設
data.get()/data.gets()都增加一次線上查詢。其他 2.2.3 的變更保留。資料修正後,本機快取會在下一次排程更新時過期,重新讀取即可取得新資料;美股更新時間為台北 05:30。要立即取得新資料,請對計算所需的相關欄位使用force_download=True重新下載。本次保留既有快取行為,不另行修正此現象。(Issue #304、PR #326)
Added
- 新增
finlab.portfolio.TradeReview,可由實際成交、股利、股票分割與資金流重建每日持股、現金、淨值及報表,並比對目標部位。from_account()支援已串接券商的歷史查詢;券商未提供的費稅、入出金或其他事件會依支援範圍估算、採持股口徑,或列入limitations,請確認限制後使用。(Issue #82、PR #322) data.indicator(..., strict=True)可選擇嚴格檢查:TA-Lib 指標只接受數值參數名稱,並拒絕 TA-Lib 的價格輸入 selector;pandas_ta 指標在嚴格模式下會拋出NotImplementedError。只檢查參數名稱,參數值仍由 TA-Lib 檢查。預設模式不變。(Issue #134、PR #318)
Fixed
finlab ai對話模式貼上多行內容時,即使最後一行沒有換行,也會合併成一題,不再拆成兩題、扣兩次額度。(PR #310)
2.2.3 (2026-10-04)
Changed
-
停損/停利後,
report.next_weights與Position.from_report()在下一次換股時,會依回測引擎將資金重新分配給剩餘持股。例如原本等權重持有五檔,停損三檔後,未設權重上限時,剩下兩檔的換股目標會由每檔 20% 改為 50%。本項修正不改回測損益與交易紀錄;實單的下一次換股部位可能變大,position_limit仍會限制個股權重。(Issue #207、PR #319)雲端排程會隨本次執行環境升級生效,不需要自行升級。自行執行的用戶請升級套件並重新啟動 Python/Jupyter kernel。若希望停損後保留現金,請在回測前把布林部位轉成浮點權重;例如原五檔各為 0.2,停損三檔後仍保留每檔 0.2。下例只將總權重超過 1 的列縮放至 1;若有缺少價格的股票,請先排除,再計算權重。
position = position.astype(float) position = position.div(position.abs().sum(axis=1).clip(lower=1), axis=0) report = sim(position, resample="M", stop_loss=0.1)行為變更
-
resample=None時,換股後到下一次部位變動前,report.next_weights與Position.from_report()不再把換股時因停損/停利排除的股票加回來,實單不會立刻買回,與回測一致。bool 與 float 部位的實單目標都會改變: 例如 3 檔各 1/3 的 float 部位,換股時排除 1 檔停損股後,實單目標由 3 檔各 1/3 改為 2 檔各 1/3,另外 1/3 留現金;bool 部位則由 3 檔各 1/3 改為 2 檔各 1/2。回測損益與交易紀錄不變。升級後下單前請先確認實單目標。(Issue #228、PR #314)行為變更
-
預設線上
data.get()/data.gets()會檢查排程外的歷史修正,即使快取尚未過期也能重新取得修正內容;已回傳的 DataFrame 仍是當時的快照,重新計算時請重新取得相關輸入。這會增加線上查詢與快取驗證成本。(Issue #304、PR #305)
Added
- 新增
finlab ai,可從終端機詢問 FinLab AI 助理。(PR #308) - 新增個股期口數回測第一階段:
TWStockFuturesMarket以整數口數、新台幣權益計算損益、費稅與保證金占用。價格採標的現股還原價,保證金比例由使用者提供;尚未包含基差、轉倉、追繳/斷頭、真實期貨資料與實單下單。(Issue #219、PR #292) - 支援期貨各月份 1 分 K 的下載與搜尋,保留跨週末夜盤資料。(PR #309)
data.universe()支援指定股票清單;台股 OHLCV 資料支援英文別名。(PR #316、#320)data.search(details=True)提供資料權限與免費資料截止日,預設搜尋也會標示 VIP 資料;免費帳號提示與文件補上台股歷史截止日 2023-12-31 與試用到期限制。(Issue #162、PR #306)
Fixed
- 修正歷史版本時間混合整秒與小數秒時無法解析的問題。(PR #312)
- 發行股數的
data.readiness()會核對上市、上櫃、興櫃的官方最新可得月份;缺少、未知或落後的期別會回傳未就緒,逐市場診斷見sources[0].periods。其他月季資料維持現行來源排程診斷。(Issue #133、PR #321)
Documentation
- 說明
next_weights是換股預覽,示範report.is_rebalance_due(),並區分換股到期、資料完整與實際成交。(Issue #163、PR #317) - 舊教學網址
/docs/getting-start/轉址至/docs/getting-started/。
2.2.2 (2026-10-03)
Changed
-
data.indicator()使用 TA-Lib 指標時,參數打錯會報錯並列出可用參數,不再忽略錯字、照預設值計算。需要還原價時,請用adjust_price=True(adj=True也可);adjusted=True、adjust=True都不是正確寫法。pandas_ta 指標不受影響。(Issue #274)行為變更
-
PortfolioSyncManager.update()換股時,若總資金已被這次不換股的策略占滿,現在會報錯並保留原持股,避免誤清倉。這次更新會全部停止,包含其他策略的停損停利。 請依錯誤提示調高total_balance,留足買股與備用現金,再重跑update();成功後才儲存或同步。只做停損停利或移除策略、不重建持股的更新不受影響。(Issue #164)錯誤提示的金額只是下限,仍需確認剩餘資金買得起目標股票;有餘額卻不足買一股的情況仍由 Issue #296 追蹤。
行為變更
Fixed
-
sim()與 lazy 換股排程:修正新版 pandas 無法解析resample='M+2'、'Q+1'等舊頻率名稱加日數位移的問題;先依 pandas 版本轉換頻率名稱,再解析位移。'M+2'與'ME+2'的換股日期相同,未帶位移的'M'與'W-FRI+1'行為不變,pandas 2.1 仍使用舊名稱。(Issue #269) -
report.display()在缺少 IPython 時,會依環境提示可用的顯示方式:Studio/Pyodide 在 cell 最後一行單獨寫report;一般 Python 腳本用report.to_html("report.html")儲存後,以瀏覽器開啟。文字摘要與原有顯示行為不變。(Issue #283)
Documentation
- 恢復中英文 API 參考總覽,舊網址
https://doc.finlab.tw/reference/轉址後可開啟,各模組文件可從總覽進入。(Issue #282) - 美股指數篩選文件與範例說明
us_universe(index='SP500'/'NDX')使用最新成分股名單,歷史回測需按日期套用成分股紀錄;既有 API 仍使用最新名單,正式資料不變。(Issue #239) - 補記 2.0.19~2.2.0 的資料讀取、季報日期轉換、主機時區與因子分析行為變更;各項記在實際生效的版本段落。(Issue #223、#274)
2.2.1 (2026-09-30)
Changed
-
hold_until()新增exit_mode,預設沿用上一筆出場條件('state'),恢復 2.1.0 以前的出場行為。要維持 2.1.0~2.2.0 只在訊號當天出場的行為,請指定'event'。(Issue #224)# 月營收、財報等條件:持續生效,直到下一筆資料更新 position = entries.hold_until(exits) # 單次事件:只在 exits 列出的日期出場 position = entries.hold_until(exits, exit_mode='event')例如:週一出場訊號為 True,週二有進場訊號,但沒有新的出場資料。
'state'會繼續擋住進場;'event'允許週二重新進場。若每天都有出場資料,兩種模式相同。使用
'event'時,請保留出場條件原本的日期,避免先與日頻條件混合;lazy 策略請先對出場條件單獨呼叫.collect()。使用'state'時,日期需由舊到新排序,且最後一筆 True 會持續擋住進場,直到出現 False。其他回測修正仍保留,結果不一定與舊版完全相同。結果可能改變
Fixed
-
data.get():修正 finlab 2.0.19~2.2.0 搭配 pyarrow < 16 時,快取過期後一直無法取得資料的問題。若看到RecordBatch沒有cast或select的錯誤,請升級後重新啟動 Python 或 Jupyter kernel,不必刪除快取。(PR #241、Issue #232)暫時無法升級 finlab 時,可改用
pip install -U "pyarrow>=16",同樣需要重新啟動。 -
季報資料使用
groupby_category()後,產業統計改用當天已公布的財報,避免算入同業尚未公布的數值;結果的索引也從季度改為公布日期。日頻、月頻資料不受影響。(PR #220、Issue #212)只有使用
groupby_category()後的季報結果,才需要因這次變更調整.loc寫法:.loc['2025-Q1']會變成查詢 1~3 月的公布資料,不再代表第一季財報,而且不一定報錯。請改成查詢指定日期以前的最新資料:industry_mean = quarterly_factor.groupby_category().mean() # 查 2025-05-15 當時已公布的產業平均;尚無資料時回傳空表 latest = industry_mean.loc[:'2025-05-15'].tail(1)尚未公布新一季財報的公司,仍使用前一季數值。
結果可能改變
-
季報日期轉換或排名後,若對原資料使用
stack().reset_index()並讀取symbol欄位,請先設定df.columns.name = "symbol";套件不再自動替原資料命名欄位。 -
data.get()下載失敗時,錯誤訊息會說明原因與處理方式,並移除可直接下載資料的網址,避免貼出錯誤求助時外流。(PR #258、Issue #247)from finlab.exceptions import DataError try: close = data.get('price:收盤價') except DataError as error: print(error)原本用
except requests.RequestException處理下載錯誤的程式仍可使用;瀏覽器(Pyodide)版請改用except DataError。自訂錯誤處理請用error.status讀取 HTTP 狀態碼、error.kind判斷錯誤類別;error.request與回應的網址、標頭、內容不再提供,非 HTTP 錯誤的error.response為 None。 -
同時開多個 Jupyter kernel 或平行回測時,
data.get()可能在歷史資料修正後仍讀到舊資料。現在下次讀取時會重新下載需要更新的資料,不必手動清除快取。(PR #260、Issue #255) -
修正重新啟動 Python 後,相同資料的計算結果或排列順序可能不同的問題,涉及
industry_rank()、weight.cap_industry()、create_custom_report()、drop_duplicate_cols()。升級後結果固定;小數尾數的差異仍可能影響剛好落在選股門檻上的股票。若有儲存結果供比對,請在升級後重新儲存。(Issue #225) 結果可能改變
2.2.0 (2026-09-28)
Added
-
data.get(dataset, as_of=...)/data.get(dataset, version=...)可下載歷史版本,data.versions(dataset)可查詢可用版本。as_of不帶時區時採台北時間,只有日期時代表當天 00:00;version則指定某一版,方便重現結果。限付費會員,下載計入每日配額,快取不重複扣額度。目前保留約兩週,預計延長至 30 天以上。財報請改用data.get('financial_statement_versions')。as_of與version只能擇一,也不能搭配start/end、逐筆/分鐘資料或use_local_data_only;API 仍可能調整。(PR #211) 實驗性 -
data.get支援台股*_revised(更正版)表的索引轉換與季報遮罩;截斷回測時,revised_at晚於截斷日的日期會改成截斷日,數值 item 會發出警告,提醒更正值無法還原成當時的數值。資料表尚未開放。(PR #209)
Changed
finlab.tools.event_study.create_factor_data()不再把補班交易的週六延到週一,當天的因子與股價會納入分析,IC 與分組報酬可能改變。非交易日仍延到下一個交易日。這項修正不影響index_str_to_date();.deadline()遇到補班交易日也會保留當天(月營收見下方 PR #210)。(PR #210;2026-09-30 補記,Issue #223) 行為變更 結果可能改變
Fixed
-
修正缺少公布日期的季報數值被提前用於回測的問題,適用於
index_str_to_date()(含sim()預設處理)與.deadline()。例如「ROA 前 20 名(.deadline())」月頻策略,修正後不再讓無法交易的 7947 占住一個名額,總報酬由 128.2% 變為 139.5%,交易數由 2465 增為 2575。2026-09-27 的台股檢查只發現.deadline()缺日期,未發現index_str_to_date()缺公布日;其他市場未檢查。(PR #208;2026-09-30 更正:原說明誤稱index_str_to_date()不受影響,Issue #274)資料比對紀錄
2026-09-27 實測台股(含興櫃)全部 211 個季報欄位,涵蓋 2013-Q1~2026-Q2、2,870 個股票代號:15,178,900 筆有值資料中,136 筆缺少
deadline()使用的截止日,占 0.000896%,全部集中在興櫃公司 7947 補丁科的 2026-Q2(92 個原始財報欄位、44 個財務指標)。這裡一筆指「股票 × 季度 × 欄位」,不是 136 家公司;該季公告日為 2026-09-17,本次掃描未發現有數值卻缺少index_str_to_date()使用之公告日的資料。比例按日期轉換前的原始資料計算,不代表填值後受影響的歷史格子比例。結果可能改變
-
月營收截止日若是補班交易的週六(2009-01-10、2016-09-10),原本被誤推到週一,現改為當天生效;截止日遇假日仍照常順延到下一個交易日。以範例策略測試:營收動能策略總報酬 471.8% → 459.7%、本益成長比策略 1421.9% → 1427.7%,其他 7 個價格與季報範例策略結果完全相同。(PR #210) 結果可能改變
2.1.1 (2026-09-24)
Fixed
- 修正 pandas 3 遇到極遠日期(例如 2999 年)時,計算台股收盤時間會出現
OutOfBoundsDatetime的問題。一般日期與時區行為不變。
2.1.0 (2026-09-24)
2.0.22 與 2.0.23 已從 PyPI 撤回(yanked)
2.0.22 讓「一般 pandas DataFrame 在左、FinlabDataFrame 在右」的運算改用 FinlabDataFrame 的對齊規則,常見範本的部位因此全為 NaN,雲端排程策略執行失敗;2.0.23 也包含這項變更。兩版已撤回;請由 2.0.21 或已撤回版本升級至 2.1.0。2.0.22/2.0.23 的其他改進(sim(end_date=...)、data.search() 別名、季度資料自動對齊日期等)都保留在 2.1.0,詳見下方各版說明。
(cond * score).is_largest(N) 請改寫為 score[cond].is_largest(N)
(cond1 & cond2) * score 會讓不符合條件的股票分數為 0。符合條件的股票少於 N 檔時,is_largest(N) 會用這些 0 分股票依欄位順序(1101、1102、1103…)補滿 N 檔,持股因此混入不符合條件的股票。改用 score[cond].is_largest(N)(或 score.where(cond).is_largest(N)):不符合的股票變成 NaN、不參與排名,符合的少於 N 檔時就只持有這些。2.1.0 遇到這種補位會發出 TopNPaddingWarning,選股結果不變。官方「小資族資優生」範本也會照這個方式更新,符合條件的股票少於 10 檔時,持股會少於 10 檔。
# 改寫前
position = ((cond1 & cond2) * score).is_largest(10)
# 改寫後
position = score[cond1 & cond2].is_largest(10)
部位用 reindex(<月營收日期>) 對齊而沒有填值時,請加上 fill_value=False,避免部位開頭出現 NaN 列(見下方 PR #194)。
已經寫成 score[cond] 仍出現警告,代表符合條件的股票在第 N 名同分(例如分數都是 0),依欄位順序取捨;需要固定結果時,再加一個次要排序分數。
想維持 2.0.21 的舊行為
各項行為變更的舊寫法如下。修正錯誤的項目(sim() 的 NaN 處理、季度橫斷面的前視、drawdown_control/target_volatility、from_weight 權重總和)沒有單獨的舊寫法,要完全重現舊結果只能 pip install finlab==2.0.21,但不建議:舊結果含有這些錯誤。
| 變更 | 維持舊行為的寫法 |
|---|---|
position[timing] 改為空手(PR #191) |
position.loc[timing.reindex(position.index, fill_value=False).to_numpy()]:刪除 False 的日期,sim() 沿用前一天持股 |
set_universe() 不帶條件改為取消篩選(PR #192) |
data.set_universe(exclude_sector=[]):限制在目前市場目錄中的所有股票 |
| Studio 預設不上傳(PR #187) | sim(..., upload=True) |
hold_until 出場訊號改為事件(PR #177) |
position = entries.hold_until(exit.reindex(entries.index, method='ffill')) |
| universe 條件選不到股票時報錯(PR #181) | 無舊寫法;過去會默默改用全市場,請修正篩選條件 |
Added
-
sim()回傳的報告新增upload_status,可查看skipped、pending、success或error;上傳失敗,以及環境變數覆蓋明確指定的報告名稱時,發出StrategyUploadWarning。原生 Python 的上傳仍在背景執行,狀態會隨上傳完成而更新。(PR #178) -
TopNPaddingWarning:is_largest(N)/is_smallest(N)用同分股票補滿 N 檔時,會列出受影響的日期與補入檔數,並提供改寫方式。只有選取邊界的同分會警告,選股結果不變。(PR #200) -
PandasLeftOperandWarning:一般 pandas DataFrame 在左、FinlabDataFrame在右做+ - * / // % ** & | ^,且兩邊日期或股票不同時發出。這時用的是 pandas 對齊(日期不往前填值、股票取聯集、回傳一般DataFrame),結果與FinlabDataFrame放在左邊不同。結果不變,可依類別過濾。(PR #193) -
ZeroShareAllocationWarning:Position.from_weight()/from_report()在整張下單時,若分配的資金買不起一張,會列出分配到 0 股的股票並提醒。請改用odd_lot=True或增加fund。下單數量不變。(PR #190、order_executor PR #23) -
data.reset_universe():取消 universe 篩選,之後的get()/gets()(含快取)回傳完整資料。巢狀universe()離開時仍還原原本的選擇。(PR #186) -
data.get_calendar()、data.readiness():查看台股交易日曆,以及策略需要的資料是否已更新。台股日頻的data.is_tradable()會等資料確實更新才回傳 True;其他市場或無法取得日曆時,沿用快取到期判斷。回測報告也會顯示預定換股日、持股進度、尚缺資料與重跑提示。(PR #182、#195、#198) -
回測報告儀表板新增「客服」面板:notebook 中
display()的報告會帶入快取的 FinLab 登入憑證(有效至多 1 小時),不必再登入即可聯絡客服;to_html()匯出的檔案不含憑證。分享含輸出的.ipynb前請留意。(PR #197)
Changed
-
sim()的upload預設(None)只在雲端排程(設定FINLAB_FORCED_STRATEGY_NAME)時上傳報告;FinLab Studio 需明確傳入upload=True才上傳,避免 AI 反覆實驗時每次回測都覆蓋線上報告。FINLAB_STRATEGY_NAME仍決定上傳時使用的策略名稱。(PR #187) 行為變更 -
data.set_universe()不帶篩選條件(或條件皆為"ALL")時等同data.reset_universe(),取消篩選;with data.universe():、set_us_universe()、with data.us_universe():相同。過去會限制為目前市場目錄中的所有股票,目錄外的代號(例如集保非標準代號、歷史代號)會被默默刪除。(PR #192) 行為變更 -
universe 篩選條件選不到任何股票(例如產業名稱打錯)時拋出
ValueError,原本的 universe 不變;過去會默默改用全市場。已啟用的 universe 與某張資料表完全沒有交集時,發出UserWarning並回傳未篩選的資料。股票代號前後的空白會先去除再比對。(PR #181) 行為變更 -
最低支援 Python 3.10(
requires-python >= 3.10)。2.0.3 起已不再提供 Python 3.9 的 wheel,現在與套件設定一致。 行為變更 -
移除 2.0.23 新增的
MissingDisclosureWarning。季度缺少對齊日期時用戶無從處理,改由資料端補齊日期,不再對用戶發出警告。 -
data.get()/data.gets()下載資料遇到 HTTP 404 或 412 時,會重新取得下載網址,再下載一次;過去直接拋出錯誤。只重試一次,重新下載仍失敗時,拋出的是重新下載那一次的錯誤。其他 HTTP 錯誤(例如 403、500)不重試,直接拋出。第一次就下載成功的情況不受影響。(PR #185;2026-09-30 補記,Issue #223) -
(只換例外型別)
sim()的resample傳入日期清單(DatetimeIndex、DataFrame、Series 或 list),而回測期間內沒有其中任何一個日期時,改拋ValueError: resample has no dates within the simulation range;過去是IndexError: list index out of range。resample傳入字串(例如'M')而回測期間內沒有任何換股日時,仍然是IndexError。兩種情況都要處理的程式請寫except (IndexError, ValueError)。(PR #185;2026-09-30 補記,Issue #223) 行為變更 -
sim()在部位日期未指定時區時,改以市場時間決定資料截止點(台股採台北時間、美股採 UTC−5),避免 Colab 等 UTC 主機在台北時間 00:00~08:00 執行時,最新訊號與持股落後一天。現在同一時刻在不同時區主機執行,結果一致。影響限於最新一期;從 2.0.23 升級的 UTC 用戶,若同時遇到非交易日 15:00 前的修正,訊號可能一次前進兩天。自訂市場tzinfo()為 None 時仍採主機時間。(PR #196;2026-09-30 補記,Issue #274) 行為變更 持股可能改變
Fixed
-
台股收盤時間改以原時間戳的精度設定 15:00,避免日曆不可用、訊號日期超出 pandas 奈秒範圍(例如 2999 年)時拋出
OutOfBoundsDatetime。一般日期與時區行為不變。 -
sim()會處理下市持股,出場後不再於後續換股買入。台股依交易所下市公告,在公告後第一個有成交價的交易日出場;公告晚於最後價格、且下市日已在資料期間內時,改以最後可用價格出場。沒有公告時,價格資料尾端至少 20 個交易日缺價才採用最後價格出場;這是依缺價推定,不代表已確認下市。resample=None在出場日重新分配部位;定期換股則保留現金到下一次換股。受影響時發出DelistedHoldingWarning,列出股票及出場日期。過去可能持續用最後價格估值、反覆買入,交易報酬顯示 NaN;歷史績效、回撤、交易及目前/下一期持股都可能改變。(PR #183) 結果可能改變 持股可能改變 -
實單換股(
PortfolioSyncManager、Position.from_report()):台股日頻的換股期間從週末或假日訊號日期的前一個交易日 15:00 開始,目標持股也從這時起改用新一期。過去只在晚上執行的排程,會在週五晚上用舊一期的目標重建部位,卻記錄成已完成換股:週頻策略實單每週落後回測一週,月底遇到週末的月頻策略整月維持舊持股,也沒有任何警告。sl_enter/tp_enter的暫時出場在同一時間結束。(PR #185、order_executor PR #24、#25) -
實單換股:
PortfolioSyncManager.update()發現持股仍是已被取代的舊一期目標(排程錯過換股期間,例如主機停機、cron 未觸發)時,記錄警告並補上報告目前的目標;過去會靜默維持舊持股直到下一次換股。持股紀錄新增applied_signal_at,記下實際採用的訊號日期;週末或假日的訊號與前一個交易日的訊號在同一個交易日執行時,不視為錯過。無法解析的舊持股紀錄只略過這項檢查,不會讓其他策略無法更新。update()需要每次排程都執行,不要只在is_rebalance_due()為 True 時才呼叫。(PR #185) -
台股日頻實單換股:
is_rebalance_due()在換股期間持續為 True,直到下一期訊號取代;排程即使開盤後或收盤後才執行,也不必再等一期。無法取得交易日曆時,改依訊號日期的收盤時間判斷。儀表板於執行交易日收盤後停止顯示「換股中」。(PR #185、new_website PR #103) -
sim():台股日頻策略在非交易日(週末、假日)台北時間 15:00 前執行時,資料截止點不再退回前一天,日期為當天的訊號會納入,next_weights與目前/下一期持股因此可能和 2.0.23 以前不同。過去只要在 15:00 前執行就一律退回前一天,即使當天沒有開盤;交易日 15:00 前仍退回前一天。取不到交易日曆時沿用原本的規則。影響的是執行當下的最新一期。(PR #185;2026-09-30 補記,Issue #223) 持股可能改變 -
sim(end_date=...)的歷史回測不再查詢交易日曆與資料 metadata,report.is_tradable()一律為 False。(PR #185) -
交易日曆、儀表板的個股資料與股票圖示、文件內嵌報告改用正式網域
r2.finlab.finance,不再使用有流量限制的r2.dev網址。交易日曆每三小時重新取得;超過有效期限的日曆只要還列有未來交易日就繼續使用,下載失敗也沿用已取得的日曆。(PR #185、new_website PR #103) -
position[timing](timing為日期索引的布林 Series)保留所有日期,timing為 False 的日期空手(布林部位為 False、權重部位為 0),與position & timing相同。過去會刪除這些日期,sim()往前填值後沿用前一天的持股,擇時濾網在該空手的期間仍然滿倉。股票索引的布林 Series(含 object dtype)仍用來選取欄位。移除只在未發布版本出現過的DateMaskSelectionWarning。(PR #191、#173) 行為變更 結果可能改變 -
sim()在輸入時統一把部位中的 NaN 視為未持有(等同fillna(0)/fillna(False));合併兩組部位(pos_a + pos_b、combine_first、pd.concat)產生的 object 欄位會轉成布林或浮點數。過去resample=None時,經過 NaN 的進出場會被略過,開頭整列都是 NaN 的部位會拋出IndexError,avgNStock也會把 NaN 算成持有。部位開頭有 NaN 列且resample=None時,回測起點可能提前。以 1,089 個雲端排程策略重跑:275 個的部位含 NaN,0 個的最新目標權重(next_weights)改變,79 個的績效指標改變,多數是因為過去略過了第一次換股。(PR #194) 結果可能改變 -
季度資料的橫斷面運算先對齊各公司的財報公告日,再以當日已公開的數值計算:
rank(axis=1)、is_largest()/is_smallest()(含 lazy)、df.cs與df.sector的各方法,以及全為季頻的neutralize()。不再讓提早公布的公司與尚未公布的同季數值比較,避免前視偏誤;cs.rank()對季度資料也不再全為 NaN。保留同值排名規則與未公布資料的空值。(PR #184、#188) 結果可能改變 -
hold_until(exit, ...):出場訊號與進場訊號一樣視為事件,只在自己的日期生效。過去exit的日期比進場稀疏(事件日、週/月/季頻)時,最後一個出場訊號會往後填滿,該股票之後無法再進場。要把低頻出場條件當成持續狀態,請寫exit.reindex(entries.index, method='ffill')。(PR #177) 結果可能改變 -
weight.drawdown_control()/target_volatility()先將布林或總絕對權重大於 1 的部位轉為sim()使用的權重,再縮放風險曝險,修正縮小部位後又被sim()正規化回滿倉的問題。縮放後超過滿倉的曝險仍受sim()上限限制。(PR #180) 結果可能改變 -
resample=None時,未來日期的部位列保留為報告中的預定換股日,不會進入實際持股;也修正未來日期的列改變稀疏部位的回測期間、或繞過每日訊號截止時間的問題。(PR #196) -
Position.from_weight()的權重絕對值總和大於 1 時,與sim()相同地等比例縮為滿倉並發出警告;過去會拋出AssertionError: Unexpectedly insufficient funds.。(PR #174、order_executor PR #21) -
finlab.tools.factor_metrics.ic()/calc_metric()不再要求日期索引名稱必須為date;未命名或使用其他名稱的索引也能正確分日計算。(PR #176) -
可轉債報告從
cb_published_info的「債券簡稱」取得名稱,兼容舊版name與代號欄位格式,並採用最新的非空名稱;修正交易與持股只顯示代號的問題。(PR #159) -
SinopacAccount.update_order()取消零股委託後,若重新下單失敗或未取得訂單代號,改拋OddLotRepriceError,避免只記錄錯誤卻讓呼叫端以為改價成功。(order_executor PR #18) -
OrderExecutor.show_alerting_stocks():修正 pandas 3 相容性,警示股代號統一使用字串。(order_executor PR #20) -
恢復 2.0.21 的行為:一般 pandas DataFrame 放在左邊與
FinlabDataFrame做四則與邏輯運算(pd_df * fdf、pd_df + fdf、-、/、//、%、**、&、|、^)恢復 2.0.21 的 pandas 對齊:日期與欄位取聯集、不往前填值,回傳一般DataFrame。2.0.22 改用FinlabDataFrame的對齊(欄位取交集、日期往前填值),「小資族資優生」等範本以empty_df = pd.DataFrame(1, index=..., columns=...)乘上面額變更比例(par_value_change_*)計算市值時,只剩有面額變更事件的股票(上市、上櫃相乘後為 0 檔),部位全為 NaN,sim()拋出ValueError。比較運算(<、>、==等)在 2.0.21 就走FinlabDataFrame對齊,維持不變。(PR #171) 行為變更 -
沒有包成
FinlabDataFrame的季度字串索引 DataFrame 與日期資料運算(包含FinlabDataFrame.align())不再拋出 2.0.22 新增的TypeError,恢復 2.0.21 的結果。FinlabDataFrame的季度資料在reindex()/reindex_like()/align()對齊日期時自動轉為財報公告日的功能保留。(PR #171) -
回測報告(
report.display()/report.to_html()):修正字級與間距跑掉的問題。手機上的月報酬表格可左右捲動,數字不再重疊。 -
回測報告:打開個股面板(⌘K 搜尋股票)時,寬螢幕上報告改排在面板左側,不再被面板蓋住。報酬比頁「策略」圖例在深色主題下看不見,改為與長條相同的顏色。
-
plot_tw_stock_radar():預設的line_polar模式座標上限改為cut_bins(預設 10),過去會乘上股票數(3 檔時為 30),圖形擠在中央;bar_polar堆疊模式不變。 -
plot_tw_stock_candles():標題置中,不再與左上角的區間按鈕重疊。
Docs
-
PyPI 說明頁改寫為英文,附上每段範例的實際輸出與回測報告各頁截圖。
-
美股範例的匯入改為
from finlab.markets.us import USMarket(原本的from finlab.market import USMarket會出錯)。 -
下單文件新增「錯誤 5:有訊號但沒有下單」,說明整張下單的無條件捨去與
ZeroShareAllocationWarning。(PR #190) -
is_largest()/is_smallest()的說明與 DataFrame 參考文件加上score[cond].is_largest(N)的寫法。(PR #200)
Engineering
- tests:以離線
sim()重現範本寫法,並固定 pandas 在左的各運算子結果與 2.0.21 相同。(PR #171)
2.0.23 (2026-09-23)
Fixed
- 季報轉日期(
index_str_to_date(),以及與日頻資料合併時)改用已公布且有值的最新一季。晚交的舊季報不再蓋掉新季報,同一天公布多季也會取最新一季;日期索引不變。以正式資料比對,每股盈餘約 200 檔、1.3 萬個交易日的數值因此修正。(PR #169) 行為變更
Added
index_str_to_date():有數值的季度因為沒有對齊日期而被略過時,發出MissingDisclosureWarning,列出筆數與範例;過去會靜默略過並沿用前一季數值。輸出不變。(PR #170)
2.0.22 (2026-09-23)
Added
-
data.search()支援搜尋資料名稱、說明、別名與欄位。例如data.search('市值')可找到etl:market_value,data.search('集保')可找到inventory與etl:inventory:*。全半形、大小寫與常見用字差異不影響搜尋;回傳型別不變。(PR #165) -
data.get():找不到資料集時改拋finlab.exceptions.DatasetNotFoundError(RuntimeError的子類別,原本的except RuntimeError仍可捕捉),列出最接近的正確 key 與口徑差異說明,不再顯示內部儲存路徑。已登記為等價的舊 key(例如margin_transactions:融資餘額、financial_statement:營業活動之淨現金流入(流出))會發出UserWarning並自動改抓正確的 key;data.gets()與start/end讀取同樣適用。(PR #165) -
sim(end_date=...):指定回測結束日,包含當天;持有中股票也只用該日以前的價格估值。sim_batch()與 lazy 部位同樣支援。過去只截斷月頻部位時,報酬曲線仍可能延伸到今天;現在可用sim(position, end_date="2025-12-31")明確截止。未指定時行為不變。(PR #166) -
report.get_stats()/get_benchmark_stats():加入與get_metrics()同名的 camelCase 別名annualReturn、sharpeRatio、sortinoRatio、calmarRatio、volatility、maxDrawdown、avgDrawdown、avgDrawdownDays、m12WinRate,數值與原本的 ffn 欄位相同,舊欄位保留。win_ratio不加別名:它只計算已出場交易,get_metrics()的winRate包含持有中的交易。(PR #166) -
finlab.tools.factor_metrics.ic(method=...):可選'pearson'(預設,結果不變)或'spearman'(Rank IC)。(PR #166)
Changed
-
report.trades['stock_id']改為只有股票代號(例如2330),可直接與價格資料合併。股票名稱請讀新欄位name(例如台積電,查無名稱時為空字串),或讀symbol取得「代號 名稱」。CloudReport.trades同樣適用;網站、Studio 與 HTML 報表顯示不變。(PR #166) 行為變更 -
季度字串索引(如
2013-Q1)自動對齊日期:FinlabDataFrame.reindex()/reindex_like()/align()對齊到日期索引時,會先以index_str_to_date()轉成各公司財報公告日。過去reindex(close.index)得到全 NaN,reindex(..., method='ffill')拋出TypeError。一般 pandas DataFrame 放在左邊與FinlabDataFrame運算(pd_df + fdf、pd_df & fdf等)也改用FinlabDataFrame的對齊規則(日期取聯集並往前填值、欄位取交集),回傳FinlabDataFrame,不再是補滿 NaN 的 pandas 結果。沒有包成FinlabDataFrame的季度索引 DataFrame 與日期資料運算時,改為拋出TypeError並提示FinlabDataFrame(df)或index_str_to_date(),不再靜默產生 NaN。(PR #166) 行為變更 -
finlab.tools.event_study.create_factor_data()的<name>_factor_quantile改為 1~5 組,與df.cs.bucket(5)一致。10 檔股票會平均分成每組 2 檔,修正原本分成 1/2/3/1/3 檔、組別為 0~4 的問題。(PR #166) 行為變更 -
report.get_stats(resample=...):resample從未生效,現在傳入會發出DeprecationWarning,結果不變;統計一律以日頻報酬計算。舊版上傳 API 的stats內容會多出上述別名欄位。(PR #166) -
FinlabDataFrame與pd.Series運算時,依 Series 的 index 決定對齊方向:以股票代號為 index 的 Series(例如pd.Series({'2330': 1.2})、close.iloc[-1])會套用到每一天,&/|中缺少的股票視為False,四則運算為 NaN;過去股票代號被拿去對齊日期,結果全為 NaN 或False。日期(或季/月字串)index 的 Series 行為不變。index 同時符合日期與股票、或兩者都不符合時,改拋ValueError,提示改用df.mul(s, axis=0)(對齊日期)或df.mul(s, axis=1)(對齊股票)。df[股票布林 Series]改為選取欄位。(PR #168) 行為變更 -
df[日期布林 Series](例如大盤擇時position[timing])仍會刪掉 False 的日期,sim()會以前一期持股補上而不是空手;現在發出FutureWarning,建議改用position & timing。下個 minor 版將改為保留這些日期並視為False。沒有日期 index 的長表(例如broker_transactions)用df[df['stock_id'] == '2330']篩選列不受影響。(#112;PR #168)
Fixed
-
finlab.login():瀏覽器登入失敗、被拒絕或逾時時,過去會直接返回、看起來像已登入;現在拋出finlab.exceptions.LoginError(RuntimeError的子類別),並說明重新登入與無瀏覽器環境改用python -m finlab token --env的方式。(PR #165) -
finlab.tools.factor_metrics.calc_ic(rank=True):過去只對因子排名、報酬維持原值,算出的既不是 Pearson 也不是 Spearman;現在每個日期對因子與報酬都排名,以成對有效值計算真正的 Spearman,結果與scipy.stats.spearmanr一致,數值會改變。(PR #166) 行為變更 -
calc_ic(rank=False):任一因子欄位全為 NaN 時會拋出IndexError;現在從「每個有 IC 的因子都有值」的第一個日期開始回傳,全 NaN 欄位保留為 NaN。(PR #166) -
sim():部位少於 3 列時拋出IndexError;現在持有到價格資料最後一天。(PR #166) -
report.display():沒有安裝 IPython 的環境(例如未安裝相依套件的 Pyodide、一般 Python 腳本)會拋出ImportError;現在改印report.to_text()文字摘要,並提示pip install ipython或report.to_html()。save_report_path仍會先寫出 HTML。(PR #166) -
data.indicator():未安裝 TA-Lib 與 pandas_ta 時,錯誤訊息列出確切的pip install TA-Lib/pip install pandas-ta與兩者的指標命名方式;在瀏覽器(Pyodide)中改為說明 FinLab Studio 已預載 TA-Lib、可重新整理頁面,以及 Studio 未預載 pandas_ta。TA-Lib 沒有該指標時會再嘗試 pandas_ta(過去安裝 TA-Lib 後無法使用 pandas_ta 指標);兩者都沒有時拋出ValueError,並對大小寫錯誤提示,例如'rsi'→'RSI'。(PR #166)
Docs
-
登入文件改為目前的流程:本機
python -m finlab login;伺服器與排程在本機執行python -m finlab token --env,設定FINLAB_REFRESH_TOKEN、FINLAB_SESSION_ID、FINLAB_API_KEY;Colab 直接finlab.login();FINLAB_API_TOKEN已棄用。並列出認證優先順序。(PR #165) -
補上 2.0.0 起未寫進文件的行為變更:
sim()的upload預設為None,只有設定FINLAB_STRATEGY_NAME或FINLAB_FORCED_STRATEGY_NAME(FinLab Studio、雲端排程)時才上傳報告;本機、Jupyter、Colab 預設不上傳,需要時請傳入upload=True或呼叫report.upload()。(PR #165)
Engineering
- tests:新增離線
sim()測試工具(合成市場與授權 stub),單元測試可直接執行實際的回測引擎與報表組裝,不需憑證或下載資料。(PR #166)
2.0.21 (2026-09-21)
Fixed
-
季度布林條件與日頻資料合併後,
~mask、A & ~B等選股條件現在能正確運算,修正選到錯誤股票的問題。升級後請重新產生舊的條件表。 首次公布財報前仍為未知值;回測視為不持有。若要使用.astype(bool)或np.where,請先fillna(False)。(PR #160) 結果可能改變 -
Report.to_pickle():修正回測報告還在背景上傳時,立即存檔可能出現RuntimeError: dictionary changed size during iteration的問題。(PR #161) -
Pyodide 盤後逐筆/分鐘資料:瀏覽器下載遇到 HTTP 錯誤時,保留伺服器回傳的錯誤內容(例如尚未收齊的交易日、權限不足),不再只顯示一般的 HTTP 錯誤。
2.0.20 (2026-09-18)
Added
data.get("tw_tick:2330", start=..., end=...)與data.get("tw_minute:2330", start=..., end=...):新增台股盤後逐筆成交與一般交易時段 1 分鐘 OHLCV。需指定起訖日期,每次最多 31 個日曆日;資料尚未收齊時會報錯。時間採台北時區,同時間多筆成交會保留;分鐘線不補缺漏,13:30 撮合獨立一列,14:30 盤後定價交易只收錄於逐筆資料。台股資料會員可使用,免費樣本為 2330/2026-06-01,歷史資料持續補齊。詳見盤後逐筆與分鐘資料。
Changed
data.gets()不支援逐筆與分鐘資料集:清單中含tw_tick:*、tw_minute:*時拋出ValueError,請改用data.get()並指定start/end。其他資料集的data.gets()行為不變。(2026-09-30 補記,Issue #223)
2.0.19 (2026-09-16)
Added
data.universe.membership():新增TSE、OTC、TSE_OTC的每日上市櫃資格布林遮罩,可在橫斷面排名前用score[eligible].is_largest(20)篩選。依目前可得的上市櫃與終止紀錄重建有效期間,上市櫃日包含在內、終止日起排除,支援轉板與多段上市期間。缺少可驗證紀錄的期間維持False,並以警告與attrs['membership_missing_history']揭露不完整歷史;不提供歷史版本快照,也不涵蓋完整 ETF 母體。(#140)data.get(dataset, start=..., end=...):一般資料集可用關鍵字參數start/end只讀取一段日期,可只給其中一個。篩選比對的是資料表儲存的date欄,不是轉換後的索引:索引是季別的資料表(例如2024-Q1),比對的是該列儲存的日期,不是季別本身。start/end只寫日期時代表當天 00:00,剛好等於start或end的資料會包含在內;date欄帶有時間的資料表,end當天 00:00 之後的資料不會回傳。資料集沒有date欄,或start晚於end時拋出ValueError。不帶start/end時回傳值不變。(2026-09-30 補記,Issue #223)
Fixed
CloudReport:讀取 legacy 持股資料時,補齊缺少的市場、移動停利與權重等執行預設值,讓設定與 canonical 報表一致;已提供的設定與持股動作不變。 (#155;PR #156)Position.from_weight()/from_report():修正傳入的allocation回呼被忽略的問題,現在會呼叫自訂分配函式;預設 greedy 分配與張數/零股換算不變。(#114;PR #151、order_executor#17)sim():空部位或全 NaN 部位會提前拋出ValueError,提示使用add(fill_value=0)合併不同標的,或以明確的 0 表示空手,取代後續難以判讀的錯誤。正常零值與稀疏部位仍可通過輸入形狀驗證。(#65;PR #149)- 回測引擎:對仍追蹤的部位,遇到 0、負值或無限大的交易價時,在除法前拋出含標的與資料列的
ValueError,避免除以零或報酬曲線變成 NaN。未持有過的資產與 NaN 缺價處理維持原樣;未修改上游報價。(#45;PR #150) Report:自訂 Series/DataFrame 成交價以custom標記匯出持股設定,修正 JSON/HTML 匯出失敗,報表顯示「自訂/Custom」。即時 Report 保留原價格矩陣;雲端執行資訊無法還原矩陣,讀回時使用close。(#76;PR #152、new_website#80)- Pyodide 資料下載:ArrayBuffer 改為每次最多轉換 8 MiB,再組合為 Python bytes,避免大型資料超過 JavaScript 單一字串長度限制。保留所有位元組值;瀏覽器整體記憶體限制仍適用。(PR #153)
Report.upload():修正雲端執行使用舊版上傳 API 時,尚未檢查伺服器回應就回報成功的問題。HTTP 非 200、無法解析的 JSON 或伺服器回傳的錯誤現在會回傳錯誤結果;若FINLAB_FORCED_STRATEGY_NAME覆蓋使用者指定的不同報告名稱,也會發出警告,說明實際寫入的部署策略。(#141)CloudReport.from_cloud():當網站報告的metrics.backtest.updateDate比 canonical 報告新時,改為載入完整的網站報告,避免讀到舊績效與舊持股。日期相同、較舊、缺漏或非數值時仍沿用 canonical 報告;此判斷不區分資料日期相同的重跑結果。(#137)ml.feature.TalibIndicatorFactory.generate_feature_names():特徵名稱去重改為保留首次抽樣順序,修正相同亂數種子下,跨 Python 行程仍可能因 hash randomization 而得到不同特徵欄位順序的問題。(#135)data.universe():表格資料的symbol/stock_id若僅因前後空白而無法匹配目前股票集合,現在會保留這些資料列並發出UserWarning,避免被靜默排除。回傳的識別碼仍保留原值,資料來源仍需清理空白。(#132)ml.DEnsembleModel:修正 feature selection 使用set(...)去重時,特徵欄位順序會受 Python hash randomization 影響,導致不同 Python 行程在相同資料與 seed 下仍可能產生不同模型輸出的問題;現在改為保留抽樣順序並去重。ml.DEnsembleModel:修正 pandas 3 Copy-on-Write 語意下,feature importance NaN 填補使用 chainedinplace=True可能不會寫回原 DataFrame 的問題,改用 assignment 形式填補。- 行為變更、回測結果可能改變
data.indicator(..., adj=True)改為真的使用還原股價計算。2.0.18 以前adj會原封不動傳給 TA-Lib,TA-Lib 靜默忽略不認得的參數,指標一直用未還原價計算,也不會報錯;adjust_price=True則兩版都用還原價。finlab.ml.feature的adj=True同樣改為用還原價計算指標:2.0.18 以前指標用未還原價,需要正規化的指標(均線類、MACD、MOM等)卻除以還原收盤價。2.0.18 以前寫adj=True的程式,升到 2.0.19 以後指標數值、訊號與回測結果可能改變。同時對adj_open/adj_high/adj_low/adj_close/adj_volume等不支援的 kwargs 明確拋錯,避免使用者誤以為指標已使用還原價。(2026-09-30 補記行為變更,Issue #274) MaeMfeAnalysis.display():移除對 Plotlyfigure_factory.create_distplot的依賴,改用graph_objects建立分布圖,修正 Plotly 7 相容性。ffn_core:月頻轉換及freq="m"/freq="y"繪圖改用相容的月底/年底頻率,修正 pandas 3 的ValueError;pandas 2.1 以上的既有用法與取樣日期不變。(#70;PR #144)Report.position_info2():修正可轉債缺少未還原收盤價時,寫入還原價 fallback 會修改不可變 Index 的錯誤。一般股票仍優先使用未還原收盤價。(#64;PR #143)- 報表數字可能改變
report.metrics.sharpe_ratio(riskfree_rate=...)、sortino_ratio(riskfree_rate=...)與report.get_metrics(riskfree_rate=...):每次呼叫都依傳入的riskfree_rate計算。過去同一份報表沿用第一次計算時的riskfree_rate,之後不論傳入什麼值都得到同一組數字:先用預設值(0.02)算過之後,再傳入其他值沒有作用;第一次呼叫就帶了其他值時,之後用預設值呼叫,得到的也是那個值算出的數字。受影響的是 Sharpe、Sortino 這類用到無風險利率的指標;年化報酬、最大回撤、波動度、Calmar 不隨riskfree_rate改變。(#127;2026-09-30 補記,Issue #223) PortfolioSyncManager.update():修正持股清單差異警告中的參數名稱,由不存在的force_override=True改為正確的force_override_difference=True,更新判斷不變。(#75;PR #142)
Documentation
- 多策略組合:說明
odd_lot/margin_trading選項需在每次update()傳入,且只套用到這次重建的策略。(#62;PR #145) - 移動停利:釐清一般多單以進場成本為分母,並區分出場訊號與實際成交;進場 100、最高價 150、
trail_stop=0.2的門檻為 130。(#69;PR #146) - 自訂 benchmark:統一改用回測前覆寫
Market.get_benchmark()的範例;更換比較基準需重跑sim(),直接指定report.benchmark不會同步更新所有圖表與統計。(#77、#80;PR #147) - 大盤擇時:以
FinlabDataFrame的position *= timing取代刪除日期的篩選方式,使用既有自動對齊規則,移除不必要的reindex與轉型。(#112;PR #148)
Engineering
- Pyodide wheel:只建置網站目前使用的 CPython 3.13 版本,避免隨 cibuildwheel 更新而產生不相容的 Python 3.14/3.15 wheel。 (PR #157)
- tests:將 CloudReport 新舊報告判斷的五個回歸測試標記為
unit,納入 CI 的pytest -m unit;修正特徵名稱順序測試的 Ruff 檢查與格式問題。(#137、#135)
2.0.18 (2026-08-19)
Fixed
data.get()/data.gets():改善 Pyodide 瀏覽器相容性。支援 WebAssembly JSPI 時維持平行pyfetch下載;不支援 stack switching 時,會自動退回 Web Worker 內的循序同步 XHR。若 metadata JSON POST 因 CORS preflight 失敗,則改用 CORS-safelisted form POST 逐筆重試,避免 Safari / WebKit 等非 JSPI 執行環境直接中止策略。FinlabDataFrame.rank(axis=1):修正同分(tie)處理。橫斷面排名的 numpy fast path 過去給的是序數排名(等同method='first'),與 pandas 預設的method='average'不一致,導致低基數/離散型因子中數值相同的股票拿到不同的百分位(同一組同分股票的橫斷面標準差不為 0)。現在同分處理一律交給 pandas,並保留「在index_str_to_date前先排名」的效能優化(季頻資料不會先展開成日頻)。行為變更:以rank(pct=True)做選股門檻、且因子含大量同分值的策略,選股結果可能與舊版不同。sim(..., upload=True):修正上傳報告會清掉cloud deploy設定的 tier 與cloud schedule set排程的問題。報告寫入 Firestore 時未帶updateMask,語意上是整份文件取代,因此 payload 未涵蓋的 tier/排程欄位會被刪除;現在改為只覆蓋報告本身的欄位。當報告名稱與部署 SID 相同時才會踩到,先前建議的「部署名稱與報告名稱錯開」workaround 在此版之後不再必要。
2.0.17 (2026-08-02)
Added
finlab status/finlab auth status: 新增精簡的帳號與資料狀態摘要,顯示目前方案、台股核心價格資料新鮮度、當日已使用/總下載額度、下一次每日額度重置時間(UTC+8 08:00),並保留既有的 active sessions 資訊。- standalone 策略分析報表:free 會員現在會看到 VIP 升級提示;若有活動期限會一併顯示,升級連結會帶入來源資訊並另開付款頁,方便從報表直接了解完整回測、最新資料與雲端排程方案。
report.get_benchmark_stats(): 新增 benchmark 績效統計 API。回傳與get_stats相同的 ffn 統計欄位(cagr、daily_sharpe、max_drawdown⋯),計算對象為回測期間的大盤 benchmark(report.daily_benchmark),方便程式化比較策略與大盤,不需另外呼叫market.get_benchmark()自行計算。
Fixed
finlab/core: 修正 standalone 策略分析報表首次載入與切換子頁時可能混用繁中、英文的問題。語系現在會在首次 render 前同步,並統一套用到獲利、風險、風報比、勝率、流動性、交易明細與持股介面的標籤、日期、分頁、空狀態及圖表 tooltip。data.get()/data.gets(): 修正 free 會員在同一個 Python interpreter 內升級 VIP 後,後續查詢仍持續回傳只到 2018 年底之 free cache 的問題。一般 free cache hit 現在會先做輕量權限 metadata recheck;偵測到 paid role 時會清除該 session 的舊 free memory cache、跳過無法補齊完整歷史的.recentmerge,並直接下載 paid full data。paid cache、prefer_local_if_exists與use_local_data_only的既有 fast path 不變。cli: 大幅加速 CLI 啟動。import finlab不再於載入時 import pandas/numpy(FinlabDataFrame改為 lazy attribute),finlab --help啟動時間由約 1.3 秒降至約 0.2 秒;from finlab import FinlabDataFrame用法不變。data: 移除 pyarrow 24+ 的pyarrow.featherdeprecation warning。資料快取讀寫改用pyarrow.ipc(Feather V2 本即 Arrow IPC 格式,檔案格式不變、新舊版本互通),回測與data.get()不再輸出pyarrow.feather.read_table is deprecated等 FutureWarning。
2.0.16 (2026-07-19)
Added
cli: 重新加入finlabshell 指令(console script)。pip install finlab後可直接執行finlab --help,不必再輸入python -m finlab;並新增finlab auth login/finlab auth logout/finlab auth status子指令,與舊版 CLI 介面相容。cli:finlab logout具冪等性。未登入時顯示「Not logged in. Nothing to do.」並以狀態碼 0 結束;憑證來自環境變數時,會改為提示 unsetFINLAB_REFRESH_TOKEN/FINLAB_SESSION_ID/FINLAB_API_KEY。
Fixed
auth: 修正登出後同一程序仍可能沿用記憶體內舊 id_token 的問題(clear_session()現在會同步清除 in-memory token cache)。auth: token refresh 加入指數退避重試(網路錯誤與 429/5xx 最多 3 次,重試改用較短 timeout),並區分「refresh token 已失效(400/401/403,提示重新執行finlab login)」與「伺服器/網路暫時性錯誤」,錯誤訊息不再輸出回應內容。cli: 舊版 Google/Firebase 登入流程(finlab.cli.login)強化:選用相依(flask、google-auth-oauthlib、pywebview)改為 lazy import,未安裝finlab[cli]extra 時 import 不再失敗並提供明確安裝指示;本機 callback 改用動態 port(不再固定 5000);登入等待加入 180 秒 timeout 與 webview 子程序清理(不再無限等待);未安裝pywebview時 fallback 至系統瀏覽器;stdout 重導向改用 try/finally;user.txt損毀時可自動復原,且憑證檔權限改為 0600。
Engineering
- CI: unit tests 改為 Python 3.10–3.13 matrix;新增 packaging job(build sdist/wheel、
twine check、乾淨 venv 安裝後執行finlab --help與finlab auth logoutsmoke test)。 - tests: 新增 CLI 指令、登入流程強化、auth 重試與 packaging smoke 單元測試(以 import hook 模擬缺少選用相依的乾淨環境)。
2.0.15 (2026-07-18)
Added
df.sector(by=...):sectoraccessor 現在可傳入自訂分類。by支援 dict(股票代號 → 產業名)、pd.Series,或 index=日期、columns=股票代號的時變分類pd.DataFrame;未列入的股票不參與計算(結果為 NaN)。所有sector.*方法(rank、zscore、mean⋯)皆適用,例如roe.sector({"2330": "AI供應鏈", ...}).rank()。df.sector.map(): 新增產業值廣播。將產業層級的數值(如產業權重)廣播成與原資料同形狀的 DataFrame,方便與因子分數運算,例如roe.sector.rank() * roe.sector.map({"半導體": 1.2})。df.weight.by_group(): 新增依群組(產業)分配權重。每日將各群組的持股權重正規化,使群組合計等於指定占比,例如selected.weight.by_group({"半導體": 0.5, "金融保險": 0.3});支援與sector(by=...)相同的自訂分類by參數與未列群組的default占比。占比合計小於 1 的部分與當日無持股的群組占比皆留為現金;合計超過 1 拋出ValueError。backtest.sim_batch(): 新增正式的原生批次回測初篩 API。傳入多個相容 position 的 dict,以與sim相同的正式 Cython 引擎逐一回測,共用套件/資料新鮮度檢查、市場資料 prefetch 與 prepared market inputs;單一 position 失敗不會中止其他項目,每筆結果為帶 provenance 的版本化 JSON-safe item(schemafinlab.agent-research.v1),並支援結構化progress_callback事件。所有完成項目的指標以共同評估期間計算(各策略輸入期間在共用價格 index 上的交集,起訖揭露於comparison_period_start/comparison_period_end),避免進場時間差異造成不公平比較;有效 position 間無重疊價格期間時拋出ValueError。sim(..., metrics_only=True): 新增 metrics-only 輕量路徑。跳過Report、trades、MAE/MFE、HTML 與上傳 payload 的建構,但執行相同的驗證、市場準備、調倉行事曆與回測引擎,回傳與report.metrics相同的Metrics型別。data.get()/data.gets(): 新增progress='display' | 'event' | 'silent'與progress_callback,可輸出結構化下載進度事件({phase, dataset?, completed?, total?, cache_hit?, download_bytes?, elapsed_ms, timestamp}),方便 agent/worker 在非 Jupyter 環境使用。dataframe.neutralize_industry_batch()/factor_alignment_profile(): 新增批次產業中性化與因子對齊 profiling。相同日期與股票欄位的因子共用 categories mapping、日期轉換與向量化產業運算,回傳容器形狀與輸入一致;預設 categories 使用綁定 market 與 data lifecycle 的快取,可用data.clear_category_cache()清除、data.category_cache_stats()檢查命中率。
Changed
data.search(): 回傳型別由list[str]改為pd.Series(object dtype,name 為dataset),可直接使用.str.contains()等向量化過濾;迭代與list()轉換行為不變。
Removed
sim()/sim_batch(): 移除fast_mode。稀疏再平衡日報酬無法提供可靠的 Sharpe 與最大回檔,既有的sim(..., fast_mode=True)與sim_batch(..., fast_mode=True)呼叫現在會拋出TypeError;輕量初篩請改用正式的metrics_only=True路徑。
Fixed
online: 修正永豐 Sinopac broker 對 shioaji 1.7.0 的相容性。shioaji 1.7 移除了login()的fetch_contract參數,改為 on-demand contract loading;同時以api.contracts.get()/api.Contracts.Stocks[]取代原本手動猜測 TSE/OTC exchange 的_resolve_exchange機制,修正 OTC 股票(如 8042)在get_stocks()中消失的問題。同時相容 shioaji 1.3–1.5 與 1.7+。hold_until(): 修正 exit 訊號含 NaN 時的處理。原本 exit 會經過額外的.ffill(),導致某檔股票 exit 一旦為 True、之後值變成 NaN(如資料缺漏)時,True 會被永久 forward-fill 而無法再進場;現在 NaN exit 值視為「無出場訊號」(與exit_when()一致),僅 index 空缺仍沿用最後觀察到的出場狀態(稀疏頻率對齊行為不變)。data: revert 2.0.14 的 full-table dataset bucket routing。沒有冒號的整張表資料集(如security_categories、tw_business_indicators)實際存放於各市場 item bucket,2.0.14 將其改導向 table bucket 反而會讀錯 GCS bucket;現在回復一律由 item bucket 提供。
2.0.14 (2026-07-03)
Added
cli: 新增python -m finlab blog指令群,可透過top、search與show讀取 FinLab 部落格 / 教學文章;show --paid會重用finlab.login()的 Firebase auth 登入狀態讀取 VIP 內容,不會印出或要求使用者貼 token。
Fixed
data: 修正沒有冒號的整張表資料集 bucket routing。tw_business_indicators、us_fundamentals等 full-table dataset 現在會走各市場 table bucket,而price:收盤價、us_price:close等欄位型 dataset 仍維持 item bucket,避免批次下載整張表時讀錯 GCS bucket。finlab/core: 更新策略持股 dashboard 的損益價格顯示邏輯。台股未出場持股旁的「價格」改顯示即時行情原始成交價c,避免沿用舊報告快照的currentPrice;損益 / 累計報酬計算仍使用調整後價格a與entryAdjPrice,維持除權息還原後的報酬口徑。online: 修正元富證券 Masterlink 零股委託改價邏輯,盤中零股、盤後零股與興櫃零股現在都會先取消剩餘委託數量再以新價格重建零股單,避免直接呼叫券商 API 修改零股價格。report.position_info2()/CloudReport.from_cloud()/cloud_functions/report_projection/finlab/core: 修正 dashboard 在 canonical holdings 與 legacy position 資料不同步時可能沿用舊 action reason,導致正報酬已出場標的被顯示為「已停損」的問題;新版會優先使用 report 上傳的 holdings,包含 canonical cloud read path,並在沒有移動停損設定時避免把正報酬一般出場列標成停損。
Engineering
ci: wheel build workflow 改為只在stablepush 或手動workflow_dispatch時執行,避免main每次 commit 都觸發跨平台 wheel build;一般 wheel 的CIBW_BUILD同步移除cp38-*,符合 cibuildwheel 4.x 已不支援 Python 3.8 的限制。process: 新增 repo-level agent 指令,要求後續每個 commit 都必須同步更新docs/change-log.md/docs/change-log.en.md與pyproject.tomlpackage version。
2.0.13 (2026-06-05)
Fixed
data/storage.py: 當同一份資料同時殘留舊版.pickle與新版.feather快取檔時,FileStorage現在會以 mtime 選擇最新檔案並清除較舊的 sibling,避免資料重新下載後仍讀到 stale cache。
2.0.12 (2026-06-01)
Added
sim()/hold_until(): 新增trail_stop_activation參數,可設定持倉獲利需先達到指定門檻後才啟用trail_stop。預設None/0保留既有行為;sim()支援多空方向,hold_until()支援既有多頭輪動停利流程。finlab/core: 策略分析 dashboard 右上角新增統一 settings modal,集中管理語言、明亮 / 深色 / 系統外觀,以及漲跌顏色(預設、東方紅漲綠跌、西方綠漲紅跌)設定。finlab/core: standalone HTML report 內嵌於 iframe 時支援 parent page 透過postMessage同步語言、明亮 / 深色主題與漲跌顏色設定,也可查詢目前 report 偏好值。finlab/core: standalone HTML report 在 iframe 內預設仍開啟內建右側股票面板;若外層以?stockPanel=parent(或stockPanelTarget=parent、parentStockPanel=1)載入,點擊股票會改送finlab:openStockPanel給 parent page,由外層自行開啟股票面板。report.to_html(): 匯出的 standalone HTML report 現在會設定瀏覽器分頁 title 與 FinLab favicon;可用report.to_html(path, title="策略名稱")客製化分頁標題。
2.0.11 (2026-05-31)
Fixed
report.display()/report.to_html(): 修正月頻換倉搭配resample_offset時,當期已由stop_loss/take_profit出場且權重歸零的標的沒有顯示在「選股」dashboard 的問題;當期已出場標的現在會保留在持股表格與圓餅 / 長條圖中,並在表格動作欄標示已停損/已停利。report.display()/report.to_html(): 已停損 / 已停利標的改用 report 內的已實現報酬與出場價顯示,不再用最新價重算累計報酬,避免出場後股價反彈時把停損列顯示為正報酬。report.display()/report.to_html(): 圓餅圖與長條圖保留已出場標的,但圖表 label 不再附加已停損/已停利文字,避免長標籤溢出;頂部 Analysis / Holdings tab active 樣式也移除底線並保留外框完整顯示。
2.0.10 (2026-05-28)
Fixed
report.display(): 修正回測儀表板「當前部位」漏顯空單(負權重)的問題;圖表部位大小改以絕對曝險計算,canonical report projection 也會保留空單部位。
2.0.9 (2026-05-27)
Changed
data.set_market("rotc"): 興櫃現在是正式 market code,會同步設定ROTCMarket,並將通用台股 dataset 名稱解析到rotc_資料表;例如data.get("price:收盤價")、data.get("monthly_revenue:去年同月增減(%)")可在興櫃 context 下直接使用,策略寫法與上市櫃/其他市場一致。data.search(market="rotc"): 興櫃 market search 現在只回傳rotc_catalog 項目,避免混入上市櫃財報與其他台股資料表。ROTCMarket.sim_datasets(): 新增興櫃回測預抓資料清單,依trade_at_price與touched_exit載入所需的興櫃 OHLCV 資料,讓sim()可直接使用data.set_market("rotc")後的預設市場。
Tests
- 補上興櫃 market context、catalog mapping/search 與
ROTCMarket.sim_datasets()單元測試,並以真實資料驗證興櫃價格、月營收與既有台股財報欄位交集可正常建立策略並回測。
2.0.8 (2026-05-18)
Changed
finlab/core: 重新打包 chart / strategy analytics web component bundle(everything.js、style.css),讓 2.0.8 wheel 內建最新 dashboard 與圖表前端資產。report/CloudReport: canonical report payload 現在會附帶holdings/position_info2原始持股資料;legacy projection 會優先使用 canonical holdings 生成position2,避免只從execution/trades反推時遺失currentPrice、profit、entryAdjPrice等 dashboard 顯示欄位,並移除 legacy synthetic position 中不再使用的rsv20placeholder。
Fix
data.transform.process_data(): 修正 PMI / NMI 資料對齊交易日時使用的收盤價 dataset key,改用 canonicalprice:收盤價,避免資料查詢與測試環境收到 escaped unicode key 而無法正確取得 close price。cloud_functions/report_projection: 保留網站策略的顯示名稱。當 website-triggered cloud run 以策略 UUID 作為 canonicalsid/name上傳時,legacy dashboard 的strategies.<sid>.name會沿用既有使用者自訂名稱,不再被 UUID 覆寫。report.position_info2(): 修正持股 dashboard 在trade_at_price="open"等非收盤交易口徑下,累計報酬 / 盈虧欄位仍以進場日調整後收盤價作為entryAdjPrice的問題。entryAdjPrice現在會跟隨實際交易價格口徑取得調整後交易價,避免表格顯示 5/13 開盤價進場,但累計報酬卻用 5/13 收盤價當分母,造成華新科 2492 這類案例顯示+3.00%而非依進場價計算的報酬。
Engineering
build: 補回 stable branch 使用的 wheel build 設定到 main,新增 cibuildwheel GitHub Actions 以建置 Windows、macOS universal2、Linux x86_64 / aarch64 與 Pyodide wheels;pyproject.toml同步加入 Pyodide wheel repair command,確保 wasm wheel 也會移除 Cython source files。
2.0.7 (2026-05-12)
Changed
dataframe: 保留禁止外部直接覆寫FinlabDataFrame.index的AttributeError行為,並強化錯誤訊息,明確說明此保護是為避免財報/月營收資料被錯誤提前使用造成 lookahead bias;訊息現在也列出安全遷移方式:使用.deadline()、.index_str_to_date(),或在確定要自行處理 pandas 時間語意時先轉成pd.DataFrame(df)。FAQ 同步補上 AssetGrowth 類因子的建議寫法與外部資料整合方式pandas: 清除 Pandas 4 相容性警告。_safe_ffill()不再於 pandas 3+ 讀取 deprecatedfuture.no_silent_downcastingoption,pandas 2.x 則會先確認 option 存在再使用;Report、Metrics、report projection 與各市場get_freq()改用 pandas 建議的大寫日頻"1D",避免resample/ offset 解析時出現'd' is deprecated警告finlab/core: 重新打包 dashboard 與 strategy analytics web component assets,讓 2.0.7 wheel 內建最新報告前端 bundle
Fix
auth:FINLAB_ID_TOKEN現在可作為新版id_token認證來源,支援 Pyodide / browser runtime 透過環境變數帶入 canonical auth token;舊版finlab.login(api_token)不再同時寫入FINLAB_ID_TOKEN,避免 legacy API token 被誤判為 Firebase id tokenreport.upload(): 保留策略名稱中的 hyphen,避免網站策略 UUID / Firestore document id 在上傳報告時被轉成底線data/storage.py:FileStorage.save_expiry()改用實際expiry.pkl檔案 mtime 更新_expiry_loaded_time,避免系統時間或遠端檔案系統 mtime 差異讓另一個 process 的 expiry 更新被跳過
Engineering
backtest/sim.py: 移除_prepare_simulation_inputs()內重複的_validate_sim_inputs()呼叫,保留sim()入口的單次 validationportfolio: 穩定 rebalance + stop trigger 測試,將第二份報告的下一次換倉時間固定推到未來,避免測試受即時資料更新延遲影響
2.0.5 (2026-05-02)
Engineering
scripts/upload.sh: Docker image build 現在會從pyproject.toml讀取 FinLab 版本作為 single source of truth,並以FINLAB_VERSIONbuild arg 傳入docker buildx build,避免發布 Jupyter image 時漏帶 package 版本
Fix
finlab/core: 重新打包 standalone report assets,修正獨立 HTML report 中點擊 position 後股票面板無法正確開啟的問題。獨立 report 現在會在 top-level page 觸發 stock-panel open event,面板 overlay 會包含關閉控制,並允許 report body 正常垂直捲動,不再鎖定整頁高度
2.0.4 (2026-05-01)
Fix
backtest/sim.py:_prefetch_market_datasets()從_prepare_simulation_inputs抽出,改在sim()進入_backtest_context()之前呼叫。此前 prefetch 與後續資料載入都在prefer_local_if_exists=True的 context 內執行,data.gets()會跳過 expiry 檢查與.recent合併,導致 session 啟動時若本地某個 sim_dataset(例如etl:adj_close)的 pickle 還未刷新,sim 會靜默使用 stale cache,使report.creturn.index[-1]比 user code 的data.get('price:收盤價').index[-1]早收(典型症狀:creturn 在某個未來 dataset 的最後更新日期截斷)。把 prefetch 提到 context 之外後,sim_datasets()列出的所有 dataset 在進入 backtest cache 鎖定區之前就會走完正常的 expiry / recent 合併流程
2.0.3 (2026-04-28)
Performance
data.gets(): 將過期快取走.recent合併的迴圈從序列改為ThreadPoolExecutor平行(最多 8 條),4 個 dataset 全部 stale 的情境在 200ms RTT 下從 ~1030ms 收斂至 ~420ms(2.4× 加速)data/auth.py、data/get.py:下載路徑統一為「單次 GET → 預先配置bytearray(content_length)+memoryview切片寫入 →feather.read_feather(pa.py_buffer(raw))zero-copy 解析 →set_dataframe_bytesverbatim 落地」,省掉舊路徑的 stream-to-disk per-chunk callback、feather metadata 驗證 read 與 pandas re-encoding。Chunk size 從 64 KiB 提高為 1 MiB,100 MB 下載的 progress callback 次數從 ~1600 次降至 ~100 次。本機 micro-benchmark 在小、中、並行情境一致觀察到 1.21–1.28× 加速
Refactor
data/get.py:移除_download_persist_file_storage_misses、_download_file_storage_misses_to_storage、_download_persist_one_file_storage_miss、_validate_feather_file與_materialize_full_misses中的isinstance(target_storage, FileStorage)分岔,FileStorage 與 CacheStorage 共用一條_download_full_miss_frames→_persist_full_miss_frames路徑data/get.py:抽出_run_parallel_tasks(keys, worker)generator,_resolve_recent_candidates與_download_full_miss_frames_threaded共用同一個min(8, n)ThreadPoolExecutor +as_completedpattern;單檔情境會自動 fallback 為 in-thread 執行data/auth.py:刪除_download_ipc_file,新增_download_feather_bytes(streaming 加 progress 都集中在這),_download_dataframe改回傳(df, raw_bytes)data/storage.py:新增FileStorage.set_dataframe_bytes(name, payload, expiry),把 raw feather bytes 原樣寫到.feather,省掉df.to_feather的重新編碼成本;移除set_feather_file、set_feather_bytes與_atomic_file_replace用不到的validate_fn參數,set_dataframe與set_dataframe_bytes共用_persist_featherhelper- 整體淨減 213 行,162 個相關測試保持綠燈
2.0.2 (2026-04-28)
Changed
markets/tw.py:TWMarket.sim_datasets()預取清單加回 5 個 TW 必載資料表(benchmark_return:發行量加權股價報酬指數、security_categories、price:成交股數、etl:is_flagged_stock、etl:market_value),改以單次批次請求取代 sim 過程中分批的 on-demand fetch;此舉部分回退 2.0.1 為了降低 peak RSS 而拆分的 on-demand 設計,記憶體會略增但換來更穩定的批次配額表現finlab/core: 重新打包everything.js與style.cssweb component dashboard assets
Fix
finlab/core: dashboard iframe height 改用requestAnimationFrame節流並比較getBoundingClientRect()高度,避免ResizeObserver與scrollHeight在某些佈局下互相觸發造成的尺寸抖動
2.0.1 (2026-04-26)
Performance
backtest: 大幅降低sim()的峰值記憶體用量。以使用者量測的簡單月頻全市場策略為例,sim(..., resample="M", upload=False)的 peak RSS 從 ~2.0–2.2 GiB 下降至約 1.29 GiB(約省 800 MB),讓原本 OOM 的 s-tier 雲端 worker 可以順利完成回測:markets/tw.py:TWMarket.sim_datasets()改為依trade_at_price與touched_exit回傳所需的 adjusted OHLC 子集,並移除原本硬編碼的 9 個資料表(移除price:收盤價、price:成交股數、benchmark_return、etl:is_flagged_stock、etl:financial_statements_disclosure_dates,這些現在由呼叫端按需 fetch)backtest/sim.py:_prefetch_market_datasets以inspect.signature偵測第三方Market子類的sim_datasets簽名,向下相容 pre-kwarg 的 zero-arg 版本dataframe/core.py:is_largest/is_smallest以np.argpartition取代np.argsort,省去filled中介矩陣;rank(axis=1)不再配置filled副本,改為就地 negation + 重用arr作為 ranks buffer(peak allocations 從 ~3.1× 降到 ~2.4× 輸入 frame)backtest/report.py: 新增_prefilter_for_trade_dates工具函式,_attach_trade_prices在呼叫add_trade_info前先將trade_price/adj_close縮到僅含交易日期的 slim 版本,使 Cython 端的 reindex 變成 no-op(少掉 ~2× frame-sized 的 transient copy)analysis/liquidityAnalysis.py:calculate_trade_info先 slimadj_trade_price/trade_price/volume再做pct_change = adj_trade / adj_prev - 1與turnover = trade_price * volume;以_previous_trading_day_slice取代close.shift()的全表副本,使 Liquidity 對 peak RSS 的貢獻從 ~512 MB 降到 ~306 MB
Features
cli: 新增python -m finlab cloud指令群,支援將策略部署至雲端並設定每日自動執行(Asia/Taipei 時區)。可透過finlab-auto-updateCloud Functions 管理策略生命週期:cloud deploy <sid>— 上傳策略(支援--code單檔.py或--zip多檔壓縮,zip 需搭配--entry-script),可同時指定--time HH:MM排程、--tier {s,m,l,xl}運算資源,以及--contest/--no-contest/--contest-alias參賽設定cloud get <sid>— 查看策略中繼資料、參賽狀態與 inline 原始碼,--code-only可僅輸出程式碼便於導向檔案cloud list— 列出所有已部署策略(SID、tier、排程、類型、參賽狀態),--limit最多 500 筆cloud run <sid>— 手動觸發一次執行(每小時每策略限 5 次),--tier可覆寫本次資源cloud logs <sid>— 查看最近執行紀錄(狀態、耗時、費用、排入時間),--show-output附上 stdout/stderrcloud schedule set/delete— 單獨調整或移除策略的每日排程cloud delete <sid>— 刪除策略與排程(執行歷史保留),-y略過確認cloud status— 顯示當月預算、已用額度、剩餘額度、可用 tier 與執行次數統計,--month YYYY-MM可查詢指定月份finlab/core: 更新 web component dashboard assetsfinlab/core: 改為直接納入主 repo,不再以finlab_coresubmodule 取得 Cython core 與 dashboard assets
Refactor
cli: 移除本機 broker、notebook、schedule、workspace 等舊 CLI 模組,改以輕量 HTTP client 呼叫 Cloud Functions,同時移除nbformat與rich_click依賴
Docs
cli: 更新docs/cli.md與docs/cli.en.md,移除已刪除的舊 CLI 指令(init、auth、broker、nb、pm、schedule),改為只記錄目前支援的python -m finlab登入、憑證、遷移與雲端策略流程
Fix
online:Position於 stop event 後不再提前套用下一期next_weights,改以next_weights.name對應的 market close 時間判斷切換時機,避免在盤中就以未來部位建倉
2.0.0 (2026-04-22)
Engineering
exceptions: 新增finlab.exceptions模組,定義結構化例外階層(FinlabError、DataError、BacktestError、BrokerError、AuthError、PortfolioError、ConfigError)backtest: 將 500 行的sim()函式重構為 5 個可獨立測試的階段函式(_validate_sim_inputs、_prepare_price_data、_normalize_position、_execute_simulation、_build_sim_report),以_NormalizedPosition與_SimulationResultdataclass 傳遞階段間資料data: 新增DataContext類別,將 13 個模組層級全域變數封裝為單一物件,支援override()context manager 安全地暫時覆蓋狀態,為未來並行策略執行奠定基礎optimize: 移除combinations.py中的eval()呼叫,改用基於 AST 的安全條件解析器,杜絕任意程式碼執行風險exceptions: 將 20 個檔案中 47 處except Exception收窄為具體例外型別(requests.RequestException、OSError、KeyError等),提升交易系統的錯誤可觀測性ci: 新增pytest-cov覆蓋率門檻(fail_under=50),於 CI 中強制執行,排除 vendored/submodule 程式碼ruff: 重新啟用BLE001(blind except)與C901(mccabe complexity)lint 規則,以 per-file-ignores 管理尚待重構的複雜函式
Features
data:data.gets()新增 pip 風格的即時下載進度顯示,支援平行下載時多列同步更新。自動偵測環境:終端機顯示 ANSI 彩色進度條(含速度與大小),Jupyter Notebook 顯示 HTML 進度條。CJK 字元寬度對齊正確,零額外依賴dataframe:df.sectoraccessor 新增 7 個產業內聚合方法:mean()— 產業內平均值std(ddof)— 產業內標準差median()— 產業內中位數sum()— 產業內總和min()— 產業內最小值max()— 產業內最大值count()— 產業內有效值數量dataframe: 新增df.weightaccessor,提供投資組合權重建構方法:cap_industry(max_weight)— 限制每個產業的最大權重,超額按比例重新分配clip_by_volume(total_fund, max_participation_ratio)— 依日均成交金額限制個股權重inverse_volatility(window)— 反波動率加權,低波動股票獲得較高權重risk_parity(window)— 風險平價加權,使每個持股的風險貢獻相等correlation(diversify)— 依相關性調整權重,分散化或集中化target_volatility(target, window)— 縮放權重以達成目標年化波動率limit_turnover(max_turnover)— 限制相鄰換倉的雙向換手率drawdown_control(max_drawdown)— 回撤超過門檻時自動縮減曝險dataframe: 新增df.csaccessor,提供跨股票(cross-sectional)資料轉換:rank()— 百分位排名winsorize(lower, upper)— 百分位縮尾處理bucket(n)— 等分位分組zscore()— 標準化demean()— 去均值dataframe: 新增df.sectoraccessor,提供產業內資料轉換(與df.cs相同的 5 個方法,但在同產業內計算)online: 新增PositionStreamMixin即時持倉串流功能:- 混合模式:以
get_position()初始化,透過 Fill 事件即時更新,定期輪詢對帳(預設 30 秒) - 新增
PositionUpdatedataclass,含snapshot_key()去重機制 RealtimeProvider自動繼承subscribe_positions()/on_position()介面
Refactor
dataframe: 將FinlabDataFrame重構為 package(finlab/dataframe/),包含core.py、weight.py、cs.py、sector.py,既有 import 路徑不受影響dataframe: 新增from finlab import FinlabDataFrame頂層匯出dataframe: 提取_get_column_categories()為共用 helper,消除groupby_category與產業權重方法之間的重複邏輯
Fix
analysis: 修正calc_shapley_values與calc_factor_return因使用 Pythonnot對 pandas boolean Series 取反而必定拋出ValueError的問題,改為正確的 element-wise~運算子 (#71)
Docs
market: 修正文件中不存在的 dataset 名稱etl:us_adj_close,改為正確的us_price:adj_close(#68)
Tests
- 新增 68 個測試,涵蓋所有新增的 weight / cs / sector 方法
- 新增
calc_factor_return與calc_shapley_values的單元測試,驗證 mask 運算與輸入驗證
1.5.13 (2026-03-22)
Features
data:universe()、us_universe()、set_universe()、set_us_universe()新增index參數,支援以市場指數(S&P 500、NASDAQ 100)篩選美股成分股。可與sector、industry、exchange組合使用 (#55, #57)market: 新增台灣可轉債市場(TW CB Market),並於finlab_core的to_html支援可轉債顯示 (#64,399e789)
Fix
storage: 修正_check_and_apply_reset_time在多個 Python process 中重複檢查 server reset time 的問題。以 marker 檔記錄已套用的 reset timestamp 與 expiry.pkl mtime,跨 process 共用,避免重複 reset。同時修正save_expiry()失敗時仍寫入 marker 導致後續永遠跳過 reset 的 bug (34c5055)analysis: 修正MaeMfeAnalysis.calc_edge_ratio()在 US market 回測時因entry_price為零導致ZeroDivisionError的問題,同時消除display()中重複的 edge ratio 計算邏輯 (#45, #66)compat: 將 pandas 已棄用的 resample aliases('M'、'Y'、'A')統一替換為'ME'/'YE'(pandas ≥ 2.2),集中至finlab.compat.MONTHLY_END/YEARLY_END常數,並修正原先使用字串比較版本號的 bug (#63)portfolio: 修正PortfolioSyncManager.from_cloud()/to_cloud()在 Firebase auth 時使用錯誤的 token 參數名稱(硬編碼api_token而非使用token_type),同時修正notebook.py傳入 tuple 而非 string 的問題 (#52)hold_until: 修正 pandas 3.0 Copy-on-Write 模式下hold_until()觸發ValueError的問題 (#67)report: 修正position2未填入交易資料與entryAdjPrice計算錯誤的問題 (d89f782)report: 修正 cloud report round-trip 中"hold"action 未正規化的問題,同時自動重建過期 Cython 模組 (c476cba)report: 修正CloudReport.__init__中updated_at未正確 propagate 至positionConfig.created的問題 (26eb765)online: 更新 submodule,修正 dashboard API calls 未正確路由token_type的問題 (87ecf68)data: 修正IndicatorName.decode在無參數 indicator 時尾部多餘分隔符號的問題 (87e3c80)data: 修正big_investments()執行後未重設 universe,導致後續策略 column mismatch 的問題 (0c84806)compat: 修正_pd_versionparser 無法解析 pandas prerelease 版本號的問題 (5399d97)
Refactor
deprecation: 改善 deprecation warnings,改為只顯示一次,並抽出 deadline 常數、去重 auth imports (b7f6072)
Docs
backtest: 更新sim()docstrings,修正 batch order 範例中 progress 計算邏輯 (#56)portfolio: 移除文件中不存在的create_report()與get_returns()方法,改用正確 API (#51)
Tests
- 修正 14 個測試失敗,涵蓋 auth、projection、E2E suites (
a194ea1)
Chore
- 升級 Docker base image 至 Python 3.12 並更新相關依賴 (
66a44df) - 新增
twine至 dev dependencies (28bb8eb)
1.5.12 (2026-03-17)
Fix
data: 修正data.get()在長時間 session(如 Google Colab)中,已載入的 dataset 即使 cache 過期仍回傳舊資料不更新的問題。原因是_loaded_datasets完全跳過 expiry 檢查,改為仍檢查本地 expiry 時間,過期時正常觸發 merge/download 流程online: 修正 Sinopac broker 將所有股票合約硬編碼為 TSE 交易所,導致 OTC 股票即時報價訂閱與 tick backfill 失敗的問題。改為透過 snapshot API 動態偵測 TSE/OTC 並快取結果 (e21f7fc)
1.5.11 (2026-03-11)
Features
report: 將 report payload 遷移至 canonical Firestore 流程(users/{uid}/reports/{sid}),搭配 cloud function projection 產出 legacy docs (4719592)data: 新增data.get_role()與data.is_vip()查詢使用者角色 (e282344)schemas: 新增finlab.schemas正式資料結構(dataclass + TypedDict)並補齊覆蓋率 (ae953cd)online: 完成 typed order output migration (0b16f26)portfolio: 完成 typed portfolio data access (337c2df)typed-boundary: 完成 strict mode typed boundary gates (65cae23)data: 在未過期資料情境下,市場交易時段is_tradable會回傳 true (121e2ac)
Refactor
symbol: 完成 shared symbol resolution cleanup (a9bf1c2)symbol: 內部統一使用symbol作為 canonical identifier (6b816b2)schemas: schema dataclass 改為 symbol-only (ac592cf)
Fix
backtest: 修正sim()上傳策略時使用 daemon thread,導致腳本結束時上傳被中斷的問題 (9b0b4c5)data:is_tradable()在無 expiry 資料時改回傳False(保守策略:無法驗證資料新鮮度則不交易)(9b0b4c5)data:is_tradable與next_future_expiry改為只檢查當次 session 已載入的 datasets (b16eda4)report: 修正 report projection legacy parity(daily_mean、return_table、drawdown_details、trail_stop等欄位)(83a4e33,dea8afa)report: 移除 Firestore legacy docs 中的 time-series 陣列,避免超過 40K index 上限 (9af94d9)report: 修正 market-close timestamps 的時區正規化 (91ba4dc)report: 保持 cloud report schedulers 與 execution 同步 (11ef166)report: 收緊 cloud report migration validation (297de5e)storage: file storage 寫入改為跨程序 atomic (8436ab8)analysis: 修正LiquidityAnalysis修改report.trades導致間歇性KeyError的問題 (a14d9fb)docs: 修正 i18n alternate links 與 redirect Location headers (784e4a1,e58b085)tests: 穩定 non-real-order 測試流程與 optional model discovery (731ed8e)
Tests
- 新增 E2E parity test,驗證 report projection 產出的 legacy docs 與舊
write_database完全一致 (5d893a3) - 收緊 E2E parity test:比較 stats、trades、所有 position 欄位及 strategy summary (
f2e5929,d702a84) - 新增 firebase admin report migration 測試覆蓋 (
7358a45) - 新增 market close timestamp normalization 測試 (
d747ccc) - 修正
test_data_freshness測試與 scoped expiry 行為對齊 (9b0b4c5) schemas: 新增 schema specs 與 TDD coverage workflow (ccf3e54)guardrail: 新增測試,涵蓋 dual keys 與 config shape (ce318b2)position: 完成 typed APIs 的 TDD cycle (cfe5d97)online: 新增 order executor typed output 測試 (0a866f3)portfolio: 新增 typed data APIs 測試 (2c4ea06)symbol: 新增 shared symbol resolver 測試 (19f6f22)strict-mode: 新增 typed strict mode 測試 (d6780dc)data: 隔離 data freshness 測試與 loaded dataset global state (fbedb2c)
Docs
- 新增 typed data migration guide 與 deprecation policy (
fb341d5) - 完成 migration runbook 的 definition of done (
e0af883)
Chore
online: 更新 submodule,所有 broker 新增Stock.pct_change(94032d5)- 合併
dataclass-migration-tdd分支 (dd670e5)
1.5.9
Refactor
analysis: 移除Report子類別(~270 行),to_text()與to_terminal()改由finlab_core的Report類別直接提供,from finlab.analysis import Report仍可使用 (#43)
Features
data: 新增 80% 配額使用量警告,在data.get()中於配額耗盡前提前通知使用者 (#40)schemas: 新增finlab.schemas,提供PositionEntry/OrderEntry/PortfolioData等正式資料結構(dataclass + TypedDict)online:OrderExecutor.generate_orders()新增as_entries與quantity_type,並提供generate_order_entries()typed 介面portfolio:PortfolioSyncManager新增get_data()/set_data()與get_data_typed()/set_data_typed()typed 存取介面
Fix
dataframe: 修正 Windows 環境下FinlabDataFrame.__setattr__路徑比對失敗,導致內部set_index被誤擋的問題backtest:sim()使用市場專屬的預設fee_ratio和tax_ratio,不再使用固定預設值 (#38)market:get_market_by_name()支援市場短代碼 fallback(MARKET_CODE_TO_CLASS)(#37)analysis: 修正 K 線圖在 Firestore API 請求失敗時無限轉圈的問題,改為顯示錯誤訊息與重試按鈕 (#23)
Docs
- 移除尚未開源的 git clone 安裝教學 (#27)
- 改善
Market.get_price()文件,補充完整參數說明、必須實作的值與實作範例 (#26) - 新增 typed data migration 指南與
symbol/stock_iddeprecation policy 說明(docs/details/typed_data_interfaces.md)
Chore
- 新增 Claude Code GitHub Actions 工作流程 (#25)
1.5.8
Features
verify: 新增verify_strategy()前視偏差(lookahead bias)自動檢測工具dataframe: 禁止直接覆寫FinlabDataFrame.index,防止 lookahead biasdataframe:rank()新增valid參數,支援有效值篩選data: 新增next_future_expiry()自動跳過到期資料data: 新增資料新鮮度檢查(data freshness check),確保交易前資料為最新terminal: 新增report.to_terminal()終端機圖表工具,無需 Jupyter 即可檢視回測結果auth: 改為 Firebase 瀏覽器登入,支援自動命名 session、環境變數認證、FINLAB_API_TOKEN遷移提示compat:stock_id→symbol全面遷移,stock_id仍可向後相容使用pyodide:report.upload()在 Pyodide 環境中改為同步執行
Performance
- 整體策略執行速度提升 3.4x(12.9s → 3.8s,含資料讀取、訊號計算、回測)
| 步驟 | 優化前 | 優化後 | 加速 |
|---|---|---|---|
data.get (4 calls) |
0.40s | 0.00s | ∞ |
vol.average(20) |
0.69s | 0.62s | 1.1x |
pb.rank() |
1.57s | 1.04s | 1.5x |
rev.rank() |
1.49s | 0.50s | 3.0x |
is_smallest(10) |
5.25s | 0.40s | 13.3x |
sim() |
3.30s | 1.08s | 3.1x |
dataframe:is_largest/is_smallest改用 numpyargsort(kind='stable')取代 pandasapply(nlargest/nsmallest),保留欄位順序一致的 tie-breaking(13.3x)dataframe:rank(axis=1)改用 numpyargsort快速路徑,並在index_str_to_date()展開前先排名,避免季資料(51 列)展開為日資料(2110 列)後才排名(3.0x)dataframe:reshape()新增快速路徑,當兩個 DataFrame 的 index/columns 已相同時跳過 reindexbacktest:sim()內部使用prefer_local_if_exists避免重複檢查雲端過期時間backtest: position normalization 改用 numpy 陣列運算取代 pandas.div().fillna()backtest:upload改為 daemon thread 非同步執行,不阻塞回測結果回傳backtest: 快取TWMarket._categories_cache避免重複呼叫data.get('security_categories')data: 新增_finalized_cache,快取data.get()處理後的結果,重複呼叫時跳過process_data轉換data: 先檢查過期時間再讀取 DataFrame,避免不必要的磁碟 I/Odata:FileStorage.get_dataframe()在記憶體快取命中時跳過os.path.getmtime系統呼叫
Fix
backtest: 修正touched_exit跳空開盤觸發停利/停損時,持倉價值被多乘cr_old導致creturn偏高的 bug。當開盤價直接超過停利(或停損)價位時,touch_open路徑的公式pos *= open_r / r與touch_high/touch_low不一致,已修正為pos = entry_pos * open_rbacktest: 修正pdays(獲利天數)計算的浮動問題analysis: 修正AlphaBetaAnalysis缺少display()方法,導致run_analysis('AlphaBetaAnalysis')無輸出dataframe: 修正 Pandas 2.0+ Copy-on-Write 環境下hold_until的相容性問題dataframe: 修正is_largest/is_smallest在遇到pd.NA時的轉換錯誤dataframe:industry_rank中eval()改為ast.literal_eval()修正安全性問題data: 修正truncate_end季度財報截斷邏輯,改用揭露日遮罩,避免誤刪已揭露資料data: 修正_finalized_cache未將universe和truncate納入快取 key 的問題data: 修正_get_expiry_dict未篩選已載入資料集的問題storage: 修正多 process 共用時 mtime 快取驗證遺失的問題portfolio: 修正策略權重為零時 Portfolio 不一致的問題portfolio: 修正 close-strategy 在歷史資料為空時,持倉被誤賣於 open sync 的問題auth: 修正 token refresh 失敗時不必要開啟瀏覽器登入的問題auth: 修正login()未先檢查快取 token 的問題auth: 改用穩定的 machine ID 取代不可靠的uuid.getnode()auth: 支援id_token於回測上傳與雲端資料請求sim: 修正 pandas 3.0 下以 DataFrame 作為trade_at_price的相容性問題
Docs
- 新增
neutralize/neutralize_industry教學文件 - 新增完整 API 參考文件與文件架構強化
- 新增 FinLab AI Skill (finlab.finance) 介紹
- 修正文件中停利與移動停利參數名稱錯誤
- 修正
trade_at_price='close'被誤標為未來函數的說明 - 修正 ML 策略流程文件使用不存在的 API
1.5.7 (2026-01-28)
Features
data: 改進data.search()函數,使用 Firestore API 並簡化輸出格式為 list,回傳可直接用於data.get()的字串列表data: 支援美股資料搜尋 (US catalog)
Refactor
data: 改進資料擷取和儲存模組,提取共用函數以提高可讀性
Fix
backtest: 修正 pandas 3.0 ArrowStringArray 相容性問題,確保 DataFrame columns 正確轉換為 numpy arraydata: 縮小indicator()的例外處理範圍,避免無效指標名稱產生誤導的 TA-Lib 安裝訊息data: 修正資料目錄中的重複項目tests: 修正calc_regression_stats測試的隨機性問題,添加固定種子確保測試穩定
Chore
- 停止支援 Python 3.8,最低需求為 Python 3.9
1.5.4 (2025-11-21)
Fix
core: 修正Report在is_rebalance_due時,在 resample 為 str 時,產生錯誤。data: 修正FileStorage在get_time_expired時在多個 process 共享時,會出現資料未自動更新的問題
Features
doc: 更精簡的範例文檔
1.5.4 (2025-11-14)
Refactor
data.universe: 重構universe模組
Fix
core: 修正Report在is_rebalance_due時,不間容舊版的問題
1.5.3 (2025-10-03)
Features
dataframe: 實作截斷視窗(truncation window)功能,依據finlab.data設定加速資料擷取
Refactor
data: 重組儲存架構與模組拆分(引入storage.py、調整__init__.py與universe.py),整合截斷流程portfolio: 精簡交易更新流程,資產價值計算納入市場別報價以提高準確性
Fix
data.indicator: 更正adjust_price型別驗證為布林值並強化錯誤訊息label:excess_over_median/mean改用subtract提升運算一致性與可讀性backtest: 改善arguments的重採樣邏輯,統一處理resample_dates與position索引型別
Docs
factor_analysis: 修正變數命名與補充更清晰的範例;更新導覽與教學內容docs: 移除不存在的導航項目並更新範例文檔與 mkdocs 設定
1.5.0 (2025-08-01)
Features
factor_analysis: 新增因子趨勢分析功能,並新增說明簡易範例文檔plot: 新增統一的 plotly 樣式,多種顏色範圍及標記功能,強化線圖的可視化效果,並支援自定義顏色區間plot: 增強plot_line函式,新增進階自定義選項和綜合範例,新增plot_line_example和plot_line_financial_example函式tests: 增加將回測結果序列化為 pickle 格式的功能
Refactor
factor_analysis: 重構函式名稱和參數以提高清晰度,更新文檔以反映變更docs: 更新變更日誌,調整模組結構及命名
Fix
data: 新增use_local_data_only和force_cloud_download功能選項feature: 優化市場配置邏輯,確保在多核環境下正確恢復原始市場設置liquidityAnalysis: 確保交易價格和成交量的形狀一致,並將其轉換為 DataFrame 格式backtest: 修正位置過濾邏輯,確保只保留有效的市場數據並轉換為浮點數doc: 修正 plotly 無法渲染的問題(改用靜態 png)
Docs
- 新增因子擁擠度分析頁面至導航
- 新增簡易教學文檔,更新實用範例教學,讓教學更清楚
- 修改實用範例文檔
- 新增 KaTeX 支援用於數學渲染,並移除過時的因子擁擠度分析
- 新增元富證券設定說明至下單 API 文檔,並移除過時的 PE-PB 圖表圖片
- 修正下單 API 文檔中對元富證券的引用
1.4.0 (2024-05-29)
Features
portfolio: 新增get_total_position方法,以 DataFrame 格式回傳當前持股pyproject: 為開發群組新增shioaji支援
Refactor
backtest: 將Exception替換為ValueError和TypeError以進行更好的錯誤處理market: 將Market類別轉換為抽象基礎類別並更新tw市場
Fix
qlib: 改善缺少finlab[qlib]模組的錯誤處理,提供更詳細的訊息data: 新增use_local_data_only和force_cloud_download功能data: 更新get函式的回傳類型為FinlabDataFramedata: 在__all__中包含額外的匯出pytorch_nn: 移除損壞的 import 並新增ICLoss用於計算資訊係數損失portfolio: 優化移除部位的邏輯並加強更新條件docker: 將finlab版本鎖定在 1.4.0
1.3.0 (2024-05-24)
Features
online: 新增口袋證券 (pocket account) 相關功能fubon: 新增元富證券的下單系統data: 新增財務數據指標的 entry namesdataframe:rank方法新增未來資料窺看警告setup: 新增 Python 3.7 和 3.8 的 classifiersrequirements: 新增Jinja2與ipython套件test: 新增pytest的開發依賴與slow標記- 更新使用 uv 來管理依賴
Refactor
alphalens: 移除alphalens模組與相關功能portfolio: 優化PortfolioSyncManager中移除部位的日誌紀錄backtest: 註解掉設定全域回測報告的未使用程式碼plot: 從plot_test.py移除過時的繪圖測試ml: 改善combine函式中的工廠初始化和型別提示
Fix
setup: 啟用find_namespace_packages支援並改善路徑處理liquidityAnalysis: 修正處置股票的判斷邏輯與漲跌幅評估的日期基準docker: 更新pandas與ta-lib版本backtest: 更新回測上傳訊息ml: 修正combine函式中的變數引用analysis: 修正drawdown的結束日期parallel: 修正ParallelExt以支援較新版本的joblibpyproject: 指定Cython版本以確保相容性
Docs
docs: 重新命名getting-start.md並更新mkdocs.ymlorder_api: 更新憑證取得與套件安裝說明
Type Safety
core: 為FinlabDataFrame和backtest模組新增型別提示
1.2.27 (2025-05-15)
Features
- 新增元富證券的下單系統
finlab.ml.feature.combine支援 dictionary of function 來產生特徵finlab.dataframe.FinlabDataFrame重構rank方法,自動處理財報橫向比較,避免 look ahead 的可能。finlab.dataframe.FinlabDataFrame重構rank方法,警告使用者使用了 look ahead 的可能。
Fix
- qlib 模型引用修正
1.2.24 (2025-05-02)
Features
- 將整個 qlib 的功能整合到 finlab.ml 中,只需要安裝 finlab 就可以使用 qlib 的功能(pip install finlab[qlib])
Refactor
report支援report.to_html(path)將報告轉換成 HTML 檔案report支援report._repr_html_()直接在 Jupyter Notebook 中顯示報告- 將
dashboard移出report模組,獨立成為finlab.core.dashboard模組
Fix
- 修復
report.trades中關於警示股、處置股、全額交割股少部分的資料錯誤 - 修復
report.weights.name以及report.next_weights.name可能為 None 的問題
1.2.23 (2025-03-25)
Fix
- 修正
report.upload在 resample=pd.DatetimeIndex 會報錯的問題
1.2.22 (2025-03-25)
Features
PositionScheduler支援多策略與重新平衡邏輯backtest.sim新增resample=None時自動計算下一個交易日
Fixes
- 更新 macOS 構建架構設定,僅保留
universal2 - 修正
resample參數的邏輯,允許直接使用 - 調整
PositionScheduler.from_report方法以符合新的resample邏輯 - 更新並修正相關的單元測試
1.2.21 (2025-03-12)
Features
report.is_stop_triggered()監測是否有停損停利觸發report.is_rebalance_due()監測是否有再平衡觸發report.to_pickle('PATH')將報告存成 pickle 檔案report.from_pickle('PATH')從 pickle 檔案讀取報告backtest.sim回測速度優化
Fixes
PortfolioSyncManager考慮 weight = 0 的情況data.get在下載異常時,會自動重試backtest.sim針對股票代號異常時,會自動跳過backtest.sim修正做空的報酬率顯示錯誤
1.2.20 (2024-12-09)
Refactor
MarketInfo現在移動至finlab.market模組之中TWMarketInfo現在移動至finlab.markets.tw模組之中,並且改名為TWMarket- fix(market_info): rename loop variable for clarity in shared memory creation
- 使用
finlab.config.set_market來設定全域市場資訊 - 取消
ml.get_market以及ml.set_market,使用finlab.config.set_market代替 - 取消
data.indicator(...market)與finlab.config.set_market合併 - 取消
df.hold_until(...market)與finlab.config.set_market合併
1.2.17 (2024-10-19)
Features
report.weight.name的名稱改成回測最後一天的日期,方便查看,report.next_weight.name的名稱改成換股日期,方便查看,支援 numpy>=2.0然而talib還沒支援,所以需要使用 talib 的話需要再等等。Position支援weight(optional) 的儲存與計算,方便快速比較張數與權重。FugleAccount改成使用 websocket 進行訂單的連線與更新OrderExecutor新增 progress 可以針對「當前部位」與「目標部位」進行內差,方便轉倉平滑過度
Fixes
finlab.online.sinopac處理當股票當天無交易時,避免直接報錯
1.2.16 (2024-10-02)
Fixed
data.get減少非必要的連線次數cli修正 webview 非必要 import 的錯誤finlab.online.sinopac修正get_trades在計算時間時,會將時間轉換成 UTC 時間finlab.portfolio修正PortfolioSyncManager在to_cloud或to_json時,可能會產生不相容的格式
1.2.15 (2024-09-08)
Fixed
position.from_report修正weight.index為非 str 的問題finlab.portfolio修正持有無法交易股票時,會報錯的問題finlab.online修正欲無法交易股票時,會報錯的問題(改成跳出警示)finlab.data修正data.search時搜索數據為空的問題finlab.portfolio修正停損停利時,在某些時刻下會跳過的問題
1.2.12 (2024-8-27)
Features
- dashboard: 新增儀表板中的「與大盤相關性」,並且能夠選擇時間區間
- portfolio: 新增
PortfolioSyncManager的get_position(at='open')的功能,用於規劃當日開盤的部位 - online.position: 優化顯示部位的功能
- online.position: 增加以 for loop 提取部位資訊的功能
- tool.factor_analysis: 增加因子分析功能,除了 IC 以外,支援
get_metric來運算因子的各種指標 - portfolio: 新增
PortfolioSyncManager自動判斷smooth_transition的時機,在初始化時不需平滑過度,於之後都使用平滑過度 - doc: 優化
portfolio下單的教學文件 - sinopac: 永豐證券支援
get_trades功能用於比對帳戶交易紀錄
Fixed
- data: 修正
data.get會於少數作業系統產生 circular import 的問題 - cli: 修正
finlab nb指令會產生import webview的問題
1.2.11 (2024-8-19)
Fixed
- backtest: 修正停損停利時,在少數情況會用到未來資料的問題
- test: 測試回測系統時,使用歷史資料
- report: 修正回測報告中的產業別顯示錯誤
- online: 修正下單時,顯示過多小數點的問題
- schedule: 修正執行策略時,使用到錯誤 Token 的問題
- portfolio.cloud_report: 修正支援 int 型態的 return (在少數情況下會用到)
- backtest: 回測 in-sample 時,將 out-sample 的資料隱藏
- data: 當下載超過 5 分鐘時,會自動終止並且顯示錯誤訊息
1.2.9 (2024-8-3)
Feature
- 新增
finlab.portfolio的PortfolioSyncManager.update使用custom_position來設定股票張數 - 新增
finlab.portfolio的PortfolioSyncManager.update使用excluded_stock_ids來設定忽略的股票
1.2.8 (2024-8-1)
Fix
- 修正在某些狀況下,回測報錯的問題
1.2.7 (2024-8-1)
Fix
- 股票結算於非收盤價,導致的報酬率計算錯誤
- 修正
finlab.portfolio中PortfolioSyncManager在update時,產生非必要性warning
1.2.5 (2024-7-29)
Feature
- 新增股票儀表板中,隱藏股票名稱的功能
Fix
- 修正股票儀表板中
open_close_avg為「平均價」 - 修正報酬率的計算方式,不同期之間不需要計算交易手續費
- 修正儀表板中
NaN的狀況
1.2.4 (2024-7-28)
Feature
- 新增
finlab.portfolio的PortfolioSyncManager使用to_file和from_file來讀取資料
Fix
- 修正
finlab.portfolio使用PortfolioSyncManager處理零股報錯問題 - 修正
finlab.portfolio使用PortfolioSyncManager零股顯示小數點第四位
1.2.2 (2024-7-27)
Fix
- 修正
finlab.cli假如尚未初始化 nb 指令會報錯的問題 - 修正
finlab.portfolio雲端下載策略,找不到策略 raise Error 提供更詳細的錯誤訊息 - 修正
finlab.portfolio針對 live_trading_performance 為 None 報錯的問題 - 修正
finlab.portfoliocreate_mutli_asset_report 路徑與回傳數值的問題 - 修正
finlab.portfoliosyn manager 在停損停利時的報錯問題 - 修正
finlab.backtest將 resample=None 的時候,報酬率計算方式為持有期間報酬率 - 修正
finlab.backtest在盤中模擬時,計算收盤結算引入NaN造成的問題 - 修正
finlab.report針對每期報酬率分開時,顯示出場原因的問題
1.2.0 (2024-7-27)
Features
- 新增
finlab.backtest的盤中儀表板和累計報酬儀表板 - 新增
finlab.backtest模擬時,不論trade_at_price為何,所有結算均於盤後進行結算 - 新增
finlab.backtest考慮開盤買賣,收盤價決定停損停利 - 新增
finlab.report將report.trades新增產業別 - 新增
finlab.portfolio模組,用於將策略用於實際投資組合 - 新增
finlab.portfolio文件教學,用於教學如何將策略用於實際投資組合 - 新增
finlab.cli模組,用於命令行操作與下單 - 新增
finlab.cli文件教學,用於教學如何使用命令行操作與下單 - 新增 doc 介紹利用 regex 來選取產業別
- 新增
finlab.online功能,讓Fugle API可以自動登入不需人工輸入密碼
Fix
- 修正
finlab.sinopac中的帳戶餘額計算於星期天凌晨提早結算的問題
1.1.6 (2024-7-11)
Fix
- 修正回測中,離線版針對資料快取讀取的問題
- 修正回測中,Windows datetime 轉換成 int32 不支援的問題
1.1.4 (2024-7-9)
Features
- 新增策略到期時間,用於提醒資料已經過期,需要重新執行
- 回側面版:同時顯示進場與當前價格
- 回測面版:將預設報酬率顯示從後往前
- 回測面版:持股價格顯示優化
Fix
- 修正 finlab.tools.factor_analysis 會因為因子日期沒有對齊而報錯的問題
- 修正 Pandas 2.2.0 版本下,銜接 Pandas 3.0.0 產生的 Warning
- 修正 ffn_core 中,Tabular 建構錯誤的問題
- 修正 ffn_core 中,針對 Pandas 3.0.0 版本的兼容性問題
- 修正回測頁面股票進場價格顯示錯誤的問題
- 回測頁面:修正股票歷史紀錄
- 回測頁面:考慮近期最大下跌
- 修正 plot 中每年平均報酬,考慮沒有回測的狀況
1.1.3 (2024-6-4)
Features
- 將finlab.tools.factor_analysis 進行修正,支援多因子
- LINE Notify 新增策略名稱發送
Fix
- 修正 show_alerting_stocks 無法使用的問題
1.1.2 (2024-5-23)
Feature
- 新增 finlab.tools.factor_analysis 模組,用於因子分析
Fix
- 修正價格 NaN 的應對處理
- 修正 finlab.ml.feature.ta 函式的多核處理邏輯,根據單核心報錯
- 修正參照下次再平衡的時機,以部位變化日期為準,改成當前的收盤價格日期為準,避免在下次再平衡時,參照到錯誤的價格
- 修正 finlab.ml.qlib.get_models 中的模型,在訓練時 label 會有 inf 或 NaN 的問題
Refactor
- 針對銀行餘額與交割訊息重構
1.1.1 (2024-4-25)
Refactor
- 在 machine_learning.md 中新增 "必要安裝" 和 "模型函式庫(非必須)" 兩個小節,清晰劃分安裝指令。
- market_info.py 中 MarketInfo 和 TWMarketInfo 類別的方法 market_close_at_timestamp 和 tzinfo 進行了修正和標準化,以改善方法的可讀性和一致性。
- 將部分方法的實現從動態到靜態,以提高效率和減少依賴。
- 新增 qlib.py 中 WrapperModel 的 fit 方法中對 segments 參數的處理,確保自定義數據段可以被正確處理。
Fix
- 修正 market_info.py 中邏輯條件判斷錯誤,正確區分條件判斷式。
- 修改 data.py 中對於 NaN 值的處理方式,避免在計算指標時包含無效數據。
- feature.py 中 ta 函式的多核處理邏輯調整,根據核心數量決定數據處理方式,避免在 docker 中無法使用。
- 修正 label.py 中,使用 maximum_adverse_excursion 函式時的錯誤,確保函式正確運行。
- 修正 label.py 中,使用 maximum_favorable_excursion 函式時的錯誤,確保函式正確運行。
1.1.0
Features
- 新增了對 Microsoft Qlib 的支持,透過在 Dockerfile 中添加 pyqlib 依賴,使得用戶能夠直接在 Docker 容器中使用 Qlib。
Fix
- 修正了版本號在多個檔案中的不一致問題,統一將版本號更改為 1.0.10。
- 重構了 finlab/ml/qlib.py 中的代碼,移除了過時的註釋和未使用的代碼,提高了代碼的清晰度和維護性。
- 更新了 finlab/online 子模組的引用,以獲取最新的功能和修復。
- 簡化了 run_online_test.sh 和 run_all_test.sh 腳本,移除了不必要的註釋和代碼,使得測試過程更為簡潔高效。
1.0.6
- fix(report): 修正 importlib.resources 在 python<=3.6, python==3.8,3.7, python >=3.9 不能用的問題
1.0.4
- feat(backtest): 新增回測與標的的相關測試功能
- fix(backtest): 修正 removing next_weight force to 1 的問題
- fix(us_market): 修正支援 market_close_at_timestamp support None 的問題
- chore(pandas 3.0): 支援新版的 Pandas >= 3.0.0 new resample string format
- feat(backtest): 新增 sl_enter 和 tp_enter,來代表立即停損停利,直到下次換股再買入的標示
1.0.3
Fix
- 修復支援網頁端執行回測
- 修正
report.current_trades假如有重複的股票名稱,以最新的部位為主 - 修正儀表板顯示每月營收的計算方式,從 1 號到 31 號,變成跟之前一樣,從上月 31 號到此月 31 號
- 修正
trail_stop在買同一張股票時,提早出場的問題 - 隔天要進場,同時又停損停利,針對
stop_trading_next_period對於report.action以及report.next_weights的顯示資料進行修正,並增加單元測試。
1.0.5
- fix(report): 修正 importlib.resources 在 python<=3.8 不能用的問題
1.0.4
- feat(backtest): 新增回測與標的的相關測試功能
- fix(backtest): 修正 removing next_weight force to 1 的問題
- fix(us_market): 修正支援 market_close_at_timestamp support None 的問題
- chore(pandas 3.0): 支援新版的 Pandas >= 3.0.0 new resample string format
- feat(backtest): 新增 sl_enter 和 tp_enter,來代表立即停損停利,直到下次換股再買入的標示
1.0.3
Fix
- 修復支援網頁端執行回測
- 修正
report.current_trades假如有重複的股票名稱,以最新的部位為主 - 修正儀表板顯示每月營收的計算方式,從 1 號到 31 號,變成跟之前一樣,從上月 31 號到此月 31 號
- 修正
trail_stop在買同一張股票時,提早出場的問題 - 隔天要進場,同時又停損停利,針對
stop_trading_next_period對於report.action以及report.next_weights的顯示資料進行修正,並增加單元測試。
1.0.2
Refactor
- 移除 tailwind default css,改而使用 vite 輸出的 style.css
- 移除 web server 改而使用 iframe docsrc (經過測試支援所有平台)
Fix
- 顯示在 docker 上 web server port 無法使用的問題
1.0.1
Features
- 顯示移動停損
- 儀表板右上角控制 light/dark 模式
- 另存儀表板至指定的路徑下
Fix
- 修正 Windows 下 report 預設讀寫編碼為 cp950 造成的問題。
- 修正停損無法顯示
- Colab 中 CSS 字體與排版調整
- light/dark 模式中,圖表座標軸顏色響應
- 修正圖表記憶體沒有釋放,導致 tab 切換延遲的問題
1.0.0
Features
- 新增 Position.from_report 的單元測試
- 在多種條件下測試 report.next_weights 功能
- 推出全新儀表板介面
- 支援 Python 3.12 版本
Fix
- 修正了在啟用停損或停利時,報告中 report.next_weights 的正規化問題
- 解決了在 Pandas 的 reindex 函數中,分類型欄位無法正確索引的問題
- 修正了在添加運算子時,分類型欄位繪圖錯誤的問題
0.5.13
Features
- 整合 Pytest(提交 e7a487c):加入了 Pytest,讓測試更高效。
- finlab.ml 日內交易報酬率計算(提交 8804fb1):新增了計算日內交易的 label
- finlab.ml.feature.ta 特徵計算支持多進程(提交 1ab0463):在特徵計算模組中引入多進程支持,提升性能。
Fix
- 優化 'get_location' 函數(提交 253e98c):改進了 'data.py' 中的 'get_location' 函數,使其更好地處理失敗情況。
- 市場信息支持時區(提交 aa2756b & 79b3671):在 'market_info.py' 中加入了時區信息的處理。
- 移動停損修正(提交 6522bf7 & e7fc1f3):調整了 'backtest.py' 中的交易計算,修正移動停損的功能。
- Dataframe 的導入修正(提交 626ada1):修正了 'dataframe.py' 中的導入問題。
- 特徵初始化修正(提交 772d659):解決了 'ml/feature.py' 中的初始化問題。
- 強制雲端下載(提交 7ec28a3):修復了 'data.py' 中的 'force_cloud_download' 實現。
Other updates
- 重構(提交 26d1518):對 'online' 模組進行了重構,使代碼結構更好。
- 文檔更新(提交 44a93d4, 9f5683f, cd4a894):更新了 'backtest.py'、'data.py' 和 'ml/feature.py' 的文檔。
- 版本更新(提交 d361d7f):將版本升級到了 0.5.13。
- 增加測試覆蓋率(提交 350dfbc):在 Docker 配置中增加了測試覆蓋率。
- 測試系統的穩健性(提交 1647479):提升了測試系統的穩健性。
- 在線測試
Position.to_list(提交 f3d086f):更新了 'online_test.py',增加了轉換為列表的功能。
0.5.12
- 修正了 run_online_test.sh 中的在線測試更新價格,以包含 FUGLE 配置的環境變量。
- 調整了 online_test.py 中的 test_update_price,以正確比較浮點數量。
- 修改了 event_study.py,通過重新索引工作日使其與非交易日兼容。
0.5.11
- 修復 position 為零時,會報 error 的問題
0.5.10
- 永豐 API 下單大於 1000 元無法下單的問題
- 修正
FinlabDataframe的 memory leak error - 修正登入顯示的樣式,避免 colab 登入時出現 error
- 修正
data.search的問題
0.5.9
- 修正 dataframe operator 運算時的 reshape 問題
- 改善
df[bool_selector]無法使用的問題
0.5.8
- 改善
data.get速度 - 更新永豐 API 下單效率(然而引出一些問題,已經修復)
0.5.7 (2023-11-4)
Fix 🚀
FinlabDataFrame:若未設置則正確使用 UUID 修正了__hash__方法。hold_until方法:修正了self、exit和rank的reindex問題。market_info.get_market_info:更正了reindex邏輯,確保使用更新後的索引。fetch_data:修正了報告部分的日均計算錯誤。data.py:為 HTTP 請求添加了User-Agent標頭以防止取得錯誤。data.py:修正了保存空DataFrame的問題。ffn_core.py:修正了calc_sharpe方法中除以零的錯誤。
Features 🚀
tools: 新增finlab.tools.event_study研究事件交易等相關功能。backtest.py:引入了fast_mode,在不考慮停損或停利的情況下進行快速回測。dataframe.py:將index_str_to_date方法進行了緩存,提高性能。report.add_trade_info:導入 Cython 優化運算速度。setup.py:編譯 Cython 擴展時啟用 O3 優化。backtest.py:為sim函數新增文檔,詳細說明新特性和參數。dataframe.py:實現了索引優化,將字符串索引轉換為日期並進行緩存。- 調整
setup.py,將 Python 版本要求從 >=3.7 改為 >=3.6。 - 更新子模組至最新提交。
Tests 🚀
- 為
report_test.py模塊新增測試,以保證查詢功能的正確性。 - 為
report_test.py新增多個針對不同數據類型的測試案例。 - 更新
run_test_docker.sh腳本,包含新的測試案例。
0.5.2 (2023-09-28)
Fix 🚀
- 在少部分的 OS 上出現 recursive import 的問題
- 修正 liquility analysis 中產生 NaN 時,被 Pandas 暗自轉換成 float 造成的問題
- trade_at_price 修正
- 修正在嘗試 merge 過程中消耗大量記憶體的問題
0.5.0 (2023-09-14)
Features 🚀
- 新增移動停損功能
sim(..., trail_stop=0.1)來設定移動停損。 data.universe支援market='etf'另外,也可以選 ETF 的種類如:domestic_etf,foreign_etf,leveraged_etf,vanilla_futures_etf,leveraged_futures_etfdata.get支援從美國、台灣兩地更新資料,會自動選擇比較近的伺服器來索取資料。data.get自動偵測並連結 Google Drive 來存放下載的資料。data.get將全面支援在本地端更新資料,以後再也不用全面下載所有資料,而是下載 patch 並藉由本地端的程式來進行維護,只有在必要的時候進行整批資料的重置(預設開啟)sim(..., trade_at_price)可選擇其他價格來模擬買賣,可選'close'、'open'、'open_close_avg'、'high_low_avg'或 'price_avg'。- 新增底層功能以確保新的網站能夠兼容
Fixes
- 修正做空的停損停利
- FinlabDataFrame.hold_until 現在輸出為 bool (而非以前的 int)
- FinlabDataFrame 更廣泛的支援自動 reshape 與填值的運算,例如「&=」、「+=」等目前已支援
- 移除了強制設置的 logger
- finlab.online 修正了獲取總餘額時的時區問題。
- data.FileStorage 解決了 Windows 系統上的文件路徑錯誤。
- ffn 移除即將不支援的語法,更新了 pandas2.1 間容的語法。
- 自動偵測 backtest(position) 中的 position.index 轉換為 datetime
- 解決 report.trades 太長上傳的問題
- 解決回測時上次出場的標的,這次不進場的錯誤
0.4.6 (2023-08-11)
Fixes 🔧
- 修正優勢價格買賣(extra_bid_pct)在委託價格超過漲跌停價時的委託失敗問題,委託價以漲跌停為上限。
- 解決了下單 API 中 Position.from_report 停損停利部位判斷錯誤的問題。
- 解決了永豐 API 零股改價失敗問題,自動刪單再重下。
- 月營收索引改為 datetime 格式,解決 data.set_storage 模式下強制下載月營收資料的問題。
- 避免 finlab.dataframe.industry rank() 出現 nan 數值。
Features 🚀
- 加入策略報籌率統計分析圖表功能 finlab.plot.StrategyReturnStats。
- Fugle 行情 API v1.0 版 相容 finlab.online,不相容 v0.3。 提醒用戶請將行情 API v0.3 版本升級至最新的 v1.0 版本,舊版本將被 Fugle 官方棄用,要注意在行情 API v1.0 版本中,採用了不同的身份驗證方式,因此 v0.3 的 API 金鑰將無法適用於 v1.0 的 HTTP API 和 WebSocket API。您需要重新申請 API 金鑰以使用最新版本的 API。請前往金鑰申請頁面進行申請。
- 新增下單 API 於「更新委託單價格」時支援優勢價格買賣(extra_bid_pct)的功能,以高於成交價的 x%買入,低於成交價的 x%賣出。
0.4.5 (2023-07-05)
Fixes 🔧
- 解決了在 hold_until 中 rank 參數 inf 導致的排名功能失效問題。
- 修正了 alphalens 在 pandas 2.0 版本上的不相容問題。
- 解決了永豐 API 下單時,零股市價無法下單的問題,現在改成漲跌停下單。
- 針對 candle plot 的標題顯示位移問題進行了修正。
- 修正了 report.position 丟入 sim 後得到一致結果的問題。
- 解決了 edge ratio 時間序列排序問題,現在可以按時間順序排序。
Features 🚀
- 加入 us_universe 選擇美股子產業的功能。
- 新增下單 API 支援優勢價格買賣的功能,現在可以以高於成交價的 x%買入,低於成交價的 x%賣出。
Doc 📚
- 新增美股策略範例,提供用戶參考和學習。
- 新增在 data.indicator 中使用美股時的 market 參數說明,使用者可以更容易理解其使用方式。
0.4.3 (2023-05-11)
Warnings: Backtesting result and performance will change.
Features 🚀
- Improved RAM usage by removing sorting and swaplevel for machine learning features (e081c924).
- Optimized backtest report (8babbd7a).
- Implemented cross-validation for machine learning (e55828c0).
- support infomation for stop loss and take profit assets (5f9272f3).
- Hold_until functionality made available for US data (8437d62).
- Added indicators control in plot_stats (7364d58).
Fixes 🔧
- Fixed deadline considering business date for DataFrame (312f2fe1).
- Fixed the issue where a float object had no attribute 'month' (d51a5901).
- Fixed run_all_test (6203f56f).
- Prevented deletion during map iteration in backtest_core (2d1d9b05).
- Fixed login info (d177ed47).
- Fixed alpha annualize estimation in analysis (26a8becf).
- Fixed issue with short selling in online module (919521b9).
- Synced win_ratio in maeMfeAnalysis (a9a31189).
- Added rotc deadline in DataFrame (ac10597).
Refactoring 💡
- Refactored f_disclosure_date to_business_date, removed date too far, and improved speed (7dcb203b).
- Refactored market selection according to DataFrame columns (039cbc96).
- Fixed bugs and future warnings in the analysis module (ec93088f).
- Refactored environment name capitalization in login module (635caed4).
- Refactored login to use FINLAB_API_TOKEN (a5c9064d).
- Informed free users that data is limited (bbabad14).
Tests 🧪
- Added test_hold_until (ccc4ba89).
Doc 🗂️
- Updated daily_sortino documentation (b7d1d91d).
- Updated get_data documentation (276862c2).
0.4.2 (2023-04-27)
新增功能:
- 在機器學習中加入了標籤交易價格的功能
- 在報告中新增了 report.display() 的使用說明
- 在市場資訊中新增了美國市場資訊
修復問題:
- 在線上程式中修正了顯示字串的問題
- 將回測功能回復到穩定版本
- 調整回測功能中根據進出場價格調整持倉的問題
- 修正 qlib.init 的偵測問題
- 在報告中修正了基準指數時區的問題
- 處理了 pandas 2.0.0 版本兼容性問題
- 處理了 talib 依賴性問題
- 修正了在回測功能中進出場比例為 nan 的問題
- 在文檔中修正了 fugle Account numpy 的引用問題
其他:
- 在機器學習中新增了相關文件
- 在市場資訊中新增了相關文件
0.4.1 (2023-04-14)
- (fix): fugle np not found
0.3.19 (2023-04-04)
- (improve): memory usage in machine learning feature creation
- (improve): machine learning feature for different freqnecy index
- (fix): data.indicator support almost all talib functions
- (fix): 2023/4/10 monthly revenue reveal change to 2023/4/12
- (fix): sinopac calculate account balance
0.3.18 (2023-03-28)
- (Breaking): update shioaji >= 1.0.0. Please refer to finlab.inline module
- (feat): finlab.ml (document are not ready yet)
- (feat): support qlib data
- (feat): report add yearly and monthly return table
- (fix): backtest entry exit signal both activate conflict
0.3.12 (2022-11-29)
- (Breaking): report.get_stats() has new format
- (feat): data.get now read expire date from server and update data dynamically
- (feat): add a bunch of analysis for backtesting report
- (feat): getpass password to hide api_token
- (fix): report.weight and report.next_weights remove considering of price changed
- (fix): backtest(..., resample_offset='10d') fix backtesting display date
- (fix): finlab.online.order_executor show_alerting_stocks fix price
- (fix): fugle order status not change even when it is filled
- (fix): support update price of fraction lot size
0.3.11 (2022-11-10)
- (Fix) finlab backtest asset shorting fee miner adjust
- (Fix) finlab.report.weights and finlab.report.next_weights not defined
- (Fix) fugle-trade remove flag accoding to 0.4.0
- (Fix) fugle-trade fetch other source when stock.close is nan
- (Fix) fugle-trade FugleAccount.get_position not latest position
- (Feat) finlab.data.universe('STOCK_FUTURE') subset of TWII stocks
- (Feat) add yearly return when upload report
- (Feat) add fugle_trade version not compatable warning
0.3.10 (2022-10-13)
0.3.9 (2022-10-13)
- (Fix) finlab.online.sinopac_account order_lot position zero
- (Fix) finlab.online.fugle_account order_lot position duplicated
- (Fix) finlab.backtest weight display remove normalized
- (Fix) finlab.data windows FileStorage fix
- (Fix) finlab.data indicator exception error
0.3.8 (2022-9-27)
- (Fix) finlab.online.order_executor price +-10% limit order restricted
- (Fix) finlab.online.order_executor Position.from_report handle price=0, weight=0, and duplicated stock id
- (Fix) finlab.plot.StrategySunburst compatibility
- (Fix) finlab.report.display display multiple chart
0.3.8.dev1 (2022-9-27)
- (Fix) talib abstract module incompatible
- (Fix) backtest result: alpha and beta
- (Fix) finlab.online.panel
- (Fix) finlab.online.fugle_account stock not traded error
- (Fix) add cert custom password for sinopac
- (Fix) remove duplicated columns from unnumeric_dtype.
- (Fix) KY company disclosure deadline
- (Chore) Candlestick data format generalized
- (Chore) raise error when data.get not found
- (Chore) logger.info to logger.warning in finlab.data
- (Chore) fig return for report.display
- (Feat) add retain_cost_when_rebalance flag
0.3.7.dev1 (2022-8-8)
- 針對 touched_exit 做更細部的回測:
- 原本觸價反彈後不會被列入觸價賣出,現在會模擬觸價賣出
- 原本開盤跳空,會沒辦法賣在 0.07,現在也會賣在更低的位置
0.3.5.dev (2022-7-18)
- 新增 finlab.optimize 枚舉條件組合回測
- 新增 mae_mfe 圖表
- mae_mfe 做空分析
- report.get_trades()['position'] 改成 weighting
- backtest touched_exit 修正
- 修復 finlab.analysis bugs
0.3.3.dev (2022-7-1)
Bugs 修正
- 修正放空股票的 weight 權重顯示問題
- TreeMap 繪圖修正
- 財報公佈歷史時間修正
Analysis 分析回測結果
新增 Analysis 架構,可以將回測結果完整分析。 之後的分析都將繼承 Analysis 並且顯示圖表,讓 report 使用起來更豐富!
liquidityAnalysis 流動性測試
策略會模擬股票在收盤或開盤價買進賣出,但實際上,股票也有可能沒辦法順利交易,例如遇到處置股、全額交割股,或是長跌停板。 liquidityAnalysis 會檢測回測時,是否有買到這類行的標的,並且計算比例,已確保策略的流動性符合您的資金需求。 查看更詳細的教學文章。
inequalityAnalysis 不等式測試
原本已經有策略,想要額外加入其他技術指標、籌碼、獲利指標,可以透過 inequalityAnalaysis 來檢視是否能夠提高選股績效。 以股價淨值比而言,我們想觀察以股價淨值比來進一步篩選股票的績效,可以用以下的方式:
要如何看結果,可以參考更詳細的教學文章。
0.3.2.dev (2022-6-23)
SunBurst 檢視策略部位
可以顯示當前的股票,有哪些產業,產業的偏重是哪一塊,查看詳細內容!
做空以及個股權重
FinLab Package 終於支援做空了,假如你原本就有一個好策略,可以做空 0050 試試看,雖然報酬率可以能會下降,但是風險也會大幅縮小!非常適合我們做多檔股票資產配置使用。
另外值得一提的是,新的版本 position 除了以前的布林訊號 (True/False) 外,也可以使用權重!所以下方程式碼,就是 50% 比重給 2330 做多,50% 給 1101 做空。
這樣的權重分配方式,完全兼容之前的版本,也就是 position 是 True / False 的狀況,因為 True 在電腦運算中,本來就代表 1 ,而 False 代表 0。權重都是 1 的情況下,程式就會跟以前一樣平均分配資產喔。
from finlab import data
from finlab import backtest
close = data.get('price:收盤價')
position = close < 0
position['2330'] = 0.5
position['1101'] = -0.5
r = backtest.sim(position)
r.display()
支援 Pandas_ta 計算技術指標
Pandas_ta 最近一兩年算是計算技術指標的後起之秀,原因在於 TaLib 有時候實太難安裝了,而且技術指標就只有那 100 個,都是老調重彈,沒有更新。有鑒於此,Pandas_ta 採用純 Pandas 計算技術指標,跟不同的作業系統有比較好的相容性。另外,Pandas_ta 也有很多最新的技術指標,例如 supertrend indicator。有非常多沒有看過的指標,像是「Even Better Sinewave 」,聽起來實在是非常有趣呀!這些都可以在 Pandas_ta 文檔中找到。