Support

Benchmark portfolio performance

Info
Info

This example builds upon concepts introduced in the Resampling data and End-of-day pricing and portfolio evaluation examples.

Overview

This example shows how to use the Historical client to benchmark a hypothetical portfolio. To do this, we will request daily open and close price data. We will then calculate the daily returns of our portfolio for one year and benchmark against a risk-free rate of 2.5% per year, and calculate the Sharpe ratio.

OHLCV-1d schema

We'll demonstrate this example using the OHLCV-1d schema. The OHLCV family of schemas contain the opening, high, low and closing prices as well as the aggregated volume of trades within a time interval. Since we are interested in end-of-day evaluation, we'll use an interval of one day, which is specified by the suffix -1d.

Many users will prefer to use the official daily settlement prices found in the statistics schema for this purpose.

Example

import databento as db

# A hypothetical portfolio mapping symbols to a quantity of shares
portfolio = {
    "DVN": 300,
    "MRO": 200,
    "FTNT": 100,
}

# Assume a risk-free rate of 2.5% per year
annual_benchmark_return = 0.025
daily_benchmark_return = ((1 + annual_benchmark_return) ** (1 / 252)) - 1

# First, create a historical client
client = db.Historical("$YOUR_API_KEY")

# Next, we will request the ohlcv-1d data
data = client.timeseries.get_range(
    dataset="XNAS.ITCH",
    start="2020-12-31T00:00:00",
    end="2022-01-01T00:00:00",
    symbols=list(portfolio.keys()),
    stype_in="raw_symbol",
    schema="ohlcv-1d",
)

# Then, convert the DBNStore to a pandas DataFrame
daily_data = data.to_df()

# Reshape the data with one column per symbol, propagating the previous price forward for dates without trades.
# Note: this does not account for corporate actions such as dividends or splits.
close_prices = daily_data.pivot(columns="symbol", values="close").fillna(method="ffill")
portfolio_value = sum(close_prices[sym] * qty for sym, qty in portfolio.items())

# Calculate some simple properties of the strategy
cost_basis = portfolio_value.iloc[0]
final_value = portfolio_value.iloc[-1]
total_return = (final_value - cost_basis) / cost_basis

# Calculate the arithmetic mean and standard deviation of the daily returns
daily_returns = portfolio_value.pct_change().dropna()
avg_return = daily_returns.mean()
std_return = daily_returns.std()

# Finally, we calculate the annualized ex-post Sharpe ratio
sharpe_ratio = (252**0.5) * (avg_return - daily_benchmark_return) / std_return

print(f"Cost basis: ${cost_basis:,.02f}")
print(f"Final portfolio value: ${final_value:,.02f}")
print(f"Total return: {total_return:.1%}")
print(f"Average of daily returns: {avg_return:.4%}")
print(f"Stdev of daily returns: {std_return:.4%}")
print(f"Annualized Sharpe ratio: {sharpe_ratio:.2f}")

Result

Cost basis: $20,989.00
Final portfolio value: $52,326.00
Total return: 149.3%
Average of daily returns: 0.3830%
Stdev of daily returns: 2.0029%
Annualized Sharpe ratio: 2.96