Indicators
Plotting Indicators
Plot Update Events
To plot all of the values of some indicators, in the initialize
method, call the plot_indicator
method. The method plots each indicator value as the indicator updates. The method accepts up to four indicators.
symbol = self.add_equity("SPY") sma_short = self.sma(symbol, 10) sma_long = self.sma(symbol, 20) self.plot_indicator("<chartName>", sma_short, sma_long)
View Charts
The following table describes where you can access your charts, depending on how to deploy your algorithms:
Location | Algorithm Lab Algorithms | CLI Cloud Algorithms | CLI Local Algorithms |
---|---|---|---|
Backtest results page | ![]() | ![]() | |
Live results page | ![]() | ![]() | |
/backtests/read endpoint | ![]() | ![]() | |
/live/read endpoint | ![]() | ![]() | |
ReadBacktest method | ![]() | ![]() | |
ReadLiveAlgorithm method | ![]() | ![]() | |
Local JSON file in your <projectName> / backtests / <timestamp> or <projectName> / live / <timestamp> directory | ![]() | ![]() |
Chart Limits
Not all indicators share the same base type(T), so you may not be able to plot them together since some indicators require points while others require TradeBars
.
# Plot indicators that extend the "Indicator" type self.plot_indicators("All Indicator Values", sma, rsi) self.plot("Current Indicator Values", sma, rsi); # Plot indicators that extend the "TradeBarIndicator" type self.plot_indicators("All Indicator Values", atr, aroon) self.plot("Current Indicator Values", atr, aroon);
If your indicator plots are complex, call the plot
method with one indicator and plot its current.value
property. For more information about plotting, see Charting.
Examples
The following examples demonstrate some common practices for plotting indicators.
Example 1: SMA Ribbon
The following algorithm trades simple moving average (SMA) crossings, which involves five SMA indicators to form an SMA ribbon. To visualize the ribbon, it plots each indicator with a different color.
class PlottingIndicatorAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2019, 1, 1) self.set_end_date(2021, 7, 1) # Add SPY data to update indicators and trade. self._spy = self.add_equity("SPY", Resolution.DAILY).symbol # Create a chart to plot the ribbon. To better visualize the plot, use different colors per series. chart = Chart("Ribbon") chart.add_series(Series("Price", SeriesType.CANDLE, "$")) chart.add_series(Series("SMA10", SeriesType.LINE, "$", Color.VIOLET)) chart.add_series(Series("SMA20", SeriesType.LINE, "$", Color.BLUE)) chart.add_series(Series("SMA30", SeriesType.LINE, "$", Color.GREEN)) chart.add_series(Series("SMA40", SeriesType.LINE, "$", Color.YELLOW)) chart.add_series(Series("SMA50", SeriesType.LINE, "$", Color.RED)) # Create 5 SMA indicators to create the SMA ribbon. self._smas = {n: self._create_sma(n) for n in [10, 20, 30, 40, 50]} def _create_sma(self, n: int) -> SimpleMovingAverage: sma = self.sma(self._spy, n, Resolution.DAILY) # Plot the indicator value to create the ribbon when the indicator updates. sma.updated += lambda sender, point: self.plot("Ribbon", f"SMA{n}", point.value) # Warm up the indicator so it's ready to use immediately. self.warm_up_indicator(self._spy, sma) return sma def on_data(self, slice: Slice) -> None: bar = slice.bars.get(self._spy) if bar: # Plot the candlestick when you get the daily bar. self.plot("Ribbon", "Price", bar.open, bar.high, bar.low, bar.close) # Follow strong upward trend. if self._is_uptrend(bar.close, self._smas): self.set_holdings(self._spy, 1) # Follow strong downward trend. elif self._is_downtrend(bar.close, self._smas): self.set_holdings(self._spy, -1) # Liquidate positions if the trend is less deterministic. else: self.liquidate() def _is_uptrend(self, price: float, smas: List[SimpleMovingAverage]) -> bool: # Uptrend occurs when price is above all SMAs and shorter SMAs are above longer SMAs. smas_list = [x[1].current.value for x in sorted(smas.items(), key=lambda x: x[0])] return all([smas_list[i] < smas_list[i-1] for i in range(1, len(smas_list))]) and price > smas_list[0] def _is_downtrend(self, price: float, smas: List[SimpleMovingAverage]) -> bool: # Downtrend occurs when price is below all SMAs and shorter SMAs are below longer SMAs. smas_list = [x[1].current.value for x in sorted(smas.items(), key=lambda x: x[0])] return all([smas_list[i] > smas_list[i-1] for i in range(1, len(smas_list))]) and price < smas_list[0]