{
  "edition": "2026-10-16",
  "engine_version": "1.0.0",
  "scope": "Synthetic educational references. Not a fitted investment strategy, forecast, provider model or client return. First publication: 2026-10-16. Model and engine version 1.0.0.",
  "cards": [
    {
      "slug": "equal-weight",
      "title": "Equal-weight allocation",
      "topic": "allocation",
      "summary": "A transparent baseline that assigns identical capital weights to a declared number of assets.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "w_i = 1 / N",
      "inputs": [
        [
          "assets",
          "Integer, 2 through 50",
          "Number of distinct included assets"
        ]
      ],
      "method": [
        "The rule contains no return estimates. That makes its arithmetic easy to inspect, but the universe is still a substantive choice. Four assets receive one quarter each; splitting one economic exposure into two tickers would change the resulting economic allocation.",
        "The output is a target vector, not a trade list. To implement it, first map the ordered assets, identify drifted holdings and decide when and how to rebalance. The turnover reference can measure an already aligned before-and-after comparison."
      ],
      "limits": [
        "Equal capital does not imply equal contribution to volatility or equal exposure to common factors. The card deliberately does not infer missing assets, cash, leverage, execution prices or costs. A passing arithmetic test says nothing about the merits of the chosen universe."
      ],
      "checks": [
        "Every weight is nonnegative; weights sum to one within floating-point tolerance.",
        "Two, four and fifty assets; fractional, missing and oversized counts rejected."
      ],
      "related": [
        "equal-weight-universe",
        "choosing-a-reference-model"
      ],
      "sources": [
        {
          "title": "MOSEK: portfolio variance and allocation constraints",
          "url": "https://docs.mosek.com/portfolio-cookbook/markowitz.html"
        }
      ]
    },
    {
      "slug": "inverse-volatility",
      "title": "Inverse-volatility weights",
      "topic": "allocation",
      "summary": "Normalize inverse standalone volatility while keeping the missing correlation assumption visible.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "w_i = (1 / sigma_i) / sum_j(1 / sigma_j)",
      "inputs": [
        [
          "volatilities",
          "2-50 decimal values, 0.000001 to 10",
          "Strictly positive, same-frequency standalone volatility"
        ]
      ],
      "method": [
        "A 10%, 20%, 40% volatility vector creates weights in the ratio 4:2:1. The common normalization sets total capital weight to one. Multiplying every volatility by the same positive scale leaves the weights unchanged.",
        "This reference is useful for checking a proposed weighting implementation, including its asset order and zero-input policy. It does not estimate volatility from prices. Choose and document the estimator, lookback and cutoff elsewhere before passing a vector here."
      ],
      "limits": [
        "Correlations are absent. In general the output is not an equal-risk-contribution solution, and a low historical volatility estimate can concentrate capital. Zero is rejected instead of receiving an infinite weight. All inputs must use one frequency."
      ],
      "checks": [
        "Scale invariance, normalization and equal-volatility equality.",
        "Zero, negative, null and string values rejected."
      ],
      "related": [
        "inverse-volatility-not-risk-parity",
        "covariance-units"
      ],
      "sources": [
        {
          "title": "MOSEK: risk budgeting and contributions",
          "url": "https://docs.mosek.com/portfolio-cookbook/risk_parity.html"
        }
      ]
    },
    {
      "slug": "two-asset-minimum-variance",
      "title": "Two-asset minimum variance",
      "topic": "allocation",
      "summary": "Inspect the analytic long-only variance minimum for exactly two exposures.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "w1* = (v2 - c12) / (v1 + v2 - 2*c12); w1 = clip(w1*, 0, 1); w2 = 1 - w1",
      "inputs": [
        [
          "covariance",
          "Symmetric PSD 2x2 matrix; entries -100 to 100",
          "Squared decimal-return units; nonnegative diagonal; one frequency"
        ]
      ],
      "method": [
        "For the default matrix the unconstrained first weight is 0.004/0.038, approximately 10.5263%. It is inside the long-only interval, so no clipping changes the result. The second exposure receives the remainder.",
        "With two assets and a valid covariance matrix, portfolio variance is a convex quadratic in the first weight. A boundary solution is therefore represented by clipping the analytic stationary point. If the difference variance is exactly zero, all feasible weights tie and the card explicitly returns equal weights with unique=false."
      ],
      "limits": [
        "This closed-form reference is not a general optimizer. It excludes expected return targets, shorting, taxes, turnover penalties and estimation uncertainty. Near-degenerate matrices can make the unconstrained weight unstable even while the constrained answer is finite."
      ],
      "checks": [
        "Analytic weights checked against independent quadratic calculations and feasible-grid minima.",
        "Boundary clipping and equal-risk tie rule tested; indefinite matrices rejected."
      ],
      "related": [
        "minimum-variance-constraints",
        "covariance-shrinkage-targets"
      ],
      "sources": [
        {
          "title": "MOSEK: portfolio variance and allocation constraints",
          "url": "https://docs.mosek.com/portfolio-cookbook/markowitz.html"
        }
      ]
    },
    {
      "slug": "covariance-shrinkage",
      "title": "Identity-target covariance shrinkage",
      "topic": "estimation",
      "summary": "Apply a declared convex shrinkage intensity without pretending it was statistically estimated.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "S_new = (1 - a)*S + a*(trace(S)/2)*I",
      "inputs": [
        [
          "covariance",
          "Symmetric PSD 2x2 matrix; entries -100 to 100",
          "Original covariance estimate; nonnegative diagonal"
        ],
        [
          "intensity",
          "Decimal, 0 to 1 inclusive",
          "User-chosen shrinkage strength"
        ]
      ],
      "method": [
        "The target uses the average of the two variances on both diagonal entries and zero off-diagonal entries. At intensity zero the matrix is unchanged; at one it becomes the target. Intermediate settings reduce the off-diagonal covariance and move each variance toward the shared mean.",
        "The default half-strength example changes the variances to 0.0325 and 0.0175, with covariance 0.003. Preserving the trace makes the target easy to reconcile, but is not an argument that this target best represents any particular investment universe."
      ],
      "limits": [
        "This is a fixed-intensity transform, not the Ledoit-Wolf estimator. It does not select a parameter, repair an indefinite starting matrix or prove better out-of-sample risk estimates. Review window, data cleaning and target suitability separately."
      ],
      "checks": [
        "Both endpoints, trace preservation and symmetry tested.",
        "Invalid intensity and non-PSD inputs fail before calculation."
      ],
      "related": [
        "covariance-shrinkage-targets",
        "arithmetic-tests-versus-validation"
      ],
      "sources": [
        {
          "title": "scikit-learn: covariance estimation and shrinkage",
          "url": "https://scikit-learn.org/stable/modules/covariance.html"
        }
      ]
    },
    {
      "slug": "portfolio-variance",
      "title": "Two-asset portfolio variance",
      "topic": "risk",
      "summary": "Reconcile capital weights and covariance into a portfolio variance and volatility at the input frequency.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "v_p = w1^2*v1 + 2*w1*w2*c12 + w2^2*v2; sigma_p = sqrt(v_p)",
      "inputs": [
        [
          "weights",
          "Two nonnegative decimals summing to one",
          "Capital weights in covariance asset order"
        ],
        [
          "covariance",
          "Symmetric PSD 2x2 matrix; entries -100 to 100",
          "Same-frequency squared decimal-return units; nonnegative diagonal"
        ]
      ],
      "method": [
        "The cross term is essential. Adding weighted standalone variances while ignoring covariance changes the model rather than simplifying the same calculation. With default weights 0.6/0.4, the variance is 0.01888; its square root is approximately 0.1374045.",
        "No annualization is hidden in the engine. Annual covariance produces annual volatility; period covariance produces period volatility. Inputs labelled percentages must first be converted to decimals, and covariance scales with the square of that conversion."
      ],
      "limits": [
        "The matrix summarizes second moments, not tail loss or liquidity. Shorting, derivatives, nonlinear exposure and cash flows are outside this two-asset card. Symmetry and positive semidefiniteness are mathematical admission checks, not evidence that an estimate is economically reliable."
      ],
      "checks": [
        "Direct quadratic form, zero weights and perfectly offsetting covariance checked.",
        "Order consistency, weight sums and PSD bounds validated."
      ],
      "related": [
        "covariance-units",
        "component-risk-and-capital"
      ],
      "sources": [
        {
          "title": "MOSEK: portfolio variance and allocation constraints",
          "url": "https://docs.mosek.com/portfolio-cookbook/markowitz.html"
        }
      ]
    },
    {
      "slug": "component-risk",
      "title": "Euler volatility contributions",
      "topic": "risk",
      "summary": "Attribute two-asset portfolio volatility to signed Euler contributions without equating risk share and capital share.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "RC_i = w_i*(S*w)_i / sigma_p; risk_share_i = RC_i / sigma_p",
      "inputs": [
        [
          "weights",
          "Two nonnegative decimals summing to one",
          "Capital fractions"
        ],
        [
          "covariance",
          "Symmetric PSD 2x2 matrix; entries -100 to 100",
          "Ordered, same-frequency covariance; nonnegative diagonal"
        ]
      ],
      "method": [
        "The marginal derivative of volatility is scaled by each capital weight to obtain its Euler contribution. In the default example, the contribution numerators are 0.01584 and 0.00304. Dividing each by total variance gives risk shares of approximately 83.8983% and 16.1017%, despite capital weights of 60% and 40%.",
        "A negative contribution is possible when an exposure offsets the rest of the portfolio strongly enough. The signed contributions still add to total volatility; forcing every value to be nonnegative would destroy that reconciliation."
      ],
      "limits": [
        "At zero total volatility the division is undefined, so contribution arrays are null rather than invented zeros. These are local variance-based allocations, not loss attribution in a stress event or a recommendation to remove a hedging exposure."
      ],
      "checks": [
        "Euler sum and risk-share sum reconciled; negative contribution fixture tested.",
        "Zero-volatility outputs explicitly withheld."
      ],
      "related": [
        "component-risk-and-capital",
        "inverse-volatility-not-risk-parity"
      ],
      "sources": [
        {
          "title": "MOSEK: risk budgeting and contributions",
          "url": "https://docs.mosek.com/portfolio-cookbook/risk_parity.html"
        }
      ]
    },
    {
      "slug": "volatility-target",
      "title": "Capped volatility scaling",
      "topic": "risk",
      "summary": "Translate a stated volatility estimate and target into a capped proportional exposure reference.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "exposure = min(target_volatility / estimated_volatility, leverage_cap)",
      "inputs": [
        [
          "target_volatility",
          "Decimal, 0 to 10",
          "Desired scale at the estimate frequency"
        ],
        [
          "estimated_volatility",
          "Decimal, 0.000001 to 10",
          "Positive risk estimate"
        ],
        [
          "leverage_cap",
          "Nonnegative multiplier, at most 10",
          "Maximum allowed model exposure"
        ]
      ],
      "method": [
        "The default 12% target divided by an 8% estimate requests 1.5 times exposure. The 1.25 cap binds, leaving a model-implied scaled volatility of 10%. The result is below target because the constraint is respected rather than silently relaxed.",
        "The estimate must precede the decision it informs. Replacing it retrospectively with realized volatility can make a historical scaling rule look implausibly precise. This static card has no observation clock, so timing and lag must be supplied by the surrounding study."
      ],
      "limits": [
        "Estimated scaled volatility is not realized risk. The formula omits financing, margin, transaction costs, gap risk and portfolio changes. Very small estimates can bind the cap; a zero estimate is rejected, not assigned unlimited exposure."
      ],
      "checks": [
        "Binding/nonbinding caps, zero target and zero cap checked.",
        "Invalid negative or zero estimate rejected."
      ],
      "related": [
        "volatility-targeting-limits",
        "out-of-sample-and-multiple-testing"
      ],
      "sources": [
        {
          "title": "RiskMetrics technical document, fourth edition",
          "url": "https://www.msci.com/documents/10199/5915b101-4206-4ba0-aee2-3449d5c7e95a"
        }
      ]
    },
    {
      "slug": "ewma-variance",
      "title": "Zero-mean EWMA variance",
      "topic": "estimation",
      "summary": "Track an explicit initial variance through a zero-mean exponentially weighted update.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "v_(t+1) = lambda*v_t + (1 - lambda)*r_t^2",
      "inputs": [
        [
          "returns",
          "2-250 decimals, -1 to 10",
          "Chronological equal-frequency observations"
        ],
        [
          "initial_variance",
          "Squared decimal, 0 to 100",
          "Variance before the first supplied return"
        ],
        [
          "lambda",
          "Decimal, 0 to 1",
          "Decay parameter, not fitted here"
        ]
      ],
      "method": [
        "Each supplied return updates the variance for the next period. The output path therefore begins after the first observation, not at the initial variance. This convention avoids attaching an updated estimate to a decision made before the return was observed.",
        "With initial variance 0.0001 and decay 0.94, the first 1% return leaves variance unchanged. The following -2% return raises it to 0.000118. A 1.5% third return then produces 0.00012442. The path and terminal value are both available for reconciliation."
      ],
      "limits": [
        "A zero conditional mean is assumed. Lambda=1 freezes the initial value; lambda=0 uses only the latest squared return. No parameter fitting, expected return adjustment, missing-period decay or empirical forecast score is provided."
      ],
      "checks": [
        "Recursion independently replayed, including decay endpoints.",
        "Initial condition, ordering and negative variance validation covered."
      ],
      "related": [
        "ewma-initialization",
        "covariance-units"
      ],
      "sources": [
        {
          "title": "RiskMetrics technical document, fourth edition",
          "url": "https://www.msci.com/documents/10199/5915b101-4206-4ba0-aee2-3449d5c7e95a"
        }
      ]
    },
    {
      "slug": "ordinary-least-squares",
      "title": "Univariate least-squares fit",
      "topic": "estimation",
      "summary": "Inspect an in-sample slope, intercept and fit summary for aligned numerical pairs.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "slope = sample_cov(x,y)/sample_var(x); intercept = mean(y) - slope*mean(x)",
      "inputs": [
        [
          "x",
          "3-250 finite numbers; each -1000000 to 1000000",
          "Explanatory values, nonconstant"
        ],
        [
          "y",
          "Same length as x; each -1000000 to 1000000",
          "Aligned response values"
        ]
      ],
      "method": [
        "The fixture pairs 1,2,3,4 with 2,4,5,7. The fitted slope is 1.6 and the intercept is 0.5, with residual sum of squares 0.2. These numbers describe the supplied pairs; they do not identify a causal mechanism or establish a forecasting relationship.",
        "The implementation uses the pinned Simple Statistics least-squares function and separately calculates residual fit. Independent Python checks use centered sums, providing a second arithmetic path. Constant x is rejected because no slope is identified; constant y retains a valid fit but withholds R-squared."
      ],
      "limits": [
        "No p-values, robust standard errors, confidence intervals, multiple regressors or out-of-sample predictions are implied. Large offsets with very small variation can be numerically ill-conditioned; rescale before interpreting. This bounded teaching implementation is not a statistical certification."
      ],
      "checks": [
        "Known line, residual sums, constant-response and constant-explanatory cases.",
        "Input alignment and missing-value rejection tested."
      ],
      "related": [
        "regression-fit-versus-forecast",
        "arithmetic-tests-versus-validation"
      ],
      "sources": [
        {
          "title": "SciPy: least-squares regression",
          "url": "https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html"
        },
        {
          "title": "Simple Statistics: reference implementation and API",
          "url": "https://simple-statistics.github.io/"
        }
      ]
    },
    {
      "slug": "beta",
      "title": "Single-benchmark return beta",
      "topic": "estimation",
      "summary": "Calculate a descriptive raw-return sensitivity to one aligned benchmark series.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "beta = sample_cov(benchmark, asset) / sample_var(benchmark)",
      "inputs": [
        [
          "asset",
          "3-250 decimal returns",
          "Chronological raw asset returns"
        ],
        [
          "benchmark",
          "Same length, nonconstant decimal returns",
          "Aligned reference returns"
        ]
      ],
      "method": [
        "The default asset series is each benchmark return plus 0.005. Its slope is exactly one and its period intercept is 0.005. The intercept is a property of this invented relationship, not a demonstrated strategy premium.",
        "A beta label is incomplete without the benchmark, sample dates, frequency and return definition. This fixture contains no real calendar or instrument identity. A real study must preserve them outside the array and ensure that each pair describes the same interval."
      ],
      "limits": [
        "No risk-free series is deducted. Do not describe this raw intercept as CAPM alpha or interpret in-sample R-squared as investment quality. Nonlinear exposure, stale prices and changing factor sensitivities require a broader specification."
      ],
      "checks": [
        "Slope reconciled with covariance/variance and a known affine series.",
        "Zero benchmark variance and unequal lengths rejected."
      ],
      "related": [
        "beta-window-and-benchmark",
        "regression-fit-versus-forecast"
      ],
      "sources": [
        {
          "title": "SciPy: least-squares regression",
          "url": "https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html"
        },
        {
          "title": "Simple Statistics: reference implementation and API",
          "url": "https://simple-statistics.github.io/"
        }
      ]
    },
    {
      "slug": "tracking-error",
      "title": "Sample tracking error",
      "topic": "validation",
      "summary": "Measure dispersion of aligned arithmetic portfolio-minus-benchmark returns with explicit annualization.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "a_t = portfolio_t - benchmark_t; TE = sample_sd(a); TE_ann = TE*sqrt(K)",
      "inputs": [
        [
          "portfolio",
          "2-250 decimal period returns",
          "Equal-length portfolio observations"
        ],
        [
          "benchmark",
          "Aligned decimals, same length",
          "Matching reference observations"
        ],
        [
          "periods_per_year",
          "Number, 1 to 366",
          "Declared annualization factor"
        ]
      ],
      "method": [
        "The default active returns are 0.01, 0.01, 0.01 and -0.005. Their sample standard deviation is 0.0075. At twelve periods per year the scaled number is approximately 0.0259808.",
        "The sample convention divides the centered squared deviations by n-1. The card reports both the original-period and annualized quantities so that a user can see whether a comparison differs because of sampling frequency or the underlying dispersion."
      ],
      "limits": [
        "Square-root time scaling is an assumption, not a calendar lookup. Autocorrelated or changing active returns can invalidate its interpretation. Tracking error says nothing by itself about whether average active performance is positive, and it is not the standard deviation of compounded relative wealth."
      ],
      "checks": [
        "Sample denominator, annualization and identical-series zero tested.",
        "Mismatched observations and unbounded scaling factors rejected."
      ],
      "related": [
        "tracking-error-conventions",
        "information-ratio-denominator"
      ],
      "sources": [
        {
          "title": "William F. Sharpe: differential-return ratios and time aggregation",
          "url": "https://web.stanford.edu/~wfsharpe/art/sr/sr.htm"
        },
        {
          "title": "Simple Statistics: reference implementation and API",
          "url": "https://simple-statistics.github.io/"
        }
      ]
    },
    {
      "slug": "information-ratio",
      "title": "Arithmetic information ratio",
      "topic": "validation",
      "summary": "Relate mean active return to sample active-return dispersion under one declared scaling convention.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "IR_ann = mean(portfolio - benchmark) / sample_sd(portfolio - benchmark) * sqrt(K)",
      "inputs": [
        [
          "portfolio",
          "2-250 decimal returns",
          "Equal-frequency portfolio series"
        ],
        [
          "benchmark",
          "Same-length decimal returns",
          "Aligned benchmark series"
        ],
        [
          "periods_per_year",
          "Number, 1 to 366",
          "Explicit scaling factor"
        ]
      ],
      "method": [
        "The default mean active return is 0.00625 and the period tracking error is 0.0075. The period ratio is 0.8333333; multiplying by sqrt(12) gives approximately 2.8867513. A short invented example can produce a large ratio without supplying any evidence about future results.",
        "An additive shift to every active observation changes the mean but not dispersion. That is useful as an arithmetic property test, not a way to manufacture a performance conclusion. The benchmark and full sample must be chosen on economic and research grounds, not selected to maximize this output."
      ],
      "limits": [
        "A zero denominator returns null with an explanation. Annualizing a few observations does not create a year of evidence. The measure excludes estimation uncertainty, serial dependence adjustments, fees not already in the input and selection bias."
      ],
      "checks": [
        "Known arithmetic ratio and zero-dispersion withholding tested.",
        "Negative means remain signed; no clipping to flattering values."
      ],
      "related": [
        "information-ratio-denominator",
        "out-of-sample-and-multiple-testing"
      ],
      "sources": [
        {
          "title": "William F. Sharpe: differential-return ratios and time aggregation",
          "url": "https://web.stanford.edu/~wfsharpe/art/sr/sr.htm"
        },
        {
          "title": "Simple Statistics: reference implementation and API",
          "url": "https://simple-statistics.github.io/"
        }
      ]
    },
    {
      "slug": "compound-return",
      "title": "Geometric return chain",
      "topic": "validation",
      "summary": "Reconcile sequential decimal returns to terminal wealth and an explicitly annualized equivalent.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "W = product(1 + r_t); R = W - 1; R_ann = W^(K/n) - 1",
      "inputs": [
        [
          "returns",
          "1-250 decimals, -1 to 10",
          "Chronological equal-length returns without external flows"
        ],
        [
          "periods_per_year",
          "Number, 1 to 366",
          "Periods corresponding to one year"
        ]
      ],
      "method": [
        "A 10% gain followed by a 10% loss leaves wealth at 0.99, not 1.00. Adding a 5% gain takes the example to 1.0395. The ordering of these returns does not change terminal compounded wealth, although it can change path-dependent drawdown.",
        "Annualization uses the supplied observation count and frequency. It is a mathematical equivalent rate, not a prediction. With a complete loss, wealth remains zero under the no-external-flow convention; later positive percentages cannot replenish an extinguished balance."
      ],
      "limits": [
        "The reference is not money-weighted performance, a cash-flow accounting engine or a broker statement reconstruction. Returns below -100% are outside its nonnegative-wealth model. Extreme short-sample annualization can overflow and is rejected instead of producing an infinite result."
      ],
      "checks": [
        "Multiplicative chain, total loss, order-invariant terminal wealth and overflow rejection.",
        "No summation substituted for compounding."
      ],
      "related": [
        "compound-return-and-cash-flows",
        "drawdown-path-and-sampling"
      ],
      "sources": [
        {
          "title": "PerformanceAnalytics: cumulative return",
          "url": "https://search.r-project.org/CRAN/refmans/PerformanceAnalytics/html/Return.cumulative.html"
        }
      ]
    },
    {
      "slug": "maximum-drawdown",
      "title": "Observed-path maximum drawdown",
      "topic": "risk",
      "summary": "Find the deepest peak-to-observation decline in a finite nonnegative wealth path.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "W_0 = 1; W_t = W_(t-1)*(1+r_t); DD_t = W_t/max(W_0...W_t)-1; MDD = min(DD_t)",
      "inputs": [
        [
          "returns",
          "1-250 decimals, -1 to 10",
          "Chronological period-end returns with no external flows"
        ]
      ],
      "method": [
        "The initial wealth point is included. An immediate negative first return therefore creates a drawdown rather than being treated as a new starting baseline. The default path 1, 1.1, 0.88, 1.012, 0.9614 has maximum drawdown -0.2.",
        "The full wealth and drawdown arrays expose the path behind the summary. Unlike terminal compounding, drawdown depends on order. Reordering a series for a stress illustration must be disclosed as a constructed scenario, not described as the historical experience of an actual investor."
      ],
      "limits": [
        "The output is a nonpositive fraction. It records only supplied observation endpoints, so an intraperiod low can be missing. It is not a forecast of worst future loss and does not model intraday liquidation, cash flows or margin."
      ],
      "checks": [
        "Initial loss, recovery, all-positive path, complete loss and reordered paths.",
        "Observed maximum reconciled independently to peak tracking."
      ],
      "related": [
        "drawdown-path-and-sampling",
        "compound-return-and-cash-flows"
      ],
      "sources": [
        {
          "title": "PerformanceAnalytics: maximum drawdown",
          "url": "https://search.r-project.org/CRAN/refmans/PerformanceAnalytics/html/maxDrawdown.html"
        }
      ]
    },
    {
      "slug": "turnover",
      "title": "Two-sided and one-way turnover",
      "topic": "implementation",
      "summary": "Measure traded capital fractions from aligned drifted and target weights under a stated convention.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "trade_i = after_i - before_i; gross = sum(abs(trade_i)); one_way = gross/2",
      "inputs": [
        [
          "before",
          "2-50 nonnegative weights summing to one",
          "Drifted pretrade weights at the measurement time"
        ],
        [
          "after",
          "Same-length weights summing to one",
          "Posttrade targets on the same NAV basis"
        ]
      ],
      "method": [
        "Moving 60/40 to 40/60 sells 20% of NAV in one exposure and buys 20% in the other. Gross traded weight is 40%; the half-sum convention reports 20% one-way turnover. Both are retained because cost formulas and reports can use different denominators.",
        "The before vector must describe holdings immediately before the rebalance. Comparing today with an older target omits price drift and can understate or overstate the actual rebalance. An asset-order mismatch can also create fictitious trades even when totals look correct."
      ],
      "limits": [
        "The half-sum convention presumes a fully invested, self-financing comparison on one NAV basis. External flows, leverage changes, cash accounting and derivatives require a richer trade ledger. The card never silently normalizes weights to hide those differences."
      ],
      "checks": [
        "No trade, full rotation and partial balanced reallocation.",
        "Sum-one, alignment and unsigned-weight constraints tested."
      ],
      "related": [
        "turnover-definitions",
        "transaction-cost-units"
      ],
      "sources": [
        {
          "title": "Cvxportfolio: turnover constraints and cash conventions",
          "url": "https://www.cvxportfolio.com/en/1.5.0/constraints.html"
        }
      ]
    },
    {
      "slug": "cost-drag",
      "title": "Linear rebalance cost drag",
      "topic": "implementation",
      "summary": "Convert a symmetric per-side basis-point cost and traded weights into a one-period return approximation.",
      "version": "1.0.0",
      "published": "2026-10-16",
      "status": "Educational reference",
      "formula": "cost_fraction = gross_traded_weight * cost_bps / 10000; net_approx = gross_return - cost_fraction",
      "inputs": [
        [
          "before",
          "Aligned long-only weights summing to one",
          "Drifted pretrade fractions"
        ],
        [
          "after",
          "Same-length weights summing to one",
          "Targets before cost-funded cash adjustment"
        ],
        [
          "cost_bps",
          "0 to 1000 basis points per traded notional",
          "Same assumed rate for buys and sells"
        ],
        [
          "gross_return",
          "Decimal, -1 to 10",
          "One-period return before this assumed cost"
        ]
      ],
      "method": [
        "The default gross traded fraction is 0.4 and the per-side cost is ten basis points, or 0.001. The assumed drag is therefore 0.0004 of starting NAV, equal to four basis points. Subtracting it from 0.02 gives an approximate net return of 0.0196.",
        "Multiplying the same rate by one-way turnover would halve the stated per-side cost. Conversely, an already round-trip cost quote cannot be used as a per-side rate without adjustment. Record the quote convention before comparing outputs."
      ],
      "limits": [
        "This linear reference is not an execution estimate. It has no participation, spread, impact, tax, financing or order timing model, and does not re-solve holdings after fees. A net approximation below -100% is possible under extreme inputs and signals that the additive illustration is outside a feasible funded account."
      ],
      "checks": [
        "Basis-point conversion, gross-versus-one-way factor and zero-cost identity.",
        "Costs remain explicit in exports and never relabelled as actual broker charges."
      ],
      "related": [
        "transaction-cost-units",
        "turnover-definitions"
      ],
      "sources": [
        {
          "title": "Cvxportfolio: proportional transaction costs",
          "url": "https://www.cvxportfolio.com/en/1.5.0/costs.html"
        },
        {
          "title": "Cvxportfolio: turnover constraints and cash conventions",
          "url": "https://www.cvxportfolio.com/en/1.5.0/constraints.html"
        }
      ]
    }
  ],
  "examples": {
    "equal-weight": {
      "assets": 4
    },
    "inverse-volatility": {
      "volatilities": [
        0.1,
        0.2,
        0.4
      ]
    },
    "two-asset-minimum-variance": {
      "covariance": [
        [
          0.04,
          0.006
        ],
        [
          0.006,
          0.01
        ]
      ]
    },
    "covariance-shrinkage": {
      "covariance": [
        [
          0.04,
          0.006
        ],
        [
          0.006,
          0.01
        ]
      ],
      "intensity": 0.5
    },
    "portfolio-variance": {
      "weights": [
        0.6,
        0.4
      ],
      "covariance": [
        [
          0.04,
          0.006
        ],
        [
          0.006,
          0.01
        ]
      ]
    },
    "component-risk": {
      "weights": [
        0.6,
        0.4
      ],
      "covariance": [
        [
          0.04,
          0.006
        ],
        [
          0.006,
          0.01
        ]
      ]
    },
    "volatility-target": {
      "target_volatility": 0.12,
      "estimated_volatility": 0.08,
      "leverage_cap": 1.25
    },
    "ewma-variance": {
      "returns": [
        0.01,
        -0.02,
        0.015
      ],
      "initial_variance": 0.0001,
      "lambda": 0.94
    },
    "ordinary-least-squares": {
      "x": [
        1,
        2,
        3,
        4
      ],
      "y": [
        2,
        4,
        5,
        7
      ]
    },
    "beta": {
      "asset": [
        0.015,
        -0.005,
        0.025,
        0.005
      ],
      "benchmark": [
        0.01,
        -0.01,
        0.02,
        0
      ]
    },
    "tracking-error": {
      "portfolio": [
        0.02,
        -0.01,
        0.03,
        0.01
      ],
      "benchmark": [
        0.01,
        -0.02,
        0.02,
        0.015
      ],
      "periods_per_year": 12
    },
    "information-ratio": {
      "portfolio": [
        0.02,
        -0.01,
        0.03,
        0.01
      ],
      "benchmark": [
        0.01,
        -0.02,
        0.02,
        0.015
      ],
      "periods_per_year": 12
    },
    "compound-return": {
      "returns": [
        0.1,
        -0.1,
        0.05
      ],
      "periods_per_year": 12
    },
    "maximum-drawdown": {
      "returns": [
        0.1,
        -0.2,
        0.15,
        -0.05
      ]
    },
    "turnover": {
      "before": [
        0.6,
        0.4
      ],
      "after": [
        0.4,
        0.6
      ]
    },
    "cost-drag": {
      "before": [
        0.6,
        0.4
      ],
      "after": [
        0.4,
        0.6
      ],
      "cost_bps": 10,
      "gross_return": 0.02
    }
  }
}
