初學者的Python金融分析日記 – QuantConnect爬分之旅 EP2 EP1補充與科技ETF動能策略(1)

目標

上支QC平台影片介紹了如何利用它們推薦的設計模式,QC平台稱這個設計模式為Alpha Framework。我們這次會延伸上次所使用的動能指標,來建立一個簡單的動能策略,這邊我們想要達到,(1)內建的動能指標能不能幫助我們提升投資效率,(2)之後我們能不能延伸這個想法來完善這個策略(3)藉由這個簡單的例子更熟悉QC的API。

動能指標

首先,讓我們先了解QC內建的動能指標是怎樣被定義的,由QC的API說明、以及原始碼可以判斷,假設是三天的動能指標(例如:mom = self.mom(Symbol(‘SPY’),3,Resolution.Daily),這每次呼叫mom.Current.Value會得到最新的價格減掉3天前的價格。某種程度在衡量價格上升的速度。 當然,這個動能指標是QC內建的動能指標,有很多能衡量價格上升速度的方式,像是短線壓長線,這些都可以當作是動能指標。

動能策略

所謂的動能策略是基於動能高就投資,動能低就不投資的想法,這個想法的背後是基於現在價格暴衝的資產,很有可能之後也暴衝的機會也比較大,可以想成強者更有可能持續強,弱者更有可能持續弱。

有不少的研究顯示,動能因子可以帶來更高的報酬,那為什麼動能指標有可能有用,以下提供幾個可能的解釋方式

解釋一:對資訊的反應慢

一般的非專業投資人可能對某些資訊的反應較慢,舉例來說,如果一個公司的收益大於預期,一般的非專業投資人可能沒辦法第一時間買到這個公司的資產,所以大型機構與專業投資人會第一時間買到這公司的股票,促使這個公司的動能上升,這時候非專業投資人再慢慢消化這個資訊,促使股票價格進一步上漲。

解釋二:心理因素

第二種解釋是從眾效應,當一個資產的動能增加,可能代表很多人買進這個資產,此時就可能產生從眾效應,更多人的選擇買入,進一步使得價格上升。

解釋三:承擔暴跌的風險

前兩個解釋都假設市場有某種的沒效率,像是資訊傳遞較慢,以及有些不理性的心理因素,但動能因子的較高報酬也有可能來自於投資人對於暴跌風險的考量,因為衝得較快的資產都常在市場不好的時候也跌得比較多,為了要補貼暴跌風險,動能較高的資產需要提供較高的報酬才能吸引投資人入場。

策略邏輯

這邊的想法很簡單,我們的交易池是QC提供的流動性高的科技ETF,使用小時的價格資料,每個禮拜調倉一次,計算最高動能的前8支ETF買進持有,計算從2015-05開始的回測表現。
細節會在下一支影片補充。

交易池

交易池是QC平台所提供的流動性科技ETF,可以從連結中看到裏面包含了

“XLK”,”QQQ”, “SOXX”, “IGV”,”VGT”, “QTEC”, “FDN”, “FXL”, “TECL”, “TECS”, “SOXL”, “SOXS”,”SKYY”, “SMH”,”KWEB””FTEC”

與買入持有的比較

下圖是買入持有的損益圖,可以看到用動能選ETF似乎真得帶給我們較多利潤。

上次影片的小補充

上次的影片大家可能會有一個疑問,我們寫得策略多久會調倉一次,也就是多久會觸發update裡面寫好的程式? 答案是QC平台的回測引擎是事件驅動的回測引擎,對於update方法來說,每次資料的更新就是一個新的事件,因此,更新的頻率會跟我們最高的資料頻率有關,因為我們上次將所有的資料設為日資料,所以會變成每天更新一次倉位。

回測表現

下一支影片在分析一下這個策略的表現。

程式細節

在下一支影片會介紹程式碼的一些細節以及為何要這樣設定。

程式碼

from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel

class MOMAlphaModel(AlphaModel):
    def __init__(self):
        self.mom = []
        self.week = 0
        self.hour = 11

    def OnSecuritiesChanged(self,algorithm,changes):
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            self.mom.append({
                "symbol":symbol,
                "indicator":algorithm.MOM(symbol,7,Resolution.Daily)
            })
            
    def Update(self,algorithm,data):
        
        if (algorithm.Time.hour != self.hour) or (algorithm.Time.weekday() != self.week):
            return []
        
            
      
        ordered = sorted(self.mom,key= lambda kv:kv['indicator'].Current.Value,reverse=True)
        selected = [asset['symbol'] for asset in ordered[:8]]               
       
        
        
        insights = []
        for asset in ordered:
            if asset['symbol'] in selected:
                insights.append(Insight.Price(asset['symbol'],timedelta(days=7),InsightDirection.Up))
            else:
                insights.append(Insight.Price(asset['symbol'],timedelta(days=7),InsightDirection.Flat))
        return insights



class MultidimensionalDynamicChamber(QCAlgorithm):

    def Initialize(self):
        # Set Start Date so that backtest has 5+ years of data
        self.SetStartDate(2015, 5, 1)
        # self.SetEndDate(2020,2,1)
        # No need to set End Date as the final submission will be tested
        # up until the review date

        # Set $1m Strategy Cash to trade significant AUM
        self.SetCash(1000000)

        # Add a relevant benchmark, with the default being SPY
        # self.AddEquity('SPY',Resolution.Daily)
        self.SetBenchmark('SPY')
        # Use the Alpha Streams Brokerage Model, developed in conjunction with
        # funds to model their actual fees, costs, etc.
        # Please do not add any additional reality modelling, such as Slippage, Fees, Buying Power, etc.
        self.SetBrokerageModel(AlphaStreamsBrokerageModel())

        self.SetExecution(ImmediateExecutionModel())

        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(rebalance =self.DateRules.Every(DayOfWeek.Monday)))
        
        self.SetAlpha(MOMAlphaModel())
        self.SetUniverseSelection(TechnologyETFUniverse())
        self.UniverseSettings.Resolution = Resolution.Hour
Share

發佈留言

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