Block 已知落差與注意事項
所屬章節:積木 Block 以 2026-09-21 全量實跑結果為準(台股 405 / 美股 260,合計 665 個啟用積木)
部分章節保留 2026-08-20 當時的實測記錄(當時台股 403 / 美股 257), 需要現況請以
len(api.Block.get_table_tw())為準。 標示「已修」的章節說明的是舊行為,現況見該節內文。
Overview
積木的參數規格來自 Excel(block_spec.json),條件邏輯來自 python 類別
(condition registry)。兩邊是各自維護的,因此存在幾處落差。
這頁列出實測確認的項目,讓呼叫端知道該防什麼。
全量驗證基準(2026-09-21):台股 405 + 美股 260 個積木,每一個都實際跑過
screener_tw / screener_us,並檢查產生的 code 能否編譯:
選出 0 檔的有 12 個,查證後都正常:孤島晨星、內困三日翻紅、連續跌停這類罕見
型態當天沒出現;以及通用積木 a3 不給 right 時分母為 0,被除零防護擋掉
(相除積木不給分母本來就沒有意義)。
所以下面列的落差都不會讓積木執行失敗,它們影響的是「參數能不能調」 與「結果是否符合名稱」。
1. 預設值會正規化成 get_table 的詞彙(已修)
這一節的問題已在 2026-09-21 修掉,保留說明是因為舊筆記和舊程式碼可能還 依賴當時的行為。
以前 con() 對你指定的參數驗證合法值,但預設值不驗,所以
「con(name) 的輸出再傳回 con() 會被拒絕」——台股 59 個、美股 18 個積木中招。
成因是 Excel 規格與 condition class 對同一個值用不同寫法:
| 積木 | class 預設 | 規格合法值 |
|---|---|---|
r19 市值排名前N名以上(下)公司 |
direction='up' |
以上 / 以下 |
dfunc4 持股N張以上大戶,周月增減<>P% |
period_type='week' |
周 / 月 |
dfunc12 散戶(大戶)持股… |
up_down='up' |
< / > |
o29 連續D日(周、月) K棒為紅K |
table='日_K' |
日 / 週 / 月 |
i14 近D日個股Beta<>N倍 |
multiple=1.0 |
0.5 / 0.8 / 1 / … |
兩者送進 class 後等價('以上' 與 'up' 都得到 'up'),所以選股結果從來
沒錯,錯的是輸出的寫法與表上對不上。
現在 con() 會把預設值正規化成規格那一側:
api.Block.con_us(id='r19')
# 之前: {'id': 'r19', 'top_n': 50, 'direction': 'up'}
# 現在: {'id': 'r19', 'top_n': 50, 'direction': '以上'}
台股 26 個、美股 4 個參數受影響,全部歸零。實測 665 個積木 resolve 後的行為,
只有 3 個從 1.0 變成 1(數值相同),其餘完全未變。
連帶 con() 變成冪等——輸出丟回去得到同一份結果,所以可以拿既有條件改參數:
c = api.Block.con_tw('今日收盤價<>開高低P%', percent=3)
api.Block.con_tw(dict(c)) == c # True
c2 = api.Block.con_tw({**c, 'percent': 5})
現況往返測試:
| 市場 | 積木數 | 往返成功 | 仍失敗 |
|---|---|---|---|
| 台股 | 405 | 394 | 8(全部是第 4 節的重複編碼) |
| 美股 | 260 | 252 | 5(同上) |
(各扣掉 3 個 operator 必填的通用積木,它們不給參數本來就建不出來。)
剩下的失敗只剩重複編碼一種原因:那些積木不能用 id 指定,要用名稱。
2. list_conditions 比 get_table 多,多的那些建不出來
input
output
美股是 (301, 260)。list_conditions 讀 registry(程式碼裡註冊的全部類別),
get_table 讀 block_spec.json(只收 Excel 中「狀態=啟用」的積木)。
多出來的分兩種,成因不同:
| 情況 | 台股 | 美股 | 說明 |
|---|---|---|---|
| Excel 有列但標「停用」 | 4:m15、r22、r23、r24 |
42:o53~o94 等 |
刻意停用。例如 m15(今日收盤價<>D日均線)已被啟用中的「今日收盤價<>D日(周月)均線」取代 |
| Excel 完全沒有這個編碼 | 3:o2x、s9x、s9y |
0 | 程式碼已完整實作(分別 222 / 217 / 245 行、有 docstring 與完整參數),但 Excel 未登錄,看起來是漏登 |
input
output
建議:要列出「可用」的積木,用 get_table_tw() 的 key,不要用 list_conditions()。
3. category 有兩套詞彙,互不通用
| 來源 | 值 | 用在哪 |
|---|---|---|
ConditionMetadata.category |
英文模組名,台股 11 種(ohlc、volume、financial…) |
list_conditions(category=...) 的過濾 |
block_spec.json 的 category |
中文次類別,台股 37 種(漲跌幅、K棒型態、MACD指標…) |
積木完整參考 的分組 |
input
output
input
output
美股的 block_spec.json 次類別全為空字串,所以美股完整參考頁只有一個「(未分類)」群組。
4. 多個積木名稱共用同一個 python編碼
台股 4 組、美股 2 組的積木名稱共用同一個 python編碼(con() 輸出的 id)。
共用本身不是問題,判斷標準是:兩個名稱是否宣稱不同的邏輯卻跑出同一件事。
| 市場 | id | 兩個名稱 | 判定 |
|---|---|---|---|
| 台股 | m9 |
D日均線斜率<>0.4 / <>-0.4 |
曾是錯誤,已修 |
| 美股 | m9 |
D日均線斜率<>0.4 / <>-0.4 |
曾是錯誤,已修 |
| 台股 | s1 |
近N日期間外資/投信/自營/官股/三大買賣超 <> V張 / 官股買(賣)超>N張 |
正常,參數集不同 |
| 台股 | r4 |
近D日,官股買(賣)超張數前N名 / 法人買賣超排行前N名 |
正常,參數集不同 |
| 台股 | m21 |
長期四均線糾結(5MA/10MA/20MA) / 同名 (old) |
不是錯誤,同一積木的舊別名 |
| 美股 | r23 |
成交值排行前N名 / 成交金額排行前N名 |
不是錯誤,同一積木的別名 |
m9:曾經是真錯誤(已修)
兩個名稱宣稱的門檻不同(0.4 / -0.4),但 con() 產生的 dict 一模一樣,
等於其中一個名稱在說謊。兩個市場的成因不同:
- 台股:兩列的『python參數』都寫
'value': -0.4(複製貼上漏改), 但『邏輯基礎』欄正確帶著各自的符號。build_spec.py在映射毫無歧義時 (python參數恰好一個數值固定值、模板恰好一個數字字面值)以模板為準校正。 全部 660 個積木裡只有這一列被校正,校正會在python build_spec.py的輸出中列出。 - 美股:兩列的『python參數』完全沒有
valuekwarg,所以都用 class 預設的0.4,-0.4那個名稱取用不到。已在美股積木API.xlsx的「均線積木」分頁補上。
修好後:
api.Block.con_tw('D日均線斜率<>0.4') # value=0.4 -> 2 檔
api.Block.con_tw('D日均線斜率<>-0.4') # value=-0.4 -> 2697 檔
api.Block.con_us('D日均線斜率<>0.4') # value=0.4 -> 56 檔
api.Block.con_us('D日均線斜率<>-0.4') # value=-0.4 -> 12531 檔
m21 與 r23:別名,不是錯誤
這兩組的兩個名稱描述的是同一件事,跑出同一個結果也就是正確的, 沒有任何名稱在說謊:
m21的(old)後綴本身就標示它是舊別名,兩列所有機器可讀欄位完全相同。r23的「成交值」與「成交金額」在中文財經語境同義,class 相同。 唯一差別是top_n的選項清單:
成交值排行前N名 top_n: [50, 100, 150, 200, 500, 1000]
成交金額排行前N名 top_n: [5, 10, 100, 150, 200, 500, 1000] ← 多了 5、10
傳同一個 top_n 給兩者,con() 的 dict 與選出的股票完全相同(實測 top_n=100
與 200 皆是)。所以只在不指定 top_n(預設都是 50)時才看起來撞在一起,
明確指定就沒有歧義——這也是第 1 節「不要依賴預設值」的用意。
成交金額排行前N名的『python參數』把id寫死成'r23'而非'${ID}', 且『功能說明』欄留著別的積木的文字(股本:小於N億…)。兩者都不影響行為 (build_spec.py忽略id欄、不讀『功能說明』),但看 Excel 時會誤導。
5. 零命中時 dataframe 是 (0, 0),沒有欄位
見 執行選股 Example 5。安全寫法:
6. api.MSMP.list['all'] 含重複代號
2873 筆但只有 2872 個不同代號('7834' 出現兩次)。
screener 的股池過濾不受影響,但自己拿去當 DataFrame 的 columns 會踩到
InvalidIndexError。見 股池 末段。
7. ConditionMetadata.path 格式不統一
同一批 metadata 裡出現四種格式:
'/blocks.api.ppi.volume/v1'
'/blocks.api.api.volume/v2'
'/blocks-api/api/volume/v3x'
'/blocks-api/api/us/ohlc/o1'
這個欄位目前沒有被程式使用,不要拿它做解析或路由。
8. 有 6 個標記「啟用」的積木被靜默丟棄
build_spec.py 第 86 行 df.dropna(subset=['python編碼', '積木名稱'])
會砍掉沒填 python編碼 的列,且不發任何警告。
Excel 中有 6 列狀態是「啟用」卻沒填 python編碼,因此完全不會出現在
get_table / con 裡:
| 市場 | 分頁 | 積木名稱 |
|---|---|---|
| 台股 | 漲跌幅積木 | 未知 |
| 台股 | 漲跌幅積木 | 停利,較成本價獲利>P% |
| 台股 | 漲跌幅積木 | 停利,較成本價獲利>M千元 |
| 台股 | 漲跌幅積木 | 停損,較成本價虧損>P% |
| 台股 | 產業概念&市值 | 已公布股利政策的股票 |
| 美股 | 財報積木 | 最近一季合約負債佔股本年增率<>P% |
所以「Excel 標啟用的數量」與「實際可用的積木數」不相等:
台股 Excel 啟用 408 列 -> 扣掉缺 python編碼 5 列 -> block_spec.json 403 個
美股 Excel 啟用 261 列 -> 扣掉缺 python編碼 1 列 -> block_spec.json 260 個
要判斷某個積木到底能不能用,只看 get_table_tw() 的 key,
不要以 Excel 的狀態欄為準。
9. 有 8 個積木的固定值仍未收錄(複合值)
規格釘死的字面常數(例如 'value': -0.4)現在會由 con() 帶進輸出,見
組積木 Example 7。但『python參數』裡「佔位符 + 字面後綴」的
複合值仍未支援,因為需要模板代入:
| id | 積木 | python參數裡的複合值 |
|---|---|---|
o29 |
連續D日(周、月) K棒為紅K | 'table': '${A}_K' |
o30 |
連續D日(周、月) K棒為黑K | 'table': '${A}_K' |
v5 |
今日(周)成交量>上一日(周)成交量P倍 | 'table': '${A}_K' |
v7 |
日周月成交量創近D日新高(低) | 'table': '${A}_K' |
v8 |
日(周)成交量漸增(減)連續3次 | 'table': '${A}_K' |
m5 |
今日收盤價突(跌)破D日均線 | 'table': '${T}_K' |
m7 |
今日收盤價(乖離率)<>D日均線P% | 'table': '${T}_K' |
r4 |
近D日,官股買(賣)超張數前N名 | 'direction': '${A}超' |
這 8 個積木的該參數不會出現在 con() 輸出,condition class 會用自己的預設值,
所以「周」「月」的變體目前選不到(例如 o29 只會跑日 K)。
python build_spec.py 會把這 8 個逐筆列出。
10. v24 的「大盤總成交金額」是全市場個股加總
今日(周月)成交金額佔今日(周月)大盤總成交金額>P%(v24)的分母,
是同一張個股矩陣橫向加總得到的全市場成交金額,不是某個現成欄位——
MSMP 裡沒有大盤總成交金額這個欄位(api.MSMP.TSE 只有 OHLC 與技術指標)。
market_value = stock_value.sum(axis=1) # 全市場當日成交額
ratio = stock_value.div(market_value, axis=0) * 100
所以分母包含 TSE + OTC + 興櫃 + ETF(也就是 日_K 覆蓋的全部標的),
各檔占比加總為 100%。實測 2026-08-19:
| threshold | 檔數 | 占比範圍 |
|---|---|---|
>1% |
25 | 1.01% ~ 5.13% |
>3% |
2 | 3.11% ~ 5.13% |
>5% |
1(2330) | 5.13% |
>10% |
0 | — |
>1% 那 25 檔占比合計 43.9%。換 stock_table 成 週_K / 月_K 也適用,
分母會自動變成該頻率的全市場加總。
11. 美股沒有股池
api.USMSMP 沒有 list,screener_us() 也沒有 pool 參數。見 股池。
12. 積木名稱可能與實際邏輯不符 —— 以 o6 為例
漲跌幅介於P1%到P2%之間(o6)的名稱沒提任何期間,參數也只有 percent1 / percent2,
讀起來像「當日漲跌幅」。實際產生的程式碼是:
close = msmp.日_K.adj_Close
close_shifted = close.shift(20) # ← 20 天,硬寫死
change_pct = ((close / close_shifted) - 1) * 100
lower_bound = change_pct > percent2
upper_bound = change_pct < percent1
也就是近 20 日漲跌幅,而且 20 沒有做成參數、改不了。
實測差距(資料日 2026-08-20,pool=['all','~etf']):
| 問法 | 檔數 |
|---|---|
con_tw('漲跌幅介於P1%到P2%之間', percent1=9, percent2=5) |
183 |
直接算 日_K.漲跌幅 當日落在 5~9% |
49 |
另外兩點:
percent1是上界、percent2是下界(要求percent1 > percent2)。 按名稱直覺寫percent1=5, percent2=9會拋ValueError: percent1 (5) must be greater than percent2 (9)。- 台股沒有「當日漲幅 > P%」的純積木。最接近的
o27是當日為長紅K,且漲幅>P%,多綁了一個長紅K條件。 要純粹的當日漲跌幅請直接用api.MSMP.日_K.漲跌幅。
通則
積木名稱不是規格。 遇到「檔數與預期差很多」時,第一件事是印出
screener_tw(...)['code'] 看它實際算什麼——那份程式碼是唯一可信的語意來源,
get_table_*() 只告訴你參數的合法值,不告訴你邏輯。
13. 參數合法值清單外的需求,改用通用積木
上面幾節講的都是「積木的規格與名稱對不上」,但更常見的情況是
規格本身就沒有你要的值——threshold 最低 20000、days 沒有 21、
n 沒有 300、5ma 固定含當根、倍數固定 1.0。
這些不是 bug,是每顆積木把窗格/聚合/位移/倍數寫死在 class 裡的必然結果。
遇到時不要硬套名稱相近的積木(那會選出語意不同的股票),
改用通用積木 a1/a2/a3,這些全部是參數。
實測 29 條常見條件(KD/MACD/RSI/布林/ADX/K棒型態/財報/營收/排行)
全部組得出來——技術指標類因為 日_技術指標 表早有現成欄位,直接比即可。