最近到Quantconnect練習寫策略,所以先做一些Quantconnect平台的分享,但是Quantopian也提供了一些很好用的工具,像是Alphalens,是一個分析交易信號表現的開源工具,之後有機會再回頭分享。
這邊介紹QuantConnect的Api設計流程,QC平台跟Quantopian一樣,有推薦的策略建構方式, 但要注意的是,這個設計流程是它們之後才用出來,這也導致社群與官方大部分的例子都不是照著這個架構來寫程式,但應該還是值得了解這個流程。
整個流程大概分成幾個部分,希望的設計思維是每個部份都是一個插件,可以隨意在不同的策略中不同套用。
這些區塊分別對應到建構一個策略所需要處理的方方面面,首先Universe Selection區塊控制交易池的選擇,Alpha Construction對應到交易信號的產生,也是我們需要花最多力氣的地方,Portfolio Construction對應如何將交易信號轉為資產配置,Execution控制如何處理交易單達到目標的資產配置,Risk model控制風險控制的功能。
除了Alpha Creation的部分之外,其外的部分都可以採用QC內建的功能,Quantconnect平台提供了GUI介面讓我們直接勾選,如下圖:
點選了 create an alpha stream,會跑出右邊的畫面,影片內會稍微解釋一下可選擇的內容。 但我們的重點是在Alpha Creation。
Alpha Creation
創建信號(alpha),需改寫一定格式的介面(IAlphaModel),主要要寫兩個方法,一個是Update(),一個是OnSecuritiesChanged()
# Algorithm framework model that produces insights
class MyAlphaModel:
def Update(self, algorithm, slice):
# Updates this alpha model with the latest data from the algorithm.
# This is called each time the algorithm receives data for subscribed securities
# Generate insights on the securities in the universe.
insights = []
return insights
def OnSecuritiesChanged(self, algorithm, changes):
# Handle security changes in from your universe model.
其中Update是用來在每個時間頻率更新交易信號,更新的交易信號需要遵守一個叫做Insights的類別格式。
class Insight:
self.Symbol # Symbol of this Insight
self.Type # Type of insight (price or volatility)
self.Direction # Insight Direction (down, flat or up)
self.Period # Insight period (TimeSpan)
self.Magnitude # Expected percent change (optional, double)
self.Confidence # Confidence in insight (optional, double)
self.Weight # Weighting of the insight (optional, double)
可以看到Insights的格式裡面可以存預測的股票代號、預測價格或是波動度、預測方向等等。
而OnSecuritiesChanged則是當資產被加到交易池時,會啟動OnSecuritiesChanged裡面的程式碼,這時候就可以拉一些歷史資料來計算這個資產的初始信號。
最後的程式碼
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel
class MOMAlphaModel(AlphaModel):
def __init__(self):
self.mom = []
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.AddedSecurities:
symbol = security.Symbol
self.mom.append({"symbol":symbol,
"indicator":algorithm.MOM(symbol,14,Resolution.Daily)})
def Update(self,algorithm, data):
ordered = sorted(self.mom, key=lambda kv:kv["indicator"].Current.Value,reverse=True)
return Insight.Group([Insight.Price(ordered[0]['symbol'],timedelta(1),InsightDirection.Up),
Insight.Price(ordered[1]['symbol'], timedelta(1), InsightDirection.Flat)])
class ParticleMultidimensionalShield(QCAlgorithm):
def Initialize(self):
# Set Start Date so that backtest has 5+ years of data
self.SetStartDate(2015, 5, 29)
self.SetEndDate(2015,12,31)
# 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
symbols = [Symbol.Create("SPY",SecurityType.Equity,Market.USA),
Symbol.Create("BND",SecurityType.Equity,Market.USA)]
self.SetBenchmark('SPY')
self.UniverseSettings.Resolution = Resolution.Daily
# 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())
self.SetUniverseSelection(ManualUniverseSelectionModel(symbols))