NBLOG_20230904 Python量化交易;股票池工具建構完美收官
Translator
Translator
Translator
NBLOG_20230904 Python量化交易;股票池工具建構完美收官
本期這篇文章。將迎來我們建構股票池工具的收官之作。依照慣例,追劇的每一季結尾,代表著總要對每一季階段性的故事做一個交代。然後也必須要適時的加入一些念想,期待著觀眾對於下一季新展開的劇情有所期待。所以不能免俗的這氣勢必是重星雲集。八仙過海搏命演出,求得出彩。也勢必交代出,這一季中隱藏在背後的黑手;讓罪惡滔天的大反派伏法,一平民心。所以也不要怪老夫出手太重;文章與程式嘛,也許都有點長。這都走到最後一集了,不一次交代,難道還要加演特別集番外篇嗎?我也就順口說說;要是真的有番外篇出現,那也不能怪我。今日準備兩道大菜,話不多說就從第一道走起。
接續上一篇所完成的那兩份股票列表,今天就要派上用場。咱們就從前100名最活躍的股票動手吧。好久沒有來個三連拍了。
import yfinance as yf
import talib
import mplfinance as mpf
import pandas as pd
import datetime
import ipywidgets as widgets
from IPython.display import display
import matplotlib.pyplot as plt
import pandas as pd
# 創建日期和股票代碼的小部件
start_date_widget = widgets.DatePicker(description='開始日期')
end_date_widget = widgets.DatePicker(description='結束日期')
# 讀取Excel檔並將其作為列表返回
df = pd.read_excel("MostActive 100.xlsx")
stk_list = df['Symbol'].tolist()
symbol_widget = widgets.Dropdown(description='股票代碼', options=stk_list)
# 創建K線形態的下拉選擇小部件
pattern_widget = widgets.Dropdown(description='選擇K線形態', options=['CDLENGULFING', 'CDLHARAMI', 'CDLMORNINGSTAR', 'CDL3WHITESOLDIERS', 'None'], value='CDLENGULFING')
button = widgets.Button(description='開始繪圖')
# 設置開始日期的初始值為'2023-01-01'
start_date_widget.value = datetime.date(2023, 1, 1)
# 定義按鈕點擊事件處理函數
def plot_stock_data(button):
# 清除之前的資料和圖形
plt.close('all')
# 獲取所選的開始日期、結束日期、股票代碼和K線形態
start_date = start_date_widget.value
end_date = end_date_widget.value
symbol = symbol_widget.value
pattern = pattern_widget.value
# 下載股票資料
data = yf.download(symbol, start=start_date, end=end_date)
# 獲取所選K線形態對應的talib函數
pattern_function = getattr(talib, pattern, None)
# 判斷是否顯示原始K線
if pattern_function is None:
mpf.plot(data, type='candle', volume=True, title=f'{symbol} - {pattern}', ylabel='Price')
else:
pattern_result = pattern_function(data['Open'], data['High'], data['Low'], data['Close'])
# 判斷是否顯示形態K線
if pattern_result.sum() == 0:
mpf.plot(data, type='candle', volume=True, title=f'{symbol} - {pattern}', ylabel='Price')
else:
# 找出K線形態的日期
pattern_dates = data.index[pattern_result != 0]
# 在K線形態的日期上標記三角箭頭
data['Arrow'] = pd.Series(index=data.index, dtype='float64')
data.loc[pattern_dates, 'Arrow'] = data.loc[pattern_dates, 'Low'] - 2
apd = mpf.make_addplot(data['Arrow'], type='scatter', markersize=60, marker='^', panel=0)
# 繪製K線圖和成交量
mpf.plot(data, type='candle', volume=True, title=f'{symbol} - {pattern}', ylabel='Price', addplot=apd)
# 將小部件和按鈕顯式顯示
display(start_date_widget)
display(end_date_widget)
display(symbol_widget)
display(pattern_widget)
display(button)
# 將按鈕的點擊事件與繪圖函數綁定
button.on_click(plot_stock_data)
好吧,接下來就是越來越沒樂趣的解說了。這一路以來,大家都已經對這些程式碼非常熟悉了。所以搞得當解說員都快失業了,沒啥好解說的;那就用力的找一些新鮮事來頂着先。
# 讀取Excel檔並將其作為列表返回
df = pd.read_excel("MostActive 100.xlsx")
stk_list = df['Symbol'].tolist()
symbol_widget = widgets.Dropdown(description='股票代碼', options=stk_list)
上面這一段應該就是這一次唯一的新鮮程式碼了。這裡所處理的也非常簡單,就是pandas一些常規的動作。將上次所得到的前100家活躍股票代碼讀入,接著把它轉成一個數列,然後放進小部件當中。這下子我們的選單當中就大爆滿到溢出來了。當然你也可以跟慘無人道、喪盡天良的,把S&P500成分股的資料加入。反正衹能說這下子,每天你就有夠忙的了。反正衹要將這個檔名改變為其他,那也就是相對更新了我觀察的股票列表。
好了、這就是今天要上的第一道大菜;驚不驚喜?意不意外?我怎麼好像聽到有許多人,怪裡怪氣的在發出一些抱怨聲了。感覺這個對Screener篩選這個字好像過不下去啊?如今每天來這麼一趟,人生哪還有什麼樂趣可言啊。其實夏天都已經快進入尾聲了,秋涼冬寒;何不趁著現在打打毛線,順便挨著選股,這不是很好的打發了時間嗎?到時候又多了件衣服,豈不得意哉。菜還沒上完,別急著走啊。天地良心,咱怎麼會用這種手段來對大家?都那麼認真用心的搞了幾個月了。就算心裡真的這麼想,可我也幹不出這種事啊。為了第二季的收視率,立馬忍痛上壓軸第二道大菜。這次真的下血本了。毫不吝嗇底片費用的支出。三連拍直接就變成了四連拍。上一次這樣大手筆的製作弄上不一會,臺下立馬就有上百名觀眾。哭紅了雙眼。
這段收官的壓箱程式碼;我們增加了許多的特色。第一就是當觀察個股的時候,除了標記箭頭在所發生形態日期上外;還會將這些日期彙集成一份列表,方便觀察。第二接著就要放大招了。咱們新增了一個全域掃描的按鍵;當點擊之後,便會將之前100個活躍股票代碼根據設定形態,逐個分析。最後除將這份列表顯示屏幕之外;順便也會輸出另存成一個新的檔案。有沒有感動到有一種莫名想要痛哭流涕的感覺?先強忍著眼淚,還是來先看看程式碼吧。
import yfinance as yf
import talib
import mplfinance as mpf
import pandas as pd
import datetime
import ipywidgets as widgets
from IPython.display import display
import matplotlib.pyplot as plt
import pandas as pd
from IPython.display import display, HTML
%matplotlib notebook
# 創建日期和股票代碼的小部件
start_date_widget = widgets.DatePicker(description='開始日期')
end_date_widget = widgets.DatePicker(description='結束日期')
# 讀取Excel檔並將其作為列表返回
df = pd.read_excel("MostActive 100.xlsx")
stk_list = df['Symbol'].tolist()
symbol_widget = widgets.Dropdown(description='股票代碼', options=stk_list)
# 創建K線形態的下拉選擇小部件
pattern_widget = widgets.Dropdown(description='選擇K線形態', options=['CDLENGULFING', 'CDLHARAMI', 'CDLMORNINGSTAR', 'CDL3WHITESOLDIERS', 'None'], value='CDLENGULFING')
# 創建按鈕小部件
plot_button = widgets.Button(description='繪製選定股票圖表')
analyze_button = widgets.Button(description='分析股票資料')
# 設置開始日期的初始值為'2023-01-01'
start_date_widget.value = datetime.date(2023, 1, 1)
# 創建一個Output小部件
output = widgets.Output()
# 存儲分析結果的清單
result = []
# 定義按鈕點擊事件處理函數
def plot_stock_data(button):
# 清除之前的資料和圖形
plt.close('all')
# 清空列表
output.clear_output(wait=True)
# 獲取所選的開始日期、結束日期、股票代碼和K線形態
start_date = start_date_widget.value
end_date = end_date_widget.value
symbol = symbol_widget.value
pattern = pattern_widget.value
# 下載股票資料
data = yf.download(symbol, start=start_date, end=end_date)
# 獲取所選K線形態對應的talib函數
pattern_function = getattr(talib, pattern, None)
# 判斷是否顯示原始K線
if pattern_function is None:
mpf.plot(data, type='candle', volume=True, title=f'{symbol} - {pattern}', ylabel='Price')
else:
pattern_result = pattern_function(data['Open'], data['High'], data['Low'], data['Close'])
# 判斷是否顯示形態K線
if pattern_result.sum() == 0:
mpf.plot(data, type='candle', volume=True, title=f'{symbol} - {pattern}', ylabel='Price')
else:
# 找出K線形態的日期
pattern_dates = data.index[pattern_result != 0]
# 將K線形態的日期和形態名稱添加到列表中
pattern_dates_list = pattern_dates.tolist()
pattern_names_list = [pattern] * len(pattern_dates)
# 在K線形態的日期上標記三角箭頭
data['Arrow'] = pd.Series(index=data.index, dtype='float64')
data.loc[pattern_dates, 'Arrow'] = data.loc[pattern_dates, 'Low'] - 2
apd = mpf.make_addplot(data['Arrow'], type='scatter', markersize=60, marker='^', panel=0)
# 繪製K線圖和成交量
mpf.plot(data, type='candle', volume=True, title=f'{symbol} - {pattern}', ylabel='Price', addplot=apd)
# 列印K線識別的日期和形態名稱列表
pattern_data = pd.DataFrame({'日期': pattern_dates_list, '形態名稱': pattern_names_list})
with output:
display(HTML("<h3>K線識別結果:</h3>"))
display(pattern_data)
def analyze_stock_data(button):
# 清除之前的資料和圖形
plt.close('all')
# 清空列表
result.clear()
output.clear_output(wait=True)
# 獲取所選的開始日期、結束日期和K線形態
start_date = start_date_widget.value
end_date = end_date_widget.value
pattern = pattern_widget.value
# 逐個處理股票代碼
for symbol in stk_list:
# 下載股票資料
data = yf.download(symbol, start=start_date, end=end_date)
# 獲取所選K線形態對應的talib函數
pattern_function = getattr(talib, pattern, None)
if pattern_function is not None:
pattern_result = pattern_function(data['Open'], data['High'], data['Low'], data['Close'])
# 判斷最後一天是否滿足K線形態條件
if pattern_result[-1] != 0:
result.append({'日期': data.index[-1].date(), '股票代碼': symbol, '形態名稱': pattern})
# 將結果轉換為DataFrame並顯示
result_df = pd.DataFrame(result)
# 保存結果為CSV檔
result_df.to_csv('KScreen.csv', index=False)
with output:
display(HTML("<h3>K線形態分析結果:</h3>"))
display(result_df)
# 將按鈕的點擊事件與相應的函數綁定
plot_button.on_click(plot_stock_data)
analyze_button.on_click(analyze_stock_data)
# 將小部件和按鈕顯式顯示
display(start_date_widget)
display(end_date_widget)
display(symbol_widget)
display(pattern_widget)
display(plot_button)
display(analyze_button)
display(output)
接下來就把這個大殺器好好的來解說一下。其實看到這裡自己心裡有蠻多感慨的。大家知道嗎?從一開始的幾行程式。就像堆砌積木一樣,一塊一塊的往上頂。這個收官的壓箱寶足足有140行。很高興與大家一路走來,共同努力之下,終於把這個工具堆砌完成。但凡走過必留下足跡。一起來為這個第一個主題目標達成感到驕傲吧!
from IPython.display import display, HTML
這是增加調用的html的互動套件。這是為了讓我們的Jupiter notebook,可以展示html語法內容。在輸出小部件裡面,我們會使用它來美化的網頁內容。
# 創建按鈕小部件
plot_button = widgets.Button(description='繪製選定股票圖表')
analyze_button = widgets.Button(description='分析股票資料')
這次我們增加了一個按鍵的小控制項。將它註明為「分析股票數據」。這個按鍵點擊之後所引發的動作,將幫我們描述screener的真正意義。這次計畫尋找活躍股票100名當中,篩選出每只的最後交易日,符合我們所需要的K線形態。包含吞噬母子、晨星與三白兵當中,符合任何一項設定,會整列表輸出;並另存為 csv檔。同樣的。在單獨股票的彙總中,除使用箭頭標示指定在形態產生日之外;同時會將下載資料時間段裡所有吻合形態的日期與形態名稱,彙整為列表顯示。
# 設置開始日期的初始值為'2023-01-01'
start_date_widget.value = datetime.date(2023, 1, 1)
# 創建一個Output小部件
output = widgets.Output()
# 存儲分析結果的清單
result = []
首先我們設定日期小附件的起始日期為2023年的1月1號。一直以來我們都是從日期小部件裡面取得它的變數來運用。之前曾經說過;這是一個可以雙向設定的變數,現在我們就是利用反向的方法來設定當你打開這個小物件時所內定的日期。至於結束日期的小物件。當沒有特定的去設定它的時候,它將會以系統的日期為主。所以可以不去關心他是否吃飽睡好。
接著下來,我們又增加了一個小部件。這個為output的小物件就是之後將會把所彙整的列表輸出到這個地方並顯示。
# 列印K線識別的日期和形態名稱列表
pattern_data = pd.DataFrame({'日期': pattern_dates_list, '形態名稱': pattern_names_list})
with output:
display(HTML("<h3>K線識別結果:</h3>"))
display(pattern_data)
這一段代碼主要在顯示。針對時限內所下載的個股資料。所有針對 k線形態所產生的日期列表。並將它顯示。這裡邊可以看到之前所講的使用html的場合。可以通過這樣的敘述來顯示html的內容。在這個例子當中,是用來顯示三級的標題。再次強調;這裡針對的是個股的形態部分。
# 逐個處理股票代碼
for symbol in stk_list:
# 下載股票資料
data = yf.download(symbol, start=start_date, end=end_date)
# 獲取所選K線形態對應的talib函數
pattern_function = getattr(talib, pattern, None)
以上這段程式包含在analyze_stock_data這個函式當中。這段函式便是整體掃描的最主要內容。調用了一個For 迴圈,來幫我們逐個讀取需要分析的個股代碼。排隊挨個去下載股票資料。此地仍沿用原先所設定的開始以及截止日期。事實上,我猜想;應該可以改為只下載最後的5天資料已經足夠。這樣應該可以大幅的加快程式的執行。因為最終的結果是要知道最後一天是否有形態的形成?而目前所設定的形態,應該都是小於5日裡面所形成的。不過我就想歸想還沒做;有興趣的朋友們可以自行動手試看看。特別針對那些把S&P500成份股加進來的。這個想法如果可行,應該是對你有幫助的。
# 將結果轉換為DataFrame並顯示
result_df = pd.DataFrame(result)
# 保存結果為CSV檔
result_df.to_csv('KScreen.csv', index=False)
with output:
display(HTML("<h3>K線形態分析結果:</h3>"))
display(result_df)
這應該是程式裡面的最後一段了。我們把彙整的輸出結果。同樣的兩步驟來處理。首先以html的格式,顯示在咱們的輸出小部件。之後將一份附件另存為csv檔案。這下子應該就真的可以打完收工了。
終於把我們第一季的內容全部介紹完了。真心希望大家在這過程裡面能有所得。以及對量化交易產生真正的熱愛。寫這些文章,心裡面真正的想法,是想透過這些操作內容,儘可能的貼近我們量化交易實物務所需來提供工具。有效率的來幫大家解決量化交易的問題。我知道很遺憾的,部落格的內容,對Python的初學者來說,並不是那麼的友好。事實上那些內容,我想在目前的網路環境,一定有許多這方面的大神,透過他們的生花妙筆解釋說明的更為詳細。大家應該都可以非常容易的去搜索到。而我比較想從一個交易者的角度來出發,跟大家一起共同來探索這些工具,到底能夠發揮多少的潛力?以及對我們的交易工作能最大的提供什麼樣的幫助?咱們的第一季就在這裡即將要畫上句點了。希望朋友們一起跟我期待,嶄新的第二季[策略與回測]到來。如果大夥有什麼點子或是對我們站裡面的意見;在這裡我會一直等待你的反饋。小別勝新婚,那我們就期待一下期見了!還是一樣祝福你早安,午安晚安。先別急著轉檯。你不會以為我跟你說有特別篇是唬你的吧?
留言
張貼留言