文件
開啟 Studio

開始使用

策略常用的 Pandas 語法

本頁內容1

FinLab 的資料都是 Pandas 表格,寫策略就是在操作這些表格。這一頁照順序整理最常用的語法:先執行第一步匯入套件,之後每段程式都能直接執行。

匯入套件

import pandas as pd
import numpy as np
from finlab import data

認識 DataFrame 與 Series

data.get() 回傳的是一個 DataFrame,以日期為索引、股票代號為欄位。取出單一欄位(一檔股票)就是 Series。

# dataframe:資料格式範例
df = data.get('price:收盤價')
df = df[df.index <= '2020-07-01']

# series:資料格式範例
series = df['0050']

取出想看的資料

看表格的頭尾與結構:

df = data.get('price:收盤價')

# head(n):取前 n 列,預設為 5
demo_head = df.head(3)

# tail(n):取後 n 列,預設為 5
demo_tail = df.tail(3)

# index:取索引
demo_index = df.index

# columns:取欄位
demo_columns = df.columns

# values:取值
demo_values = df.values

用日期或股票代號篩選(loc 用標籤):

# boolean indexing:索引布林邏輯篩選
# ex:取得索引大於 2020 年份的資料
demo_boolean_indexing = df[df.index > '2020']

# loc:使用標籤篩選欄列
# ex:選擇 2020-01-03~2020-01-08 中所有標的的股價
demo_loc1 = df.loc['2020-01-03':'2020-01-08']

# ex:選擇 0050 & 1101 & 2330 的股價,以下兩種方法等價
demo_loc2 = df.loc[:, ['0050', '1101', '2330']]
demo_column_select = df[['0050', '1101', '2330']]

# ex:選擇 2020-01-03~2020-01-08 中 0050 & 1101 & 2330 的股價
demo_loc3 = df.loc['2020-01-03':'2020-01-08', ['0050', '1101', '2330']]

用位置篩選(iloc),以及取前 n 大、前 n 小:

# iloc:使用標籤位置篩選欄列
# ex:選擇第 6 列到第 10 列的資料
demo_iloc1 = df.iloc[5:10]

# ex:選擇 df 表中第 6 檔到第 10 檔標的資料
demo_iloc2 = df.iloc[:, 5:10]

# ex:選擇第 6 列到第 10 列 & 第 6 檔到第 10 檔標的資料
demo_iloc3 = df.iloc[5:10, 5:10]

# nlargest:取前 n 大
# ex:取近一日股價前 n 大的標的
demo_nlargest = df.iloc[-1].nlargest(10)

# nsmallest:取前 n 小
# ex:取近一日股價前 n 小的標的
demo_nsmallest = df.iloc[-1].nsmallest(10)

調整顯示的列數與欄數

Pandas 為了預防資源消耗,預設顯示列數為 10,中間的資料以 ... 帶過。想全部展開或調整顯示數量,可以這樣設定。注意這個設定是全域的,之後的顯示都會受影響。

df = data.get('price:收盤價')

# 列數全展開
pd.set_option("display.max_rows", None)

# 欄數全展開
pd.set_option("display.max_columns", None)

# 最多顯示 20 列
pd.set_option("display.max_rows", 20)

# 最多顯示 20 欄
pd.set_option("display.max_columns", 20)

# 還原顯示數預設初始值
pd.reset_option("^display")

比較與統計運算

拿整張表和數字比較,會得到同樣形狀的布林表:大於 100 的格子是 True(計算時視為 1),否則是 False(計算時視為 0)。下圖以收盤價和 60 日均線比較為例:

close 收盤價
233023172454
10/279851120
10/2810150118
10/2910449121
10/3010352117
close.average(60) 60 日均線
233023172454
10/2710052115
10/2810051116
10/2910151117
10/3010151118
position 要持有的股票
233023172454
10/27FalseFalseTrue
10/28TrueFalseTrue
10/29TrueFalseTrue
10/30TrueTrueFalse
每一格是一檔股票在一天的值。比較運算一次算完整張表,日期與股票會自動對齊;True 就是那天要持有的股票。數字為示意。
df = data.get('price:收盤價')

# 產生股價大於 100 元的布林 DataFrame
# 若大於 100 則顯示 True(計算時視為 1),否則顯示 False(計算時視為 0)
price_up_10 = df > 100

# sum:加總,axis=0 為整欄加總,axis=1 為整列加總
# ex:計算每日股價大於 100 的標的數量
demo_sum = price_up_10.sum(axis=1)

# mean:平均數,常用於計算均線
demo_mean = df.mean()

# median:中位數
demo_median = df.median()

# std:標準差,常用於計算乖離率
demo_std = df.std()

# max:最大值
demo_max = df.max()

