| Overall Statistics |
|
Total Trades 373 Average Win 0.05% Average Loss -0.06% Compounding Annual Return 10.131% Drawdown 2.700% Expectancy 0.222 Net Profit 1.599% Sharpe Ratio 1.079 Loss Rate 33% Win Rate 67% Profit-Loss Ratio 0.83 Alpha 0.311 Beta -11.514 Annual Standard Deviation 0.088 Annual Variance 0.008 Information Ratio 0.864 Tracking Error 0.088 Treynor Ratio -0.008 Total Fees $373.00 |
from datetime import date
class LexxHelp(QCAlgorithm):
def Initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
self.SetStartDate(2013, 12, 31) #Set Start Date
self.SetEndDate(2014, 3, 1) #Set End Date
self.SetCash(100000) #Set Strategy Cash
#self.current_month = 12
# what resolution should the data *added* to the universe be?
self.UniverseSettings.Resolution = Resolution.Daily
# An indicator(or any rolling window) needs data(updates) to have a value, doesnt help due to monthly selection?
#self.UniverseSettings.MinimumTimeInUniverse = 10
#self.SetWarmUp(10+1)
# this add universe method accepts two parameters:
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
# Set dictionary of indicators
self.indicators = {}
# Set a list of the selected universe
self.universe = []
self.__numberOfSymbols = 50
self.__numberOfSymbolsFine = 10
#self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
def OnData(self, data):
# This updates the indicators at each data step(based on resolution)
for symbol in self.universe:
# is symbol iin Slice object? (do we even have data on this step for this asset)
if not data.ContainsKey(symbol):
continue
# 686 | 13:35:43: Runtime Error: Python.Runtime.PythonException: AttributeError : 'NoneType' object has no attribute 'Price'
if data[symbol] is None:
continue
# Does this slice have the price data we need at this moment?
if data[symbol].Price is None:
continue
# Either create a new indicator, or update one we already have
if symbol not in self.indicators:
self.indicators[symbol] = SymbolData(symbol, self)
self.indicators[symbol].update_value(self.Time, data[symbol].Price)
# We are warming up the indicators, cannot trade or other stuff
if self.IsWarmingUp: continue
# now you can use logic to trade, random example:
lowerband = self.indicators[symbol].bb_1.LowerBand.Current.Value
upperband = self.indicators[symbol].bb_2.UpperBand.Current.Value
# Log the symbol, price & indicators.
self.Log("{0}\tPrice : {1:0.2f}\tUPPERBAND : {2:0.2f}\tLOWERBAND : {3:0.2f}".format(symbol,
data[symbol].Price,
upperband,
lowerband))
# SLOW, but used to generate some trades.
#ma = self.History(symbol, 10).close.mean()
# current price: self.Securities[symbol].Price or data[symbol].Price
if self.Securities[symbol].Price < lowerband:
#self.SetHoldings(symbol, -0.99/float(len(self.universe)))
self.SetHoldings(symbol, 0.99/float(len(self.universe)))
elif self.Securities[symbol].Price > upperband:
#self.SetHoldings(symbol, 0.99/float(len(self.universe)))
self.Liquidate(symbol)
# sort the data by daily dollar volume and take the top 'NumberOfSymbols'
def CoarseSelectionFunction(self, coarse):
# Attempt to only try rebalance quarterly on the 1st day of the month
today = self.Time
self.Log("Day = {} Month = {}".format(today.day,today.month))
if today.day == 1 and (today.month == 1 or today.month == 4 or today.month == 7 or today.month == 10):
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
result = [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ]
self.universe = result
return self.universe
else:
return self.universe
# sort descending by daily dollar volume
#sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
# return the symbol objects of the top entries from our sorted collection
#return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ]
# sort the data by P/E ratio and take the top 'NumberOfSymbolsFine'
def FineSelectionFunction(self, fine):
# Attempt to only try rebalance quarterly on the 1st day of the month
today = self.Time
if today.day == 1 and (today.month == 1 or today.month == 4 or today.month == 7 or today.month == 10):
sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.FCFYield, reverse=True)
result = [ x.Symbol for x in sortedByPeRatio[:self.__numberOfSymbolsFine] ]
return self.universe
else:
return self.universe
# sort descending by P/E ratio
#sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.FCFYield, reverse=True)
# resulting symbols
#result = [ x.Symbol for x in sortedByPeRatio[:self.__numberOfSymbolsFine] ]
# Only update our universes on a new month? Not sure I like this hack, might work better in coarse to save more resources?
#if self.current_month != self.Time.month:
#self.Log(str(self.Time.month)+ " : " +str(len(result)))
# self.current_month = self.Time.month
# self.universe = result
# return result
#else:
#return self.universe
# this event fires whenever we have changes to our universe
def OnSecuritiesChanged(self, changes):
# liquidate removed securities
for security in changes.RemovedSecurities:
if security.Invested:
self.Liquidate(security.Symbol)
# clean up
del self.indicators[security.Symbol]
class SymbolData(object):
def __init__(self, symbol, context):
self.symbol = symbol
"""
I had to pass ATR from outside object to get it to work, could pass context and use any indica
var atr = ATR(Symbol symbol, int period, MovingAverageType type = null, Resolution resolution = null, Func`2[Data.IBaseData,Data.Market.IBaseDataBar] selector = null)
"""
#self.ema = context.EMA(symbol, self.window)
#self.indicator = context.BB(symbol, self.window)
self.bb_1 = context.BB(symbol,12,1, MovingAverageType.Simple, Resolution.Daily)
self.bb_2 = context.BB(symbol,10,1, MovingAverageType.Simple)
#self.indicator2 = context.BB(symbol,20,1,MovingAverageType.Simple,Resolution.Daily)
"""
Runtime Error: Python.Runtime.PythonException: NotSupportedException : AverageTrueRange does not support Update(DateTime, decimal) method overload. Use Update(IBaseDataBar) instead.
"""
#def update_bar(self, bar):
# self.atr.Update(bar)
def update_value(self, time, value):
self.bb_1.Update(time, value)
self.bb_2.Update(time, value)class CoarseFineFundamentalATRComboAlgorithm(QCAlgorithm):
def Initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
self.SetStartDate(2014, 1, 1) #Set Start Date
self.SetEndDate(2014, 6, 1) #Set End Date
self.SetCash(50000) #Set Strategy Cash
# what resolution should the data *added* to the universe be?
self.UniverseSettings.Resolution = Resolution.Daily
# An indicator(or any rolling window) needs data(updates) to have a value
self.atr_window = 20
self.UniverseSettings.MinimumTimeInUniverse = self.atr_window
self.SetWarmUp(self.atr_window)
# this add universe method accepts two parameters:
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
#self.flag1 = 1 # variable to control the monthly rebalance of coarse and fine selection function
# Set dictionary of indicators
self.indicators = {}
# Set a list of the selected universe
self.universe=[]
self.__numberOfSymbols = 200
self.__numberOfSymbolsFine = 10
self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
#self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY", 10), Action(self.CoarseSelectionFunction))
# sort the data by daily dollar volume and take the top 'NumberOfSymbols'
def CoarseSelectionFunction(self, coarse):
# sort descending by daily dollar volume
sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
# return the symbol objects of the top entries from our sorted collection
return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ]
# sort the data by P/E ratio and take the top 'NumberOfSymbolsFine'
def FineSelectionFunction(self, fine):
# sort descending by P/E ratio
sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.FCFYield, reverse=True)
# resulting symbols
self.universe = [ x.Symbol for x in sortedByPeRatio[:self.__numberOfSymbolsFine] ]
# take the top entries from our sorted collection
return self.universe
def OnData(self, data):
# Return before trying to run a loop on empty list
#if not self.universe:
# return
for symbol in self.universe:
# is symbol in Slice object? (do we even have data on this step for this asset)
#if not data.ContainsKey(symbol):
# return
#self.indicators[symbol].update_value(self.Time, data[symbol].Price)
#continue
if self.IsWarmingUp: continue
if data.ContainsKey(symbol):
self.indicators[symbol].update_value(self.Time, data[symbol].Price)
#else:
# continue
# new symbol? setup indicator object. Then update
if symbol not in self.indicators:
self.indicators[symbol] = SymbolData(symbol, self, self.atr_window)
# update by bar
#self.indicators[symbol].update_bar(data[symbol])
#update by value
#self.indicators[symbol].update_value(self.Time, data[symbol].Price)
# now you can use logic to trade, random example:
lowerband = self.indicators[symbol].get_atr()
upperband = self.indicators[symbol].get_atr2()
# Log the symbol, price & indicators
self.Log(str(symbol) + " : " + str(self.indicators[symbol].get_atr()))
self.Log("PRICE : {}".format(str(self.Securities[symbol].Price)))
self.Log("UPPERBAND : {}".format(str(lowerband)))
self.Log("LOWERBAND : {}".format(str(lowerband)))
# Trading Indicators
if lowerband != 0.0:
if not self.Portfolio[symbol].HoldStock:
if float(self.Securities[symbol].Price) < lowerband:
self.SetHoldings(symbol, 0.02)
elif self.Portfolio[symbol].HoldStock:
if float(self.Securities[symbol].Price) > upperband:
self.Liquidate(symbol)
# this event fires whenever we have changes to our universe
def OnSecuritiesChanged(self, changes):
# liquidate removed securities
for security in changes.RemovedSecurities:
if security.Invested:
self.Liquidate(security.Symbol)
# clean up
del self.indicators[security.Symbol]
class SymbolData(object):
def __init__(self, symbol, context, window):
self.symbol = symbol
"""
I had to pass ATR from outside object to get it to work, could pass context and use any indica
var atr = ATR(Symbol symbol, int period, MovingAverageType type = null, Resolution resolution = null, Func`2[Data.IBaseData,Data.Market.IBaseDataBar] selector = null)
"""
self.window = window
#self.indicator = context.EMA(symbol, self.window)
#self.indicator = context.BB(symbol, self.window)
self.indicator = context.BollingerBands(symbol,12,2,MovingAverageType.Simple)
self.indicator2 = context.BollingerBands(symbol,12,1,MovingAverageType.Simple)
self.atr = 0.0
"""
Runtime Error: Python.Runtime.PythonException: NotSupportedException : AverageTrueRange does not support Update(DateTime, decimal) method overload. Use Update(IBaseDataBar) instead.
"""
def update_bar(self, bar):
self.indicator.Update(bar)
def update_value(self, time, value):
self.indicator.Update(time, value)
def get_atr(self):
#return self.indicator.Current.Value
return self.indicator.LowerBand.Current.Value
def get_atr2(self):
#return self.indicator.Current.Value
return self.indicator2.UpperBand.Current.Value