Plot BacktestΒΆ
visualize a backtest, including the value investent, asset price and any signals. see Backtest Example
Python source code: ../../../src/boatwright/Visualization/plot_backtest.py
from ..Backtest import Backtest
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime as dt
def plot_backtest(backtest:Backtest, figsize=(6.5,3)):
# dates = [dt.datetime.fromtimestamp(ts) for ts in backtest.data["timestamp"]]
dates = backtest.data["datetime"]
figs = []
axs = []
# AUM and buy/hold reference
try:
fig, ax = plt.subplots(figsize=figsize)
figs.append(fig)
axs.append(ax)
ax.plot(dates, backtest.data["aum"], label="aum", color="blue")
buy_and_hold = (backtest.broker.starting_aum / backtest.data["close"].iloc[0]) * backtest.data["close"]
ax.plot(dates, buy_and_hold, label="buy & hold", color="black")
ax.set_ylabel(backtest.broker.quote_symbol)
ax.legend(loc="best")
except:
pass
# Asset
try:
fig = plt.figure(figsize=figsize)
ax = fig.add_subplot(sharex=axs[0])
figs.append(fig)
axs.append(ax)
quote_fraction = backtest.data["quote_amount"] / backtest.data["aum"]
base_fraction = backtest.data["base_amount"] * backtest.data["close"] / backtest.data["aum"]
ax.plot(dates, quote_fraction, color="black", label=backtest.strategy.broker.quote_symbol)
ax.plot(dates, base_fraction, color="blue", label=backtest.strategy.symbol)
ax.set_ylabel("fraction")
ax.legend(loc="best")
except:
pass
# Close
try:
fig = plt.figure(figsize=figsize)
ax = fig.add_subplot(sharex=axs[0])
figs.append(fig)
axs.append(ax)
ax.plot(dates, backtest.data["close"], label=backtest.strategy.symbol, color="black")
ax.set_ylabel(f"close price [{backtest.broker.quote_symbol}]")
except:
pass
# buy / sells markers
try:
buy_orders = [o for o in backtest.broker.orders["FILLED"].values() if o.side=="BUY" and (o.type == "MARKET" or o.type == "LIMIT")]
buy_dates = [order.time_closed for order in buy_orders]
buy_prices = [order.info["avg_price"] for order in buy_orders]
ax.scatter(buy_dates, buy_prices, color="lime", marker="^", label="buy", zorder=5, alpha=0.75)
sell_orders = [o for o in backtest.broker.orders["FILLED"].values() if o.side=="SELL" and (o.type == "MARKET" or o.type == "LIMIT")]
sell_dates = [order.time_closed for order in sell_orders]
sell_prices = [order.info["avg_price"] for order in sell_orders]
ax.scatter(sell_dates, sell_prices, color="red", marker="v", label="sell", zorder=5, alpha=0.75)
ax.legend(loc="upper left")
except:
pass
# plot any additional signals as specified by the strategy
for key, info in backtest.strategy.plot_info().items():
while len(axs)-1 < info["ax_n"]:
fig = plt.figure(figsize=figsize)
ax = fig.add_subplot(sharex=axs[0])
figs.append(fig)
axs.append(ax)
try:
ax = axs[info["ax_n"]]
plot_kwargs = info
plot_kwargs.pop("ax_n")
if not "label" in plot_kwargs.keys(): plot_kwargs["label"] = key
ax.plot(dates, backtest.data[key], **plot_kwargs)
ax.legend(loc="upper left")
except:
pass
# make the dates axes pretty
for a in axs:
a.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d, %H:%M'))
for label in a.get_xticklabels(which='major'):
label.set(rotation=20, horizontalalignment='right')
for f in figs:
f.tight_layout()
return figs, axs