Custom Charts for Visualizing Trades, Prices, and Moving Averages
Summary
This QuantConnect example demonstrates how to create and populate custom charts for an algorithm. It defines a trade chart with buy and sell markers alongside a price line, a separate chart for fast and slow moving averages, and a candlestick chart built from weekly consolidated data. The example shows how chart types and series can be organized and plotted during an algorithm’s lifecycle.
The trading rules are only illustrative: the algorithm buys SPY on certain calendar days when not invested and liquidates on others, rather than using the plotted moving averages to generate signals. It also plots daily prices and periodically samples the moving averages. The document is useful for learning chart construction and data visualization in QuantConnect, but it provides no performance results and does not evaluate whether its sample trading schedule is profitable.
Key ideas
- A chart can contain multiple series, including lines and scatter markers.\nSeparate charts can display trade activity and indicator values.\nWeekly data can be consolidated and plotted as candlesticks.\nThe sample trading schedule illustrates plotting and is not evidence of a validated strategy.
Tags
Full text
# CustomChartingAlgorithm
# CustomChartingAlgorithm
Algorithm demonstrating custom charting support in QuantConnect. The entire charting system of quantconnect is adaptable. You can adjust it to draw whatever you'd like. Charts can be stacked, or overlayed on each other. Series can be candles, lines or scatter plots. Even the default behaviours of QuantConnect can be overridden.
## Source (Apache-2.0)
```python
# 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 *
### <summary>
### Algorithm demonstrating custom charting support in QuantConnect.
### The entire charting system of quantconnect is adaptable. You can adjust it to draw whatever you'd like.
### Charts can be stacked, or overlayed on each other. Series can be candles, lines or scatter plots.
### Even the default behaviours of QuantConnect can be overridden.
### </summary>
### <meta name="tag" content="charting" />
### <meta name="tag" content="adding charts" />
### <meta name="tag" content="series types" />
### <meta name="tag" content="plotting indicators" />
class CustomChartingAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2016,1,1)
self.set_end_date(2017,1,1)
self.set_cash(100000)
spy = self.add_equity("SPY", Resolution.DAILY).symbol
# In your initialize method:
# Chart - Master Container for the Chart:
stock_plot = Chart("Trade Plot")
# On the Trade Plotter Chart we want 3 series: trades and price:
stock_plot.add_series(Series("Buy", SeriesType.SCATTER, 0))
stock_plot.add_series(Series("Sell", SeriesType.SCATTER, 0))
stock_plot.add_series(Series("Price", SeriesType.LINE, 0))
self.add_chart(stock_plot)
# On the Average Cross Chart we want 2 series, slow MA and fast MA
avg_cross = Chart("Average Cross")
avg_cross.add_series(Series("FastMA", SeriesType.LINE, 0))
avg_cross.add_series(Series("SlowMA", SeriesType.LINE, 0))
self.add_chart(avg_cross)
# There's support for candlestick charts built-in:
weekly_spy_plot = Chart("Weekly SPY")
spy_candlesticks = CandlestickSeries("SPY")
weekly_spy_plot.add_series(spy_candlesticks)
self.add_chart(weekly_spy_plot)
self.consolidate(spy, Calendar.WEEKLY, lambda bar: self.plot("Weekly SPY", "SPY", bar))
self.fast_ma = 0
self.slow_ma = 0
self.last_price = 0
self.resample = datetime.min
self.resample_period = (self.end_date - self.start_date) / 2000
def on_data(self, slice):
if slice["SPY"] is None: return
self.last_price = slice["SPY"].close
if self.fast_ma == 0: self.fast_ma = self.last_price
if self.slow_ma == 0: self.slow_ma = self.last_price
self.fast_ma = (0.01 * self.last_price) + (0.99 * self.fast_ma)
self.slow_ma = (0.001 * self.last_price) + (0.999 * self.slow_ma)
if self.time > self.resample:
self.resample = self.time + self.resample_period
self.plot("Average Cross", "FastMA", self.fast_ma)
self.plot("Average Cross", "SlowMA", self.slow_ma)
# On the 5th days when not invested buy:
if not self.portfolio.invested and self.time.day % 13 == 0:
self.order("SPY", (int)(self.portfolio.margin_remaining / self.last_price))
self.plot("Trade Plot", "Buy", self.last_price)
elif self.time.day % 21 == 0 and self.portfolio.invested:
self.plot("Trade Plot", "Sell", self.last_price)
self.liquidate()
def on_end_of_day(self, symbol):
#Log the end of day prices:
self.plot("Trade Plot", "Price", self.last_price)
```Shown in full with attribution under the source's licence. Licence: Apache-2.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.