客製化因子¶
上一個章節(lecture/Factors.ipynb)我們介紹了何謂因子以及如何使用因子,TQuant Lab 已經內建許多不同因子。然而在因子研究不斷勃發之下,許多新型態價量因子持續問世,或許您也有自己的專屬策略因子,因此本章將示範如何客製化因子並運用於 TQuant Lab 中。
概念上而言,客製化因子與內建因子十分相同。兩者皆以 inputs, window_length, mask 為輸入參數,並且輸出 factor 物件的類別。
假使欲計算每檔股票每天的滾動標準差 (standard deviation),我們可以使用 zipline.pipeline.CustomFactor
子類與 compute
方法函式建構。
class zipline.pipeline.CustomFactor¶
Parameters:¶
-
inputs: iterable, optional
輸入資料。
-
outputs: iterable[str], optional
輸出的因子。
-
window_length: int, optional
輸入資料的時間窗格。
-
mask: zipline.pipeline.Filter, optional
決定哪些資產需要計算因子。
def compute(self, today, assets, out, *inputs)¶
- today: 為pandas.Timestamp型態,記錄 Pipeline 啟動當天的日期。
- assets: 是長度為 N 的numpy array,紀錄 sids(資產)。
- *inputs: 為 MxN 的 numpy.arrays,M 為 window_length 且 N 為資產數量,可以設立多個inputs。
- out: 是長度為 N 的numpy arrays。out 將會產出當天的 CustomFactor 計算結果。
導入價量資料與必要模組¶
import os
import pandas as pd
import numpy as np
import tejapi
import warnings
warnings.filterwarnings('ignore')
os.environ['TEJAPI_BASE'] = 'https://api.tej.com.tw'
os.environ['TEJAPI_KEY'] = 'YOUR KEY'
os.environ['mdate'] = '20080401 20230702'
os.environ['ticker'] = '2330 2409'
from zipline.pipeline import Pipeline, CustomFactor
from zipline.TQresearch.tej_pipeline import run_pipeline
from zipline.pipeline.data import TWEquityPricing
from zipline.pipeline.filters import StaticAssets,StaticSids
from zipline.api import sid, symbol
# ingest stock data
!zipline ingest -b tquant
建立計算標準差的因子¶
於此例我們使用 np.nanstd
計算輸入值的標準差,輸入值與時間區間會依照 make_pipeline()
中的 StdDev
所給的 inputs 與 window_length 所決定。以此例中,若我們想要計算台積電 (2330) 與友達 (2409) 的 7 日收盤價標準差,可以設定為:
- inputs = [TWEquityPricing.close], TWEquityPricing 內建 bundle 內所有股票的價量資料。
- window_length = 7
接著使用 run_pipeline
呼叫 Pipeline
,於回測期間內,逐日計算因子,最終產出 dataframe。可以發現該dataframe有MultiIndex,分別是時間與標的,並且每個指標於每天都會生成 7 日收盤價標準差。
zipline.TQresearch.tej_pipeline.run_pipeline¶
執行 Pipeline 並生成資料表。
Parameters:¶
- pipeline: zipline.pipeline.Pipeline 欲運行的 pipeline 函式。
- start_date: pd.Timestamp pipeline 起始執行的日期。需注意該日期必須於 bundle 時間區間內。
- end_date: pd.Timestamp pipeline 執行結束的日期。需注意該日期必須於 bundle 時間區間內。
Returns¶
pd.DataFrame, 輸出 Pipeline 執行結果。
class StdDev(CustomFactor):
def compute(self, today, assets, out, values):
out[:] = np.nanstd(values, axis=0)
def make_pipeline():
std_dev = StdDev(inputs=[TWEquityPricing.close], window_length=7)
return Pipeline(
columns={
'std_dev':std_dev
}
)
result = run_pipeline(make_pipeline(), pd.Timestamp('2013-01-03', tz='UTC'), pd.Timestamp('2023-01-03', tz='UTC'))
result
預設輸入參數¶
當建立客製化因子時,也可以預先設定輸入之參數,於此例中我們欲建立一個計算開收盤價差 10 日平均的因子,在 TenDayMeanDifference
中我們預先宣告 inputs
與 window_length
為 [TWEquityPricing.close, TWEquityPricing.open]
與 window_length = 10
。
class TenDayMeanDifference(CustomFactor):
inputs = [TWEquityPricing.close, TWEquityPricing.open]
window_length = 10
def compute(self, today, assets, out, c_price, o_price):
out[:] = np.nanmean(c_price - o_price, axis=0)
def make_pipeline():
close_open_diff = TenDayMeanDifference()
return Pipeline(
columns={
'close_open_diff':close_open_diff
}
)
result = run_pipeline(make_pipeline(), pd.Timestamp('2013-01-03', tz='UTC'), pd.Timestamp('2023-01-03', tz='UTC'))
result
若在 make_pipeline
中賦予 TenDayMeanDifference
新的參數則會覆蓋掉預設的參數(TWEquityPricing.high
、TWEquityPricing.low
),可以發現下方表格的結果與上方表格不同。
def make_pipeline():
close_open_diff = TenDayMeanDifference(inputs=[TWEquityPricing.high, TWEquityPricing.low])
return Pipeline(
columns={
'close_open_diff':close_open_diff
}
)
result = run_pipeline(make_pipeline(), pd.Timestamp('2013-01-03', tz='UTC'), pd.Timestamp('2023-01-03', tz='UTC'))
result
window length 時間區間¶
Pipeline
會在每個交易日計算出因子的真實數值。
請注意因子的時間區間必定是從前一個交易日開始計算,以計算前 10 日最低收盤價格為因子,我們可以建立 TenDaysLowest
。所得出資料表包含每日各股票往前十個日的最低收盤價,以 2023-03-19 為例,在計算因子時就會從 2023-03-18 開始向前推十日。
class TenDaysLowest(CustomFactor):
inputs=[TWEquityPricing.close]
window_length=10
def compute(self, today, assets, out, close):
out[:] = np.nanmin(close, axis=0)
def make_pipeline():
tendl = TenDaysLowest()
return Pipeline(
columns={
'TenDaysLowest':tendl
}
)
results = run_pipeline(make_pipeline(), pd.Timestamp('2013-03-18', tz='UTC'), pd.Timestamp('2023-01-03', tz='UTC'))
results
由上表可以發現 2013-03-19 台積電的 TenDaysLowest
為 100.5,而下表可以發現確實從 2013-03-05 到 2013-03-18 之間的最低收盤價為 100.5 而非 2013-03-19 的 100,代表 pipeline 在計算因子時是從前一日開始,避免前視偏誤。
from zipline.data.data_portal import DataPortal, get_bundle
df_bundle = get_bundle(bundle_name='tquant',
calendar_name='TEJ',
start_dt=pd.Timestamp('2013-01-05', tz='UTC'),
end_dt=pd.Timestamp('2023-01-03', tz='UTC'))
df_bundle.loc[(df_bundle['symbol']=='2330') & (df_bundle['date'].between('2013-03-04','2013-03-19'))][["date", 'close']]