> ## Documentation Index
> Fetch the complete documentation index at: https://octo-98895abd.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Termo

> B3 forward (termo) contracts as published — one code's daily history, term included in the grain.

### Overview

*Termo* is B3's forward market: a trade agreed today for settlement a fixed number of days out. It rides the same COTAHIST tape as [`quotes`](/api-docs/quotes) under **`tpmerc` = `030`**, and it is a small segment — on the order of a hundred prints per session, against tens of thousands of options.

Everything is unadjusted; every row carries `adjusted: false`.

<Warning>
  **The grain is `(codneg, trade_date, market, board, term_days)`.** One code can print several terms or boards in the same session. Preserve those distinctions when indexing the observations.

  **There is no `underlying` column**, for the same reason as [options](/api-docs/options): the codneg root usually names the underlying paper, but B3 publishes no mapping, and deriving one would be inventing an identity join.
</Warning>

### `POST /rpc/termo_history`

One code's daily prints over a window.

```sql theme={null}
api.termo_history(p_codneg TEXT,
                  p_from   DATE DEFAULT CURRENT_DATE - 365,
                  p_to     DATE DEFAULT CURRENT_DATE)
```

<Note>
  **Parameters, response columns and types are generated** from the SQL catalog and render
  under **Endpoints → Derivatives** in the sidebar. This page carries what a schema cannot.
</Note>

`p_from` and `p_to` are both **inclusive**.

### Field notes

Only the columns that need explaining:

| Field | What to know |
| - | - |
| `p_codneg` | The CODNEG exactly as B3 publishes it in COTAHIST for TPMERC `030`, e.g. `PETR4T`. Upper-cased and trimmed server-side. [`lookup`](/api-docs/lookup) does **not** resolve termo codes and no endpoint enumerates them, so you must already know it. Probing is safe: a code with no prints returns `200 []`, never a fabricated price. |
| `term_days` | COTAHIST `prazot`, the contract's term in days — **text**, as stored, not an integer. Part of the grain, same as `quotes.term_days`. |
| `currency` | Defaults to `R$` when the source leaves it blank. The only column on this endpoint where a value is supplied rather than published. |
| `quantity` | Exactly as COTAHIST publishes it — no lot normalisation. |
| `adjusted` | Always `false` on this forward endpoint. |
| `market`, `board` | Original TPMERC and CODBDI codes; keep both as source identity. |
| `contract_price`, `contract_expiry` | PREEXE and DATVEN, the secondary-forward contract value and maturity as published; not yield or credit spread. |
| `contract_correction` | INDOPC source code; the catalog carries a dated reference. Unknown descriptions remain null. |
| `contract_points`, `contract_points_raw` | PTOEXE decoded with six implied decimals, and its original text. Zero filler or unreadable points decode to null; the raw text survives. |
| `distribution_number` | DISMES sequence code, not a dividend amount. |
| `fetched_at` | Warehouse timestamp, not a historical source-publication vintage. |

Source-field provenance for the price columns, since the names differ from B3's:
`spec` ← `especi`, `bid` ← `oferta_compra`, `ask` ← `oferta_venda`, `trades` ← `negocios`,
`quantity` ← `quantidade`, `quotation_factor` ← `fator_cotacao`. Every COTAHIST field is
defined on the [COTAHIST dictionary](/api-docs/cotahist-dictionary).

Rows are ordered by `trade_date`, then `term_days` shortest-first — sorted by length and then
as text, so `30` precedes `60` precedes `120` without a numeric cast that could fail on
malformed source data.

### Example

<CodeGroup>
  ```bash curl theme={null}
  curl -s -X POST "$SILO_URL/rpc/termo_history" \
    -H "apikey: $SILO_ANON_KEY" \
    -H "Authorization: Bearer $SILO_ANON_KEY" \
    -H "Content-Type: application/json" \
    -d '{"p_codneg":"PETR4T","p_from":"2026-08-01","p_to":"2026-08-26"}'
  ```

  ```python Python theme={null}
  import pandas as pd

  body = {"p_codneg": "PETR4T", "p_from": "2026-08-01", "p_to": "2026-08-26"}
  rows = requests.post(f"{URL}/rpc/termo_history", headers=H, json=body).json()

  # term_days is part of the key — index on it, don't collapse it away.
  df = pd.DataFrame(rows).set_index(["trade_date", "market", "board", "term_days"])
  ```

  ```javascript JavaScript theme={null}
  const { data } = await supabase.rpc('termo_history', {
    p_codneg: 'PETR4T',
    p_from: '2026-08-01',
    p_to: '2026-08-26',
  })
  ```
</CodeGroup>

```json theme={null}
[
  { "codneg": "PETR4T", "trade_date": "2026-08-26", "term_days": "30",
    "spec": "PN", "currency": "R$", "open": 41.0, "high": 41.5, "low": 40.8,
    "average": 41.2, "close": 41.3, "bid": 41.2, "ask": 41.4,
    "trades": 12, "quantity": 5000, "volume": 206500.0,
    "isin": "BRPETRACNPR6", "quotation_factor": 1,
    "adjusted": false, "source": "b3_cotahist" },
  { "codneg": "PETR4T", "trade_date": "2026-08-26", "term_days": "60",
    "spec": "PN", "currency": "R$", "open": 41.5, "high": 42.0, "low": 41.3,
    "average": 41.7, "close": 41.8, "bid": 41.7, "ask": 41.9,
    "trades": 8, "quantity": 3000, "volume": 125400.0,
    "isin": "BRPETRACNPR6", "quotation_factor": 1,
    "adjusted": false, "source": "b3_cotahist" }
]
```

<Warning>
  **One 1,000-row page, and it refuses above it.** A wider window raises SQLSTATE `22023`
  naming the function — never a truncated series. Because several terms can print per
  session, a busy code reaches the page faster than a cash ticker: roughly
  1,000 ÷ (terms per session) sessions.

  `termo_history` has **no cursor**: narrow `p_from` / `p_to` and call again. A term series
  over a page is a sign the window is too wide, not something to walk.
</Warning>

***

## Termo in `panel`

[`panel`](/api-docs/panel) accepts termo codnegs for `close` and `volume`, as `id_type`
`termo` / `asset_class` `derivative`. But a panel row is one value per `(id, date, metric)`,
and termo's real grain has `term_days` in it — so when several terms print in one session the
panel keeps the **shortest term** and drops the rest, rather than averaging them into a
number nobody quoted. That is a deliberate narrowing, and it is why the full grain lives
here: for anything term-aware, use `termo_history`, not `panel`.

`close_return` is not offered for termo (or for options) — it accepts `ticker` ids only.

## Prices are raw

No split, dividend, or corporate-action adjustment anywhere in this warehouse; `adjusted` is
a constant `false`. If you need returns, difference `close` yourself, and be aware that a
corporate action in the window will show up as a large move that is not a return.

## Empty and error behavior

* **Unknown code → `200 []`.** Never a fabricated price.
* **Known code, no prints in the window** → also `200 []`. Termo is thin; a code can go days
  without a print, and a quiet window is indistinguishable from a wrong code. Check
  [`coverage`](/api-docs/coverage)'s `derivatives` row for what the warehouse actually holds.
* A malformed date returns `400`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.