Shopping Cart

購物車內沒有任何商品。

函式 def 把重複的動作包裝起來!

一、前言

我們在寫程式的時候,往往會遇到同一段程式碼不斷被重複使用。比如說,我們在選股模型的程式會需要讀取價量資料,而在做回測的時候也會需要讀取一樣的資料。那我們是不是可以寫成一個公版函式,變成一個一般化的、大家都能呼叫來使用的「功能」?

題外話,為了讓非程式底子的讀者在看過一遍就能學會,我們這裡盡量使用生活化的用詞,會大量捨棄程式開發上的標準用語「特性」、「方法、「實例」等來做教學,對於用語要求非常精準的讀者,建議直接閱讀相關教科書即可。

立即訂閱電子報,掌握最新資訊!

    稱呼

    電子郵件

    以下非必填,但若您願意分享,我們將能推送更精準的內容給您

    投資經驗

    是否為理工科背景、工程師或有寫程式的經驗?

    有興趣的主題
    量化交易台股期貨海外期貨虛擬貨幣美股

    有興趣的量化交易軟體/平台
    不清楚MultiChartsTradingViewPythonXQ

    想透過量化交易達成甚麼目的?
    不確定自動交易選股回測投資績效量化自己的投資方法想找現成的策略套用

    還有什麼想詢問的?

    20241111 1920 400
    20241111 978 258


    二、函式 def 怎麼用?

    def plus(x, y):
      z = x + y
      return z

    以上方的函式為例,第一行 def以及一個半形空格後,接著的是函式名稱,這裡我取名叫做 plus。名稱後方的括號內,定義好我要傳入的兩個參數名稱,分別叫做 x 和 y。同一行最後再加個半形冒號。

    第二行開始是定義函式「負責」的任務,相比於 def 第一行,要做一次 tab 縮排,表示是屬於這個函式的內容。上方的例子,函式 plus 的任務首先就是 把 x 和 y 相加的結果存到 z,很單純的加法。

    接著,return z 把 z 值回傳回來。換句話說,如果你需要用到這個運算回傳回來的結果,在呼叫函式的時候,記得在等號左邊把回傳值接起來。

    如下方程式碼:

    z = plus(3, 5) #運算結果 z = 8
    
    a1 = 10
    a2 = 12
    result = plus(a1, a2) #運算結果 result = 22

    注意到了嗎?我可以直接把值打在 plus 後的括號內,用 z 把回傳值 8 接起來;我也可以另外定義兩個變數,把變數傳進去。

    變數名稱 a1, a2 和接回傳值的變數名稱 result,不必遵循 plus 內寫的 x, y, z。函式內的x, y, z 只是區域變數,只在 def 內生效。

    Py 101209161710
    Py 101209161711

    三、讀取價量資料的 def,怎麼寫比較好?

    基本上先取一個好的函式名稱,例如 get_price 簡單易懂。再來是函式內容:讀取資料後,把每次讀取價量資料後的例行資料整理也寫進來。

    接著考量一下,我也不是每一次都要把所有股票的資料都讀取進來,太沒效率了!因此,我們應該把想要讀取的股票代碼清單當作參數傳入函式中。此外,我們也只想取用指定日期區間的資料,不需要回傳一整份資料,太笨重了!

    這樣的思路足夠清晰了!因此,依照這個思路,函式會長成這樣:

    import pandas as pd
    from datetime import datetime
    
    def get_price(
      symbol_list: list = [],
      start_date: datetime = datetime(1970,1,1),
      end_date: datetime = datetime(1970,1,1) 
    ): 
      price = {}
      for symbol in symbol_list:
        path = f“./price/{symbol}.csv”
        data = pd.read_csv(path, index_col=”time”, parse_dates=True)
        price[symbol] = data.loc[start_date, end_date]   
    
      return price

    這裡說明一下,函式 def 怎麼會變得如此讓人眼花撩亂。Python 對於換行、縮排有很嚴謹的定義,不過有一個規則是,在括號中間的換行視為同一行。

    因此,當我們同一行的字元數太多的時候,建議是以上方的例子來做分行:左括號後和右括號前不放程式碼,而括號中間的傳入參數都 tab 縮排一次。基本上一些常見的 IDE 開發工具所提供的排版插件,大致上也是會排成類似這個樣式,相當方便事後維護。

    這個例子裡,傳入參數後也多了一些東西。基本上它的格式是:

    傳入參數名稱: 參數型態 = 預設值

    以第一個傳入參數 symbol_list 來講,我指定它的型態是 list,預設值是一個空的 list。如此定義可以避免一些未預期的錯誤,嚴謹一些還是有好處的。

    再來解釋一下函式內在做什麼:這裡開一個空的字典(dictionary)叫做 price,預計存入每一個股票代碼作為索引,來對應到它的價量資料。

    因此,在 for 迴圈中,我們每一圈取出一個股票代碼,假設我們的價量資料 csv 存在 price 目錄下,csv 檔案名稱以股票代碼本身作為命名,我們透過 pd.read_csv 即可讀取相關資料。這裡各位讀者可以置換自己的檔案放置路徑。此外,關於 pd.read_csv 的參數細節,可以自行查詢官方文件,或是待之後有機會我們再來詳細解說。

    最後,把蒐集好的 price 字典回傳回來,就大功告成了。

    回想一下,我們前面說要打造一個一般化的函式,讓計算選股模型可以用、回測也可以用,這樣子確實是大功告成了!

    當然,實務上還有一些細節需要處理,例如檢查 csv 檔案是否存在,或是再稍微整理一下回傳資料的長相,才比較方便取用。

    四、關於 def 的其他建議

    到目前為止,各位讀者應該能做一些 def 的基本操作了。上面有提到的其他套件例如 pandas 和 datetime,如果不熟的話,建議先查閱相關官方文件,我們之後也會把這部分的教學補齊,敬請期待。

    但其實 def 要用得好還有一些小撇步:

    1. 這裡建議一個函式只負責做一件事,例如一個函式負責讀取整理價量資料,就不要再把回測的程式碼寫在這個函式裡。函式架構做得好,日後維護沒煩惱。
    2. 另外,名稱也要定義清楚,例如上方例子的 get_price 是指讀取本地端的價量資料,會不會和價量資料的爬蟲的函式命名存在衝突,需不需要再定義得更清楚?
    3. 關於函式命名格式,許多初學者依照自己的喜好命名,例如 getpricefromlocalfile,這是一個必須改掉的壞習慣。上方例子我們用的是 get_price 的蛇形命名,用底線分隔不同的單字。常見的還有駝峰式,之後有機會再來介紹一下。

    本系列會從 Python 基本的語法開始介紹,讓沒有程式背景的新手,也能開始用 Python 程式交易。如果你是進階的交易者,可以點擊連結觀看量化通其他 Python 進階文章,認識 爬蟲實用套件資產配置 等內容。

    建議可以照順序閱讀,從零開始學習 Python:


    加入LINE社群量化交易討論群」無壓力討論與分享!

    加入Discord 「量化交易討論群」即時獲取實用的資源!

    Write Together 101306261122
    Write Together 101306261121
    QP66
    QP66

    具備逾十年交易經驗,研究交易資產橫跨股票、債券、外匯、原物料,以及加密貨幣。現為量化避險基金交易員,亦曾任職於資金規模逾百億的避險基金,以及在區塊鏈企業擔任顧問一職。

    擅長從宏觀至微觀,由淺入深挖掘交易機會,並運用Python實現全自動化的投資組合管理。

    文章: 24

    發佈留言

    發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *