Skip to content
My ETF Portfolio
BuildETFsStressModelHistoryAPI
Market closedNY --:--:--
My ETF Portfolio

Decision support, not investment advice. Outputs are model estimates from the inputs you provide — review taxes, risk, fees, and fund details before acting.

Build a portfolioETF explorerStress labMethodologyRun historyAPI accessAPI reference
Rates: FRED · Equity risk premium: Damodaran · Fund data refreshed on a research schedulemyetfportfolio.com
HomeBuildETFsModel
DOCS Developer documentation

API Reference

Complete REST API for the ETF portfolio optimizer. Tax-aware allocation, risk metrics, semantic ETF search, and factor analysis.

OpenAPI 3.1 specGet an API key
Guide
  1. Overview
  2. Quickstart
  3. Authentication
  4. Errors & limits
Endpoints
Portfolio Optimizer
  1. POSToptimize
  2. POSTsensitivity
  3. POSTgreeks
ETF Research & Discovery
  1. POSTsearch
  2. GET{ticker}
  3. GETetf-master
  4. GETetf-discovery
  5. GETetf-discovery-themes
  6. GETetf-universe-summary
  7. GETetf-provider-health
  8. GETetf-eligibility
  9. GETetf-eligibility-models
  10. GETsocial-search
Market Data
  1. GETcurve
  2. GETsnapshot-yields
  3. GETyield-comparison
  4. GETinstruments
  5. GETinstruments-6040
  6. GETtax-options
Risk & Stress
  1. POSTstress
  2. POSToptimize
Orchestration
  1. GETorchestrate
  2. POSToptimize
  3. GETvalidate-6040
Public
  1. POSTsignup
  2. GEThealth
Reference
  1. Schemas
  2. SDK examples
Base URL
https://myetfportfolio.com/v1
Version
1.0.0
Endpoints
26
Spec
OpenAPI 3.1

Quickstart

  1. 1

    Get an API key

    Join the waitlist at /api-access. We'll provision a key like etf_live_<32 hex chars>. Keys are per-tenant and can be rotated or revoked.

  2. 2

    Make your first call

    Send a POST to /portfolio/optimize with your investment constraints. The API returns optimized ETF weights, risk metrics, and tax analysis.

  3. 3

    Parse the response

    combined_weights is a {ticker: weight} map. equity_pct and bond_pct give the sleeve split. Risk metrics include volatility, Sortino ratio, and efficient frontier points.

  4. 4

    Explore research endpoints

    Use /portfolio/search for semantic ETF discovery, /instruments for the ETF universe, and /portfolio/etf-factor-scorecard/{ticker} for factor analysis.

Authentication

All protected endpoints require an X-API-Key header. Keys are per-tenant, formatted as etf_live_<32 hex chars>, and can be rotated or revoked at any time. Rate limiting is applied per tenant via a Redis token bucket; the X-Tenant-Id response header confirms which tenant was billed for the request.

Auth header example
curl https://myetfportfolio.com/v1/portfolio/optimize \
  -H "X-API-Key: etf_live_yourkeyhere" \
  -H "Content-Type: application/json"

Errors & rate limits

CodeMeaningHow to fix
401Invalid or missing X-API-Key header.Verify your API key is correct and hasn't been revoked.
422Request body failed Pydantic validation.Check field types and required fields against the schema.
429Rate limit exceeded (fair-use limit for your API key).Wait for the Retry-After period, then retry. No paid upgrade path is published today.
500Internal server error.Retry with exponential backoff. Contact support if persistent.

Rate limits

Fair-use limits apply per API key (typically a modest RPM). When exceeded, the API returns 429 with a Retry-After header (in seconds). There are no published paid tiers or upgrade SKUs — limits exist to keep the service healthy.

Decision support

Responses are portfolio ideas and scorecards, not advice or order routing. See disclaimer on AllocatorResponse and methodology at /how-we-model.

Portfolio Optimizer

