---
title: 'FINLAB擴充套件'
disqus: hackmd
---
Finext
===
>[name=吾夜遊酩,2024/6/15]
<!-- 

-->
* 這是一個基於finlab的擴充套件,提供延伸功能,假設使用者已經熟悉finlab,功能說明會慢慢補上,如果有時間ㄉ話
* finlab免費版即可使用,差在資料更新與每日能下載多少資料
* 可能會遇到版本,環境問題,需有基礎程式能力除錯
環境
---
### 建議環境
* 作業系統:Ubuntu 22.04.3 LTS (WSL) / mac (M1)
* Python 3.11.0
* finlab 1.1.1
* pyspark 3.5.0
* ipython 8.21.0
### 下載finext
```gherkin=
pip install finext
```
初始化
---
```python=
import finlab
from finext.co_tools import Codata, FinlabDataFrame
#指定db儲存路徑,依照你的電腦資料夾路徑更改
db_path = "/home/sb0487/trade/finlab/finlab_db"
#初始化,建構實例
c = Codata( df_type = "findf", db_path = db_path, force_download = False )
```
* df_type有三種型態,莫認為FinlabDataFrame:
1."findf": FinlabDataFrame
2."cudf": cuda的DataFrame
3."sparkdf":spark的DataFrame
>force_download為強制重新下載資料庫資料,機制詳見[finlab官方](https://doc.finlab.tw/reference/data/)
資料下載
---
```python=
eps = c.get('financial_statement:每股盈餘')
```
與官方data.get差異在於會顯示最後一次修改時間,幫助使用者注意資料狀態
>
>output:
>Daily usage: 1.3 / 500 MB - financial_statement:每股盈餘
最後更新時間: 2024-06-01 19:59:32, ['financial_statement:每股盈餘']
年報季報搜尋-1.爬蟲
---
``` mermaid
graph TD;
自行設定股票清單-->stock_list;
從finlab季報eps表中獲取股票清單-->stock_list;
stock_list -->年報爬蟲;
stock_list -->季報爬蟲;
年報爬蟲-->年報爬蟲失敗list;
季報爬蟲-->季報爬蟲失敗list;
年報爬蟲失敗list-->年報爬蟲;
季報爬蟲失敗list-->季報爬蟲;
```
```python=
import re
import finlab
from finext.co_tools import Codata, FinlabDataFrame
#指定db儲存路徑,依照你的電腦資料夾路徑更改
db_path = "/home/sb0487/trade/finlab/finlab_db"
#初始化
c = Codata( df_type = "findf", db_path = db_path, force_download = False )
eps = c.get('financial_statement:每股盈餘')
#抓取股票清單
pattern = re.compile(r'^\d{4}$')
all_stock_list = [value for value in list(eps.columns) if pattern.match(value)]
```
首先我們需要準備一份爬蟲清單,型態為list,我們用finlab資料庫季報的eps資料,抓取所有的股票代號,並去除etf
```python=
"""年報爬蟲"""
#指定年報儲存路徑,依照你的電腦資料夾路徑更改
save_dir = "/home/sb0487/trade/data/112年報"
#先用三隻股票測試是否能順利抓取
stock_list = all_stock_list[:3]
year = 112
sleep = 2
failed_list = c.crawl_annual_reports(year,stock_list,save_dir,sleep)
```
這邊會使用到selenium套件,記得要安裝chromedriver
* 參數說明
1. year: 年報年分,西元
2. sleep: 每個步驟停頓秒數,視網速,電腦效能,證交所是否會檔而定
3. failed_list: 會有許多情況導致爬不到,failed_list會記錄本次沒爬到的股票清單,可以把他做為stock_list,再爬1run
>順利的話,output:
>PDF 文件已保存到: /home/sb0487/trade/data/112年報/112_1101.pdf
PDF 文件已保存到: /home/sb0487/trade/data/112年報/112_1102.pdf
PDF 文件已保存到: /home/sb0487/trade/data/112年報/112_1103.pdf
```python=
"""季報爬蟲"""
#指定年報儲存路徑,依照你的電腦資料夾路徑更改
save_dir = "/home/sb0487/trade/data/112季報/Q3"
#先用三隻股票測試是否能順利抓取
stock_list = all_stock_list[:3]
year = 112
quarter = 3
sleep = 2
failed_list = c.crawl_quarterly_reports(year,quarter,stock_list,save_dir,sleep)
```
這邊會使用到selenium套件,記得要安裝chromedriver
* 參數說明
1. year: 年報年分,西元
2. quarter: 季度
3. sleep: 每個步驟停頓秒數,視網速,電腦效能,證交所是否會檔而定
4. failed_list: 會有許多情況導致爬不到,failed_list會記錄本次沒爬到的股票清單,可以把他做為stock_list,再爬1run
```python=
"""檢查資料夾,查詢哪些股票尚未下載"""
undownloaded_stocks_list = c.get_undownloaded_stocks(save_dir,all_stock_list)
```
年報季報搜尋-2.載入
---
因為檔案數量多,這邊使用pyspark以節省讀檔時間,然而因電腦性能這步驟會有出錯的可能,通常是記憶體過小,若無法解決請用一般載入
``` mermaid
graph TD;
自行設定股票清單-->stock_list;
從finlab季報eps表中獲取股票清單-->stock_list;
stock_list -->載入PDF;
載入PDF-->spark載入;
載入PDF-->一般單線程載入;
```
```python=
pip install PyMuPDF
```
```python=
import re
import finlab
from finext.co_tools import Codata, FinlabDataFrame
#指定db儲存路徑,依照你的電腦資料夾路徑更改
db_path = "/home/sb0487/trade/finlab/finlab_db"
#初始化
c = Codata( df_type = "findf", db_path = db_path, force_download = False )
eps = c.get('financial_statement:每股盈餘')
#抓取股票清單
pattern = re.compile(r'^\d{4}$')
all_stock_list = [value for value in list(eps.columns) if pattern.match(value)]
```
初始化並拿到股票清單
```python=
"""saprk載入"""
pdf_path = "/home/sb0487/trade/data/113季報/Q1"
stock_list = all_stock_list
df = c.load_pdf_spark(stock_list,pdf_path,memory = "5g")
```
這邊只要給他stock_list與PDF所在資料夾即可,每個driver都需要5g以上記憶體,若kernel crash,可嘗試提高記憶體
若報錯可在網頁輸入`http://localhost:4040/jobs/`將錯誤碼貼給chat-gpt,或者一般單線程載入
```python=
"""一般單線程載入"""
pdf_path = "/home/sb0487/trade/data/113季報/Q1"
stock_list = all_stock_list
df = c.load_pdf(stock_list,pdf_path)
```
年報季報搜尋-3.應用
---
簡單舉例來說,以下都可以用關鍵字搜尋:
1. 如果你想知道哪些股票是與NVIDIA有關係,而還沒被提及的
2. 某檔股票漲了一大段,想知道那些公司有持有他
3. 某樣特殊產品缺貨,還有哪一家公司有在做?
4. 賴總統在再生醫療雙法三讀通過時提到"智慧醫療",想知道每家生技公司提到ai的次數?
```python=
"""關鍵字"""
df['count'] = df['PDF Content'].str.count("NVIDIA")
df_filtered = df[df['count'] >= 1]
```
相關係數排名
---
指定某檔股票,從股票清單中找出與該股票相關係數最高與最低的TOP30
```python=
import re
import finlab
from finext.co_tools import Codata, FinlabDataFrame
#指定db儲存路徑,依照你的電腦資料夾路徑更改
db_path = "/home/sb0487/trade/finlab/finlab_db"
#初始化
c = Codata( df_type = "findf", db_path = db_path, force_download = False )
close = c.get('price:收盤價')
```
初始化並拿到股價df
```python=
import pandas as pd
import re
pattern = re.compile(r'^\d{4}$')
close = close[[col for col in close.columns if pattern.match(col)]]
```
這邊去除etf等,使用者可以自行決定要去除哪些股票,如果要保留etf,這行就刪掉
```python=
start_date = '2020-08-07'
end_date = '2023-08-07'
close = close.loc[start_date:end_date]
```
指定日期區間,範例如程式碼
```python=
c.get_corr_ranked("2330",close)
```
輸出結果如下

時間序列比較圖
---
指定某兩檔股票,繪圖與計算其區間相關係數
```python=
import re
import finlab
from finext.co_tools import Codata, FinlabDataFrame
#指定db儲存路徑,依照你的電腦資料夾路徑更改
db_path = "/home/sb0487/trade/finlab/finlab_db"
#初始化
c = Codata( df_type = "findf", db_path = db_path, force_download = False )
close = data.get('price:收盤價')
```
初始化並拿到股價df
```python=
start_date = '2020-08-07'
end_date = '2023-08-07'
close = c.loc[start_date:end_date]
```
指定日期區間
```python=
c.get_tm_series_chart(["2330","0050"],close,lag = 0)
```
* 如果 lag 為正數,則第二個股票的時間序列會被向後移動相應的滯後期數。
* 圖表上顯示滯後後的時間序列與滯後前的原始時間序列進行比較。
* 函數會計算滯後期數後的相關係數,並在圖表標題中顯示出來,用於分析兩數列之間在不同滯後期的相關性,從而確定領先滯後關係(Cross-Correlation Analysis)。
輸出結果如下

* 若要嚴謹一點的統計學,在檢定兩數列之間的領先滯後關係之前,至少要有兩步驟。
1. 確定這兩個數列是否為隨機漫步(random walk),意即它們是否是平穩的(stationary),通常金融數據為一階平穩,所以通常取差分是標準步驟。推薦 Dickey-Fuller Test, H0為數列存在單根
3. 完成以上步驟後,可以進行兩數列之間的領先滯後檢驗。Granger Causality Test或Cross-Correlation Analysis,不過還是建議是不要在統計學上浪費時間TAT
### 額外範例,長榮航與wti油價相關係數
```python=
import re
import finlab
from finext.co_tools import Codata, FinlabDataFrame
#指定db儲存路徑,依照你的電腦資料夾路徑更改
db_path = "/home/sb0487/trade/finlab/finlab_db"
#初始化
c = Codata( df_type = "findf", db_path = db_path, force_download = False )
close = c.get('price:收盤價')
```
初始化並拿到股價df
```python=
start_date = '2020-08-07'
end_date = '2023-08-07'
close = c.loc[start_date:end_date]
```
指定日期區間
```python=
import yfinance as yf
# 下載數據並重命名欄位
wti_data = yf.download(tickers="CL=F", period="10y", interval="1d")[['Close']].rename(columns={'Close': 'wti_close'})
# 將索引轉換為日期格式
wti_data.index = wti_data.index.date
# 併入finlab的dataframe
merged_df = close.join(wti_data, how='inner')
```
記得要下載yfinance
```python=
c.get_tm_series_chart(["2618","wti_close"],close = merged_df,lag = 0)
```
輸出結果如下

<!--
User flows
---
```sequence
Alice->Bob: Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob->Alice: I am good thanks!
Note left of Alice: Alice responds
Alice->Bob: Where have you been?
```
> Read more about sequence-diagrams here: http://bramp.github.io/js-sequence-diagrams/
Project Timeline
---
```mermaid
gantt
title A Gantt Diagram
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2014-01-12 , 12d
anther task : 24d
```
> Read more about mermaid here: http://mermaid-js.github.io/mermaid/
## Appendix and FAQ
:::info
**Find this document incomplete?** Leave a comment!
:::
###### tags: `Templates` `Documentation`
-->