Skip to main content

Finance — portfolio metrics & risk limits

The problem. A trading desk runs several portfolios, each holding positions in many instruments. Risk wants a tidy, queryable home for per-portfolio time-series — mark-to-market value, daily P&L, one-day Value-at-Risk — segmented so each desk sees only its own books, plus an event whenever a portfolio breaches a risk limit.

This scenario leans on datasets to partition data by desk, and on events as a durable record of limit breaches.

Set up demo data

New workspace? Run this once (Python) to create the desk's dataset and a portfolio mark-to-market series with a month of daily values. Safe to re-run.

import datahub_sdk, numpy as np, pandas as pd

client = datahub_sdk.DataHubClient.from_env()

desk_id = client.datasets.create([datahub_sdk.Dataset(external_id="desk_equities", name="Equities desk")])[0].id
client.timeseries.create([datahub_sdk.TimeSeries(external_id="portfolio_growth_mtm_usd",
name="Growth portfolio — MtM (USD)", unit="usd", value_type="numeric", data_set_id=desk_id)])
idx = pd.date_range(end=pd.Timestamp.now(tz="UTC"), periods=30, freq="1d")
client.timeseries.insert_from_lists(timestamps=idx,
values=1e7 + np.cumsum(np.random.normal(0, 5e4, 30)), ts="portfolio_growth_mtm_usd")

1. Partition by desk with a dataset

A dataset is the unit of grouping and access. Give each desk its own; everything the desk owns — series, positions — carries its data_set_id.

DataSetModel desk = new DataSetModel();
desk.setExternalId("desk_equities");
desk.setName("Equities desk");
var created = client.datasets().create(List.of(desk));
long deskId = created.getItems().iterator().next().getId();

2. Record per-portfolio metrics

Create a series per portfolio metric, tagged with the desk's data_set_id, then append a point at each mark. Values are exact decimals — pick a NUMERIC value type so currency amounts store faithfully.

var mtm = Timeseries.of("portfolio_growth_mtm_usd")
.name("Growth portfolio — mark-to-market (USD)")
.setValueType("numeric")
.setDataSetId(deskId);
mtm.setUnit("usd");
client.timeseries().create(mtm);

client.timeseries().ingest(Map.of(
"portfolio_growth_mtm_usd", List.of(
Datapoint.of(Instant.now(), "10428155.42")))); // exact decimal as text

3. Flag a risk-limit breach

When a portfolio's one-day VaR exceeds its mandate, record a var_limit_breach event. Because the event carries structured metadata, risk can reconstruct exactly which book breached, by how much, and when.

EventModel breach = new EventModel();
breach.setExternalId("var_limit_breach_growth_" + System.currentTimeMillis());
breach.setType("var_limit_breach");
breach.setStatus("open");
breach.setDataSetId(deskId);
breach.setMetadata(Map.of(
"portfolio", "portfolio_growth", "var_1d_usd", "512340", "limit_usd", "500000"));
breach.setEventTime(ZonedDateTime.now());
client.events().create(List.of(breach));
Exact money

Use the NUMERIC value type for monetary series — it stores exact decimals, unlike the floating-point types. See the Time-series reference for the full list of value types.

See the result

Chart the portfolio's mark-to-market over the month:

import matplotlib.pyplot as plt

rf = datahub_sdk.RetrieveFilter(ts="portfolio_growth_mtm_usd",
start=pd.Timestamp.now(tz="UTC") - pd.Timedelta(days=30), end=pd.Timestamp.now(tz="UTC"))
s = pd.Series({pd.to_datetime(p.timestamp): float(p.value)
for p in client.timeseries.retrieve_datapoints(rf)[0].get_datapoints()}).sort_index()
s.plot(title="Growth portfolio mark-to-market (USD)"); plt.show()

See also