Chat
Show my 10 worst drawdown days over the last 6 months and what drove each.
Classified this as a drawdown & contribution computation — routing to Code Mode rather than a native widget, since no single surface joins worst-day identification with per-date position attribution. Plan: pull 6 months of daily returns for Global Alpha Fund, isolate the 10 worst days, fetch position-level contributions for each date, then reconcile contributions against portfolio returns before answering.
code
import pandas as pd
from arcana import sdk

pf = sdk.portfolio("Global Alpha Fund")

# 1 — Daily portfolio returns, trailing 6 months
returns = pf.returns(start="2025-12-12", end="2026-06-12", freq="D")

# 2 — The 10 worst drawdown days in the window
worst = returns.sort_values("return_bps").head(10)

# 3 — Position-level contributions on those dates
contrib = pf.contributions(dates=worst.index)

# 4 — Reconcile: contributions must sum back to the portfolio return.
#     Tolerance: max(5 bps, 2% of |portfolio return|)  — hybrid rule
check = contrib.groupby("date")["contribution_bps"].sum().to_frame("sum_bps")
check["portfolio_bps"] = worst["return_bps"]
check["residual_bps"] = (check["sum_bps"] - check["portfolio_bps"]).abs()
check["tolerance_bps"] = pd.concat([
    pd.Series(5.0, index=check.index),
    0.02 * check["portfolio_bps"].abs(),
], axis=1).max(axis=1)
check["reconciled"] = check["residual_bps"] <= check["tolerance_bps"]

# 5 — Top 3 contributors per drawdown date
top3 = (contrib.sort_values(["date", "contribution_bps"])
               .groupby("date").head(3))

print(worst.join(check[["residual_bps", "reconciled"]]))
print(top3)
output

                
Data
Daily portfolio returns — Global Alpha Fund · 12 Dec 2025 → 12 Jun 2026
Position-level daily contributions · 10 dates · Arcana performance store (as of 12 Jun 2026, 06:00 ET)
Universe
Positions held on each drawdown date (87–94 names)
Method
Identified the 10 lowest daily portfolio returns in the trailing 6 months, pulled position-level contributions for each date, and reconciled contributions against the portfolio return.
Validation checks
Residual
Reconciled when |Σ position contributions − portfolio return| ≤ max(5 bps, 2% × |portfolio return|). Hybrid tolerance applied internally; constants owned by analytics. Residuals surface above; the formula stays in this disclosure (PRD §8).

Three episodes account for 8 of your 10 worst days: the early-March semis selloff (4 days, NVDA the largest detractor on each), the mid-April financials drawdown (3 days, JPM-led), and the mid-February mega-cap pullback. NVDA appears among the top contributors on 5 of the 10 dates — your single largest drawdown driver this half.

DatePortfolio returnTop contributors (bps)
04 Mar 2026−212 bpsNVDA −58 · MSFT −41 · AVGO −33
05 Mar 2026−187 bpsNVDA −49 · TSM −38 · AMD −27
17 Apr 2026−166 bpsJPM −44 · GS −31 · MS −24
13 Feb 2026−158 bpsAAPL −39 · AMZN −33 · META −29
03 Mar 2026−141 bpsNVDA −36 · MSFT −30 · GOOGL −22
16 Apr 2026−129 bpsJPM −33 · BAC −26 · C −19
12 Feb 2026−117 bpsAMZN −31 · META −25 · NFLX −18
07 Apr 2026−104 bpsXOM −28 · CVX −22 · COP −17
21 Jan 2026−98 bpsLLY −26 · UNH −21 · JNJ −15
12 Mar 2026−91 bpsNVDA −24 · AVGO −19 · QCOM −14
Caveat: Position-level contributions did not fully reconcile with portfolio-level returns for 2 of the 10 drawdown dates, so those rows should be treated as directional. Affected dates are flagged in the table (07 Apr · 12 Mar).
I couldn't complete this computation. Portfolio returns came back fine and the 10 worst days were identified, but the position-contribution request returned no data for 04–05 Mar 2026 even after retries — so the drawdowns can't be attributed reliably. No partial numbers; you can retry now, or rephrase to run without attribution.
Prototype · Code Mode states
Click the status chip to expand the computation receipt · View code opens the code box · keys 1–4 switch states