Pular para conteúdo

Interpolador

Classe interpoladora para interpolação de taxas de juros.

Parameters:

Name Type Description Default
dias_uteis ArrayLike

Sequência de dias úteis (DU) conhecidos.

required
taxas ArrayLike

Sequência de taxas de juros conhecidas.

required
metodo Literal['flat_forward', 'linear']

Método de interpolação a usar. Opções: "flat_forward" ou "linear".

required
extrapolar bool

Controla apenas o comportamento na ponta longa (DU acima do maior vértice conhecido). Se True, retorna a última taxa conhecida; se False (padrão), retorna NaN. A ponta curta (DU abaixo do menor vértice) sempre retorna a primeira taxa conhecida, independentemente desta flag.

False

Raises:

Type Description
ValueError

Se não houver ao menos um vértice válido na curva.

Notes
  • Esta classe usa convenção de 252 dias úteis por ano.
  • Instâncias desta classe são imutáveis. Para modificar as configurações de interpolação, crie uma nova instância.

Para um prazo alvo du, a classe encontra automaticamente os dois vértices conhecidos que o cercam: j é o anterior e k é o seguinte. O usuário informa apenas du; os índices j e k são detalhes internos.

No método "linear", a taxa é calculada por:

\[ tx_{du} = tx_j + \frac{(du - du_j)(tx_k - tx_j)}{du_k - du_j} \]

No método "flat_forward", definindo \(t = du/252\), \(t_x = du_x/252\), \(F_x = 1 + tx_x\), \(C_x = F_x^{t_x}\) e \(w = (t - t_j)/(t_k - t_j)\), a taxa é:

\[ tx_{du} = \left(C_j\left(\frac{C_k}{C_j}\right)^w\right)^{1/t} - 1 \]

A interpolação flat-forward interpola o fator acumulado entre os dois vértices e converte o resultado de volta para uma taxa no prazo alvo.

Examples:

>>> from pyield import Interpolador
>>> dus = [30, 60, 90]
>>> txs = [0.045, 0.05, 0.055]

Interpolação linear:

>>> linear = Interpolador(dus, txs, "linear")
>>> linear(45)
0.0475

Interpolação flat forward:

>>> flat_fwd = Interpolador(dus, txs, "flat_forward")
>>> flat_fwd(45)
0.04833068080970859
>>> print(flat_fwd(100))  # Extrapolação desabilitada por padrão
nan
>>> print(flat_fwd(-10))  # Entrada inválida retorna NaN
nan

Se extrapolação estiver habilitada, a última taxa conhecida é usada:

>>> flat_fwd_extrap = Interpolador(dus, txs, "flat_forward", extrapolar=True)
>>> flat_fwd_extrap(100)
0.055
Source code in pyield/interpolador.py
def __init__(
    self,
    dias_uteis: ArrayLike,
    taxas: ArrayLike,
    metodo: Literal["flat_forward", "linear"],
    extrapolar: bool = False,
):
    df = (
        pl.DataFrame({"dus": dias_uteis, "txs": taxas})
        .with_columns(pl.col("dus").cast(pl.Int64))
        .with_columns(pl.col("txs").cast(pl.Float64))
        .drop_nulls()
        .drop_nans()
        .unique(subset="dus", keep="last")
        .sort("dus")
    )
    if df.is_empty():
        raise ValueError("A curva deve conter ao menos um vértice válido.")
    self._df = df
    self._method = str(metodo)
    self._dus = tuple(df.get_column("dus"))
    self._txs = tuple(df.get_column("txs"))
    self._extrapolate = bool(extrapolar)

interpolar(du)

Interpola a taxa para um único dia útil.

Parameters:

Name Type Description Default
du int

DU escalar inteiro para interpolação.

required

Returns:

Type Description
float

Taxa interpolada como float. Retorna float("nan") quando o DU

float

for negativo ou estiver acima do maior vértice conhecido com

float

extrapolar=False. DU abaixo do menor vértice sempre retorna

float

