| Overall Statistics |
|
Total Trades 17 Average Win 18.19% Average Loss -4.68% Compounding Annual Return 303.425% Drawdown 26.100% Expectancy 2.054 Net Profit 105.153% Sharpe Ratio 6.296 Probabilistic Sharpe Ratio 90.171% Loss Rate 38% Win Rate 62% Profit-Loss Ratio 3.89 Alpha 3.248 Beta 0.848 Annual Standard Deviation 0.588 Annual Variance 0.346 Information Ratio 5.558 Tracking Error 0.57 Treynor Ratio 4.367 Total Fees $37.26 |
class InsightWeightingPortfolioConstructionModel(EqualWeightingPortfolioConstructionModel):
'''Provides an implementation of IPortfolioConstructionModel that generates percent targets based on the
Insight.Weight. The target percent holdings of each Symbol is given by the Insight.Weight from the last
active Insight for that symbol.
For insights of direction InsightDirection.Up, long targets are returned and for insights of direction
InsightDirection.Down, short targets are returned.
If the sum of all the last active Insight per symbol is bigger than 1, it will factor down each target
percent holdings proportionally so the sum is 1.
It will ignore Insight that have no Insight.Weight value.'''
def __init__(self, rebalance = Resolution.Daily, portfolioBias = PortfolioBias.LongShort):
'''Initialize a new instance of InsightWeightingPortfolioConstructionModel
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)'''
super().__init__(rebalance, portfolioBias)
def ShouldCreateTargetForInsight(self, insight):
'''Method that will determine if the portfolio construction model should create a
target for this insight
Args:
insight: The insight to create a target for'''
# Ignore insights that don't have Weight value
return insight.Weight is not None
def DetermineTargetPercent(self, activeInsights):
'''Will determine the target percent for each insight
Args:
activeInsights: The active insights to generate a target for'''
result = {}
# We will adjust weights proportionally in case the sum is > 1 so it sums to 1.
weightSums = sum(self.GetValue(insight) for insight in activeInsights if self.RespectPortfolioBias(insight))
weightFactor = 1.0
if weightSums > 1:
weightFactor = 1 / weightSums
for insight in activeInsights:
result[insight] = (insight.Direction if self.RespectPortfolioBias(insight) else InsightDirection.Flat) * self.GetValue(insight) * weightFactor
return result
def GetValue(self, insight):
'''Method that will determine which member will be used to compute the weights and gets its value
Args:
insight: The insight to create a target for
Returns:
The value of the selected insight member'''
return insight.Weightclass TrailingStopRiskModel(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that limits the maximum possible loss
measured from the highest unrealized profit'''
def __init__(self, algorithm, maximumDrawdownPercent):
'''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.algorithm = algorithm
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'''
riskAdjustedTargets = list()
for kvp in algorithm.Securities:
symbol = kvp.Key
security = kvp.Value
# Remove if not invested
if not security.Invested:
self.trailingHighs.pop(symbol, None)
continue
# Add newly invested securities
if symbol not in self.trailingHighs:
self.trailingHighs[symbol] = security.Holdings.AveragePrice # Set to average holding cost
continue
# 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]
drawdown = (security.Low / securityHigh) - 1
if drawdown < self.maximumDrawdownPercent:
# liquidate
self.algorithm.Debug(f"{algorithm.Time}Past the drawdown limit... Liquidating")
riskAdjustedTargets.append(PortfolioTarget(symbol, 0))
return riskAdjustedTargetsclass ImmediateExecutionModel(ExecutionModel):
'''Provides an implementation of IExecutionModel that immediately submits market orders to achieve the desired portfolio targets'''
def __init__(self):
'''Initializes a new instance of the ImmediateExecutionModel class'''
self.targetsCollection = PortfolioTargetCollection()
def Execute(self, algorithm, targets):
'''Immediately submits orders for the specified portfolio targets.
Args:
algorithm: The algorithm instance
targets: The portfolio targets to be ordered'''
# for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call
self.targetsCollection.AddRange(targets)
if self.targetsCollection.Count > 0:
for target in self.targetsCollection.OrderByMarginImpact(algorithm):
# calculate remaining quantity to be ordered
quantity = OrderSizing.GetUnorderedQuantity(algorithm, target)
if quantity != 0:
algorithm.MarketOrder(target.Symbol, quantity)
self.targetsCollection.ClearFulfilled(algorithm)from CandleStickAlphaModel import PierceAlpha # Alpha Model
from ImmediateExecution import ImmediateExecutionModel # Execution Model
from TrailingStopModel import TrailingStopRiskModel # Risk Model
from InsightWeightingPortfolioConstructionModel import InsightWeightingPortfolioConstructionModel # Portfolio Construction
from datetime import timedelta
# https://www.quantconnect.com/forum/discussion/7684/creating-consolidated-data-from-universe-filters/p1
class DynamicNadionCoil(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2020, 6, 11) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
self.SetWarmUp(20)
# Manual Universe Selection
self.symbol = self.AddEquity("TSLA", Resolution.Minute, Market.USA).Symbol
self.consolidated = self.Consolidate(self.symbol, timedelta(days = 1), self.TenMinuteBarHandler)
self.number = 1
self.AddAlpha(PierceAlpha(self, symbol = self.symbol))
self.SetExecution(ImmediateExecutionModel())
self.SetPortfolioConstruction(InsightWeightingPortfolioConstructionModel())
self.SetRiskManagement(TrailingStopRiskModel(self, maximumDrawdownPercent = .3))
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
if self.IsWarmingUp:
self.Debug("Still warming up...")
return
def TenMinuteBarHandler(self, consolidated):
# self.Debug(f"{consolidated.EndTime} >> TenMinuteBarHandler >> {consolidated.Close}")
returnclass PierceAlpha(AlphaModel):
def __init__(self, algorithm, symbol):
## Add Quandl data for the Federal Interest Rate
self.symbol = symbol
self.algorithm = algorithm
self.pattern = self.algorithm.CandlestickPatterns.Piercing(self.symbol)
def Update(self, algorithm, slice):
self.insights = []
if self.pattern.IsReady:
## Check for all Symbols in current data Slice
if not slice.ContainsKey(self.symbol):
self.algorithm.Debug("There is no data")
elif slice is None:
self.algorithm.Debug("No Slice")
# self.algorithm.Debug("{} | Open: {} Close: {} " . format(self.symbol ,slice[self.symbol].Open, slice[self.symbol].Close) )
# self.algorithm.Log("self pattern is {} " . format(self.pattern))
elif self.pattern is None:
self.algorithm.Debug("pattern not yet defined. skipping")
elif self.pattern.Current.Value == 1:
self.algorithm.Debug("Time: {} pattern is 1 going long" . format(slice.Time) )
self.insights.append(Insight.Price(self.symbol, timedelta(days = 5), InsightDirection.Up, None, None, None, 1))
elif self.pattern.Current.Value == -1:
self.algorithm.Debug("pattern is -1 going short")
self.insights.append(Insight.Price(self.symbol, timedelta(days = 5), InsightDirection.Down))
else:
self.algorithm.Debug("no pierce recognized skipping")
return self.insights