Core optimization endpoints — send constraints, get optimized ETF allocations with risk and tax metrics.

POST/portfolio/optimizeAPI key

Optimize a portfolio

Core decision-support endpoint. Send constraints (capital, risk, tax rates, horizon) and receive a multi-ETF target allocation with after-tax metrics, parametric tail risk, FoF scorecard vs AOR-class funds, TLH notes, and illustrative stress. Always implements the multi-ETF book — FoF is scorecard only, never a substitute CALL.

BodyAllocatorRequest→returnsAllocatorResponse

Request
curl -X POST https://myetfportfolio.com/v1/portfolio/optimize \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "policy_id": "taxable_low_tax",
    "capital": 100000,
    "risk_tolerance": "MODERATE",
    "creativity": "balanced",
    "account_tax_type": "taxable",
    "federal": 0.24,
    "state": 0.05,
    "ltcg": 0.15,
    "investment_horizon_years": 10
  }'
Response
{
  "disclaimer": "Decision support / ideas — not investment advice. ...",
  "equity_pct": 60,
  "bond_pct": 40,
  "combined_weights": {
    "SCHB": 0.27, "SCHF": 0.15, "SCHV": 0.10, "SPLV": 0.08,
    "BND": 0.20, "BIV": 0.10, "BSV": 0.05, "VTIP": 0.05
  },
  "estimated_after_tax_return_pct": 6.85,
  "estimated_portfolio_volatility_pct": 12.4,
  "estimated_sortino_ratio": 0.82,
  "blended_expense_ratio": 0.004,
  "bond_weighted_duration": 6.2,
  "tax_savings_bps": 47.0,
  "efficient_frontier": [
    {"equity_pct": 0.10, "volatility": 3.2, "after_tax_return": 3.1},
    {"equity_pct": 0.60, "volatility": 12.4, "after_tax_return": 6.85}
  ],
  "benchmark_comparison": {
    "benchmark_symbol": "AOR",
    "recommendation": "custom_portfolio",
    "implementation_call": "custom_multi_etf",
    "fof_scorecard": "beats_simple_fof",
    "custom_portfolio_justified": true,
    "matched_risk_edge_bps": 42.0,
    "fee_edge_bps": 12.0
  },
  "tail_risk": {
    "cvar_method": "parametric_multivariate_student_t_df6_portfolio_risk_simulation",
    "var_95": 0.12,
    "max_drawdown_kind": "path_wealth_simulation"
  },
  "acceptance_test_results": {"tests_passed": true}
}
POST/allocator/sensitivityAPI key

Sensitivity analysis

Re-run the allocator with expected returns shocked ±10% and tax rates shocked (federal ±7pp, state ±2pp). Reports weight L1 distance and stability scores at both role level (the headline — did the asset allocation move?) and ticker level (which counts benign same-role ETF swaps), plus muni weight deltas.

BodyAllocatorRequest→returnsobject

Request
curl -X POST https://myetfportfolio.com/v1/allocator/sensitivity \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy_id":"taxable_low_tax","capital":100000,"risk_tolerance":"MODERATE","federal":0.24,"state":0.05}'
Response
{
  "shock_method": "scale_live_yields_or_snapshot_±10pct; tax federal±7pp and state±2pp",
  "shock_return_up": {"weights": {...}, "distance_from_base": {"l1_distance": 0.04}},
  "shock_return_down": {"weights": {...}, "distance_from_base": {"l1_distance": 0.03}},
  "shock_tax_high": {"federal": 0.31, "muni_weight": 0.12, "distance_from_base": {...}},
  "shock_tax_low": {"federal": 0.17, "muni_weight": 0.02, "distance_from_base": {...}},
  "stability_score": {"role_average_l1_distance": 0.036, "ticker_average_l1_distance": 0.156, "interpretation": "stable", "ticker_interpretation": "unstable"},
  "tax_stability_score": {"role_average_l1_distance": 0.02, "ticker_average_l1_distance": 0.08, "interpretation": "stable"}
}
POST/portfolio/greeksAPI key

