Portfolio Agent EvalsHarbor task suite · ETF analyze → backtest → rebalance
Portfolio Analytics & Exposure/pf-analyze-factor-regression

Factor exposures with Newey–West inference and an implied-vs-direct reconciliation

Regress ETF and household excess returns on FF5 + momentum with Newey–West standard errors, and reconcile weight-implied versus directly-estimated household exposures.

T3hardAnalyzemulti-metricready
Edit
readystatic
Agent budget
30 min
Verifier budget
3 min
Tier target
25–50% pass expected

instruction.md

What the agent sees (CONVENTIONS.md is appended automatically)

Factor exposures with HAC inference

Using /app/data/factors.csv (daily decimals: mkt_rf, smb, hml, rmw, cma, mom, rf), regress daily excess returns of each held ETF on the six factors with an intercept over the trailing 5 years (1260 observations, or the ETF's available subset if shorter). Report in /app/output/factors.json: betas, alpha annualised (x252), R-squared, and t-statistics using Newey–West HAC covariance with Bartlett kernel and lag 5, no small-sample correction.

Also regress the household (current weights, daily rebalanced) over the common window where every held ETF has data, and report household_implied_betas = sum of w_i x beta_i where each beta_i is re-estimated on that same common window, plus max_abs_diff between implied and direct household betas. State in why_differ whether the two should agree and why.

Verification

reward.json metrics · weights sum to 1.00

MetricWeightCheck
betas
0.35
abs 1e-6 per ETF.
alpha_r2
0.1
abs 1e-6.
nw_tstats
0.35
abs 1e-4.
implied_consistency
0.2
max_abs_diff < 1e-8 and why_differ states they agree by linearity on a common window.

Harbor scaffold

Generated from this record — task.toml, Dockerfile, verifier, oracle stub

schema_version = "1.4"

[task]
name = "portfolio-agent-evals/pf-analyze-factor-regression"
version = "1.0.0"
description = "Regress ETF and household excess returns on FF5 + momentum with Newey–West standard errors, and reconcile weight-implied versus directly-estimated household exposures."
keywords = ["etf", "portfolio", "analyze", "portfolio-analytics", "econometrics", "hac-inference", "self-checking"]

[metadata]
author_name = "portfolio-agent-evals"
difficulty = "hard"
category = "quant-finance"
tags = ["portfolio-analytics", "tier-3", "analyze", "multi-metric"]
theme = "Portfolio Analytics & Exposure"
tier = 3
reward_type = "multi-metric"

[agent]
timeout_sec = 1800.0

[verifier]
timeout_sec = 180.0

[environment]
# Offline by design: all data is synthetic and generated at build time.
network_mode = "none"
cpus = 2
memory_mb = 4096
storage_mb = 10240
build_timeout_sec = 900.0

Traps

Each must carry signal: a trap-blind solution must lose credit

  • One ETF launched inside the window: full-window betas use its subset, but the reconciliation must use the common window.
  • Factors are already excess; only ETF returns need rf subtracted.
  • Newey–West lag-5 Bartlett weights 1 - l/(L+1); no (T/(T-k)) correction.
  • Cash weight scales implied betas (cash has zero loadings).

Inputs

Fixtures mounted in the environment

  • /app/data/factors.csv
  • /app/data/prices/
    One held ETF launched inside the 5-year window.
  • /app/portfolio/holdings.csv, /app/portfolio/accounts.csv
  • /app/data/dividends.csv

Outputs

What the verifier reads from /app/output

  • /app/output/factors.json
    JSON
    Loadings, alphas, HAC t-stats and reconciliation.

Anti-gaming

Loadings are seed-generated with known truth; the verifier recomputes from data, not from truth.

Oracle notes

solution/solve.sh must score 1.0 on five seeds

numpy lstsq plus explicit HAC sandwich; statsmodels cov_type HAC with use_correction=False matches.

Reviews (0)

Design review before a task is marked ready

    Reviews are read-only in static export.
    Tier 3 · Expert25–50% pass expected. Created 2026-01-01, updated 2026-01-01.