Data Provenance¶
Provenance is AbaQuant’s metadata layer that explains where data came
from, when it was retrieved or constructed, how cache was used, and what
transformations were applied. This notebook shows .provenance attached to
derivative diagnostics, a manual rate curve, a portfolio allocator, a
backtest, a credit assessment, an integrated risk dashboard, and an
exportable report.
Sections:
Build one object from each domain
Inspect
.provenanceon eachMerge provenance from multiple sources
Setup¶
import abaquant
print(f"AbaQuant version: {abaquant.__version__}")
AbaQuant version: 1.0.0rc1
import numpy as np
import pandas as pd
from abaquant import RiskDashboard
from abaquant.credit import (
BalanceSheetInputs,
CashFlowInputs,
CreditAnalysisInputs,
IncomeStatementInputs,
calculate_credit_proxy_metrics,
)
from abaquant.derivatives.models import BlackScholesMertonModel
from abaquant.portfolio import PortfolioAllocator
from abaquant.rates import RateCurve
1. Build one object from each domain¶
def deterministic_returns() -> pd.DataFrame:
index = pd.date_range("2026-01-01", periods=24, freq="D")
step = np.arange(len(index), dtype=float)
return pd.DataFrame(
{
"NVDA": 0.0010 + np.sin(step / 3.0) * 0.0015,
"MSFT": 0.0007 + np.cos(step / 4.0) * 0.0010,
"AAPL": 0.0008 + np.sin(step / 5.0) * 0.0009,
},
index=index,
)
def deterministic_credit_assessment():
inputs = CreditAnalysisInputs(
balance_sheet=BalanceSheetInputs(
total_debt=120.0, total_equity=260.0, current_assets=190.0, inventory=30.0,
current_liabilities=85.0, cash_and_cash_equivalents=45.0, total_assets=640.0,
total_liabilities=300.0, retained_earnings=105.0, long_term_debt=100.0,
),
income_statement=IncomeStatementInputs(
revenue=520.0, gross_profit=270.0, ebit=85.0, ebitda=100.0,
interest_expense=10.0, net_income=60.0,
),
cash_flow_statement=CashFlowInputs(operating_cash_flow=82.0),
reporting_currency="USD",
reporting_period="FY2026",
)
return calculate_credit_proxy_metrics(inputs)
option = BlackScholesMertonModel(100.0, 105.0, 1.0, 0.04, 0.22)
diagnostics = option.diagnostics("call")
curve = RateCurve.from_rates({0.5: 0.04, 1.0: 0.045, 2.0: 0.05})
allocator = PortfolioAllocator(deterministic_returns(), annual_risk_free_rate=curve.zero_rate(1.0))
backtest = allocator.backtest(weights="equal_weight", rebalance="weekly", benchmark="equal_weight")
credit = deterministic_credit_assessment()
dashboard = RiskDashboard(
allocator,
credit_assessments={"NVDA": credit},
weights={"NVDA": 1 / 3, "MSFT": 1 / 3, "AAPL": 1 / 3},
backtest=backtest,
)
report = dashboard.report()
2. Inspect .provenance on each¶
Every object above carries .provenance — an immutable DataProvenance
record with provider, dataset, retrieval timestamp, cache status, and an
ordered list of transformation steps.
def summarize_provenance(label: str, provenance) -> None:
payload = provenance.as_dict()
print(
f"{label:24s}: provider={payload['provider']}, dataset={payload['dataset']}, "
f"reporting_date={payload['reporting_date']}, steps={len(payload['transformation_steps'])}"
)
summarize_provenance("option diagnostics", diagnostics.provenance)
summarize_provenance("manual rate curve", curve.provenance)
summarize_provenance("portfolio inputs", allocator.context.provenance)
summarize_provenance("backtest", backtest.provenance)
summarize_provenance("credit assessment", credit.provenance)
summarize_provenance("risk dashboard", dashboard.provenance)
summarize_provenance("dashboard report", report.provenance)
option diagnostics : provider=derived, dataset=derivative_diagnostics, reporting_date=None, steps=4
manual rate curve : provider=manual, dataset=rate_curve, reporting_date=latest, steps=2
portfolio inputs : provider=manual, dataset=portfolio_optimization_inputs, reporting_date=2026-01-24, steps=3
backtest : provider=derived, dataset=portfolio_backtest, reporting_date=2026-01-24, steps=5
credit assessment : provider=derived, dataset=credit_proxy_assessment, reporting_date=FY2026, steps=4
risk dashboard : provider=derived, dataset=risk_dashboard, reporting_date=None, steps=16
dashboard report : provider=derived, dataset=risk_dashboard_report, reporting_date=None, steps=17
diagnostics.provenance.as_dict()
{'provider': 'derived',
'dataset': 'derivative_diagnostics',
'retrieved_at_utc': '2026-08-25T04:16:49+00:00',
'cache_status': {},
'source_labels': ['BlackScholesMertonModel', 'call'],
'currency': None,
'reporting_date': None,
'transformation_steps': ['model pricing',
'intrinsic value decomposition',
'moneyness calculation',
'Greek selection'],
'request': {'model_class': 'BlackScholesMertonModel', 'option_type': 'call'},
'notes': []}
3. Merge provenance from multiple sources¶
merge_provenance() combines several provenance records into one derived
record — useful when one result depends on more than one upstream input
(e.g., a report built from a rate curve and a credit assessment).
from abaquant.core import merge_provenance
combined = merge_provenance([curve.provenance, credit.provenance])
combined.as_dict()
{'provider': 'derived',
'dataset': 'combined',
'retrieved_at_utc': '2026-08-25T04:16:49+00:00',
'cache_status': {},
'source_labels': ['MANUAL_0.5Y', 'MANUAL_1Y', 'MANUAL_2Y'],
'currency': None,
'reporting_date': None,
'transformation_steps': ['manual rate curve construction',
'maturity sorting',
'credit metric calculation',
'Altman Z-score calculation',
'Piotroski F-score calculation',
'synthetic credit proxy scoring'],
'request': {'source_provenance': [{'provider': 'manual',
'dataset': 'rate_curve',
'retrieved_at_utc': '2026-08-25T04:16:49+00:00',
'cache_status': {},
'source_labels': ['MANUAL_0.5Y', 'MANUAL_1Y', 'MANUAL_2Y'],
'currency': 'USD',
'reporting_date': 'latest',
'transformation_steps': ['manual rate curve construction',
'maturity sorting'],
'request': {'curve_date': 'latest'},
'notes': []},
{'provider': 'derived',
'dataset': 'credit_proxy_assessment',
'retrieved_at_utc': '2026-08-25T04:16:49+00:00',
'cache_status': {},
'source_labels': [],
'currency': 'USD',
'reporting_date': 'FY2026',
'transformation_steps': ['credit metric calculation',
'Altman Z-score calculation',
'Piotroski F-score calculation',
'synthetic credit proxy scoring'],
'request': {'input_provenance': {'provider': 'manual',
'dataset': 'credit_analysis_inputs',
'retrieved_at_utc': '2026-08-25T04:16:49+00:00',
'cache_status': {},
'source_labels': [],
'currency': 'USD',
'reporting_date': 'FY2026',
'transformation_steps': ['grouped credit input validation'],
'request': {},
'notes': []}},
'notes': []}]},
'notes': []}
Takeaway¶
For reproducible research, keep four things together: the result object,
its input parameters, its .provenance metadata, and the AbaQuant package
version. Provenance explains computational lineage — it does not
guarantee provider correctness, licensing compliance, or economic validity.
See docs/reference/provenance.rst.