| Overall Statistics |
|
Total Trades 3162 Average Win 0.12% Average Loss -0.02% Compounding Annual Return 14.226% Drawdown 17.600% Expectancy 5.714 Net Profit 364.239% Sharpe Ratio 1.569 Probabilistic Sharpe Ratio 96.006% Loss Rate 11% Win Rate 89% Profit-Loss Ratio 6.52 Alpha 0.094 Beta 0.187 Annual Standard Deviation 0.076 Annual Variance 0.006 Information Ratio -0.101 Tracking Error 0.144 Treynor Ratio 0.636 Total Fees $3162.50 Estimated Strategy Capacity $11000000.00 Lowest Capacity Asset TLT SGNKIKYGE9NP |
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect.Algorithm.Framework.Alphas import *
from Portfolio.EqualWeightingPortfolioConstructionModel import *
class AccumulativeInsightPortfolioConstructionModel(EqualWeightingPortfolioConstructionModel):
'''Provides an implementation of IPortfolioConstructionModel that allocates percent of account
to each insight, defaulting to 3%.
For insights of direction InsightDirection.Up, long targets are returned and
for insights of direction InsightDirection.Down, short targets are returned.
By default, no rebalancing shall be done.
Rules:
1. On active Up insight, increase position size by percent
2. On active Down insight, decrease position size by percent
3. On active Flat insight, move by percent towards 0
4. On expired insight, and no other active insight, emits a 0 target'''
def __init__(self, rebalance = None, portfolioBias = PortfolioBias.Long, percent = 0.04):
'''Initialize a new instance of AccumulativeInsightPortfolioConstructionModel
Args:
rebalance: Rebalancing parameter. If it is a timedelta, date rules or Resolution, it will be converted into a function.
If None will be ignored.
The function returns the next expected rebalance time for a given algorithm UTC DateTime.
The function returns null if unknown, in which case the function will be called again in the
next loop. Returning current time will trigger rebalance.
portfolioBias: Specifies the bias of the portfolio (Short, Long/Short, Long)
percent: percent of portfolio to allocate to each position'''
super().__init__(rebalance)
self.portfolioBias = portfolioBias
self.percent = abs(percent)
self.sign = lambda x: -1 if x < 0 else (1 if x > 0 else 0)
def DetermineTargetPercent(self, activeInsights):
'''Will determine the target percent for each insight
Args:
activeInsights: The active insights to generate a target for'''
percentPerSymbol = {}
insights = sorted(self.InsightCollection.GetActiveInsights(self.currentUtcTime), key=lambda insight: insight.GeneratedTimeUtc)
for insight in insights:
targetPercent = 0
if insight.Symbol in percentPerSymbol:
targetPercent = percentPerSymbol[insight.Symbol]
if insight.Direction == InsightDirection.Flat:
# We received a Flat
# if adding or subtracting will push past 0, then make it 0
if abs(targetPercent) < self.percent:
targetPercent = 0
else:
# otherwise, we flatten by percent
targetPercent += (-self.percent if targetPercent > 0 else self.percent)
targetPercent += self.percent * insight.Direction
# adjust to respect portfolio bias
if self.portfolioBias != PortfolioBias.Long and self.sign(targetPercent) != self.portfolioBias:
targetPercent = 0
percentPerSymbol[insight.Symbol] = targetPercent
return dict((insight, percentPerSymbol[insight.Symbol]) for insight in activeInsights)
def CreateTargets(self, algorithm, insights):
'''Create portfolio targets from the specified insights
Args:
algorithm: The algorithm instance
insights: The insights to create portfolio targets from
Returns:
An enumerable of portfolio targets to be sent to the execution model'''
self.currentUtcTime = algorithm.UtcTime
return super().CreateTargets(algorithm, insights)from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
import numpy as np
from itertools import groupby
class AlphaFiveUSTreasuries(QCAlgorithm):
def Initialize(self):
#1. Required: Five years of backtest history
self.SetStartDate(2005, 1, 1)
self.SetStartDate(2010, 1, 1)
#2. Required: Alpha Streams Models:
# self.SetBrokerageModel(BrokerageName.AlphaStreams)
#3. Required: Significant AUM Capacity
self.SetCash(25000)
#4. Required: Benchmark to SPY
self.AddEquity("SPY", Resolution.Daily)
self.SetBenchmark("SPY")
Benchmark = "QQQ"
#self.SetPortfolioConstruction(AccumulativeInsightPortfolioConstructionModel())
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
# self.SetExecution(TradeExecution()))
#Market Indicators
self.spy = "SPY"
self.iwm = "IWM"
self.mdy = "MDY"
self.qqq = "QQQ"
self.vix = "VIX"
self.assets = ["QQQ","TLT"]
#self.assets = ['QQQ', 'FDN', 'TLT', 'TLH']
self.symbols = {}
self.portfolioValue = RollingWindow[Decimal](500)
self.timeDelta = int(self.GetParameter("timeDelta"))
self.SetWarmup(500)
# Add Equity ------------------------------------------------
for i in range(len(self.assets)):
self.symbols[self.assets[i]] = self.AddEquity(self.assets[i],Resolution.Minute).Symbol
self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.AfterMarketOpen(Benchmark, 30), self.EveryDayAfterMarketOpen)
# Stock Selector
# self.AddUniverse(self.Coarse, self.Fine)
# self.activelyTrading = []
# self.weight = 0
# self.numberOfSymbolsCoarse = 500
# self.exposureToSector = 2
self.lastMonth = -1
def Coarse(self, coarse):
if self.Time.month == self.lastMonth:
return Universe.Unchanged
self.lastMonth = self.Time.month
allCoarse = [x for x in coarse if x.HasFundamentalData and x.Price > 1 and x.Volume > 1]
finalCoarse = sorted(allCoarse, key = lambda x: x.DollarVolume, reverse = True)
return [x.Symbol for x in finalCoarse][:self.numberOfSymbolsCoarse]
def Fine(self, fine):
filteredSymbols = []
sortedBySector = [x for x in fine]
for code, g in groupby(sortedBySector, lambda x: x.AssetClassification.MorningstarSectorCode):
for x in sorted(g, key = lambda x: x.ValuationRatios.PERatio, reverse = True)[:self.exposureToSector]:
filteredSymbols.append(x.Symbol)
return filteredSymbols[:2]
def EveryDayAfterMarketOpen(self):
if not self.Portfolio.Invested:
insights = []
for ticker, symbol in self.symbols.items():
insights.append( Insight.Price(symbol, timedelta(days=(int(self.GetParameter("timeDelta")))), InsightDirection.Up, 0.01, None, None, 1/len(self.symbols)) )
self.EmitInsights(insights)
else:
qb = self
#==============================
# Initialize instance of Random Forest Regressor
regressor = RandomForestRegressor(n_estimators=100, min_samples_split=5, random_state = 1990)
# Fetch history on our universe
df = qb.History(qb.Securities.Keys, 500, Resolution.Hour)
# Get train/test data
returns = df.unstack(level=1).close.transpose().pct_change().dropna()
X = returns
y = [x for x in qb.portfolioValue][-X.shape[0]:]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 1990)
# Fit regressor
regressor.fit(X_train, y_train)
# Get long-only predictions
weights = regressor.feature_importances_
symbols = returns.columns[np.where(weights)]
selected = zip(symbols, weights)
# ==============================
insights = []
for symbol, weight in selected:
insights.append( Insight.Price(symbol, timedelta(days=(int(self.GetParameter("timeDelta")))), InsightDirection.Up, 0.01, None, None, weight) )
self.EmitInsights(insights)
def OnData(self, data):
self.portfolioValue.Add(self.Portfolio.TotalPortfolioValue)
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Portfolio import PortfolioTarget
from QuantConnect.Algorithm.Framework.Risk import RiskManagementModel
class TrailingStopRiskManagementModel(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that limits the maximum possible loss
measured from the highest unrealized profit'''
def __init__(self, maximumDrawdownPercent = 0.04):
'''Initializes a new instance of the TrailingStopRiskManagementModel class
Args:
maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown'''
self.maximumDrawdownPercent = -abs(maximumDrawdownPercent)
self.trailingHighs = dict()
self.lastDay = -1
self.percentGain = 0.005
def ManageRisk(self, algorithm, targets):
'''Manages the algorithm's risk at each time step
Args:
algorithm: The algorithm instance
targets: The current portfolio targets to be assessed for risk'''
if algorithm.Time.day == self.lastDay:
return []
self.lastDay = algorithm.Time.day
riskAdjustedTargets = list()
for kvp in algorithm.Securities:
symbol = kvp.Key
security = kvp.Value
percentChange = algorithm.Securities[symbol].Holdings.UnrealizedProfitPercent / 0.01
# Add newly invested securities
if symbol not in self.trailingHighs:
self.trailingHighs[symbol] = security.Close # Set to average holding cost
continue
# Remove if not invested
if not security.Invested and symbol in self.trailingHighs:
try:
self.trailingHighs.pop(symbol, None)
except:
continue
continue
if percentChange.is_integer() and percentChange > 0:
self.trailingHighs[symbol] = security.Close
# Check for new highs and update - set to tradebar high
# if self.trailingHighs[symbol] < security.High:
# self.trailingHighs[symbol] = security.High
# continue
# Check for securities past the drawdown limit
securityHigh = self.trailingHighs[symbol]
if securityHigh == 0:
riskAdjustedTargets.append(PortfolioTarget(symbol, 0))
continue
drawdown = (security.Low / securityHigh) - 1
if drawdown < self.maximumDrawdownPercent:
# liquidate
riskAdjustedTargets.append(PortfolioTarget(symbol, 0))
return riskAdjustedTargets
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
from System import *
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Data import *
from QuantConnect.Data.Market import *
from QuantConnect.Orders import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Execution import *
from QuantConnect.Algorithm.Framework.Portfolio import *
import numpy as np
from datetime import datetime
class VolumeWeightedAveragePriceExecutionModel(ExecutionModel):
'''Execution model that submits orders while the current market price is more favorable that the current volume weighted average price.'''
def __init__(self):
'''Initializes a new instance of the VolumeWeightedAveragePriceExecutionModel class'''
self.targetsCollection = PortfolioTargetCollection()
self.symbolData = {}
# Gets or sets the maximum order quantity as a percentage of the current bar's volume.
# This defaults to 0.01m = 1%. For example, if the current bar's volume is 100,
# then the maximum order size would equal 1 share.
self.MaximumOrderQuantityPercentVolume = 0.02
def Execute(self, algorithm, targets):
'''Executes market orders if the standard deviation of price is more
than the configured number of deviations in the favorable direction.
Args:
algorithm: The algorithm instance
targets: The portfolio targets'''
# update the complete set of portfolio targets with the new targets
self.targetsCollection.AddRange(targets)
# for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call
if self.targetsCollection.Count > 0:
for target in self.targetsCollection.OrderByMarginImpact(algorithm):
symbol = target.Symbol
# calculate remaining quantity to be ordered
unorderedQuantity = OrderSizing.GetUnorderedQuantity(algorithm, target)
# fetch our symbol data containing our VWAP indicator
data = self.symbolData.get(symbol, None)
if data is None: return
# check order entry conditions
if self.PriceIsFavorable(data, unorderedQuantity):
# adjust order size to respect maximum order size based on a percentage of current volume
orderSize = OrderSizing.GetOrderSizeForPercentVolume(data.Security, self.MaximumOrderQuantityPercentVolume, unorderedQuantity)
if orderSize != 0:
algorithm.MarketOrder(symbol, orderSize)
self.targetsCollection.ClearFulfilled(algorithm)
def OnSecuritiesChanged(self, algorithm, changes):
'''Event fired each time the we add/remove securities from the data feed
Args:
algorithm: The algorithm instance that experienced the change in securities
changes: The security additions and removals from the algorithm'''
for removed in changes.RemovedSecurities:
# clean up removed security data
if removed.Symbol in self.symbolData:
if self.IsSafeToRemove(algorithm, removed.Symbol):
data = self.symbolData.pop(removed.Symbol)
algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator)
for added in changes.AddedSecurities:
if added.Symbol not in self.symbolData:
self.symbolData[added.Symbol] = SymbolData(algorithm, added)
def PriceIsFavorable(self, data, unorderedQuantity):
'''Determines if the current price is more than the configured
number of standard deviations away from the mean in the favorable direction.'''
if unorderedQuantity > 0:
if data.Security.BidPrice < data.VWAP:
return True
else:
if data.Security.AskPrice > data.VWAP:
return True
return False
def IsSafeToRemove(self, algorithm, symbol):
'''Determines if it's safe to remove the associated symbol data'''
# confirm the security isn't currently a member of any universe
return not any([kvp.Value.ContainsMember(symbol) for kvp in algorithm.UniverseManager])
class SymbolData:
def __init__(self, algorithm, security):
self.Security = security
self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, security.Resolution)
name = algorithm.CreateIndicatorName(security.Symbol, "VWAP", security.Resolution)
self.vwap = IntradayVwap(name)
algorithm.RegisterIndicator(security.Symbol, self.vwap, self.Consolidator)
@property
def VWAP(self):
return self.vwap.Value
class IntradayVwap:
'''Defines the canonical intraday VWAP indicator'''
def __init__(self, name):
self.Name = name
self.Value = 0.0
self.lastDate = datetime.min
self.sumOfVolume = 0.0
self.sumOfPriceTimesVolume = 0.0
@property
def IsReady(self):
return self.sumOfVolume > 0.0
def Update(self, input):
'''Computes the new VWAP'''
success, volume, averagePrice = self.GetVolumeAndAveragePrice(input)
if not success:
return self.IsReady
# reset vwap on daily boundaries
if self.lastDate != input.EndTime.date():
self.sumOfVolume = 0.0
self.sumOfPriceTimesVolume = 0.0
self.lastDate = input.EndTime.date()
# running totals for Σ PiVi / Σ Vi
self.sumOfVolume += volume
self.sumOfPriceTimesVolume += averagePrice * volume
if self.sumOfVolume == 0.0:
# if we have no trade volume then use the current price as VWAP
self.Value = input.Value
return self.IsReady
self.Value = self.sumOfPriceTimesVolume / self.sumOfVolume
return self.IsReady
def GetVolumeAndAveragePrice(self, input):
'''Determines the volume and price to be used for the current input in the VWAP computation'''
if type(input) is Tick:
if input.TickType == TickType.Trade:
return True, float(input.Quantity), float(input.LastPrice)
if type(input) is TradeBar:
if not input.IsFillForward:
averagePrice = float(input.High + input.Low + input.Close) / 3
return True, float(input.Volume), averagePrice
return False, 0.0, 0.0