資源
常見問題
本頁內容13
依你正在做的事找問題:登入、下載資料、寫條件、回測、下單,最後是平台、訂閱與客服。每一題的第一句就是答案。第一次用 FinLab,先看快速上手。
卡住時先試這幾步
| 狀況 | 先試 | 詳細說明 |
|---|---|---|
| 無法登入或抓不到資料 | 重新執行 finlab.login(),再測試 data.get('price:收盤價') | 下載資料 |
| 不知道資料表名稱 | 用 data.search('關鍵字') 搜尋欄位 | finlab.data |
| 停損停利不如預期 | 確認 position 是不是稀疏訊號,或改用 hold_until() | 歷史回測 |
| 實盤下單與券商串接 | 先完成帳戶設定,再用 OrderExecutor 預覽委託 | 下單教學 |
登入
找不到登入視窗,或抓不到資料怎麼辦?
在程式最前面執行 finlab.login()(新版登入流程),登入後再下載資料。在 VSCode、終端機或其他 IDE 執行時最常遇到這個狀況。
import finlab
finlab.login()
from finlab import data
close = data.get('price:收盤價')自動化環境沒辦法開瀏覽器登入。先在本機執行:
python -m finlab token --env再把輸出的環境變數設定到伺服器或排程系統。
舊版的 finlab.login('token') 仍然相容,但不建議把 token 寫進程式碼。
下載資料
為什麼資料只到 2023 年底?
因為你還沒訂閱 VIP:免費帳號的台股資料開放到 2023-12-31(最後交易日 2023-12-29)。訂閱 VIP 後,就能使用到最新交易日的歷史資料。
為什麼下載的資料只有日期,數值全是空的?
多半是先前用 set_universe 設了股票範圍。執行 data.reset_universe() 移除它,或整個 kernel 重新啟動後再執行原本的程式即可。
data.get() 出現 DatasetNotFoundError,說找不到資料表?
先用 data.search() 確認資料表名稱沒有拼錯,再確認已經登入。常見原因有三個:
- 資料表名稱拼錯
- 還沒登入,或登入狀態失效
- 非 VIP 會員存取最新資料
import finlab
from finlab import data
# 1. 確認已登入
finlab.login()
# 2. 搜尋正確的欄位名稱
print(data.search('收盤'))
# 3. 用正確名稱重新下載
close = data.get('price:收盤價')
print(f"資料範圍:{close.index[0]} ~ {close.index[-1]}")在伺服器或排程環境,先在本機執行 python -m finlab token --env,再把輸出的環境變數設定到執行環境。更多下載錯誤見下載資料。
下載成功,表卻是空的(Empty DataFrame)?
通常是 data.universe() 的篩選條件太嚴,或類股名稱不存在;也可能是資料來源暫時沒有資料。先檢查表是不是空的:
from finlab import data
close = data.get('price:收盤價')
if close.empty:
print("資料為空:檢查 universe 篩選條件是否過嚴,或資料表本身是否沒有資料")
else:
print(f"資料正常:{close.shape[0]} 個交易日,{close.shape[1]} 檔股票")怎麼把「企業基本資訊」的欄位整理成日期 × 股票的表?
把那一欄複製到每個日期,做成 index 為日期、columns 為股票代號的 FinlabDataFrame,就能和其他資料一起運算。以「已發行普通股數或TDR原發行股數」為例:
import pandas as pd
from finlab import data
from finlab.dataframe import FinlabDataFrame
basic_info = data.get('company_basic_info').set_index('stock_id')
營業收入 = data.get('financial_statement:營業收入淨額')
流通在外股數 = basic_info['已發行普通股數或TDR原發行股數']
流通在外股數 = FinlabDataFrame(
pd.DataFrame([list(流通在外股數)], columns=basic_info.index, index=營業收入.index)
)寫選股條件
不同頻率的資料,要先用 reindex 對齊嗎?
不需要:data.get() 拿到的資料在做四則運算或比較時,FinLab 會自動幫你對齊日期。自己 reindex 反而要花很多時間調整資料。
from finlab import data
close = data.get('price:收盤價') # 日資料
roa = data.get('fundamental_features:ROA稅後息前') # 季資料close 和 roa 都是 FinlabDataFrame,所以不必先把 roa 轉成日資料:
# 不需要這樣寫
roa_daily = roa.reindex(close.index, method='ffill')
condition = (close < 30) & (roa_daily > 0)
# 直接寫就好
condition = (close < 30) & (roa > 0)運算時 FinLab 會在背後算出 roa_daily。
為什麼不能直接改 df.index?可以只給警告嗎?
不行,這是刻意的安全保護:對 FinlabDataFrame 直接設定 index 會丟出 AttributeError,不是一般的格式轉換錯誤,也不建議改成警告。
data.get() 回傳的 FinlabDataFrame 保留月營收、財報原本的時間標記,例如 2024-M01、2024-Q1。直接覆寫 index,很容易把「資料所屬的期間」誤當成「當時已經公布、可以交易的日期」,讓回測用到當時還拿不到的資料(lookahead bias,未來資料汙染)。
要計算 AssetGrowth 這類需要對齊不同資料的因子,通常不必先手動 reindex 原始資料:
from finlab import data
close = data.get('price:收盤價')
asset = data.get('financial_statement:資產總額')
# FinlabDataFrame 會在運算時自動對齊不同頻率的資料
asset_growth = asset / asset.shift(4) - 1
# 要把最後的 position 換成交易日頻率,再對 position 做 reindex
position = (asset_growth > 0).index_str_to_date()
position = position.reindex(close.index, method='ffill')如果你明確需要把季報或月營收的索引轉成日期,用這兩個方法:
df = df.index_str_to_date() # 依各股實際公布日
df = df.deadline() # 依統一公告截止日外部 CSV 或自訂市場的資料,先用一般的 pandas.DataFrame 解析日期、清理資料,再轉成 FinlabDataFrame:
import pandas as pd
from finlab.dataframe import FinlabDataFrame
raw = pd.read_csv('factor.csv', index_col=0)
raw.index = pd.to_datetime(raw.index)
factor = FinlabDataFrame(raw)確定要用一般 pandas 的規則處理 index
先轉成 pandas.DataFrame。這樣會離開 FinlabDataFrame 的自動對齊與防前視保護,時間標記是否正確要自己確認:
import pandas as pd
df = pd.DataFrame(df)
df.index = pd.to_datetime(df.index)想在特定月份(例如 7、8 月)不交易?
做一個月份條件,再和其他條件取交集。以 7、8 月不要有策略訊號為例:
month_condition = close.index.to_series().apply(lambda x: x.month not in [7, 8])怎麼更細地自訂換股頻率?
在把 position 交給回測之前,直接對 position 用 pandas 的 resample,用法見 pandas 文件。
回測
為什麼設了停損停利,卻沒有出場?
因為 position 當天有部位時,sim() 以 position 為準。只有 position 的日期是稀疏的(例如只有每月一列),系統查不到當天該持有的部位,才會用 stop_loss 判斷要不要賣出:
report = sim(position, stop_loss=0.1)這樣設計是因為:如果停損之後 position 仍然是 True,明天究竟算已經停損,還是應該重新買進?很難定義。所以 position 是 True 時就以 position 為準,不額外停損,是最單純的做法。也因此,position 的日期若是每個交易日,stop_loss 確實不會有作用。改用 hold_until() 設定停損:
buy = close > close.average(20)
sell = close < close.average(60)
# 原本的
position = buy.hold_until(sell)
# 加上停損
position = buy.hold_until(sell, stop_loss=0.1)從原本的 position 取出進場與出場點,再設定停損停利:
position.is_entry().hold_until(position.is_exit(), stop_loss=0.1)回測跑完,卻沒有任何交易?
多半是進場條件太嚴,position 幾乎都是 False,get_trades() 回傳空的表。其他原因:資料日期範圍太短、篩選後的股票池太小。先看平均每天有幾檔符合條件:
from finlab.backtest import sim
# 檢查進場訊號
entry_stats = position.sum(axis=1)
print(f"平均每日進場股票數:{entry_stats.mean():.2f}")
print(f"最大進場股票數:{entry_stats.max()}")
if entry_stats.mean() < 1:
# 進場條件過嚴:放寬條件(如價格區間),或用 .is_largest(N) 固定檔數
# 用分數排名、不是用條件:每天都選出相對 20 日均線最強的 30 檔
ma20 = close.average(20)
position_fixed = (close / ma20).is_largest(30)
report = sim(position, resample='M')
trades = report.get_trades()
print(f"{len(trades)} 筆交易" if len(trades) else "沒有交易紀錄,請放寬進場條件")回測出現 KeyError: Timestamp('2023-05-01')?
這代表某個日期不在資料裡,通常是用了多個資料源、日期範圍不一致,或 shift()、rolling() 讓前期資料缺失。三種處理方式:
from finlab import data
data.truncate_start = '2020-01-01'from finlab import data
close = data.get('price:收盤價')
volume = data.get('price:成交股數')
# 檢查日期範圍
print(f"收盤價:{close.index[0]} ~ {close.index[-1]}")
print(f"成交量:{volume.index[0]} ~ {volume.index[-1]}")
# 只留兩邊都有的日期
common_dates = close.index.intersection(volume.index)
close_aligned = close.loc[common_dates]
volume_aligned = volume.loc[common_dates]position = (close > close.average(20)) & (volume > 1000)
position_cleaned = position.dropna(how='all', axis=0) # 移除全為 NaN 的列
position_cleaned = position_cleaned.fillna(False)更多回測錯誤見歷史回測。
回測報酬跟自己算的不一樣?
先確認三件事:有沒有用還原股價計算、策略確切的進出場時間點、成交用的是開盤價還是收盤價。還有疑慮,可以到 Discord 論壇區討論。
本機或 Colab 的績效,跟平台上跑出來的不一樣?
以在本機或 Colab 用最新版套件執行的結果為準。
可以不要把回測報表上傳到網頁嗎?
不用設定,本機與 Colab 預設就不會上傳:sim() 的 upload 預設為 None,只有設定了 FINLAB_FORCED_STRATEGY_NAME 環境變數時才會上傳,例如雲端排程、在 FinLab Studio 網站手動執行的筆記本。2.1.0 起,Studio AI 與桌面版也要傳入 upload=True 才上傳。想明確關閉,仍可傳入 upload=False:
report = sim(position, upload=False)為什麼 display_mae_mfe_analysis 沒有顯示 Edge ratio?
要在 sim() 設定 mae_mfe_window 參數,參數說明見 finlab.backtest。
該怎麼優化與驗證策略?
概念可以參考回測 SOP 這篇文章,再用 FinLab 回測系統實作:用策略參數優化調參數,照從研究到實盤的流程,保留一段樣本外期間做驗證。
下單
可以直接在 FinLab 平台上下單嗎?
不行。要串接券商的下單 API,需要在其他環境執行。
怎麼串接券商 API 下單?
FinLab 與永豐證券、玉山 Fugle 合作:開好相關帳戶後,照下單教學開始串接,文件裡也附有教學影片,依步驟執行即可。
券商帳戶連線失敗?
多半是環境變數沒設好(API KEY、憑證路徑),或憑證檔案不存在、密碼錯誤;也可能是網路連線問題。執行 SinopacAccount() 或 EsunAccount() 出錯時,先逐項檢查:
import os
from finlab.online.sinopac_account import SinopacAccount
# 檢查環境變數
required_vars = [
'SHIOAJI_API_KEY',
'SHIOAJI_SECRET_KEY',
'SHIOAJI_CERT_PATH',
'SHIOAJI_CERT_PASSWORD',
]
for var in required_vars:
if not os.environ.get(var):
print(f"{var} 未設定")
# 檢查憑證檔案
cert_path = os.environ.get('SHIOAJI_CERT_PATH')
if cert_path and not os.path.exists(cert_path):
print(f"憑證檔案不存在:{cert_path}")
# 嘗試連線
try:
acc = SinopacAccount()
print("帳戶連線成功")
except Exception as e:
print(f"連線失敗:{e},請檢查 API key、憑證路徑與密碼")各券商需要的設定見下單教學。
下單時,怎麼避免賣掉不屬於這個策略的股票?
先建一個 Position 放手單部位(和這次策略無關的持股),再把策略部位與手單部位加總,交給 OrderExecutor 下單:
from finlab.online.order_executor import OrderExecutor, Position
strategy = Position.from_report(report, 1_000_000) # 這個策略的部位,投入 100 萬
manual = Position({'2330': 1}) # 手單部位:自己另外持有的一張 2330
executor = OrderExecutor(strategy + manual, account=account)
executor.create_orders(view_only=True) # 先預覽下單時顯示資金不足?
可用資金不夠買進 position 指定的股票。常見原因:配置給策略的資金太多、沒算到手續費與證交稅、帳戶餘額和預期不同。下單前先比較可用現金與配置金額:
from finlab.online.order_executor import OrderExecutor, Position
fund = 1_000_000 # 要配置給這個策略的資金(新台幣)
available_cash = account.get_cash()
print(f"可用資金:NT$ {available_cash:,.0f}")
print(f"預計配置:NT$ {fund:,.0f}")
if fund > available_cash * 0.9: # 留 10% 緩衝
print("資金不足:降低配置資金、追加資金,或減少持股數量")
else:
position = Position.from_report(report, fund)
executor = OrderExecutor(position, account=account)
executor.create_orders(view_only=True) # 先預覽部分訂單被券商拒絕?
最常見的原因是處置股沒有先圈存;股票暫停交易、漲跌停鎖死也會無法成交。先列出新委託裡的處置股與警示股,圈存後再下單:
from finlab.online.order_executor import OrderExecutor
executor = OrderExecutor(position, account=account)
# 1. 列出處置股與警示股
executor.show_alerting_stocks()
# 2. 先預覽
executor.create_orders(view_only=True)
# 3. 確認後執行
if input("確認無誤後輸入 'YES' 執行下單:") == 'YES':
executor.create_orders()有列出處置股時,先到券商平台圈存,作法依券商而定,例如富果、永豐。
錯過策略的進出場日期,該怎麼辦?
可以用 Edge Ratio 分析判斷適不適合中途進場,詳細說明見 Ben 大的文章。
自訂市場與外部資料
自訂市場讀不到資料檔(FileNotFoundError)?
CSV 檔案不存在、路徑錯誤,或用了相對路徑但工作目錄不對。讀檔前先檢查檔案在不在,錯誤訊息裡印出工作目錄:
import os
import pandas as pd
from finlab.market import Market
class CryptoMarket(Market):
def __init__(self, data_dir='./data'):
self.data_dir = data_dir
def get_price(self, trade_at_price='close', adj=True):
file_path = os.path.join(self.data_dir, f'crypto_{trade_at_price}.csv')
if not os.path.exists(file_path):
raise FileNotFoundError(
f"找不到資料檔案:{file_path}\n"
f"請確認檔案在 {self.data_dir} 目錄、檔名正確,"
f"目前工作目錄:{os.getcwd()}"
)
return pd.read_csv(file_path, index_col=0, parse_dates=True)
try:
market = CryptoMarket(data_dir='/path/to/data')
close = market.get_price('close')
except FileNotFoundError as e:
print(e)完整作法見自訂市場。
資料格式錯誤(Index must be DatetimeIndex)?
index 不是 DatetimeIndex,或欄位是字串而不是數值,回測就會失敗。讀進 CSV 後先轉換:
import pandas as pd
df = pd.read_csv('data.csv', index_col=0)
# 把 index 轉成 DatetimeIndex
if not isinstance(df.index, pd.DatetimeIndex):
try:
df.index = pd.to_datetime(df.index)
except Exception as e:
print(f"無法轉換 index:{e}")
print(f"index 範例:{df.index[:3].tolist()}")
print("請確認第一欄是日期格式(如 2020-01-01)")
# 把非數值欄位轉成數值
non_numeric_cols = df.select_dtypes(exclude=['number']).columns.tolist()
for col in non_numeric_cols:
df[col] = pd.to_numeric(df[col], errors='coerce')機器學習
模型訓練時說資料量太少?
訓練集不到 1000 筆,或特徵與標籤對齊後損失大量資料。先算一下訓練集有幾筆:
from finlab import data
from finlab.ml import feature as mlf, label as mll
close = data.get('price:收盤價')
features = mlf.combine({'momentum': close / close.shift(20)}, resample='W')
labels = mll.excess_over_mean(features.index, resample='W')
# 特徵與標籤對齊
data_ml = features.join(labels.rename('label'), how='inner')
# 切分訓練集
train_data = data_ml[data_ml.index.get_level_values(0) <= '2022-12-31']
print(f"訓練集:{len(train_data)} 筆")不到 1000 筆時:
- 增加歷史資料範圍
- 縮短 resample 的間隔(例如
'M'改成'W'),樣本之間隔得越短,筆數越多 - 減少特徵數量(降低缺失值)
完整流程見機器學習策略流程。
訓練集與測試集的日期重疊了?
沒有照時間順序切分,訓練集的最後一天晚於或等於測試集的第一天,就會造成資料洩露(data leakage)。用固定的切分日,並檢查日期順序:
train_end = '2022-12-31'
test_start = '2023-01-01'
train_data = data_ml[data_ml.index.get_level_values(0) <= train_end]
test_data = data_ml[data_ml.index.get_level_values(0) >= test_start]
train_last_date = train_data.index.get_level_values(0).max()
test_first_date = test_data.index.get_level_values(0).min()
if train_last_date >= test_first_date:
raise ValueError(
f"訓練集與測試集日期重疊:訓練集最後 {train_last_date},"
f"測試集最早 {test_first_date},會造成資料洩露"
)模型預測結果全是 NaN?
模型訓練失敗卻沒有報錯,或預測用的資料含有 NaN、Inf。檢查預測資料,必要時補值後重新預測:
import finlab.ml.qlib as q
train = train_data.dropna()
model = q.LGBModel()
model.fit(train.drop(columns=['label']), train['label'])
all_pred = model.predict(data_ml.drop(columns=['label']))
if all_pred.isna().all().all():
X_pred = data_ml.drop(columns=['label'])
print(f"NaN 數量:{X_pred.isna().sum().sum()}")
print(f"Inf 數量:{(X_pred == float('inf')).sum().sum()}")
# 補缺失值後重新預測
X_pred = X_pred.fillna(0).replace([float('inf'), float('-inf')], 0)
all_pred = model.predict(X_pred)
print(f"預測完成:{all_pred.notna().sum().sum()} 筆")安裝與執行環境
TA-Lib 要怎麼安裝?
用 pip 安裝即可,PyPI 已提供 Windows、macOS、Linux 預先編譯的版本:
pip install ta-lib!pip install ta-lib在其他 kernel 用 conda 安裝:
conda install -c conda-forge ta-lib其他安裝方式見 TA-Lib 官方安裝教學。
在 Colab 怎麼匯出、匯入資料,路徑要怎麼設?
先掛接 Google 雲端硬碟:在頁面左側「檔案」選單點「掛接雲端硬碟」,或執行:
from google.colab import drive
drive.mount('/content/drive')掛接後,/drive/MyDrive(完整路徑 /content/drive/MyDrive)就是雲端硬碟的根目錄。
在平台上執行時出現 MemoryError?
這是超過了網頁的記憶體限制,建議改到 Google Colab 執行。
可以用手機操作 FinLab 量化平台嗎?
看策略績效、個股與產業資訊,用手機沒問題;撰寫並執行策略則受記憶體限制,建議用電腦。
AI 編程助手
怎麼用 AI 助手寫 FinLab 策略?
安裝 FinLab 官方的 AI Skill:到 finlab.finance 依照指示安裝到 Claude Code、Cursor、Windsurf 等 AI 編程工具,AI 就會熟悉整套 API。安裝後你可以:
- 問「幫我用營收成長和技術突破寫一個選股策略」,AI 會產生可執行的程式碼
- 問「
data.get有哪些財報相關的資料表?」,AI 會列出正確的鍵名 - 貼上錯誤訊息,AI 會幫你診斷並修正
- 要求「幫我把這個策略加上 10% 停損並回測」,AI 會直接修改程式碼
詳細說明見快速上手。
AI Skill 和 FinLab Studio 有什麼不同?
Studio 在瀏覽器裡用,不必安裝;AI Skill 裝在你自己電腦上的 AI 編程工具裡。
- FinLab Studio:線上 AI 平台,不需安裝任何東西,直接在瀏覽器中對話撰寫策略。
- FinLab Skill:安裝到本機的 AI 編程工具(Claude Code、Cursor 等),AI 可以直接在你的開發環境讀寫檔案、執行程式碼、除錯。適合已經有本機開發環境的進階用戶。
FinLab 平台
怎麼設定策略每天自動更新,不用每天按?
在平台策略頁面上方按「自動更新」,選擇要更新的策略、設定時間,就會每天自動更新。
策略訊號有異動時,會通知我嗎?
會。在平台上設定自動更新的策略,訊號出現異動時會寄 email 通知,在工作日 06:00~07:00 之間寄出。
策略名稱旁的綠點是什麼意思?
表示該策略當天是訊號異動日或換股日。
策略清單的「當前統計」和「近期更動清單」差在哪?
「當前統計」是策略目前實際的持股;「近期更動清單」除了目前實際持股,也包含各檔股票近期的異動。
為什麼「近期異動清單」每天都在變?
策略用到的資料每天更新,還沒進場的選股也會跟著變。實際操作時,照原本設定的換股週期換股即可。
帳號、訂閱與客服
可以更改訂閱綁定的信用卡嗎?
可以。到平台右上角的會員頁面,點「付款設定與紀錄」分頁,再點「更改發票以及信用卡」。
註冊錯帳號了,想換成另一個 FinLab 帳號?
先用新的 Google 帳號登入,再用舊帳號的 email 寄信到 finlab.company@finlab.tw 申請更換。
有使用上的問題,要去哪裡問助教?
到 FinLab 的 Discord 聊天室:在 Discord 搜尋「Python 選股實驗室」,或從 FinLab 網頁左側「社群 > Discord 聊天室」進入。
- 發問以平台與套件使用的疑難雜症為主;一般程式語法或與 FinLab 無關的問題,可以先試著用 Google 或 ChatGPT 解決。
- 完整描述你遇到的狀況:使用環境、套件版本、使用時間,並附上完整程式碼與錯誤訊息。資訊越完整,助教越能快速幫你解決。
- 策略撰寫的問題,盡量有條理地描述完整概念,能得到更有效率的解法。
- 訊息量大時問題容易被洗掉,多利用論壇區做主題式討論,延伸討論也容易追蹤。
客服時間是?多久會回覆?
客服時間為週一至週五 9:00~17:00,在 Discord 留下的問題會盡量在兩個工作天內回覆。
想許願新功能,要去哪裡?
到 Discord 的 VIP 專屬許願池留下你的願望,限 VIP。
哪裡可以看到新的研究與教學?
研究與教學訊息會公布在 Discord 的教學資源頻道與 FB 粉專;研究成果多半以部落格文章、YouTube 影片發表,都可以直接追蹤:
下一步
這一頁有幫到你嗎?