跳轉到

更新日誌

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)

    atr_ratio = (high - low).rolling(14).mean() / close
    report = sim(position, stop_loss=atr_ratio * 2, take_profit=atr_ratio * 4)
    position = entries.hold_until(exits, stop_loss=atr_ratio * 2)
    
  • 新增 finlab.backtest.metrics_from_nav():傳入其他回測框架或自訂帳本產生的日頻淨值 Series,即可用與 sim() 相同的口徑計算年化報酬、夏普值、最大回撤等淨值績效。淨值須已扣除交易成本並排除入出金的影響;本函式不產生 Report、交易明細、持倉或委託。(PR #367)

    import pandas as pd
    from finlab.backtest import metrics_from_nav
    
    nav = pd.Series([100, 102, 101], index=pd.date_range("2026-01-01", periods=3))
    metrics = metrics_from_nav(nav)
    print(metrics.annual_return(), metrics.sharpe_ratio(), metrics.max_drawdown())
    

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)

    from finlab import data
    
    data.describe('price:收盤價')
    data.describe('monthly_revenue')  # 整張表的欄位與說明
    data.describe('us_price:close', market='us')
    
  • 新增環境變數 FINLAB_MAX_DOWNLOAD_WORKERS,設定 data.get()/data.gets() 同時下載的數量:預設 8,設為 1 時依序下載,適合限制執行緒數的環境。另新增 data.free_memory(),釋放已讀取資料占用的記憶體,下次讀取會從本機快取載入;自己仍持有的 DataFrame 不會被釋放,請先 del 不再使用的變數。(Issue #119、PR #337)

    import os
    from finlab import data
    
    os.environ['FINLAB_MAX_DOWNLOAD_WORKERS'] = '1'
    close = data.get('price:收盤價')
    
    del close
    data.free_memory()
    
  • finlab ai 新增 --history [N] 列出最近的提問(預設 10 則)、--show <提問ID> 讀取指定提問與所有回覆(包含事後追加的處理進度),以及 --json 輸出,方便自己的程式或 AI agent 讀取。(Issue #328、PR #329)

    python -m finlab ai --history
    python -m finlab ai --show <提問ID> --json
    

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 文件把小型方案(tier s)的規格誤寫成 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)

    # timeperiod 不要誤寫成 timperiod
    sma = data.indicator('SMA', timeperiod=10, adjust_price=True)
    

    行為變更

  • 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)

    pip install -U finlab
    

    暫時無法升級 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 填補使用 chained inplace=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():移除對 Plotly figure_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、跳過無法補齊完整歷史的 .recent merge,並直接下載 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.feather deprecation warning。資料快取讀寫改用 pyarrow.ipc(Feather V2 本即 Arrow IPC 格式,檔案格式不變、新舊版本互通),回測與 data.get() 不再輸出 pyarrow.feather.read_table is deprecated 等 FutureWarning。

2.0.16 (2026-07-19)

Added

  • cli: 重新加入 finlab shell 指令(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 結束;憑證來自環境變數時,會改為提示 unset FINLAB_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 logout smoke test)。
  • tests: 新增 CLI 指令、登入流程強化、auth 重試與 packaging smoke 單元測試(以 import hook 模擬缺少選用相依的乾淨環境)。

2.0.15 (2026-07-18)

Added

  • df.sector(by=...): sector accessor 現在可傳入自訂分類。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(schema finlab.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 改為只在 stable push 或手動 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.toml package 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 中不再使用的 rsv20 placeholder。

Fix

  • data.transform.process_data(): 修正 PMI / NMI 資料對齊交易日時使用的收盤價 dataset key,改用 canonical price:收盤價,避免資料查詢與測試環境收到 escaped unicode key 而無法正確取得 close price。
  • cloud_functions/report_projection: 保留網站策略的顯示名稱。當 website-triggered cloud run 以策略 UUID 作為 canonical sid / 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+ 讀取 deprecated future.no_silent_downcasting option,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 token
  • report.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() 入口的單次 validation
  • portfolio: 穩定 rebalance + stop trigger 測試,將第二份報告的下一次換倉時間固定推到未來,避免測試受即時資料更新延遲影響

2.0.5 (2026-05-02)

Engineering

  • scripts/upload.sh: Docker image build 現在會從 pyproject.toml 讀取 FinLab 版本作為 single source of truth,並以 FINLAB_VERSION build 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_bytes verbatim 落地」,省掉舊路徑的 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_completed pattern;單檔情境會自動 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_feather helper
  • 整體淨減 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.css web 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 先 slim adj_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-update Cloud 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/stderr
  • cloud schedule set/delete — 單獨調整或移除策略的每日排程
  • cloud delete <sid> — 刪除策略與排程(執行歷史保留),-y 略過確認
  • cloud status — 顯示當月預算、已用額度、剩餘額度、可用 tier 與執行次數統計,--month YYYY-MM 可查詢指定月份
  • finlab/core: 更新 web component dashboard assets
  • finlab/core: 改為直接納入主 repo,不再以 finlab_core submodule 取得 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)

