# Portfolio Optimizer API
> Live mean-variance (Markowitz) portfolio optimisation that quants and allocators run across a basket of assets, computed on demand from the price series you pass in — no key, no cache, nothing stored. The optimize endpoint returns the two cornerstone portfolios: the minimum-variance portfolio and the maximum-Sharpe (tangency) portfolio, each with its optimal weights, expected return, volatility and Sharpe ratio. The frontier endpoint traces the efficient frontier — a set of optimal risk/return points and the weights that achieve them — so you can plot the whole risk/return curve. The stats endpoint returns the per-asset annualised return and volatility plus the full correlation and covariance matrices, the raw material behind the optimisation. It exploits diversification: by combining assets with low or negative correlation the optimiser finds a portfolio whose volatility is lower than any single holding. Works for any basket — stocks, funds, ETFs, crypto, FX or commodities. This is a multi-asset allocation engine, fundamentally different from single-asset risk and CAPM tools: it answers how to weight several assets together, not how one behaves. Weights can be negative, representing a short leg, as in classic unconstrained Markowitz. Computed locally and deterministically, so it is instant and private. Ideal for robo-advisors, portfolio dashboards, asset-allocation research and back-tests. Rates are fractions (0.02 = 2%). Live, nothing stored. 3 compute endpoints. For single-asset Sharpe/drawdown use a risk-metrics API; for beta use a CAPM API.

## Authentication
All requests require your oanor API key in the `x-oanor-key` header. Get one at https://www.oanor.com/developer/keys.

```bash
curl -H "x-oanor-key: oanor_live_…" "https://api.oanor.com/portfoliooptimizer-api/..."
```

## Pricing
- **Free** (Free) — 4,200 calls/Mo, 2 req/s
- **Starter** ($9/Mo) — 85,000 calls/Mo, 6 req/s
- **Pro** ($27/Mo) — 450,000 calls/Mo, 18 req/s
- **Business** ($62/Mo) — 2,800,000 calls/Mo, 45 req/s

## Endpoints

### Portfolio

#### `GET /v1/frontier` — Efficient-frontier points and weights