Portfolio risk greeks

Compute risk-factor exposures, sleeve breakdown, concentration metrics, credit quality, distribution risk, and tax metrics for a given set of weights.

BodyPortfolioGreeksRequest→returnsPortfolioGreeks

Request
curl -X POST https://myetfportfolio.com/v1/portfolio/greeks \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "weights": {"SCHB": 0.35, "SCHF": 0.15, "BND": 0.30, "VTIP": 0.10, "SPLV": 0.10},
    "federal": 0.37, "state": 0.05
  }'
Response
{
  "risk_exposures": {"equity_beta": 0.82, "duration": 5.1, "credit_spread": 0.34},
  "sleeve_breakdown": {"equity": 0.60, "fixed_income": 0.40},
  "concentration": {"max_position": 0.35, "hhi": 0.091},
  "tax_metrics": {"effective_rate": 0.28, "after_tax_yield": 0.031},
  "suitability_flags": []
}

ETF Research & Discovery

Search, filter, and analyze the ETF universe. Semantic search, factor scorecards, eligibility, and discovery themes.

POST/portfolio/searchAPI key

Semantic ETF search

Search ETFs by natural-language query. Uses embeddings + pgvector cosine similarity to find ETFs whose provider description semantically matches. Results are re-ranked by semantic similarity and liquidity.

BodySemanticSearchRequest→returnsSemanticSearchResponse

Request
curl -X POST https://myetfportfolio.com/v1/portfolio/search \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "low cost broad market index", "limit": 5}'
Response
{
  "query": "low cost broad market index",
  "total": 5,
  "results": [
    {
      "ticker": "SCHB",
      "fund_name": "Schwab US Broad Market ETF",
      "semantic_similarity": 0.91,
      "liquidity_score": 0.98,
      "blended_score": 0.94,
      "expense_ratio": 0.0003,
      "aum": 32000000000,
      "asset_class": "equity"
    }
  ]
}
GET/portfolio/etf-factor-scorecard/{ticker}API key

ETF factor scorecard

Returns factor betas (Mkt-RF, SMB, HML, RMW, CMA, Mom), alpha, R-squared, volatility, and max drawdown for a given ETF ticker.

Parameters
NameTypeRequiredDefaultDescription
tickerstringRequired—ETF ticker symbol (e.g. SCHB)
lookback_yearsintegerOptional5Regression lookback period
Request
curl https://myetfportfolio.com/v1/portfolio/etf-factor-scorecard/SCHB?lookback_years=5 \
  -H "X-API-Key: YOUR_KEY"
Response
{
  "ticker": "SCHB",
  "status": "ok",
  "source": "fama_french_5_plus_mom",
  "lookback_years": 5,
  "observations": 260,
  "alpha_annualized": 0.0012,
  "r_squared": 0.98,
  "volatility_annualized": 0.16,
  "max_drawdown": -0.24,
  "factor_betas": {"Mkt-RF": 0.99, "SMB": -0.05, "HML": 0.02, "RMW": 0.03, "CMA": 0.01, "Mom": 0.01}
}
GET/portfolio/etf-masterAPI key

ETF master list

Browse the full ETF universe with filters for theme, account fit, review status, universe role, expense ratio, and liquidity.

Parameters
NameTypeRequiredDefaultDescription
themestringOptional—Filter by theme (e.g. core_equity, muni_bonds)
account_fitstringOptional—Filter by account type fit
review_statusstringOptional—Filter by review status
universe_rolestringOptional—Filter by universe role
max_expense_rationumberOptional—Maximum expense ratio filter
min_liquidity_scorenumberOptional—Minimum liquidity score
limitintegerOptional250Max results
offsetintegerOptional0Pagination offset
Request
curl "https://myetfportfolio.com/v1/portfolio/etf-master?theme=core_equity&limit=10" \
  -H "X-API-Key: YOUR_KEY"