查看 FinLab 2.0.0 功能亮點頁面

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 與 _SimulationResult dataclass 傳遞階段間資料
  • 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.sector accessor 新增 7 個產業內聚合方法:
  • mean() — 產業內平均值
  • std(ddof) — 產業內標準差
  • median() — 產業內中位數
  • sum() — 產業內總和
  • min() — 產業內最小值
  • max() — 產業內最大值
  • count() — 產業內有效值數量
  • dataframe: 新增 df.weight accessor,提供投資組合權重建構方法:
  • 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.cs accessor,提供跨股票(cross-sectional)資料轉換:
  • rank() — 百分位排名
  • winsorize(lower, upper) — 百分位縮尾處理
  • bucket(n) — 等分位分組
  • zscore() — 標準化
  • demean() — 去均值
  • dataframe: 新增 df.sector accessor,提供產業內資料轉換(與 df.cs 相同的 5 個方法,但在同產業內計算)
  • online: 新增 PositionStreamMixin 即時持倉串流功能:
  • 混合模式:以 get_position() 初始化,透過 Fill 事件即時更新,定期輪詢對帳(預設 30 秒)
  • 新增 PositionUpdate dataclass,含 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 因使用 Python not 對 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_version parser 無法解析 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_id deprecation 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 bias
  • dataframe: 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 改用 numpy argsort(kind='stable') 取代 pandas apply(nlargest/nsmallest),保留欄位順序一致的 tie-breaking(13.3x)
  • dataframe: rank(axis=1) 改用 numpy argsort 快速路徑,並在 index_str_to_date() 展開前先排名,避免季資料(51 列)展開為日資料(2110 列)後才排名(3.0x)
  • dataframe: reshape() 新增快速路徑,當兩個 DataFrame 的 index/columns 已相同時跳過 reindex
  • backtest: 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/O
  • data: 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_r
  • backtest: 修正 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 array
  • data: 縮小 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 函式的回傳類型為 FinlabDataFrame
  • data: 在 __all__ 中包含額外的匯出
  • pytorch_nn: 移除損壞的 import 並新增 ICLoss 用於計算資訊係數損失
  • portfolio: 優化移除部位的邏輯並加強更新條件
  • docker: 將 finlab 版本鎖定在 1.4.0

1.3.0 (2024-05-24)

Features

  • online: 新增口袋證券 (pocket account) 相關功能
  • fubon: 新增元富證券的下單系統
  • data: 新增財務數據指標的 entry names
  • dataframe: rank 方法新增未來資料窺看警告
  • setup: 新增 Python 3.7 和 3.8 的 classifiers
  • requirements: 新增 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 以支援較新版本的 joblib
  • pyproject: 指定 Cython 版本以確保相容性

Docs

  • docs: 重新命名 getting-start.md 並更新 mkdocs.yml
  • order_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.portfolio create_mutli_asset_report 路徑與回傳數值的問題
  • 修正 finlab.portfolio syn 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_etf
  • data.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 會檢測回測時,是否有買到這類行的標的,並且計算比例,已確保策略的流動性符合您的資金需求。 查看更詳細的教學文章。

report.run_analysis('LiquidityAnalysis')

inequalityAnalysis 不等式測試

原本已經有策略,想要額外加入其他技術指標、籌碼、獲利指標,可以透過 inequalityAnalaysis 來檢視是否能夠提高選股績效。 以股價淨值比而言,我們想觀察以股價淨值比來進一步篩選股票的績效,可以用以下的方式:

report.run_analysis('InequalityAnalysis', name='price_earning_ratio:股價淨值比')

要如何看結果,可以參考更詳細的教學文章。

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 文檔中找到。

from finlab import data

values = data.indicator('supertrend')