**Parameters:**
- `assets` (query, required, string) — Asset blocks name:series separated by ; Example: `stocks:100,103,101,106,104,109;bonds:50,49.5,50.5,49.8,50.6,49.9`
- `points` (query, optional, string) — Number of frontier points (default 12) Example: `12`
- `risk_free` (query, optional, string) — Annual risk-free rate (fraction) Example: `0.02`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/portfoliooptimizer-api/v1/frontier?assets=stocks%3A100%2C103%2C101%2C106%2C104%2C109%3Bbonds%3A50%2C49.5%2C50.5%2C49.8%2C50.6%2C49.9&points=12&risk_free=0.02"
```

**Response:**
```json
{
    "data": {
        "assets": [
            "stocks",
            "bonds"
        ],
        "points": 12,
        "source": "PORTFOLIO",
        "frontier": [
            {
                "weights": {
                    "bonds": 0.672182,
                    "stocks": 0.327818
                },
                "volatility": 0.024805,
                "sharpe_ratio": 56.720021,
                "expected_return": 1.426945
            },
            {
                "weights": {
                    "bonds": 0.672863,
                    "stocks": 0.327137
                },
                "volatility": 0.024808,
                "sharpe_ratio": 56.588707,
                "expected_return": 1.423829
            },
            {
                "weights": {
                    "bonds": 0.6715,
                    "stocks": 0.3285
                },
                "volatility": 0.024813,
                "sharpe_ratio": 56.828468,
                "expected_return": 1.430061
            },
            {
                "weights": {
                    "bonds": 0.673545,
                    "stocks": 0.326455
                },
                "volatility": 0.02482,
                "sharpe_ratio": 56.434696,
                "expected_return": 1.420713
            },
            {
                "weights": {
                    "bonds": 0.670819,
                    "stocks": 0.329181
                },
                "volatility": 0.02483,
                "sharpe_ratio": 56
…(truncated, see openapi.json for full schema)
```

#### `GET /v1/optimize` — Minimum-variance + maximum-Sharpe portfolios

**Parameters:**
- `assets` (query, required, string) — Asset blocks name:series separated by ; Example: `stocks:100,103,101,106,104,109;bonds:50,49.5,50.5,49.8,50.6,49.9`
- `risk_free` (query, optional, string) — Annual risk-free rate (fraction) Example: `0.02`
- `as` (query, optional, string) — prices (default) or returns Example: `prices`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/portfoliooptimizer-api/v1/optimize?assets=stocks%3A100%2C103%2C101%2C106%2C104%2C109%3Bbonds%3A50%2C49.5%2C50.5%2C49.8%2C50.6%2C49.9&risk_free=0.02&as=prices"
```

**Response:**
```json
{
    "data": {
        "note": "Weights are unconstrained Markowitz (may be negative = short). Returns/volatility annualised.",
        "assets": [
            "stocks",
            "bonds"
        ],
        "source": "PORTFOLIO",
        "risk_free": 0.02,
        "observations": 5,
        "maximum_sharpe": {
            "weights": {
                "bonds": 0.668604,
                "stocks": 0.331396
            },
            "volatility": 0.024955,
            "sharpe_ratio": 57.033732,
            "expected_return": 1.443303
        },
        "minimum_variance": {
            "weights": {
                "bonds": 0.672352,
                "stocks": 0.327648
            },
            "volatility": 0.024805,
            "sharpe_ratio": 56.689331,
            "expected_return": 1.426166
        },
        "periods_per_year": 252
    },
    "meta": {
        "timestamp": "2026-06-11T07:49:23.731Z",
        "request_id": "364c8544-2be7-415d-a331-72f08152c097"
    },
    "status": "ok",
    "message": "Portfolio optimised",
    "success": true
}
```

#### `GET /v1/stats` — Per-asset return/vol + correlation & covariance

**Parameters:**
- `assets` (query, required, string) — Asset blocks name:series separated by ; Example: `stocks:100,103,101,106,104,109;bonds:50,49.5,50.5,49.8,50.6,49.9`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/portfoliooptimizer-api/v1/stats?assets=stocks%3A100%2C103%2C101%2C106%2C104%2C109%3Bbonds%3A50%2C49.5%2C50.5%2C49.8%2C50.6%2C49.9"
```

**Response:**
```json
{
    "data": {
        "note": "Returns and (co)variances annualised by periods_per_year. Matrices are ordered as the assets array.",
        "assets": [
            "stocks",
            "bonds"
        ],
        "source": "PORTFOLIO",
        "per_asset": [
            {
                "asset": "stocks",
                "return_annualised": 4.500542,
                "volatility_annualised": 0.491874
            },
            {
                "asset": "bonds",
                "return_annualised": -0.072027,
                "volatility_annualised": 0.240675
            }
        ],
        "observations": 5,
        "periods_per_year": 252,
        "covariance_matrix": [
            [
                0.24193994,
                -0.11698605
            ],
            [
                -0.11698605,
                0.05792426
            ]
        ],
        "correlation_matrix": [
            [
                1,
                -0.988212
            ],
            [
                -0.988212,
                1
            ]
        ]
    },
    "meta": {
        "timestamp": "2026-06-11T07:49:23.826Z",
        "request_id": "c7eadb58-30a1-4778-82a1-07a86cfdaac1"
    },
    "status": "ok",
    "message": "Portfolio stats computed",
    "success": true
}
```

### Meta

#### `GET /v1/meta` — Spec

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/portfoliooptimizer-api/v1/meta"
```

**Response:**
```json
{
    "data": {
        "note": "assets = name:series blocks separated by ';' (assets=stocks:100,102,...;bonds:50,50.5,...). Prices by default; as=returns for returns. risk_free & periods_per_year optional; rates are fractions (0.02 = 2%).",
        "source": "Computed in-process from caller-supplied asset price series (no upstream)",
        "service": "portfoliooptimizer-api",
        "endpoints": {
            "GET /v1/meta": "This document.",
            "GET /v1/stats": "Per-asset return/vol + correlation & covariance matrices (assets=...).",
            "GET /v1/frontier": "Efficient-frontier points and weights (assets=...&points=12).",
            "GET /v1/optimize": "Minimum-variance + maximum-Sharpe portfolios (assets=stocks:100,102,101,104;bonds:50,50.5,50.2,51)."
        },
        "description": "Live mean-variance (Markowitz) portfolio optimisation computed on demand from a basket of asset price series. The optimize endpoint returns the minimum-variance and maximum-Sharpe (tangency) portfolios — optimal weights, expected return, volatility and Sharpe; the frontier endpoint traces the efficient frontier of optimal risk/return points and weights; the stats endpoint returns per-asset annualised return and volatility plus the correlation and covariance matrices. A multi-asset allocation engine, distinct from single-asset risk and CAPM tools. Unconstrained Markowitz (weights may be negative = short). Computed locally, nothing stored.",
        "upstream_status": "ok
…(truncated, see openapi.json for full schema)
```


---
Marketplace page: https://www.oanor.com/api/portfoliooptimizer-api
OpenAPI spec: https://www.oanor.com/api/portfoliooptimizer-api/openapi.json
