商品期貨策略 之 Python 精簡多品種 MACD 趨勢策略框架(註釋版)

Python 精簡多品種 MACD 趨勢策略框架(註釋版)

Python超級精簡的多品種MACD趨勢策略框架, 代碼超級精簡, 註釋超級詳細囉嗦。 >_<!
需要引用 python版CTP商品期貨交易類庫(支持2/3 測試版) 模板, 模板的代碼有JS語言版本的註釋(邏輯一致)。

  • 代碼附上:
'''
/*backtest
start: 2016-01-30        
end: 2016-12-30           
period: 1440
periodBase: 60
mode: 0                 
*/
'''
# 以上 爲設置的回測默認參數
# ------------ 
# 作者: Zero
# ------------

class Trader:                                   # 聲明一個 python 類 
    def __init__(self, q, symbol):              # Trader 類的構造函數, 參數 self(代表類實例化以後的對象) , q(引用 商品期貨交易類庫 模板 構造的 交易處理對象),   symbol (商品期貨合約代碼)
        self.q = q                              # 給 構造函數 構造的對象添加屬性q  ,並用 參數 q 賦值。 
        self.symbol = symbol                    # 同上, 給構造的對象添加symbol 屬性,並用 參數 symbol 賦值。
        self.position = 0                       # 添加 屬性 position 賦值 0    ,   該屬性是用於 記錄倉位數量。
        self.isPending = False                  # 添加 屬性 isPending 賦值 False     ,   該屬性用於標記 對象狀態,是否是掛起狀態。

    def onOpen(self, task, ret):                # 類成員函數 , 執行開倉完成後的 回調函數(即 在模擬多線程處理交易的對象q 完成當前任務後 回調該 onOpen 函數處理一些開倉後的工作。)
        if ret:                                 # 交易處理對象 q ,會在處理交易任務完成後 回調onOpen ,傳入2個參數 ,第一個 就是由形參task 接收,具體數據爲執行的交易任務數據, 第二個參數就是 交易完成的情況
                                                # 如果ret 爲有效數據(交易未成功 ret 爲 None),則處理  if 塊內代碼
            self.position = ret['position']['Amount'] * (1 if (ret['position']['Type'] == PD_LONG or ret['position']['Type'] == PD_LONG_YD) else -1)
                                                # 對調用該函數的對象的屬性position 賦值, ret['position']['Amount'] 爲交易後的持倉數量,根據 ret['position']['Type'] 持倉類型 等於 PD_LONG (持多倉)
                                                # 還是 PD_LONG_YD(持空倉)去選擇 ret['position']['Amount'] 乘 1 還是 -1 ,最後把持倉數量賦值 給 position ,(作用是通過 position 區分持多倉還是持空倉)
        Log(task["desc"], "Position:", self.position, ret)  # 打印多個項: q 執行的任務的數據 task 字典的 描述內容,賦值過的position , q 對象處理的交易的完成情況(當前持倉信息)
        self.isPending = False                  # 給 isPending 賦值 False 即代表 當前的 品種 交易邏輯 處於 非掛起狀態,可以接受任務。

    def onCover(self, task, ret):               # 平倉任務完成後要執行的回調函數, 參數同  onOpen 一致
        self.isPending = False                  # 設置 isPending 爲False 當前 品種的交易邏輯爲 非掛起狀態,可以接受任務。
        self.position = 0                       # 給記錄持倉的變量  position 賦值 爲0, 即沒有持倉。
        Log(task["desc"], ret)                  # 打印 交易處理對象 q 本次處理的任務 描述(desc),  完成處理的結果(ret)

    def onTick(self):                           # 主要交易邏輯 , MACD 策略核心。
        if self.isPending:                      # 如果 Trader類構造的當前邏輯對象的 isPending 屬性 爲True 則代表 目前有 交易任務 正在 交易處理對象q 隊列中執行。
            return                              # 交易邏輯處於掛起狀態,不做任何處理。
        ct = exchange.SetContractType(self.symbol)   # 根據構造函數 傳入的 symbol 賦值給 對象成員屬性symbol 傳入 API 函數 即:交易平臺對象exchange 的 SetContractType 函數, 用來設置操作的合約類型
        if not ct:                              # SetContractType 函數切換 交易合約代碼(symbol) 成功後會返回 該合約的詳細信息, 如果返回 None , 即 not ct 爲真, 則立即返回,等待下一輪。
            return

        r = exchange.GetRecords()               # 聲明 變量 r (用來儲存K線數據) , 調用 API 函數 GetRecords 獲取 設置後的該合約的 K線數據,賦值給 r 。
        if not r or len(r) < 35:                # 如果 r 爲 None 或者 r的長度小於35 (因爲要計算 MACD 指標,必須有足夠數量的K線bar,小於35 無法計算)
            return                              # 立即返回 ,下一輪處理。
        macd = TA.MACD(r)                       # 調用 API  指標函數  TA.MACD  ,傳入實參 r ,計算MACD 指標數據 ,並賦值給 變量 macd 。(TA.MACD 成功返回的數據是一個 二維數組 [dif, dea, 量柱]) 
                                                # 不明白 dif 、dea 的可以百度  MACD 指標
        diff = macd[0][-2] - macd[1][-2]        # 計算dif和dea的差值 (注意,此處計算使用的是計算出的倒數第二bar的dif、dea,因爲倒數第一bar 的K線是一直變動的,macd指標也是一直在變動,準確不變的是倒數第二bar)
        if abs(diff) > 0 and self.position == 0:     # 開倉,如果此刻 指標 (dif - dea)的絕對值 大於0 並且 沒有持倉(即: position 等於 0)
            self.isPending = True                    # 改變狀態 設置爲 掛起狀態,  isPending = True 
            self.q.pushTask(exchange, self.symbol, ("buy" if diff > 0 else "sell"), 1, self.onOpen)      # 調用交易處理對象q的成員函數pushTask發出開倉交易任務,參數:exchange交易平臺對象(傳入即可)
                                                     # self.symbol 合約代碼(構造時傳入), 根據diff 大於0 還是小於0 去設置 "buy" 或者 "sell", 1 這個參數指的是下單量1手, self.onOpen 傳入回調函數的引用 
        if abs(diff) > 0 and ((diff > 0 and self.position < 0) or (diff < 0 and self.position > 0)):     # 平倉,如果此刻指標(dif - dea)的絕對值 大於0 並且 and後的 條件任意一個成立執行if 塊內代碼,
                              # diff 大於0 並且 持空倉          或者     diff小於0 並且 持多倉 ,均爲 平倉條件。
            self.isPending = True               # 設置 爲掛起狀態。
            self.q.pushTask(exchange, self.symbol, ("closebuy" if self.position > 0 else "closesell"), 1, self.onCover)    # 發送平倉交易任務, 參數 同上發送開倉任務。