Response
[
  {"symbol": "SCHB", "name": "Schwab US Broad Market ETF", "expense_ratio": 0.0003, "aum": 32000000000},
  {"symbol": "VTI", "name": "Vanguard Total Stock Market ETF", "expense_ratio": 0.0003, "aum": 41000000000}
]
GET/portfolio/etf-discoveryAPI key

ETF discovery candidates

List ETF discovery candidates filtered by minimum liquidity score and theme.

Parameters
NameTypeRequiredDefaultDescription
min_liquidity_scorenumberOptional0.0Minimum liquidity score threshold
themestringOptional—Filter by discovery theme
GET/portfolio/etf-discovery-themesAPI key

List discovery themes

Returns all available ETF discovery themes with candidate counts, seed counts, and metadata.

Request
curl https://myetfportfolio.com/v1/portfolio/etf-discovery-themes \
  -H "X-API-Key: YOUR_KEY"
Response
{
  "themes": [
    {"theme": "core_equity", "account_fit": "general", "candidate_count": 45, "innovation_score": 0.10},
    {"theme": "tax_aware_muni", "account_fit": "taxable", "candidate_count": 22, "innovation_score": 0.15}
  ]
}
GET/portfolio/etf-universe-summaryAPI key

ETF universe summary

High-level summary of the ETF universe: total count, breakdown by asset class, theme, and review status.

GET/portfolio/etf-provider-healthAPI key

ETF provider health

Health metrics for ETF providers (AUM trends, closure risk, fund family concentration).

GET/portfolio/etf-eligibilityAPI key

ETF model eligibility

List ETFs eligible for specific optimization models, with filters for model ID, eligibility status, theme, and account fit.

Parameters
NameTypeRequiredDefaultDescription
model_idstringOptional—Filter by model ID
eligiblebooleanOptional—Filter by eligibility
themestringOptional—Filter by theme
account_fitstringOptional—Filter by account fit
limitintegerOptional250Max results
offsetintegerOptional0Pagination offset
GET/portfolio/etf-eligibility-modelsAPI key

List eligibility models

Returns all available optimization model IDs with labels, descriptions, and default account types.

GET/portfolio/social-searchAPI key

Social media ETF search

Search social media (Reddit, YouTube) for ETF-related discussions and analysis by topic. Returns curated posts with relevance scoring.

Parameters
NameTypeRequiredDefaultDescription
topicstringRequired—Search topic (e.g. 'SCHB vs VTI', 'muni bond ETFs')
sourcesstringOptionalreddit,youtubeComma-separated list of sources to search
Request
curl "https://myetfportfolio.com/v1/portfolio/social-search?topic=SCHB%20vs%20VTI" \
  -H "X-API-Key: YOUR_KEY"
Response
{
  "topic": "SCHB vs VTI",
  "results": [
    {"source": "reddit", "title": "SCHB vs VTI - virtually identical?", "url": "...", "sentiment": "neutral"},
    {"source": "youtube", "title": "Best Total Market ETFs 2026", "url": "...", "sentiment": "positive"}
  ]
}

Market Data

Treasury curves, snapshot yields, yield comparisons, and instrument metadata.

GET/fred/curveAPI key

FRED Treasury curve

Fetch the current Treasury yield curve, SOFR rate, and equity indices from FRED. Requires FRED_API_KEY on the server.

Request
curl https://myetfportfolio.com/v1/fred/curve \
  -H "X-API-Key: YOUR_KEY"
Response
{
  "curve": {"1M": 0.052, "3M": 0.048, "6M": 0.045, "1Y": 0.042, "2Y": 0.041, "5Y": 0.040, "10Y": 0.041, "30Y": 0.043},
  "sofr": 0.053,
  "equity_indices": {"SPX": 5432.10, "NDX": 19234.50}
}
GET/snapshot-yieldsAPI key

Snapshot yields

Current snapshot of yields for all tracked instruments (money market, T-bills, muni, BOXX, etc.).

