| Overall Statistics |
|
Total Orders 542 Average Win 5.64% Average Loss -3.02% Compounding Annual Return 21.479% Drawdown 53.100% Expectancy 0.210 Start Equity 100000 End Equity 228674.82 Net Profit 128.675% Sharpe Ratio 0.511 Sortino Ratio 0.608 Probabilistic Sharpe Ratio 11.831% Loss Rate 58% Win Rate 42% Profit-Loss Ratio 1.87 Alpha 0.154 Beta 0.687 Annual Standard Deviation 0.424 Annual Variance 0.18 Information Ratio 0.442 Tracking Error 0.285 Treynor Ratio 0.315 Total Fees $1702.48 Estimated Strategy Capacity $1700000000.00 Lowest Capacity Asset TSLA UNU3P8Y3WFAD Portfolio Turnover 34.46% |
#region imports
from AlgorithmImports import *
#endregion
# 0. INITIALIZE
from datetime import datetime
import decimal
import numpy as np
class DynamicBreakoutAlgorithm(QCAlgorithm):
# 1.0 INITIALIZATION
def Initialize(self):
self.SetStartDate(2021,1,15)
self.SetEndDate(2025,4,15)
self._cash = 100000
self.SetCash(self._cash)
# 2.1. UNIVERSE SELECTION MODEL
eq = self.AddEquity("TSLA", Resolution.Daily, Market.USA)
n_eq = self.AddEquity("SPY", Resolution.Daily, Market.USA)
self.syl = eq.Symbol
# 2.4. EXECUTION MODEL
self.Schedule.On(self.DateRules.EveryDay(self.syl), self.TimeRules.BeforeMarketClose(self.syl,1), Action(self.SetSignal))
# 3. PARAMETERS
# 3.1. LOOKBACK FOR BOLLINGERS, LIMITED BY MAXIMUM LOOKBACK AND MINIMUM LOOKBACK
self.numdays = 20
self.ceiling = 60
self.floor = 10
# 3.2. BREAKOUT POINTS
self.buypoint = None
self.sellpoint= None
self.longLiqPoint = None
self.shortLiqPoint = None
self.yesterdayclose= None
# 4. INFORMATION FOR BENCHMARKING AND PLOTTING
self.SetBenchmark(self.syl)
self.reference = self.History(self.syl, 1, Resolution.Daily)['close']
self._initialValue = self.reference.iloc[0]
# 5. DEFINITION OF AN INDICATOR
self.Bolband = self.BB(self.syl, self.numdays, 0.5, MovingAverageType.Exponential, Resolution.Daily)
def SetSignal(self):
# 2.2. ALPHA MODEL
close = self.History(self.syl, 31, Resolution.Daily)['close']
todayvol = np.std(close[1:31])
yesterdayvol = np.std(close[0:30])
deltavol = (todayvol - yesterdayvol) / todayvol
self.numdays = int(round(self.numdays * (1 + deltavol)))
if self.numdays > self.ceiling:
self.numdays = self.ceiling
elif self.numdays < self.floor:
self.numdays = self.floor
self.high = self.History(self.syl, self.numdays, Resolution.Daily)['high']
self.low = self.History(self.syl, self.numdays, Resolution.Daily)['low']
self.buypoint = max(self.high)
self.sellpoint = min(self.low)
historyclose = self.History(self.syl, self.numdays, Resolution.Daily)['close']
historyopen = self.History(self.syl, self.numdays, Resolution.Daily)['open']
self.longLiqPoint = np.mean(historyclose)
self.shortLiqPoint = np.mean(historyopen)
self.yesterdayclose = historyclose.iloc[-1]
if not self.Bolband.IsReady: return
# 2.3. PORTFOLIO CONSTRUCTION MODEL
holdings = self.Portfolio[self.syl].Quantity
if self.yesterdayclose > self.Bolband.UpperBand.Current.Value and self.Portfolio[self.syl].Price >= self.buypoint:
self.SetHoldings(self.syl, 2)
elif self.yesterdayclose < self.Bolband.LowerBand.Current.Value and self.Portfolio[self.syl].Price <= self.sellpoint:
self.SetHoldings(self.syl, -2)
else:
self.SetHoldings(self.syl, 1)
#2.4. RISK MANAGEMENT
if holdings > 0 and self.Portfolio[self.syl].Price <= self.longLiqPoint:
self.Liquidate(self.syl)
elif holdings < 0 and self.Portfolio[self.syl].Price >= self.shortLiqPoint:
self.Liquidate(self.syl)
# 2.5. LOG
self.Log(str(self.yesterdayclose)+(" # of days ")+(str(self.numdays)))
def OnData(self,data):
self.Plot("Equity Performance", "Equity", self.Portfolio[self.syl].Price)
self.Plot("Equity Performance", "Upper", self.Bolband.UpperBand.Current.Value)
self.Plot("Equity Performance", "Lower", self.Bolband.LowerBand.Current.Value)
self.Plot("Strategy Equity", "Benchmark", self._cash*self.Securities["TSLA"].Close/self._initialValue)