def main():                                     # 入口函數
    q = ext.NewTaskQueue()                      # 調用 python版商品期貨交易類庫 模板 的導出函數(即接口),  ext.NewTaskQueue  返回一個 構造的 交易處理對象。引用 給 變量 q 
    Log(_C(exchange.GetAccount))                # 啓動 調用 _C 容錯函數 ,傳入要容錯處理的  API : GetAccount 函數,  返回賬戶信息 由 Log 函數 輸出到日誌 , 顯示。
    tasks = []                                  # 聲明一個 空數組  tasks  。
    for symbol in ["MA701", "rb1701"]:          # 遍歷 數組 ["MA701", "rb1701"] 中的元素 , 每次循環 把其中的元素symbol 和 交易處理對象q 作爲 參數 傳遞給 Trader 類的構造函數 去構造交易邏輯對象。
        tasks.append(Trader(q, symbol))         # 構造好的  交易邏輯對象 壓入 tasks 數組。用以 循環遍歷執行處理。
    while True:                                 # 設置一個 while 死循環
        if exchange.IO("status"):               # 每次循環 調用  API 函數 IO ,傳入參數  "status" 去檢測 與 期貨公司 前置服務器 的連接狀態(CTP協議), 返回 True 即連接 交易服務器 和 行情服務器
            for t in tasks:                     # 遍歷 tasks 數組, 調用 構造 的 Trader 類的 對象 t的成員函數 onTick ,不斷檢測行情, 擇時開倉 、平倉。
                t.onTick()                      # 見 Trader 類 中的 onTick 函數
            q.poll()                            # 調用 交易處理對象 q 的成員函數 poll  去處理 q 對象內的隊列中的 交易任務。
        Sleep(1000)                         # 程序每次 while 循環 暫停一段時間 Sleep(1000) 即: 暫停1秒 (1000毫秒),以免訪問 API 過於 頻繁。

歡迎提出BUG ,建議。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章