Pandas 策略開發基礎語法
1. 安裝環境
2. 創造資料物件
data.get() 回傳的是一個 DataFrame,以日期為索引、股票代號為欄位。取單一欄位則為 Series。
# dataframe:資料格式範例
df = data.get('price:收盤價')
df = df[df.index <= '2020-07-01']
# series:資料格式範例
series = df['0050']
3. 資料檢索
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
# 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:使用標籤位置篩選欄列
# 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)
4. 顯示控制
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")
5. 資料運算
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()
6. 移動窗格作業
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()
7. 使用 FinlabDataFrame 的功能
除了使用熟悉的 Pandas 語法,還可以使用 FinlabDataFrame 的 function!
data.get() 的資料繼承 FinlabDataFrame 的功能,可用函式如下:
| 函式 | 說明 |
|---|---|
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)
8. 視覺化
8-1. 乖離率線圖
使用布林通道(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)
8-2. 相關性熱力圖
將多檔股票的相關性以熱力圖呈現,快速觀察標的之間的連動關係。
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'})
9. 策略範例
9-1. 均線多頭
選出股價同時站上 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)
9-2. 突破布林通道上緣
選出收盤價剛突破布林通道上緣的股票,並限制股價在 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)