Request
curl https://myetfportfolio.com/v1/snapshot-yields \
  -H "X-API-Key: YOUR_KEY"
Response
{
  "yields": {"SGOV": 0.052, "USFR": 0.051, "BOXX": 0.048, "BND": 0.041},
  "date": "2026-07-06"
}
GET/yield-comparisonAPI key

After-tax yield comparison

Compare gross yield, after-tax yield, and tax-equivalent yield for key cash/fixed-income ETFs given a tax profile.

Parameters
NameTypeRequiredDefaultDescription
federalnumberOptional0.37Federal marginal rate
niitnumberOptional0.038Net investment income tax
statenumberOptional0.0399State marginal rate
muni_instatenumberOptional0.0In-state muni fraction
Request
curl "https://myetfportfolio.com/v1/yield-comparison?federal=0.37&state=0.05" \
  -H "X-API-Key: YOUR_KEY"
Response
[
  {"symbol": "SGOV", "type": "treasury", "gross": 5.20, "after_tax": 3.28, "tax_equiv": 5.20},
  {"symbol": "BOXX", "type": "etf_boxx", "gross": 4.80, "after_tax": 4.80, "tax_equiv": null}
]
GET/instrumentsAPI key

List instruments

List all instruments in the fixed-income universe with type, duration, true-liquidity flag, and default cap.

GET/portfolio/instruments-6040API key

List 60/40 instruments

List all ETFs in the 60/40 equity universe with full metadata: expense ratio, dividend yield, qualified %, TLH partner, AUM, bid-ask spread.

GET/tax-optionsAPI key

Tax configuration options

Returns available tax years, federal rates, NIIT rates, and state rate presets.

Risk & Stress

Stress testing and multi-account household asset-location optimization.

POST/stressAPI key

Stress test a portfolio

Run a parametric stress battery on a set of portfolio weights: parallel rate shocks (±100bp), curve twists (steepener/flattener), muni credit/liquidity gaps, and one 2008-style equity-crash-plus-Treasury-rally mark. Returns a mark-to-market pnl_pct (decimal, before income) and per-symbol detail for each scenario. These are illustrative parametric shocks, not historical replays.

BodyStressRequest→returnsStressResponse

Request
curl -X POST https://myetfportfolio.com/v1/stress \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "weights": {"SCHB": 0.35, "SCHF": 0.15, "BND": 0.30, "VTIP": 0.10, "SPLV": 0.10}
  }'
Response
{
  "shocks": [
    {"label": "Parallel +100bp", "pnl_pct": -0.031, "detail": {"BND": -0.062, "VTIP": -0.021}},
    {"label": "Parallel -100bp", "pnl_pct": 0.031, "detail": {"BND": 0.062, "VTIP": 0.021}},
    {"label": "Steepener (long +100bp)", "pnl_pct": -0.018, "detail": {"BND": -0.036}},
    {"label": "Flattener (short +100bp)", "pnl_pct": -0.009, "detail": {"BSV": -0.018}},
    {"label": "Muni +50bp / 2% NAV gap", "pnl_pct": -0.004, "detail": {"MEAR": -0.02}},
    {"label": "Muni +150bp / 5% NAV gap", "pnl_pct": -0.011, "detail": {"MEAR": -0.05}},
    {"label": "2008-style crisis (equity crash + Treasury rally)", "pnl_pct": -0.184, "detail": {"SCHB": -0.37, "BND": 0.05}}
  ]
}
POST/household/optimizeAPI key

Multi-account household optimization

Two-stage household asset-location optimization. Stage 1 runs the standard allocator on household total capital to determine target weights. Stage 2 assigns assets across account wrappers (taxable, IRA, Roth, 401k) by after-tax priority to maximize tax efficiency. Returns per-wrapper allocations and location benefit in basis points.

BodyHouseholdAllocatorRequest→returnsHouseholdAllocatorResponse

