Source code for fynance.plot.attribution
#!/usr/bin/env python3
# coding: utf-8
""" Per-asset attribution figures for a multi-asset book. """
from __future__ import annotations
# Built-in packages
from typing import Any
# Third-party packages
import numpy as np
__all__ = ['plot_contribution', 'plot_turnover']
def _as_book(arr: Any) -> np.ndarray:
""" Coerce to a 2-D ``(T, N)`` book (a 1-D series becomes a single column). """
a = np.asarray(arr, dtype=np.float64)
return a if a.ndim == 2 else a.reshape(a.shape[0], -1)
[docs]
def plot_contribution(asset_returns: Any, index: Any = None, ax: Any = None) -> Any:
""" Plot the cumulative per-asset gross contribution of a book.
``asset_returns`` is the per-asset gross return book ``(T, N)`` (each column
is one asset's contribution; together they sum to the book gross return). The
cumulative sum per asset shows how much each asset added to the book over
time. Returns the matplotlib ``Axes``.
"""
import matplotlib.pyplot as plt
cum = np.cumsum(_as_book(asset_returns), axis=0)
x = range(cum.shape[0]) if index is None else index
if ax is None:
_, ax = plt.subplots()
for i in range(cum.shape[1]):
ax.plot(x, cum[:, i], lw=1.2, label=f"asset {i}")
ax.set_title("Per-asset contribution (cumulative gross)")
ax.set_ylabel("Cumulative return")
ax.grid(alpha=0.3)
ax.legend(loc="best", fontsize=8, ncol=2)
return ax
[docs]
def plot_turnover(positions: Any, index: Any = None, ax: Any = None) -> Any:
""" Plot the per-asset turnover ``|Δ position|`` of a book.
``positions`` is the position book ``(T, N)``; the turnover at each step is
the absolute change in position per asset (the first step charges entry from
flat, matching the cost model). Returns the matplotlib ``Axes``.
"""
import matplotlib.pyplot as plt
pos = _as_book(positions)
turn = np.abs(np.diff(pos, axis=0, prepend=np.zeros((1, pos.shape[1]))))
x = range(turn.shape[0]) if index is None else index
if ax is None:
_, ax = plt.subplots()
for i in range(turn.shape[1]):
ax.plot(x, turn[:, i], lw=1.0, label=f"asset {i}")
ax.set_title("Per-asset turnover")
ax.set_ylabel("|Δ position|")
ax.grid(alpha=0.3)
ax.legend(loc="best", fontsize=8, ncol=2)
return ax