| Overall Statistics |
|
Total Trades 1006 Average Win 0.70% Average Loss -0.99% Compounding Annual Return -82.941% Drawdown 83.800% Expectancy -0.347 Net Profit -83.024% Sharpe Ratio -2.67 Probabilistic Sharpe Ratio 0.000% Loss Rate 62% Win Rate 38% Profit-Loss Ratio 0.71 Alpha -0.709 Beta 0.231 Annual Standard Deviation 0.26 Annual Variance 0.068 Information Ratio -2.765 Tracking Error 0.274 Treynor Ratio -3.01 Total Fees $2208.32 Estimated Strategy Capacity $1100000.00 Lowest Capacity Asset CNTE SAI0XJNH6IJP |
#region imports
from AlgorithmImports import *
#endregion
class FadingTheGap(QCAlgorithm):
def Initialize(self):
#Backtesting parameters
self.SetStartDate(2017, 11, 1)
self.SetEndDate(2018, 11, 1)
self.SetCash(100000)
self.minimumDollar = 100
self.maximumDollar = 5000
self.topVolume = 100
# Universe Settings
self.UniverseSettings.Resolution = Resolution.Minute
self.AddUniverse(self.CoarseSelectionFunction)
# Securities list that is dynamically changes by the universe coarse filter
self.SecuritiesList = []
# Schedules
self.AddEquity("SPY", Resolution.Minute)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 1), self.OpeningBar)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.AfterMarketOpen("SPY", 45), self.ClosePositions)
def CoarseSelectionFunction(self, coarse):
# Sort equities by volume - highest volume first
sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)
# Filter equities by price
filteredByPrice = [c.Symbol for c in sortedByDollarVolume if c.Price > self.minimumDollar and c.Price < self.maximumDollar]
# Retrieve top equities
self.SecuritiesList = filteredByPrice[:self.topVolume]
return self.SecuritiesList
def OpeningBar(self):
securityDelta = {}
securitySTD = {}
securityDeviations = {}
# Go through all the top traded securities of the day
for symbol in self.SecuritiesList:
# Retrieve the previous closing price of those securities
history = self.History(symbol, 2, Resolution.Daily)
if history.empty: continue
previousClose = history.iloc[len(history.index) - 2]['close']
if previousClose <= 0: continue
# Retrieve the current day open of the same securities
if not self.Securities.ContainsKey(symbol): continue
if self.Securities[symbol] is None: continue
if self.Securities[symbol].Open <= 0: continue
currentOpen = self.Securities[symbol].Open
delta = 0
if currentOpen < previousClose:
# Record the delta if the open is less than the previous close in securityDelta dictionary
delta = currentOpen - previousClose
else: continue
# Retrieve the standard deviation of the security for the past 60 minutes
velocityHistory = self.History(symbol, 60, Resolution.Minute)
std = velocityHistory.loc[:, 'close'].std()
# Calculate and record the deviation if it is 3 deviations away
# 68% (1 sigma deviation)
# 95% (2 sigma deviation)
# 99.7% (3 sigma deviation)
# < -3 says that the drop is a .3% deviation
deviation = delta / std
if deviation < -3:
securityDeviations[symbol] = deviation
self.Log(deviation)
if len(securityDeviations) > 0:
# Sort any notable deviations by ascending order - strongest deviations first
sortedDeviations = sorted(securityDeviations.items(), key=lambda x: x[1])
# Retrieve the top two winners
topDeviations = sortedDeviations[:2]
# Invest 100% in the security with the biggest deviation
for security in topDeviations:
self.SetHoldings(security[0], 1)
def ClosePositions(self):
self.Liquidate()