Request
curl -X POST https://myetfportfolio.com/v1/household/optimize \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "wrappers": [
      {"account_tax_treatment": "taxable", "capital": 150000},
      {"account_tax_treatment": "ira", "capital": 200000},
      {"account_tax_treatment": "roth", "capital": 100000}
    ],
    "policy_id": "taxable_low_tax",
    "risk_tolerance": "MODERATE",
    "federal": 0.37,
    "state": 0.05,
    "ltcg": 0.20
  }'
Response
{
  "household_weights": {"SCHB": 0.27, "SCHF": 0.15, "BND": 0.20, "SPLV": 0.08, "VTIP": 0.05},
  "per_wrapper": [
    {"wrapper": "taxable", "weights": {"SCHB": 0.30, "SPLV": 0.12, "VTIP": 0.08}},
    {"wrapper": "ira", "weights": {"SCHF": 0.25, "BND": 0.25}},
    {"wrapper": "roth", "weights": {"SCHB": 0.20, "SCHV": 0.10}}
  ],
  "location_benefit_bps": 23.5,
  "household_equity_pct": 0.60,
  "household_bond_pct": 0.40,
  "notes": ["Tax-exempt bonds placed in taxable account", "High-growth equities tilted to Roth"]
}

Orchestration

Multi-model orchestration and validation endpoints for running multiple optimization models in one call.

GET/portfolio/orchestrateAPI key

Orchestrate universe

Run the orchestration pipeline across multiple models for a given account type and objective. Returns per-model results.

Parameters
NameTypeRequiredDefaultDescription
account_typestringOptionaltaxableAccount type
objectivestringOptionalresearchObjective
limit_per_modelintegerOptional10Results per model
POST/portfolio/orchestrate/optimizeAPI key

Optimize orchestrated portfolio

Optimize across multiple models in one call. Takes account type, risk level, capital, and tax parameters.

BodyPortfolioOrchestrateOptimizeRequest→returnsobject

Request
curl -X POST https://myetfportfolio.com/v1/portfolio/orchestrate/optimize \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_type": "taxable",
    "risk_level": "moderate",
    "capital": 100000,
    "federal": 0.37,
    "state": 0.05
  }'
Response
{
  "models": {
    "taxable_low_tax": {"equity_pct": 0.60, "combined_weights": {...}},
    "taxable_high_tax": {"equity_pct": 0.50, "combined_weights": {...}}
  }
}
GET/portfolio/validate-6040API key

Validate 60/40 model

Validate the taxable 60/40 model for a given capital, risk tolerance, and covariance mode.

Parameters
NameTypeRequiredDefaultDescription
capitalnumberOptional100000Portfolio capital
risk_tolerancestringOptionalMODERATERisk tolerance
covariance_modestringOptionalheuristicCovariance mode

Public

Unauthenticated endpoints — waitlist signup and health check.

POST/waitlist/signupPublic

Join the API waitlist

Public endpoint — no API key required. Rate-limited by client IP (5 req/min). Honeypot field (website) silently succeeds without storing. Duplicate emails are idempotent. Always returns {"status": "ok"} to avoid leaking internal details.

BodyWaitlistSignupRequest

Request
curl -X POST https://myetfportfolio.com/v1/waitlist/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "company": "Acme Capital", "use_case": "Robo-advisor backend"}'
Response
{"status": "ok"}
GET/healthPublic

Health check

Returns service health status. No authentication required.

Request
curl https://myetfportfolio.com/v1/health
Response
{"status": "ok", "plane": "research", "time": "2026-07-14T12:00:00", "database": {"ok": true}}

Schema reference

Key fields for the main request and response models. The full OpenAPI 3.1 spec (75+ fields on AllocatorRequest, 39 on AllocatorResponse) is available as openapi.json.

AllocatorRequestkey fields

