Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Basic Charts

This page shows how to draw certain type of charts using roboquant.

It uses the YahooFeed to fetch historical data for several assets and then runs a simple EMA Crossover strategy. The results are visualized using the matplotlib library and the roboquant plotting capabilities.

We start with importing the required packages and setting some defaults.

import roboquant as rq
import matplotlib.pyplot as plt

# Setup some defaults for matplotlib
rq.set_light_style()

Then we load the prices of 8 very different assets to make the results a bit more interesting.

feed = rq.feeds.YahooFeed("MSFT", "F", "GLD", "GSG", "BND", "LQD", "IBIT", "VIXY")

Feed Chart

Price Chart

Plot a price and optionally the volume for one of the assets in the feed.

feed.plot("MSFT");
<Figure size 2400x1350 with 2 Axes>

Correlation Chart

Sometimes it is useful to inspect the correlation between the assets we want to trade in. There is a special plot method available that makes this visible.

feed.to_timeseries().plot_corr(fontsize=7);
<Figure size 2400x1350 with 2 Axes>

Backtest Charts

Once we run a backtest we can plot the account related charts and charts for any metrics we captured.

In the code snippet below the MetricsJournal.pnl() will capture metrics like the total equity at each step of the run.

strategy = rq.strategies.EMACrossover()
journal = rq.journals.MetricsJournal.pnl()
account = rq.run(feed, strategy, journal=journal)

Trade Chart

A trade chart is a price chart with added markers for when trades for that asset took place. A red up-pointing triangle for a SELL trade and a green down-pointing triangle for a BUY trade.

tf = rq.Timeframe.previous("365 days")
feed.plot("MSFT", timeframe=tf, trades=account.trades);
<Figure size 2400x1350 with 2 Axes>

Equity Chart

Equity is a good example of a metric that is usefull to capture during a run. It provides insights how the total equity is evolving during a run and shows also the volatility of our strategy when it comes to returns.

equity = journal.get_metrics("pnl/equity")
equity.plot();
<Figure size 2400x1350 with 1 Axes>

Allocation Chart

For larger portfolios it is useful to see which percentage is allocated to which asset.

Since assets can be denoted in different currencies, roboquant takes care of converting them to a single currency before plotting.

_, ax = plt.subplots(figsize=(3, 3))
account.plot_allocation(include_cash=True, ax = ax);
<Figure size 450x450 with 1 Axes>

Custom layouts

You can customize many of the plots by providing parameter arguments that will be passed on to matplotlib. You can also add some more lines to the plot.

equity = journal.get_metrics("pnl/equity")
ax = equity.plot(color="green")

ax.axhline(equity["pnl/equity"].mean(), linestyle="--")
equity.rolling(50).mean().plot(ax=ax, color="red")
ax.set_title("My Custom Title");
<Figure size 2400x1350 with 1 Axes>

Or you can take full control of the layout and create more advanced chart figures. Below we create a figure with 8 subplots. We also create a more informative title.

tf = rq.Timeframe.previous("365 days")
_, axs = plt.subplots(4, 2, figsize=(20, 30))

for ax, asset in zip(axs.flatten(), feed.assets()):
    pnl = account.pnl(asset)
    ax = feed.plot(asset, timeframe=tf, ax=ax, trades=account.trades)
    ax.set_title(f"{asset.symbol} ({pnl:,.0f})")
<Figure size 3000x4500 with 16 Axes>

Multi-run

Rather that running a single back test, we can also run multiple back tests and plot the results on the same chart. This is useful to see how the strategy performs over different timeframes or with different parameters.

One pattern we use to plot multiple runs on the same chart is:

ax = None
for i in some_range:
    ...
    ax = something.plot(ax=ax, ....)

The first time the plot method is invoked, ax is None and the plot method will create a new figure and axis. It will return this axis, so that next time the plot method is invoked it will plot on the existing axis.

Walk Forward

Perform a walk-forward over 4 equal timeframes and plot the equity curve of each run on the same chart.

timeframes = feed.timeframe().split(4)
ax = None

for timeframe in timeframes:
    strategy = rq.strategies.EMACrossover()
    journal = rq.journals.MetricsJournal.pnl()
    rq.run(feed, strategy, journal=journal, timeframe=timeframe)
    equity = journal.get_metrics("pnl/equity")
    ax = equity.plot(ax=ax, legend=False)
<Figure size 2400x1350 with 1 Axes>

Sample Random Timeframes

Run randomly sampled 1-year back tests and plot the equity curve for each run on the same chart. This provides visual insights how the equity curves are distributed.

timeframes = feed.timeframe().sample(100, "365 days")
ax = None

for timeframe in timeframes:
    strategy = rq.strategies.EMACrossover(5, 13)
    journal = rq.journals.MetricsJournal.pnl()
    rq.run(feed, strategy, journal=journal, timeframe=timeframe)

    # Skip the first 13 trading days since the strategy is still
    # warming up and the equity curve is flat during this period.
    equity = journal.get_metrics("pnl/equity")[13:]

    ax = equity.plot_without_timeline(ax=ax, linewidth=2, color="grey", alpha=0.2, legend=False)
<Figure size 2400x1350 with 1 Axes>