Indicators
Manual Indicators
Introduction
Manual indicators are indicators that don't automatically update from the underlying security data. Manual updates let you customize how you update the indicator and let you use the indicator in dynamic universes without causing your algorithm to slow down over time. It's not always necessary to create manual indicators though. If your algorithm only uses a static universe and you want to update the indicator with data from the security subscription, create an automatic indicator. Automatic indicators are easier to create and update.
Naming Convention
The class name to create a manual indicator is the indicator name spelled in pascal case. For example, to create a manual simple moving average indicator, use the SimpleMovingAverage
class.
Create Manual Indicators
To create manual indicators, instantiate an indicator with its constructor. To view all of the available indicators and their constructors, see Supported Indicators.
// Create an indicator private Delay _delay; _delay = new Delay(20); // Create a candlestick pattern private TwoCrows _twoCrows; _twoCrows = new TwoCrows();
# Create an indicator self.delay = Delay(20) # Create a candlestick pattern self.two_crows = TwoCrows()
You can track indicators by their name. To name a manual indicator, pass a string as the first argument to the constructor.
// Name an indicator _delay = new Delay("AAPL Past Price", 20); Log(_delay.Name); // Name a candlestick pattern _twoCrows = new TwoCrows("Two Crows Pattern"); Log(_twoCrows.Name);
# Name an indicator self.delay = Delay("AAPL Past Price", 20) self.Log(self.delay.Name) # Name a candlestick pattern self.two_crows = TwoCrows("Two Crows Pattern") self.Log(self.two_crows.Name)
If you don't name an indicator, it's given a default name. For example, the default name for a Delay
indicator is "Delay(period)".
Manual Updates
With manual updates, you control what data you use to update the indicator. For instance, you can use the 3:30 PM price in your daily moving average instead of the daily closing price or you can use the maximum temperature of the past 10 cloudy days.
To update an indicator, call the Update
method. The Update
method expects one of the following arguments:
- Time/decimal pair
IndicatorDataPoint
QuoteBar
TradeBar
- Custom data bar
To view what data type you should use to update an indicator, see Supported Indicators.
You can update indicators at any point in your algorithm, but the most common places are during the OnData
event handler or during a consolidation event handler.
def Initialize(self) -> None: self.symbol = self.AddEquity("SPY", Resolution.Daily).Symbol self.rsi = RelativeStrengthIndex(10, MovingAverageType.Simple) self.ad = AccumulationDistribution() self.consolidator = TradeBarConsolidator(timedelta(days=3)) # Update the AD indicator with the consolidated bar self.consolidator.DataConsolidated += (lambda _, bar : self.ad.Update(bar)) self.SubscriptionManager.AddConsolidator(self.symbol, self.consolidator) def OnData(self, slice: Slice) -> None: # Update the RSI indicator value with the new input close price every day if slice.Bars.ContainsKey(self.symbol): bar = slice.Bars[self.symbol] self.rsi.Update(bar.EndTime, bar.Close)
private Symbol _symbol; private RelativeStrengthIndex _rsi; private AccumulationDistribution _ad; public override void Initialize() { _symbol = AddEquity("SPY", Resolution.Daily).Symbol; _rsi = new RelativeStrengthIndex(10, MovingAverageType.Simple); _ad = new AccumulationDistribution(); var consolidator = new TradeBarConsolidator(TimeSpan.FromDays(3)); //Update the AD indicator with the consolidated bar consolidator.DataConsolidated += (_, bar) => _ad.Update(bar); SubscriptionManager.AddConsolidator(_symbol, consolidator); } public override void OnData(Slice slice) { // Update the RSI indicator value with the new input close price every day if (slice.Bars.ContainsKey(_symbol)) { var bar = slice.Bars[_symbol]; _rsi.Update(bar.EndTime, bar.Close); } }
Automatic Updates
With automatic updates, your indicators automatically update with the security data on a schedule you set. To configure automatic updates, create a consolidator and then call the RegisterIndicator
method. If your algorithm has a dynamic universe, save a reference to the consolidator so you can remove it when the universe removes the security. If you register an indicator for automatic updates, don't call the indicator's Update
method or else the indicator will receive double updates.
# Create a security subscription self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol # Create a manual indicator self.indicator = RelativeStrengthIndex(10, MovingAverageType.Simple) # Create a consolidator self.consolidator = TradeBarConsolidator(1) # Register the indicator to update with the consolidated data self.RegisterIndicator(self.symbol, self.indicator, self.consolidator)
// Create a security subscription _symbol = AddEquity("SPY", Resolution.Hour); // Create a manual indicator _indicator = new RelativeStrengthIndex(10, MovingAverageType.Simple); // Create a consolidator _consolidator = new TradeBarConsolidator(1); // Register the indicator to update with the consolidated data RegisterIndicator(_symbol, _indicator, _consolidator);
Data point indicators use only a single price data in their calculations. By default, those indicators use the closing price. For assets with TradeBar
data, that price is the TradeBar
close price. For assets with QuoteBar
data, that price is the mid-price of the bid closing price and the ask closing price. To create an indicator with the other fields like the Open
, High
, Low
, or Close
, provide a selector
argument to the RegisterIndicator
method.
self.RegisterIndicator(self.symbol, self.indicator, self.consolidator, Field.High)
RegisterIndicator(_symbol, _rsi, _consolidator, Field.High);
The Field
class has the following selector
properties:
To create a custom selector
, define a function that calculates the value.
RegisterIndicator(_symbol, _indicator, _consolidator, x => { var bar = x as IBaseDataBar; return (bar.Low + bar.High) / 2; });
Warm Up Indicators
Indicators use historical data to compute their value. Before you start trading with an indicator, warm it up. There are several ways to warm-up manual indicators.
Manual Indicator Warm-up
If you have access to the QCAlgorithm
object, you can manually warmup indicators with a history request.
private SimpleMovingAverage _sma; _sma = SimpleMovingAverage(20); var history = algorithm.History(_symbol, 20, Resolution.Daily); foreach (var bar in history) { sma.Update(bar.Time, bar.Close); }
self.sma = SimpleMovingAverage(20) history = algorithm.History(self.symbol, 20, Resolution.Daily) if not history.empty: for time, row in history.loc[self.symbol].iterrows(): self.sma.Update(time, row.close)
Warm-up Helper Method
If an indicator inherits the IIndicatorWarmUpPeriodProvider
class, you can warm it up with the WarmUpIndicator
method.
_sma = SimpleMovingAverage(20); algorithm.WarmUpIndicator(_symbol, _sma);
self.sma = SimpleMovingAverage(20) algorithm.WarmUpIndicator(self.symbol, self.sma)
To warm up the indicator with a resolution that's different from the security resolution, pass a resolution or TimeSpan
timedelta
argument to the WarmUpIndicator
method. The resolution you provide should be greater than or equal to the security resolution. For example, if the security has minute resolution data, you should warm up the indicator with data that spans at least one minute.
// Warm-up with daily bars algorithm.WarmUpIndicator(_symbol, _sma, Resolution.Daily); // Warm-up with 3-day bars algorithm.WarmUpIndicator(_symbol, _sma, TimeSpan.FromDays(3));
# Warm-up with daily bars algorithm.WarmUpIndicator(self.symbol, self.sma, Resolution.Daily) # Warm-up with 3-day bars algorithm.WarmUpIndicator(self.symbol, self.sma, timedelta(days=3))
The WarmUpIndicator
method uses the default Value
of the historical data to warm up the indicator. In most cases, this is the closing price. To warm up the indicator with a different data field, pass a Field
argument to the method.
algorithm.WarmUpIndicator(_symbol, _sma, Resolution.Daily, Field.High);
algorithm.WarmUpIndicator(self.symbol, self.sma, Resolution.Daily, Field.High)
Algorithm Warm-up
If you create indicators at the beginning of your algorithm, you can set an algorithm warm-up period to warm up the indicators. When you set an algorithm warm-up period, the engine pumps data in and automatically updates all the indicators from before the start date of the algorithm. To ensure that all the indicators are ready after the algorithm warm-up period, choose a lookback period that contains sufficient data.
private SimpleMovingAverage _sma; // In Initialize var symbol = AddEquity("SPY", Resolution.Daily).Symbol; _sma = SimpleMovingAverage(20); SetWarmUp(20); // In OnData
_sma.Update(data["SPY"]); // Delete this line if you registered the indicator for automatic updates if (IsWarmingUp)
{ return; }
# In Initialize self.symbol = self.AddEquity("SPY", Resolution.Daily).Symbol self.sma = SimpleMovingAverage(20) self.SetWarmUp(20) # In OnData
self.sma.Update(data[self.symbol]) # Delete this line if you registered the indicator for automatic updates if self.IsWarmingUp: return