FieldTypeDefaultDescription
policy_idstringtaxable_low_taxOptimization policy (taxable_low_tax, taxable_high_tax, taxable_cash, etc.)
capitalnumber100000Total portfolio capital in USD
risk_tolerancestringMODERATEHow much equity: CONSERVATIVE, MODERATE, AGGRESSIVECONSERVATIVEMODERATEAGGRESSIVE
creativitystringbalancedStrategy breadth: vanilla, balanced, creativevanillabalancedcreative
account_tax_typestringtaxableAccount type for tax treatment
federalnumber0.37Federal marginal tax rate (decimal)
statenumber0.0399State marginal tax rate (decimal)
ltcgnumber0.20Long-term capital gains rate (decimal)
niitnumber0.038Net investment income tax rate (decimal)
investment_horizon_yearsinteger10Investment horizon in years
bond_duration_ceilingnumber5.0Maximum weighted-average bond duration
bond_stylestringanyBond sleeve styleanyshortintermediatelongbarbell
factor_model_enabledbooleanfalseUse named-factor covariance (Fama-French 5 + momentum)
black_litterman_enabledbooleanfalseBlend market equilibrium with CAPM views
expected_return_shrinkagenumber0.5Shrink after-tax returns toward the per-sleeve mean before the solve (0 = raw, 1 = min-variance in-sleeve). Damps weight churn under noisy expected-return inputs.
max_positionsintegernullCap on number of ETFs in final portfolio
excluded_symbolsstring[]nullTickers to exclude from optimization

AllocatorResponsekey fields

FieldTypeDescription
disclaimerstringDecision-support / ideas — not investment advice and not order routing. Present on every response.
equity_pctnumberEquity sleeve allocation (decimal, e.g. 0.60 = 60%)
bond_pctnumberBond sleeve allocation (decimal)
combined_weightsobject{ticker: weight} map of the full portfolio
equity_weightsobject{ticker: weight} map of equity sleeve only
bond_weightsobject{ticker: weight} map of bond sleeve only
estimated_after_tax_return_pctnumberEstimated annual after-tax return (%)
estimated_portfolio_volatility_pctnumberEstimated annual volatility (%)
estimated_sortino_rationumberSortino ratio (risk-adjusted return)
blended_expense_rationumberWeighted-average ETF expense ratio
bond_weighted_durationnumberWeighted-average bond duration (years)
tax_savings_bpsnumberTax savings vs naive allocation (basis points)
efficient_frontierarrayEfficient frontier points: {equity_pct, volatility, after_tax_return}
benchmark_comparisonobjectBenchmark frontier comparison data
tail_riskobjectTail risk metrics: VaR/CVaR from a multivariate Student-t (df=6) simulation plus a path-wealth max drawdown
tlh_opportunitiesarrayTax-loss harvesting opportunities
stress_scenariosarrayParametric stress results (rate shocks, curve twists, muni gaps, 2008-style crisis)
acceptance_test_resultsobjectInternal validation checks (turnover, duration, concentration)
proposed_ordersarrayConcrete buy/sell orders to reach target weights

SDK examples

Python · requests
import requests

API_BASE = "https://myetfportfolio.com/v1"
API_KEY = "YOUR_KEY"

# Optimize a portfolio
response = requests.post(
    f"{API_BASE}/portfolio/optimize",
    headers={
        "X-API-Key": API_KEY,
        "Content-Type": "application/json",
    },
    json={
        "policy_id": "taxable_low_tax",
        "capital": 100000,
        "risk_tolerance": "MODERATE",
        "account_tax_type": "taxable",
        "federal": 0.37,
        "state": 0.05,
        "ltcg": 0.20,
    },
)

data = response.json()
print(f"Equity: {data['equity_pct']:.0%}")
print(f"Bonds:  {data['bond_pct']:.0%}")
print(f"After-tax return: {data['estimated_after_tax_return_pct']:.2f}%")
print(f"Volatility: {data['estimated_portfolio_volatility_pct']:.2f}%")
print(f"Sortino: {data['estimated_sortino_ratio']:.2f}")

for ticker, weight in data["combined_weights"].items():
    print(f"  {ticker}: {weight:.1%}")