2022年4月到5月初受FED縮表、通膨超出預期、國內疫情爆發等利空因素引起殺盤,跌得昏天暗地,台積電差點跌破500元,更不用說體質更脆弱的小型股倒一片,OTC指數在2022年已回檔超過20%,融資斷頭ptt文齊發,令投資人煎熬。
可以抄底了沒?到底還要跌多久?是許多人想知道的問題。止跌的關鍵在不穩定籌碼被洗出了沒?只要投機籌碼仍多,股價就容易因利空產生恐慌急殺。
融資維持率是其中一個重要指標,該指標相關介紹可見“大盤融資維持率|地板指標幫你搶長線反彈|0050擇時策略優化?”,利用融資成數、融資保證金計算,正常水位為1.67,近期大盤融資維持率又跌到150上下的偏低水位,搭配融資餘額持續退場,可見浮動籌碼逐漸被洗出場,有機會開始逐底。
若之後融資維持率10日均線開始上揚、融資維持率突破10日均線,則多方籌碼才會再有凝聚現象,不再受到過大的套牢壓力籠罩後,才有機會出現像樣的反彈。
融資維持率不見得每個券商app都有,透過FinLab API與Plotly,我們可以輕易製作出客製化的圖表來觀察融資維持率,只要有Python的基礎都能輕易上手。
生成融資維持率
透過以下簡單的程式,我們能生成繪圖所需要用到的資料。
from finlab import data
融資今日餘額 = data.get('margin_transactions:融資今日餘額')
融資券總餘額 = data.get('margin_balance:融資券總餘額')
融資券總餘額 = 融資券總餘額.loc[融資今日餘額.index.intersection(融資券總餘額.index)]
融資券總餘額['上市融資買賣超'] = (融資券總餘額['上市融資交易金額']-融資券總餘額['上市融資交易金額'].shift()).fillna(0)/100000000
融資券總餘額['上櫃融資買賣超'] = (融資券總餘額['上櫃融資交易金額']-融資券總餘額['上櫃融資交易金額'].shift()).fillna(0)/100000000
close = data.get('price:收盤價')
benchmark = data.get('benchmark_return:發行量加權股價報酬指數').squeeze()
融資總餘額 = 融資券總餘額[['上市融資交易金額','上櫃融資交易金額']].sum(axis=1)
融資餘額市值 = (融資今日餘額*close*1000).sum(axis=1)
融資維持率 = (融資餘額市值/融資總餘額)
融資維持率
台股大盤融資指標圖組繪製
我們將用上述的資料套入Plotly製作動態圖組,一目瞭然市場動態,並學習使用plotly.layout去控制外觀與圖表互動工具。以下會對程式的細節提出重點講解。
目標結果
程式範例
#@title 台股大盤融資指標
start= '2020-01-01' #@param {type:"date"}
end = "2022-05-17" #@param {type:"date"}
import pandas as pd
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import numpy as np
df = 融資維持率.loc[(融資維持率.index>=start)&(融資維持率.index<=end)]
df2 = 融資券總餘額.loc[(融資券總餘額.index>=start)&(融資券總餘額.index<=end)]
fig = make_subplots(rows=3,
cols=1,
shared_xaxes=True,
vertical_spacing=0.05,
specs=[[{"secondary_y": True}],
[{"secondary_y": True}],
[{"secondary_y": True}],
],
subplot_titles=('融資維持率',
'上市融資餘額',
'上櫃融資餘額',
)
)
date_index=df.index
benchmark_values=benchmark.reindex(df.index)
# 融資mt_rate
fig.add_trace(
go.Scatter(x=date_index, y=benchmark_values, name="大盤加權報酬指數",line=dict(width=3)),
secondary_y=False, row=1, col=1
)
fig.add_trace(
go.Scatter(x=date_index, y=df.values, name="融資維持率"),
secondary_y=True, row=1, col=1
)
fig.add_trace(
go.Scatter(x=date_index, y=df.rolling(10).mean().values, name="融資維持率_ma10"),
secondary_y=True, row=1, col=1
)
# 買賣超
fig.add_trace(
go.Scatter(x=date_index, y=df2['上市融資交易金額'], fill='tozeroy',
line=dict(width=0.5, color='#efd267'), name="上市融資餘額"),
secondary_y=False, row=2, col=1
)
fig.add_trace(
go.Bar(x=date_index, y=df2['上市融資買賣超'],
marker_color=df2['上市融資買賣超'].apply(lambda s: 'red' if s>0 else 'green' ), name="上市融資買賣超"),
secondary_y=True, row=2, col=1
)
# otc買賣超
fig.add_trace(
go.Scatter(x=date_index, y=df2['上櫃融資交易金額'], fill='tozeroy',
line=dict(width=0.5, color='#efd267'), name="上櫃融資餘額"),
secondary_y=False, row=3, col=1
)
fig.add_trace(
go.Bar(x=date_index, y=df2['上櫃融資買賣超'],
marker_color=df2['上櫃融資買賣超'].apply(lambda s: 'red' if s>0 else 'green' ), name="上櫃融資買賣超"),
secondary_y=True, row=3, col=1
)
# remove empty date(holiday)
dt_all = pd.date_range(start=date_index.values[0], end=date_index.values[-1])
# retrieve the dates that are in the original datset
dt_obs = [d.strftime("%Y-%m-%d") for d in pd.to_datetime(close.index)]
# define dates with missing values
dt_breaks = [d for d in dt_all.strftime("%Y-%m-%d").tolist() if not d in dt_obs]
# hide dates with no values
fig.update_xaxes(rangebreaks=[dict(values=dt_breaks)])
# Add figure title
fig.update_layout(
width=1500,
height=800,
title='台股大盤融資5',
title_font_color="navy",
title_font_size=20,
hovermode='x unified',
yaxis=dict(
title='指數',
showgrid=False
),
yaxis2=dict(
title='融資維持率',
),
yaxis3=dict(
title='price',
showgrid=False
),
yaxis4=dict(
title='買賣超(億)',
),
yaxis5=dict(
title='price',
showgrid=False
),
yaxis6=dict(
title='買賣超(億)',
),
showlegend=True,
xaxis=dict(
rangeselector=dict(
buttons=list([
dict(count=1,
label="1m",
step="month",
stepmode="backward"),
dict(count=6,
label="6m",
step="month",
stepmode="backward"),
dict(count=1,
label="YTD",
step="year",
stepmode="todate"),
dict(count=1,
label="1y",
step="year",
stepmode="backward"),
dict(count=3,
label="3y",
step="year",
stepmode="backward"),
dict(step="all")
])
),
type="date"
),
xaxis2=dict(
type="date"
),
xaxis3=dict(
rangeslider=dict(
visible=True
),
type="date"
),
)
fig.show()
多重子圖
plotly的make_subplots可控制多重圖組的畫布。
rows與cols參數控制畫布有多少張子圖,如此範例是三列一欄的子圖,繪圖物件的定位也依據此來設定。
shared_xaxes用來設定子圖是否要共用X軸,像此範例因有使用rangeslider做拉桿,希望拖動時間軸時,所有子圖能一起連動,所以設定為True。
vertical_spacing與horizontal_spacing參數為控制子圖間垂直與水平的間隙。
specs為設定圖組的格式,此範例因爲要設定雙Y軸縣市不同數據,有加入 {“secondary_y”: True}。
融資維持率折線圖
畫布加入add_trace(xxx)的意思是加入子圖物件至大畫布裡,如以下程式是在第一列第一行 (也就是第一張子圖) 繪製融資維持率,並將數值對應到右側的Y軸,設定secondary_y=True。
fig.add_trace(
go.Scatter(x=date_index, y=df.values, name="融資維持率"),
secondary_y=True, row=1, col=1
)
餘額區域圖
區域圖又稱Filled Area Plot,使用go.Scatter(fill=’tozeroy’)即可將折線圖以下的區域設定填滿顏色。
買賣超長條圖
長條圖是用go.bar()來控制,這邊要注意長條圖顏色控制用融資買賣超的正負數來控制。
假日空值處理
plotly的小坑是時間序列若碰非連續,會有斷點。像台股資料週六、日未交易,圖表就會有被卡掉的現象。需用fig.update_xaxes(rangebreaks=[dict(values=dt_breaks)])來解決。
layout設定
設定畫布的大標題、長寬、子圖的X、Y軸細節,如showgrid只用每個子圖其中一個Y軸對應,不然雙Y軸對應會顯得雜亂。
rangeselector能產生圖標左上的日期選取按鈕工具列,點擊1m會將資料帶到近1月,點擊YTD會將資料帶到最近一年度之後的資料,如今天是2022-05-17,會將資料限縮在2022-01-01之後。
rangeslider則是子圖最下方的拉桿控制。
結語
plotly有許多互動圖表功能可使用,熟悉後就十分方便,能玩轉更種資料,將FinLab API延伸出更多應用。
融資籌碼指標除了大盤融資維持率,個股的維持率與斷頭指標的估算也能幫助我們判斷個股是否落底,靜待下回分曉囉