開始使用
策略常用的 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 收盤價 | 2330 | 2317 | 2454 | |
|---|---|---|---|
| 10/27 | 98 | 51 | 120 |
| 10/28 | 101 | 50 | 118 |
| 10/29 | 104 | 49 | 121 |
| 10/30 | 103 | 52 | 117 |
close.average(60) 60 日均線 | 2330 | 2317 | 2454 | |
|---|---|---|---|
| 10/27 | 100 | 52 | 115 |
| 10/28 | 100 | 51 | 116 |
| 10/29 | 101 | 51 | 117 |
| 10/30 | 101 | 51 | 118 |
position 要持有的股票 | 2330 | 2317 | 2454 | |
|---|---|---|---|
| 10/27 | False | False | True |
| 10/28 | True | False | True |
| 10/29 | True | False | True |
| 10/30 | True | True | False |
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)下一步
- 10 分鐘寫出第一個策略 用這些語法寫進出場條件,回測並上傳。
- 寫選股條件 FinlabDataFrame 選股函式的完整說明。
- 下載資料 財報、月營收、法人籌碼,以及怎麼找資料表名稱。
- 歷史回測 把 position 交給 sim() 回測。
這一頁有幫到你嗎?