# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from AlgorithmImports import *
from QuantConnect.Algorithm.CSharp import *
###
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
### framework you can use for designing an algorithm.
###
###
###
###
class IndicatorSuiteAlgorithm(QCAlgorithm):
'''Demonstration algorithm of popular indicators and plotting them.'''
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.symbol = "SPY"
self.symbol2 = "GOOG"
self.customSymbol = "IBM"
self.price = None
self.SetStartDate(2013, 1, 1) #Set Start Date
self.SetEndDate(2014, 12, 31) #Set End Date
self.SetCash(25000) #Set Strategy Cash
# Find more symbols here: http://quantconnect.com/data
self.AddEquity(self.symbol, Resolution.Daily)
self.AddEquity(self.symbol2, Resolution.Daily)
self.AddData(CustomData, self.customSymbol, Resolution.Daily)
# Set up default Indicators, these indicators are defined on the Value property of incoming data (except ATR and AROON which use the full TradeBar object)
self.indicators = {
'BB' : self.BB(self.symbol, 20, 1, MovingAverageType.Simple, Resolution.Daily),
'RSI' : self.RSI(self.symbol, 14, MovingAverageType.Simple, Resolution.Daily),
'EMA' : self.EMA(self.symbol, 14, Resolution.Daily),
'SMA' : self.SMA(self.symbol, 14, Resolution.Daily),
'MACD' : self.MACD(self.symbol, 12, 26, 9, MovingAverageType.Simple, Resolution.Daily),
'MOM' : self.MOM(self.symbol, 20, Resolution.Daily),
'MOMP' : self.MOMP(self.symbol, 20, Resolution.Daily),
'STD' : self.STD(self.symbol, 20, Resolution.Daily),
# by default if the symbol is a tradebar type then it will be the min of the low property
'MIN' : self.MIN(self.symbol, 14, Resolution.Daily),
# by default if the symbol is a tradebar type then it will be the max of the high property
'MAX' : self.MAX(self.symbol, 14, Resolution.Daily),
'ATR' : self.ATR(self.symbol, 14, MovingAverageType.Simple, Resolution.Daily),
'AROON' : self.AROON(self.symbol, 20, Resolution.Daily),
'B' : self.B(self.symbol, self.symbol2, 14)
}
# Here we're going to define indicators using 'selector' functions. These 'selector' functions will define what data gets sent into the indicator
# These functions have a signature like the following: decimal Selector(BaseData baseData), and can be defined like: baseData => baseData.Value
# We'll define these 'selector' functions to select the Low value
#
# For more information on 'anonymous functions' see: http:#en.wikipedia.org/wiki/Anonymous_function
# https:#msdn.microsoft.com/en-us/library/bb397687.aspx
#
self.selectorIndicators = {
'BB' : self.BB(self.symbol, 20, 1, MovingAverageType.Simple, Resolution.Daily, Field.Low),
'RSI' :self.RSI(self.symbol, 14, MovingAverageType.Simple, Resolution.Daily, Field.Low),
'EMA' :self.EMA(self.symbol, 14, Resolution.Daily, Field.Low),
'SMA' :self.SMA(self.symbol, 14, Resolution.Daily, Field.Low),
'MACD' : self.MACD(self.symbol, 12, 26, 9, MovingAverageType.Simple, Resolution.Daily, Field.Low),
'MOM' : self.MOM(self.symbol, 20, Resolution.Daily, Field.Low),
'MOMP' : self.MOMP(self.symbol, 20, Resolution.Daily, Field.Low),
'STD' : self.STD(self.symbol, 20, Resolution.Daily, Field.Low),
'MIN' : self.MIN(self.symbol, 14, Resolution.Daily, Field.High),
'MAX' : self.MAX(self.symbol, 14, Resolution.Daily, Field.Low),
# ATR and AROON are special in that they accept a TradeBar instance instead of a decimal, we could easily project and/or transform the input TradeBar
# before it gets sent to the ATR/AROON indicator, here we use a function that will multiply the input trade bar by a factor of two
'ATR' : self.ATR(self.symbol, 14, MovingAverageType.Simple, Resolution.Daily, Func[IBaseData, IBaseDataBar](self.selector_double_TradeBar)),
'AROON' : self.AROON(self.symbol, 20, Resolution.Daily, Func[IBaseData, IBaseDataBar](self.selector_double_TradeBar))
}
# Custom Data Indicator:
self.rsiCustom = self.RSI(self.customSymbol, 14, MovingAverageType.Simple, Resolution.Daily)
self.minCustom = self.MIN(self.customSymbol, 14, Resolution.Daily)
self.maxCustom = self.MAX(self.customSymbol, 14, Resolution.Daily)
# in addition to defining indicators on a single security, you can all define 'composite' indicators.
# these are indicators that require multiple inputs. the most common of which is a ratio.
# suppose we seek the ratio of BTC to SPY, we could write the following:
spyClose = Identity(self.symbol)
ibmClose = Identity(self.customSymbol)
# this will create a new indicator whose value is IBM/SPY
self.ratio = IndicatorExtensions.Over(ibmClose, spyClose)
# we can also easily plot our indicators each time they update using th PlotIndicator function
self.PlotIndicator("Ratio", self.ratio)
# The following methods will add multiple charts to the algorithm output.
# Those chatrs names will be used later to plot different series in a particular chart.
# For more information on Lean Charting see: https://www.quantconnect.com/docs#Charting
Chart('BB')
Chart('STD')
Chart('ATR')
Chart('AROON')
Chart('MACD')
Chart('Averages')
# Here we make use of the Schelude method to update the plots once per day at market close.
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose(self.symbol), self.update_plots)
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 (#not data.Bars.ContainsKey(self.symbol) or
not self.indicators['BB'].IsReady or
not self.indicators['RSI'].IsReady):
return
self.price = data[self.symbol].Close
if not self.Portfolio.HoldStock:
quantity = int(self.Portfolio.Cash / self.price)
self.Order(self.symbol, quantity)
self.Debug('Purchased SPY on ' + self.Time.strftime('%Y-%m-%d'))
def update_plots(self):
if not self.indicators['BB'].IsReady or not self.indicators['STD'].IsReady:
return
# Plots can also be created just with this one line command.
self.Plot('RSI', self.indicators['RSI'])
# Custom data indicator
self.Plot('RSI-FB', self.rsiCustom)
# Here we make use of the chats decalred in the Initialize method, plotting multiple series
# in each chart.
self.Plot('STD', 'STD', self.indicators['STD'].Current.Value)
self.Plot('BB', 'Price', self.price)
self.Plot('BB', 'BollingerUpperBand', self.indicators['BB'].UpperBand.Current.Value)
self.Plot('BB', 'BollingerMiddleBand', self.indicators['BB'].MiddleBand.Current.Value)
self.Plot('BB', 'BollingerLowerBand', self.indicators['BB'].LowerBand.Current.Value)
self.Plot('AROON', 'Aroon', self.indicators['AROON'].Current.Value)
self.Plot('AROON', 'AroonUp', self.indicators['AROON'].AroonUp.Current.Value)
self.Plot('AROON', 'AroonDown', self.indicators['AROON'].AroonDown.Current.Value)
# The following Plot method calls are commented out because of the 10 series limit for backtests
#self.Plot('ATR', 'ATR', self.indicators['ATR'].Current.Value)
#self.Plot('ATR', 'ATRDoubleBar', self.selectorIndicators['ATR'].Current.Value)
#self.Plot('Averages', 'SMA', self.indicators['SMA'].Current.Value)
#self.Plot('Averages', 'EMA', self.indicators['EMA'].Current.Value)
#self.Plot('MOM', self.indicators['MOM'].Current.Value)
#self.Plot('MOMP', self.indicators['MOMP'].Current.Value)
#self.Plot('MACD', 'MACD', self.indicators['MACD'].Current.Value)
#self.Plot('MACD', 'MACDSignal', self.indicators['MACD'].Signal.Current.Value)
def selector_double_TradeBar(self, bar):
trade_bar = TradeBar()
trade_bar.Close = 2 * bar.Close
trade_bar.DataType = bar.DataType
trade_bar.High = 2 * bar.High
trade_bar.Low = 2 * bar.Low
trade_bar.Open = 2 * bar.Open
trade_bar.Symbol = bar.Symbol
trade_bar.Time = bar.Time
trade_bar.Value = 2 * bar.Value
trade_bar.Period = bar.Period
return trade_bar