# min:最小值
demo_min = df.min()

# cumsum:累加
# ex:累積漲多少元
demo_diff = df.diff()
demo_cumsum = demo_diff.cumsum()

# cumprod:累乘
# ex:計算累積報酬率
demo_pct_change = df.pct_change() + 1
demo_cumprod = demo_pct_change.cumprod()

# cummax:累積最大值,常用於計算 drawdown
demo_cummax = df.cummax()

# cummin:累積最小值
demo_cummin = df.cummin()

# quantile:第 c 百分位數數值,常用於取標的前 c% 強標的
demo_quantile = df.iloc[-1].quantile(0.9)

# corr:相關性
demo_corr = df.iloc[:, :5].corr()

# describe:取統計資料
demo_describe = df.describe()

用移動窗格算均線與漲跌幅

df = data.get('price:收盤價')

# shift:資料移動,常用於前後期數值增減比較、年增率計算
# ex:收盤價向下平移一列
demo_shift1 = df.shift()
# ex:收盤價向上平移一列
demo_shift2 = df.shift(-1)

# rolling:移動窗格作業,常結合資料運算公式做滾動式計算
# ex:計算 20 日移動平均線(前 n 筆資料未滿 10 日取 NaN,未滿 20 日以 n 日計算)
demo_rolling = df.rolling(20, min_periods=10).mean()

# diff:列數相減
# ex:取每日漲跌價
demo_diff = df.diff()

# pct_change:列數相除
# ex:取每日漲跌幅
demo_pct_change = df.pct_change()

用 FinlabDataFrame 的函式

data.get() 的資料繼承了 FinlabDataFrame 的功能,除了熟悉的 Pandas 語法,還能用這些函式:

函式說明
average(n)取移動平均,min_periods=int(n/2)
is_largest(n)取前 n 大
is_smallest(n)取前 n 小
rise(n=1)取比前第 n 筆高
fall(n=1)取比前第 n 筆低
sustain(nwindow, nsatisfy=None)取滾動 nwindow 筆加總大於等於 nsatisfy
quantile_row(n)取每一列(每天)的 n 分位數值
df[['0050', '1101']].average(10)
df.iloc[-10:].is_largest(5)
df.iloc[-10:].is_smallest(5)
df.iloc[-10:, 10:15].rise()
df.iloc[-10:, 10:15].fall()

# ex:是否連兩日上漲?
df.iloc[-10:, 10:15].rise().sustain(2)

# ex:取近 10 日股價前 90% 分位數
df.iloc[-10:].quantile_row(0.9)

畫圖檢查

乖離率線圖:用布林通道(Bollinger Bands)畫出股價走勢與上下軌道。

df = data.get('price:收盤價').iloc[-400:]['2330']
mean_20 = df.rolling(20).mean()
std_value = df.rolling(20).std()

up = mean_20 + std_value * 2
down = mean_20 - std_value * 2
up.plot(label='up', legend=True)
down.plot(label='down', legend=True)
mean_20.plot(label='ma_20', legend=True)
df.plot(title='bias plot', label='close', legend=True, figsize=(20, 8), grid=True)

相關性熱力圖:把多檔股票的相關性畫成熱力圖,快速觀察彼此的連動關係。

df = data.get('price:收盤價')
check_list = ['1101', '1102', '2330', '2454', '6263', '9939']
demo_corr = df.iloc[-600:][check_list].corr()

demo_corr.style.background_gradient(cmap='viridis').set_properties(
    **{'font-size': '20px'}
)

組成選股策略

均線多頭:選出股價同時站上 5 日、10 日、20 日、60 日均線的股票,取前 10 大。

df = data.get('price:收盤價')
# 限定範圍
df = df[(df.index > '2015') & (df.index < '2019')]

cond1 = df > df.rolling(5).mean()
cond2 = df > df.rolling(10, min_periods=5).mean()
cond3 = df > df.rolling(20, min_periods=10).mean()
cond4 = df > df.rolling(60, min_periods=40).mean()

position = df * (cond1 & cond2 & cond3 & cond4)
position = position[position > 0]
position = position.is_largest(10)

突破布林通道上緣:選出收盤價剛突破布林通道上緣的股票,並限制股價在 5~200 元之間。

df = data.get('price:收盤價')
mean_20 = df.rolling(20).mean()
std_value = df.rolling(20).std()

up = mean_20 + std_value * 2

# 收盤價剛站上布林通道上緣
cond1 = (df > up) & (df.shift() < up)
cond2 = (df > 5) & (df < 200)
position = cond1 & cond2
position = position[position > 0]
position = position.is_smallest(20)

下一步

↑↓ 選擇 Enter 開啟 Esc 關閉