Indicators
Plotting Indicators
Plot Update Events
To plot all of the values of some indicators, in the Initialize
initialize
method, call the PlotIndicator
plot_indicator
method. The method plots each indicator value as the indicator updates. The method accepts up to four indicators.
var symbol = AddEquity("SPY"); var smaShort = SMA(symbol, 10); var smaLong = SMA(symbol, 20); PlotIndicator("<chartName>", smaShort, smaLong)
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)
Plot Current Values
To plot the current value of indicators, call the Plot
plot
method. The method accepts up to four indicators.
// In Initialize var symbol = AddEquity("SPY"); var smaShort = SMA(symbol, 10); var smaLong = SMA(symbol, 20); // In OnData Plot("<chartName>", smaShort, smaLong)
# In Initialize symbol = self.add_equity("SPY") sma_short = self.sma(symbol, 10) sma_long = self.sma(symbol, 20) # In OnData self.plot("<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 PlotIndicators("All Indicator Values", sma, rsi); Plot("Current Indicator Values", sma, rsi); // Plot indicators that extend the "TradeBarIndicator" type PlotIndicators("All Indicator Values", atr, aroon); Plot("Current Indicator Values", atr, aroon);
# 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
plot
method with one indicator and plot its Current.Value
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.
public class PlottingIndicatorAlgorithm : QCAlgorithm { private Symbol _spy; private Dictionary<int, SimpleMovingAverage> _smas; public override void Initialize() { SetStartDate(2019, 1, 1); SetEndDate(2021, 7, 1); // Add SPY data to update indicators and trade. _spy = AddEquity("SPY", Resolution.Daily).Symbol; // Create a chart to plot the ribbon. To better visualize the plot, use different colors per series. var chart = new Chart("Ribbon"); chart.AddSeries(new Series("Price", SeriesType.Candle, "$")); chart.AddSeries(new Series("SMA10", SeriesType.Line, "$", Color.Violet)); chart.AddSeries(new Series("SMA20", SeriesType.Line, "$", Color.Blue)); chart.AddSeries(new Series("SMA30", SeriesType.Line, "$", Color.Green)); chart.AddSeries(new Series("SMA40", SeriesType.Line, "$", Color.Yellow)); chart.AddSeries(new Series("SMA50", SeriesType.Line, "$", Color.Red)); // Create 5 SMA indicators to create the SMA ribbon. _smas = new[]{10, 20, 30, 40, 50}.ToDictionary(k => k, v => { var sma = SMA(_spy, v, Resolution.Daily); // Plot the indicator value to create the ribbon when the indicator updates. sma.Updated += (_, point) => Plot("Ribbon", $"SMA{v}", point.Value); // Warm up the indicator so it's ready to use immediately. WarmUpIndicator(_spy, sma); return sma; }); } public override void OnData(Slice slice) { if (slice.Bars.TryGetValue(_spy, out var bar)) { // Plot the candlestick when you get the daily bar. Plot("Ribbon", "Price", bar.Open, bar.High, bar.Low, bar.Close); // Follow strong upward trend. if (IsUptrend(bar.Close, _smas)) { SetHoldings(_spy, 1m); } // Follow strong downward trend. else if (IsDowntrend(bar.Close, _smas)) { SetHoldings(_spy, -1m); } // Liquidate positions if the trend is less deterministic. else { Liquidate(); } } } public bool IsUptrend(decimal price, IDictionary<int, SimpleMovingAverage> smas) { // Uptrend occurs when price is above all SMAs and shorter SMAs are above longer SMAs. var smasList = smas.OrderBy(kvp => kvp.Key) .Select(kvp => kvp.Value) .ToList(); return Enumerable.Range(1, smasList.Count-1).All(i => smasList[i] < smasList[i-1]) && price > smasList[0]; } public bool IsDowntrend(decimal price, IDictionary<int, SimpleMovingAverage> smas) { // Downtrend occurs when price is below all SMAs and shorter SMAs are below longer SMAs. var smasList = smas.OrderBy(kvp => kvp.Key) .Select(kvp => kvp.Value) .ToList(); return Enumerable.Range(1, smasList.Count-1).All(i => smasList[i] > smasList[i-1]) && price < smasList[0]; } }
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]