| Overall Statistics |
|
Total Orders 1704 Average Win 1.11% Average Loss -1.03% Compounding Annual Return 27.370% Drawdown 33.900% Expectancy 0.309 Start Equity 1000000 End Equity 14187747.05 Net Profit 1318.775% Sharpe Ratio 1.058 Sortino Ratio 1.094 Probabilistic Sharpe Ratio 66.393% Loss Rate 37% Win Rate 63% Profit-Loss Ratio 1.07 Alpha 0.109 Beta 0.807 Annual Standard Deviation 0.164 Annual Variance 0.027 Information Ratio 0.806 Tracking Error 0.116 Treynor Ratio 0.215 Total Fees $68342.15 Estimated Strategy Capacity $33000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 20.66% Drawdown Recovery 751 |
from AlgorithmImports import *
from datetime import timedelta, time
class BlackSwan_SPY_Algorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015, 1, 12)
self.SetCash(1_000_000)
self.SetWarmup(timedelta(30))
self.SetBenchmark("SPY")
self.spy = self.AddEquity("SPY", Resolution.Minute).Symbol
self.uvxy = self.AddEquity("UVXY", Resolution.Minute).Symbol
self.UniverseSettings.Resolution = Resolution.Hour
self.base_weight = 0.995
self.sniper_spy_weight = 0.045
self.sniper_uvxy_weight = 0.95
self.base_duration = timedelta(30)
self.SetAlpha(
BlackSwan_SPY(self.spy,self.uvxy,base_weight=self.base_weight,sniper_spy_weight=self.sniper_spy_weight,sniper_uvxy_weight=self.sniper_uvxy_weight,period_sma=2,resolution=Resolution.Hour))
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
self.SetExecution(ImmediateExecutionModel())
self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.AfterMarketOpen(self.spy, 1),self.EmitBaseInsight)
def EmitBaseInsight(self):
self.EmitInsights(
Insight.Price(self.spy,self.base_duration,InsightDirection.Up,None,None,"base",self.base_weight))
def OnData(self, data):
if self.IsWarmingUp:
return
if not self.Portfolio.Invested:
self.EmitBaseInsight()
class BlackSwan_SPY(AlphaModel):
def __init__(self,spy_symbol,uvxy_symbol,base_weight=0.995,sniper_spy_weight=0.045,sniper_uvxy_weight=0.95,period_sma=2,resolution=Resolution.Hour):
self.spy = spy_symbol
self.uvxy = uvxy_symbol
self.base_weight = base_weight
self.sniper_spy_weight = sniper_spy_weight
self.sniper_uvxy_weight = sniper_uvxy_weight
self.period_sma = period_sma
self.resolution = resolution
self.data = None
self.Name = "BlackSwan_SPY"
def Update(self, algorithm, data):
remaining = self._remaining_until_eod(algorithm)
if remaining <= timedelta(0):
return []
if self.data is None or not self.EmitNow(algorithm):
return []
price = algorithm.Securities[self.uvxy].Price
direction = InsightDirection.Up if self.data.VOL_UP(price) else InsightDirection.Flat
if direction == self.data.PreviousDirection:
return []
self.data.PreviousDirection = direction
if direction == InsightDirection.Up:
return [
Insight.Price(self.spy, remaining, InsightDirection.Up, None, None, "sniper", self.sniper_spy_weight),
Insight.Price(self.uvxy, remaining, InsightDirection.Up, None, None, "sniper", self.sniper_uvxy_weight),
]
return [
Insight.Price(self.uvxy, remaining, InsightDirection.Flat, None, None, "sniper", 0),
Insight.Price(self.spy, remaining, InsightDirection.Up, None, None, "base_restore", self.base_weight),
]
def OnSecuritiesChanged(self, algorithm, changes):
for security in changes.AddedSecurities:
if security.Symbol == self.uvxy:
self.data = SymbolData(algorithm, self.uvxy, self.period_sma, self.resolution)
def EmitNow(self, algorithm):
t = algorithm.Time.time()
return algorithm.Securities[self.uvxy].HasData and time(9, 56) <= t <= time(14, 4)
def _remaining_until_eod(self, algorithm):
close_dt = algorithm.Time.replace(hour=14, minute=15, second=0, microsecond=0)
return close_dt - algorithm.Time
class SymbolData:
def __init__(self, algorithm, symbol, period_sma, resolution):
self.PreviousDirection = InsightDirection.Flat
self.SMA = algorithm.SMA(symbol, period_sma, resolution)
def VOL_UP(self, price):
return self.SMA.IsReady and price < round(self.SMA.Current.Value * 1.09, 2)
OrderTypeKeys = [
'Market', 'Limit', 'StopMarket', 'StopLimit', 'MarketOnOpen',
'MarketOnClose', 'OptionExercise',
]
OrderTypeCodes = dict(zip(range(len(OrderTypeKeys)), OrderTypeKeys))