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

一、前言

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

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

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

    電子郵件

    有興趣的主題
    量化交易金融知識台灣股市國內期貨海外期貨虛擬貨幣

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

    還有什麼詢問的?

    好富投 1920x400
    好富投 978x258

    點我了解更多資訊


    二、函式 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:

      電子郵件

      有興趣的主題
      量化交易金融知識台灣股市國內期貨海外期貨虛擬貨幣

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

      還有什麼詢問的?


      量化通粉絲社群,一起討論程式交易!

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

      加入臉書社團「程式交易 Taiwan」即時獲取實用的資源!

      QP66
      QP66

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

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

      文章: 24

      發佈留言

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