此文章為VIP限定
財經資料項目很多,除了以台股為主的FinLab資料庫,有時可能還有其他外部資料使用的需求,像是總體經濟、美股、港股、加密貨幣等等。市面上已經有不少免費又好用的財經資料庫API服務,FinLab不會再重新造輪,而是讓大家可以串接外部資料做更多元的應用。
這一篇文章會教大家使用FRED總體經濟網站的API輕鬆地獲取總經資料,並示範運用外部資料打造自己的總體經濟分析儀表板與如何套用美股標的到FinLab回測系統。
FRED API 操作說明
FRED (Federal Reserve Economic Data) 是路易斯聯邦儲備銀行研究部維護的數據庫,網站提供免費、多元、更新及時的總經資料庫、檢索、圖表功能。
和市面上的總經網站主要的差別是提供 FRED® API 服務,允許開發人員編寫程序和構建應用程式,可以根據數據源、發布、類別、系列和其他偏好自定義請求資料,比較方便程式人客製化使用資料。
帳號註冊&獲取API_KEY
依照FRED官網指示來操作,先註冊帳號,之後再申請API_KEY。
API使用規則
講解幾個最常用的功能,其他功能詳見FRED API文檔操作:
拉取總經指標的時間序列
詳見fred/series/observations,例如我們要抓取美股汽車庫存銷售比 (AISRSA) 的時間序列,可以從網址結構獲取series_id (AISRSA),並使用python的requests.get() 抓取api回傳資料,我們可以將fred_api寫成下列function,只要替換不同series_id,就能獲取各式資料。
import requests
import json
def get_fred_series_data(series_id='AISRSA',api_key=''):
res=requests.get(f'https://api.stlouisfed.org/fred/series/observations?series_id={series_id}&api_key={api_key}&file_type=json')
df=json.loads(res.text)
return df
aisrsa = get_fred_series_data('AISRSA')
依據索引拉取其他相關指標
當我們獲得”汽庫存銷售比”時,我們還想獲得其他汽車相關數據,像是”美國國內汽車製造數 (DAUPSA)”和”汽車零售銷售數 (DAUTOSA)”,之後將指標疊圖,做更細部的汽車進銷存分析。要怎麼知道汽車的索引還有哪些指標呢?
我們可以從 fred/series/categories 獲得 AISRSA的索引分類資料,從下圖的程式回傳資料可以得知,上層索引名稱為Motor Vehicles,id為32993。
# https://fred.stlouisfed.org/docs/api/fred/series_categories.html
# return: {'categories': [{'id': 32993, 'name': 'Motor Vehicles', 'parent_id': 33202}]}
series_id='AISRSA'
res=requests.get(f'https://api.stlouisfed.org/fred/series/categories?series_id={series_id}&api_key={api_key}&file_type=json')
df=json.loads(res.text)
df
再透過 fred/category/series 對應Motor Vehicles的id32993,取得汽車類別有哪些其他相關指標。再將其他相關指標的id透過前頭提到的fred/series/observations,取得時間序列資料。
# https://fred.stlouisfed.org/docs/api/fred/category_series.html
category_id=32993
res=requests.get(f'https://api.stlouisfed.org/fred/category/series?category_id={category_id}&api_key={api_key}&file_type=json')
df=json.loads(res.text)
覺得檢索方法複雜的,也可以透過網頁點選獲取相關id。
資料應用範例
美國汽車相關總體經濟指標繪圖
FRED只有單指標的繪圖,但透過api的資料結合plotly,我們可以很輕鬆客製化車用數據儀表板,像系的程式見文尾的colab檔案。
何時買的到新車?
總經數據週期長,很少拿來直接交易應用,但若到極端值,倒是可以注意一下大局下的細節。
2008、2020年的經濟衰退造成汽車庫存銷售比攀升到3以上的高水位,但指標轉壞的數據公告時,汽車類股股價早已下跌一大段,反而是中長線好買點,總經數據的遞延性是要注意的地方。
疫情後,美國汽車庫存銷售比受到汽車晶片缺乏的影響,雖然去年一直有新聞說會緩解,但新車製造數始終起不來,庫存銷售比現在低到只剩0.373,持續創造歷史低點,此現象前所未見。
正常來講,這個比率會大於1,確保有足夠數量應對市場需求。2015年來庫存去化到現在,美國車商如福特 (F)、通用 (GM)手上幾乎沒有新車庫存,在銷售數據不變下,庫存用盡會遇到無貨可賣的窘境。這連帶引發中古車價飆高、車用零組件廠商營收衰退、高端新車買不到等問題。前陣子台積電釋出消費電子有動能減緩的現象,手機鏡頭廠大立光也對未來展望保守,這兩家法說和財測都有一定參考價值。高毛利的手機晶片過去是晶圓代工廠的製造優先名單,汽車晶片相對低毛利,過去兩年在消費電子熱潮、晶圓代工產能有限下,只能委屈排在優先名單後。現在大廠釋出產業變化的看法,汽車電子能不能趁這個機會佔到產能,真的解決晶片荒呢?就看汽車庫存銷售比能不能物極必反,產生訂單遞延的爆發效應。除了整車廠,哪一些美股新車零組件能受惠呢?汽車族群經過利空測試後,復甦期與沈寂的股價表現值得留意。
美股回測
FinLab量化平台目前沒有對外開放美股資料的使用,但其實回測模組是有相關的接口讓大家自由回測全球市場。以下會使用美股汽車製造商的股價與汽車總經數據做簡單的策略回測範例,向大家示範如何串接美股資料套用回測程式。
美股資料爬蟲
下列是運用yahoo資料源爬取美股股價,程式修改來自於這篇”用爬蟲爬全世界股價“
import requests
import io
import datetime
import pandas as pd
import logging
# Get an instance of a logger
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
auto_manufacturers = {
"BLBD": "BLUE BIRD CORP",
"ELMS": "ELECTRIC LAST MILE SOLUTIONS INC",
"F": "FORD MOTOR CO",
"FFIE": "FARADAY FUTURE INTELLIGENT ELECTRIC INC",
"FSR": "FISKER INC",
"GM": "GENERAL MOTORS CO",
"GOEV": "CANOO INC",
"HYZN": "HYZON MOTORS INC",
"LCID": "LUCID GROUP INC",
"NKLA": "NIKOLA CORP",
"PTRA": "PROTERRA INC",
"RIDE": "LORDSTOWN MOTORS CORP",
}
def crawl_yahoo_finance(targets, all_data=True):
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'}
data = []
for stock_id in targets:
now = datetime.datetime.now()
now_timestamp = int(now.timestamp()) + 86400
if all_data:
start_time = 0
url = f"https://query1.finance.yahoo.com/v7/finance/download/{stock_id}?period1={start_time}&" \
f"period2={now_timestamp}&interval=1d&events=history"
try:
response = requests.get(url, headers=headers)
f = io.StringIO(response.text)
df = pd.read_csv(f, index_col='Date', parse_dates=['Date'])
df = df[~df.index.duplicated(keep='last')]
df['stock_id'] = stock_id
df = df.reset_index()
df = df.rename(columns={'Date': 'date', 'High': 'high', 'Low': 'low', 'Open': 'open', 'Close': 'close',
'Volume': 'vol', 'Adj Close': 'adj_close'})
except Exception as e:
logger.error(e)
df = None
data.append(df)
df = pd.concat(data)
return df
auto_price = crawl_yahoo_finance(auto_manufacturers.keys())
# 處理股價格式成pivot
adj_close = auto_price.pivot(index='date', columns='stock_id', values='adj_close')
adj_close = FinlabDataFrame(adj_close)
總經指標格式處理
總經指標要注意處理date,上月資料於近月底公布,ex:2021-4-30公告 2021-03月份數據,所以要使用date_range另外生成往後推的日期數列。
將汽車類股的stock_id對應進去,每一欄stock_id都有總經數據,並將總經數據dataframe套用到FinLab模組的FinlabDataFrame物件,方便之後選股條件交集運算。
aisrsa_df = pd.DataFrame(aisrsa['observations'])
aisrsa_df['value'] = aisrsa_df['value'].astype(float)
dates = pd.to_datetime(aisrsa_df['date'])
start = dates.iloc[0]+ relativedelta(months=1)
end = dates.iloc[-1]+ relativedelta(months=2)
update_date = pd.date_range(start=start,end=end,freq='M')
aisrsa_df = pd.DataFrame({i:aisrsa_df['value'] for i in auto_manufacturers.keys()})
aisrsa_df.index = update_date
aisrsa_df.index.name = 'date'
aisrsa_df = FinlabDataFrame(aisrsa_df)
aisrsa_df
選股條件
非常簡單,只有兩個條件。
還原股價站上月線,每月換股。
汽車庫存銷售銷售比大於12日均線,運用指標遞延的特性,抓汽車製造循環。
cond1 = adj_close > adj_close.average(20)
cond2 = aisrsa_df > aisrsa_df.average(12)
position = cond1 & cond2
美股市場market_info設定
這一步是將美股回測套用到FinLab的關鍵。
回測工具 sim(market=”TWSTOCK”) 會依照個別市場的MarketInfo物件,拉取對應市場的資料,目前內建market只有TWMarketInfo (台股)、CryptoMarketInfo (加密貨幣),所以要外插一個USMarketInfo 給market參數。
USMarket的benchmark改用SP500指數。
回測若要upload,要注意時間序列長度有寫入限制,範例回測2000年後的數據。
程式如下:
from finlab.market_info import MarketInfo
from finlab.backtest import sim
class USMarketInfo(MarketInfo):
@staticmethod
def get_benchmark():
world_index = data.get('world_index:close')
sp500 = world_index['^GSPC'].ffill()
return sp500
@staticmethod
def get_asset_id_to_name():
return {}
@staticmethod
def get_price(trade_at_price, adj=True):
if isinstance(trade_at_price, pd.Series):
trade_at_price.name = position.name
return trade_at_price.to_frame()
if isinstance(trade_at_price, pd.DataFrame):
return trade_at_price
if isinstance(trade_at_price, str):
if adj & (trade_at_price=='close'):
trade_at_price = 'adj_' + trade_at_price
price = auto_price.pivot(index='date', columns='stock_id', values=trade_at_price)
return price
raise Exception(f'**ERROR: trade_at_price is not allowed (accepted types: pd.DataFrame, pd.Series, str).')
report = sim(position=position.loc['2000':],resample='M',market=USMarketInfo,upload=True,name='test',stop_loss=0.1,position_limit=0.33)
report.display()
結語
這篇文章涉及FRED API串接、美股股價爬蟲、總經指標繪圖、指標解說、美股與總經回測~一條龍帶大家走一遍,開展了FinLab系統更多的可能性。
一樣附上程式範例檔,一同來開發多元市場的策略吧!