a primeira taxa conhecida.

Raises:

Type Description
TypeError

Se du não for um inteiro.

Source code in pyield/interpolador.py
def interpolar(self, du: int) -> float:
    """Interpola a taxa para um único dia útil.

    Args:
        du: DU escalar inteiro para interpolação.

    Returns:
        Taxa interpolada como float. Retorna ``float("nan")`` quando o DU
        for negativo ou estiver acima do maior vértice conhecido com
        ``extrapolar=False``. DU abaixo do menor vértice sempre retorna
        a primeira taxa conhecida.

    Raises:
        TypeError: Se ``du`` não for um inteiro.
    """
    # Aceita qualquer tipo integral (int, np.int64, etc) e rejeita float/string.
    if not isinstance(du, numbers.Integral):
        raise TypeError("du deve ser int. Use interpolar_expr para coluna Polars.")
    return self._taxa_interpolada(int(du))

interpolar_expr(du)

Cria expressão Polars que interpola taxas para uma coluna de DU.

Útil para adicionar uma coluna de taxas interpoladas a um DataFrame via with_columns, compondo livremente com outras expressões Polars (ex.: cálculo de inflação implícita na mesma chamada). A curva e o método são os configurados na instância.

Parameters:

Name Type Description Default
du str | Expr

Nome de coluna ou expressão Polars com os DUs alvo. A coluna deve ser inteira (será convertida para Int64 internamente).

required

Returns:

Type Description
Expr

pl.Expr: Expressão Float64 sem alias com as taxas interpoladas. null quando o DU for nulo, negativo, ou estiver acima do maior vértice conhecido com extrapolar=False.

Examples:

>>> from pyield import Interpolador
>>> interp = Interpolador(
...     [30, 60, 90], [0.045, 0.05, 0.055], "flat_forward"
... )
>>> df = pl.DataFrame({"du": [15, 45, 75]})
>>> df.with_columns(taxa=interp.interpolar_expr("du"))
shape: (3, 2)
┌─────┬──────────┐
│ du  ┆ taxa     │
│ --- ┆ ---      │
│ i64 ┆ f64      │
╞═════╪══════════╡
│ 15  ┆ 0.045    │
│ 45  ┆ 0.048331 │
│ 75  ┆ 0.052997 │
└─────┴──────────┘
Source code in pyield/interpolador.py
def interpolar_expr(self, du: str | pl.Expr) -> pl.Expr:
    """Cria expressão Polars que interpola taxas para uma coluna de DU.

    Útil para adicionar uma coluna de taxas interpoladas a um DataFrame via
    ``with_columns``, compondo livremente com outras expressões Polars (ex.:
    cálculo de inflação implícita na mesma chamada). A curva e o método são
    os configurados na instância.

    Args:
        du: Nome de coluna ou expressão Polars com os DUs alvo. A coluna
            deve ser inteira (será convertida para Int64 internamente).

    Returns:
        pl.Expr: Expressão Float64 sem alias com as taxas interpoladas.
            ``null`` quando o DU for nulo, negativo, ou estiver acima do
            maior vértice conhecido com ``extrapolar=False``.

    Examples:
        >>> from pyield import Interpolador
        >>> interp = Interpolador(
        ...     [30, 60, 90], [0.045, 0.05, 0.055], "flat_forward"
        ... )
        >>> df = pl.DataFrame({"du": [15, 45, 75]})
        >>> df.with_columns(taxa=interp.interpolar_expr("du"))
        shape: (3, 2)
        ┌─────┬──────────┐
        │ du  ┆ taxa     │
        │ --- ┆ ---      │
        │ i64 ┆ f64      │
        ╞═════╪══════════╡
        │ 15  ┆ 0.045    │
        │ 45  ┆ 0.048331 │
        │ 75  ┆ 0.052997 │
        └─────┴──────────┘
    """
    expr = pl.col(du) if isinstance(du, str) else du
    return expr.map_batches(self._interpolar_serie, return_dtype=pl.Float64)