Strasmore Research
Aprendizado Matt ConnorPor Matt Connor · Atualizado 2026-07-23

como calcular retorno mensal de ações

Entenda como o cálculo do retorno mensal de um ticker depende da escolha dos preços, do ajuste de dividendos e da correção por splits na série histórica.

Se você perguntar o que uma ação "fez em junho", receberá números diferentes de fontes distintas — todos corretos. O retorno mensal de uma ação é definido por escolhas que a maioria das pessoas não vê: quais dois preços marcam os limites do mês, se os dividendos são contados e se a série de preços foi ajustada para splits. Esta página executa as convenções conflitantes sobre os dados reais, lado a lado, para que as diferenças deixem de ser misteriosas.

Close-to-close: a convenção padrão

A convenção utilizada por provedores de índices, lâminas de fundos e a maioria das páginas de cotações: o retorno do mês parte do fechamento da última sessão regular do mês anterior até o fechamento final deste mês. O último fechamento de maio é o ponto de partida para junho. O cálculo é simples: preço final menos preço inicial, dividido pelo preço inicial. Um exemplo didático: uma ação que fecha maio a $50,00 e fecha junho a $53,50 rendeu (53,50 − 50,00) ÷ 50,00 = 0,07, ou 7%, no mês. Cada convenção nesta página utiliza inputs diferentes para a mesma fórmula. Veja o caso real de junho de 2026, ao lado da principal alternativa:

QueryJunho de 2026 medido de duas formas — close-to-close vs open-to-close, NVDA e SPY
O SQL exato por trás de cada número
SELECT ticker,
       round(argMaxIf(cl, day, day <= '2026-05-31'), 2) AS may_final_close,
       round(argMinIf(op, day, day >= '2026-06-01'), 2) AS june_first_open,
       round(argMaxIf(cl, day, day <= '2026-06-30'), 2) AS june_final_close,
       round(100 * (argMaxIf(cl, day, day <= '2026-06-30') - argMaxIf(cl, day, day <= '2026-05-31'))
             / argMaxIf(cl, day, day <= '2026-05-31'), 2) AS close_to_close_pct,
       round(100 * (argMaxIf(cl, day, day <= '2026-06-30') - argMinIf(op, day, day >= '2026-06-01'))
             / argMinIf(op, day, day >= '2026-06-01'), 2) AS open_to_close_pct,
       round(abs(100 * (argMaxIf(cl, day, day <= '2026-06-30') - argMinIf(op, day, day >= '2026-06-01'))
                 / argMinIf(op, day, day >= '2026-06-01')
             - 100 * (argMaxIf(cl, day, day <= '2026-06-30') - argMaxIf(cl, day, day <= '2026-05-31'))
                 / argMaxIf(cl, day, day <= '2026-05-31')), 2) AS convention_gap_points
FROM (
    SELECT ticker,
               toDate(toTimeZone(window_start, 'America/New_York')) AS day,
               argMinIf(toFloat64(open), window_start, rth) AS op,
               argMaxIf(toFloat64(close), window_start, rth) AS cl
        FROM (
            SELECT ticker, window_start, open, close,
                   toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
                   AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York') AS rth
            FROM global_markets.delayed_stocks_minute_aggs
            WHERE ticker IN ('NVDA', 'SPY')
              AND window_start >= '2026-05-28 04:00:00'
              AND window_start < '2026-07-01 08:00:00'
        )
        GROUP BY ticker, day
)
GROUP BY ticker
ORDER BY ticker

O mês de junho da NVDA foi de -5.39% close-to-close — mas de -7.4% medido da primeira abertura da sessão regular de junho até o seu último fechamento. Mesma ação, mesmo mês, 2.01 pontos percentuais de diferença entre as duas respostas corretas. A diferença total é apenas o intervalo entre o fechamento e a abertura (overnight + fim de semana): a NVDA fechou maio a $211.15 e abriu junho a $215.73 — esse salto pertence a "junho" na convenção open-to-close e ao limite de transição no close-to-close. O SPY apresenta a mesma estrutura de forma mais suave: -1.33% close-to-close contra -1.2% open-to-close.

Nenhum dos números está errado. O close-to-close responde "o que um investidor que manteve a posição experimentou durante a transição do mês?". O open-to-close responde "o que o trading do próprio mês entregou para quem comprou na abertura de junho?". Eles divergem sempre que o mercado apresenta gaps na transição — e gaps de overnight são rotina, não exceção.

Dividends: price return vs total return

The second choice: does the cash a stock paid out during the month count? A price return ignores it; a total return adds it back. For most single months the gap is small — a quarterly payer distributes roughly a quarter of its yield per quarter — but it compounds into a chasm over years, and June 2026 happened to be an SPY payment month:

QuerySPY Junho de 2026 — price return vs total return (incluindo ex-dividend de junho)
O SQL exato por trás de cada número
WITH px AS (
    SELECT argMaxIf(cl, day, day <= '2026-05-31') AS may_close,
           argMaxIf(cl, day, day <= '2026-06-30') AS jun_close
    FROM (
        SELECT ticker,
               toDate(toTimeZone(window_start, 'America/New_York')) AS day,
               argMinIf(toFloat64(open), window_start, rth) AS op,
               argMaxIf(toFloat64(close), window_start, rth) AS cl
        FROM (
            SELECT ticker, window_start, open, close,
                   toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
                   AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York') AS rth
            FROM global_markets.delayed_stocks_minute_aggs
            WHERE ticker IN ('NVDA', 'SPY')
              AND window_start >= '2026-05-28 04:00:00'
              AND window_start < '2026-07-01 08:00:00'
        )
        GROUP BY ticker, day
    )
    WHERE ticker = 'SPY'
),
dv AS (
    SELECT sum(cash_amount) AS div_per_share
    FROM global_markets.stocks_dividends
    WHERE ticker = 'SPY'
      AND ex_dividend_date >= '2026-06-01'
      AND ex_dividend_date <= '2026-06-30'
)
SELECT round(may_close, 2) AS may_final_close,
       round(jun_close, 2) AS june_final_close,
       round(div_per_share, 4) AS june_dividend_per_share,
       round(100 * (jun_close - may_close) / may_close, 2) AS price_return_pct,
       round(100 * div_per_share / may_close, 2) AS dividend_contribution_pct,
       round(100 * ((jun_close + div_per_share) - may_close) / may_close, 2) AS total_return_pct
FROM px CROSS JOIN dv

SPY's June price return was -1.33%; add the $1.9035 per-share distribution that went ex-dividend during the month and the total return improves to -1.08% — a 0.25% contribution from cash. Index families publish both flavors (the "S&P 500" you see quoted is usually the price index), fund performance pages are required to show total return, and screeners mix the two freely. When two sources disagree by a few tenths on a dividend payer's month, the dividend is the first suspect — the ex-dividend date determines which month a payment belongs to.

A single June is tenths of a percent. Horizon is what separates the two conventions — here is the same arithmetic stretched across five years:

QuerySPY em cinco anos, junho de 2021 a junho de 2026 — price return vs return com dividendos
O SQL exato por trás de cada número
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS day,
           argMaxIf(toFloat64(close), window_start,
               toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
               AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York')) AS cl
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND ((window_start >= '2021-06-28 04:00:00' AND window_start < '2021-07-01 08:00:00')
        OR (window_start >= '2026-06-26 04:00:00' AND window_start < '2026-07-01 08:00:00'))
    GROUP BY day
),
px AS (
    SELECT argMaxIf(cl, day, day <= '2021-06-30') AS start_close,
           argMaxIf(cl, day, day <= '2026-06-30') AS end_close
    FROM daily
),
dv AS (
    SELECT round(sum(cash_amount), 2) AS divs_per_share,
           count() AS payments
    FROM global_markets.stocks_dividends
    WHERE ticker = 'SPY'
      AND ex_dividend_date >= '2021-07-01'
      AND ex_dividend_date <= '2026-06-30'
)
SELECT round(start_close, 2) AS june_2021_close,
       round(end_close, 2) AS june_2026_close,
       divs_per_share AS dividends_paid_per_share,
       payments AS dividend_payments,
       round(100 * (end_close - start_close) / start_close, 2) AS five_year_price_return_pct,
       round(100 * ((end_close + divs_per_share) - start_close) / start_close, 2) AS five_year_return_with_divs_pct,
       round(100 * divs_per_share / start_close, 2) AS dividend_points_added
FROM px CROSS JOIN dv

From its June 2021 close of $428.07 to its June 2026 close of $746.32, SPY's five-year price return measures 74.35%. Over the same span it paid 20 distributions totaling $34.07 per share; counting that cash lifts the figure to 82.3% — 7.96 points of gap before a single dividend is reinvested. A true total-return index reinvests each payment on its ex-date, and the reinvested shares push the gap wider still. On a mature payer, "large margins" is not a figure of speech; it is the default outcome of years of quarterly cash.

Fechamento ajustado vs. fechamento bruto: a armadilha do split

A maioria das ferramentas de gráfico — Yahoo Finance, Google Finance e a maioria dos apps de corretoras — utiliza o fechamento ajustado: uma série histórica de preços onde os valores passados foram divididos por splits (e, em algumas plataformas, ajustados também por dividendos) para que a linha seja comparável ao longo do tempo. Nosso banco de dados armazena o tape conforme ele foi registrado. Em um mês comum, os dois valores coincidem. Em um mês com split de ações, eles apresentam resultados completamente diferentes — como o split de dez para um da NVDA, executado em 10 de junho de 2024, dentro do mês:

QueryNVDA Junho de 2024 — cálculo raw close-to-close vs return ajustado pelo split
O SQL exato por trás de cada número
WITH px AS (
    SELECT argMaxIf(cl, day, day <= '2024-05-31') AS may_close,
           argMaxIf(cl, day, day <= '2024-06-30') AS jun_close
    FROM (
        SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS day,
               argMaxIf(toFloat64(close), window_start,
                   toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
                   AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York')) AS cl
        FROM global_markets.delayed_stocks_minute_aggs
        WHERE ticker = 'NVDA'
          AND window_start >= '2024-05-29 04:00:00'
          AND window_start < '2024-07-01 08:00:00'
        GROUP BY day
    )
),
sp AS (
    SELECT split_to / split_from AS ratio
    FROM global_markets.stocks_splits
    WHERE ticker = 'NVDA'
      AND execution_date >= '2024-06-01'
      AND execution_date <= '2024-06-30'
)
SELECT round(may_close, 2) AS may_final_close_raw,
       round(jun_close, 2) AS june_final_close_raw,
       toInt32(ratio) AS shares_after_split_per_old_share,
       round(100 * (jun_close - may_close) / may_close, 2) AS raw_price_change_pct,
       round(may_close / ratio, 2) AS may_close_split_adjusted,
       round(100 * (jun_close - may_close / ratio) / (may_close / ratio), 2) AS adjusted_return_pct
FROM px CROSS JOIN sp

Lendo o valor bruto, a NVDA "caiu" de $1097.46 para $123.41 naquele mês de junho — um colapso de -88.75%. Nada disso ocorreu: na data de execução, cada ação antiga tornou-se 10 novas e o preço foi dividido proporcionalmente, mantendo o valor em dólar de cada investidor. Dividindo o fechamento de maio pela mesma proporção — $109.75 em base ajustada — o mês de junho de 2024 registra 12.45%, um mês de alta. Qualquer fonte que cite dados ajustados reportará algo próximo ao segundo valor; um cálculo ingênuo sobre os preços brutos reportará o primeiro. O fechamento ajustado é o motivo mais comum para duas fontes divergirem drasticamente sobre um retorno mensal histórico — quando um número parecer impossivelmente grande em qualquer direção, verifique o calendário de splits antes de qualquer outra coisa.

Qual "fechamento" é o correto?

Uma outra fronteira reside nas convenções: o próprio preço de fechamento. O número utilizado em todos os fatos relevantes é o preço oficial do leilão de fechamento — o valor único definido pelo leilão de fechamento às 16:00 ET. No entanto, as negociações continuam após o horário regular, e a última cotação da sessão estendida pode divergir do fechamento oficial:

QuerySPY em 30 de junho de 2026 — official-close vs o print final do extended-hours
O SQL exato por trás de cada número
SELECT round(argMaxIf(toFloat64(close), window_start, rth), 2) AS regular_session_close,
       round(argMax(toFloat64(close), window_start), 2) AS last_extended_print,
       round(100 * (argMax(toFloat64(close), window_start) - argMaxIf(toFloat64(close), window_start, rth))
             / argMaxIf(toFloat64(close), window_start, rth), 3) AS after_hours_drift_pct
FROM (
    SELECT window_start, close,
           toTimeZone(window_start, 'America/New_York') >= toDateTime('2026-06-30 09:30:00', 'America/New_York')
           AND toTimeZone(window_start, 'America/New_York') < toDateTime('2026-06-30 16:00:00', 'America/New_York') AS rth
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= '2026-06-30 04:00:00'
      AND window_start < '2026-07-01 08:00:00'
)

Em 30 de junho, os dois divergiram em -0.003% — um valor pequeno naquela noite, mas em uma noite de divulgação de resultados de uma única ação, a sessão estendida pode apresentar variações em escala percentual que o retorno mensal oficial atribuirá ao próximo mês. Negociações after-hours e premarket detalha essa fronteira. Um caso limítrofe relacionado: os limites mensais ocasionalmente coincidem com sessões encurtadas por feriados, onde o pregão regular termina às 13:00 ET e o fechamento oficial ocorre em um leilão de fechamento antecipado — o calendário de feriados do mercado lista essas datas.

Capitalização de doze meses em um ano

O retorno anual não é a soma de doze retornos mensais — é o seu produto. A fórmula de ligação: converta cada mês em um fator de crescimento (1 + retorno), multiplique os doze fatores entre si e subtraia 1. Um mês de −5% seguido por um mês de +5% soma zero, mas o resultado composto é 0,95 × 1,05 − 1 = −0,25%. Aqui está o caminho mensal real do SPY nos doze meses encerrados em junho de 2026:

QueryRetornos mensais close-to-close do SPY — doze meses encerrados em junho de 2026, simples e log
O SQL exato por trás de cada número
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS day,
           argMaxIf(toFloat64(close), window_start,
               toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
               AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York')) AS cl
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= '2025-06-24 04:00:00'
      AND window_start < '2026-07-01 08:00:00'
    GROUP BY day
),
monthly AS (
    SELECT toStartOfMonth(day) AS month_start,
           argMax(cl, day) AS month_close
    FROM daily
    GROUP BY month_start
),
rets AS (
    SELECT month_start,
           formatDateTime(month_start, '%Y-%m') AS month,
           round(month_close, 2) AS month_final_close,
           100 * (month_close / lagInFrame(month_close) OVER (ORDER BY month_start) - 1) AS r
    FROM monthly
)
SELECT month,
       month_final_close,
       round(r, 2) AS simple_return_pct,
       round(100 * log(1 + r / 100), 2) AS log_return_pct
FROM rets
WHERE isFinite(r)
ORDER BY month_start

Doze meses de fechamento a fechamento, de 2.28% em 2025-07 a -1.33% em 2026-06 — a última linha é o mesmo valor do SPY em junho de 2026 medido no primeiro painel. Conecte os doze meses corretamente e compare com o atalho de apenas somar as porcentagens:

QuerySoma vs compounding — doze retornos mensais do SPY calculados de três formas
O SQL exato por trás de cada número
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS day,
           argMaxIf(toFloat64(close), window_start,
               toTimeZone(window_start, 'America/New_York') >= toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 09:30:00'), 'America/New_York')
               AND toTimeZone(window_start, 'America/New_York') < toDateTime(concat(toString(toDate(toTimeZone(window_start, 'America/New_York'))), ' 16:00:00'), 'America/New_York')) AS cl
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= '2025-06-24 04:00:00'
      AND window_start < '2026-07-01 08:00:00'
    GROUP BY day
),
monthly AS (
    SELECT toStartOfMonth(day) AS month_start,
           argMax(cl, day) AS month_close
    FROM daily
    GROUP BY month_start
),
rets AS (
    SELECT month_start,
           100 * (month_close / lagInFrame(month_close) OVER (ORDER BY month_start) - 1) AS r
    FROM monthly
),
ends AS (
    SELECT argMin(month_close, month_start) AS base_close,
           argMax(month_close, month_start) AS final_close
    FROM monthly
)
SELECT count() AS months_linked,
       round(sum(r), 2) AS simple_sum_pct,
       round(100 * (exp(sum(log(1 + r / 100))) - 1), 2) AS geometric_compound_pct,
       round(100 * (any(final_close) / any(base_close) - 1), 2) AS direct_twelve_month_pct,
       round(100 * (exp(sum(log(1 + r / 100))) - 1) - sum(r), 2) AS compounding_gap_points,
       round(sum(100 * log(1 + r / 100)), 2) AS sum_of_monthly_log_returns_pct,
       round(100 * log(any(final_close) / any(base_close)), 2) AS twelve_month_log_return_pct
FROM rets CROSS JOIN ends
WHERE isFinite(r)

Os doze meses somam 19.83%, mas o resultado composto é 20.79% — e o cálculo direto, do fechamento de junho de 2025 ao de junho de 2026, resulta em 20.79%, coincidindo com o valor composto em vez da soma. A diferença aqui é de 0.96 pontos em um ano relativamente calmo; o gap aumenta com a volatilidade e o horizonte temporal. Somar porcentagens mensais é um hábito comum em planilhas, mas está tecnicamente incorreto.

As duas últimas colunas mostram a convenção construída para soma: o log return, o logaritmo natural do fator de crescimento, ln(1 + retorno). Os log returns mensais somam 18.89% — idênticos ao log return de doze meses de 18.89%, que é exatamente o motivo pelo qual analistas e modelos de risco os utilizam. Para meses com retornos pequenos, as duas convenções mal diferem (2025-11: 0.21% simples, 0.21% log); quanto maior o mês, maior a divergência (2026-04: 10.49% simples, 9.97% log). Lâminas de fundos citam retornos simples; log returns são usados em artigos de pesquisa e cálculos de volatilidade.

O checklist que reconcilia quaisquer duas fontes

Quando dois números de retorno mensal divergem, quase sempre a diferença ocorre em um destes quatro critérios:

  1. Endpoints — close-to-close (o padrão) ou open-to-close (o trading do próprio mês). Diferentes sempre que houver um gap na abertura ou no fechamento.
  2. Dividends — price return ou total return. Diferentes em qualquer mês que contenha uma data ex-dividend.
  3. Adjustment — preços brutos ou série de adjusted-close. Muito diferentes em qualquer mês que contenha um split.
  4. O próprio fechamento — print oficial do leilão (o padrão) versus a última negociação, que pode incluir o extended hours.

Aplique os mesmos critérios em ambas as fontes e a divergência desaparece — uma comparação entre fundo e índice só é válida quando ambos utilizam as mesmas quatro configurações; se houver erro em uma delas, a comparação medirá o critério em vez da performance. Nosso próprio resumo de junho de 2026 declara sua convenção antecipadamente justamente por este motivo — todos os números mensais ali são close-to-close, prints oficiais e price return.

FAQ de retornos mensais

O que é o retorno close-to-close?

A variação percentual entre o preço de fechamento da sessão regular do período anterior e o fechamento final deste período. É a convenção padrão para retornos diários, mensais e anuais de ações em fact sheets e relatórios de índices.

Por que dois sites mostram retornos diferentes para a mesma ação e mês?

Quase sempre devido a uma de quatro convenções: diferentes pontos de referência (close-to-close vs open-to-close), contagem ou não de dividendos, preços brutos versus ajustados por split, ou uma fonte de preço de fechamento diferente. As medidas de junho de 2026 da NVDA apresentam -5.39% ou -7.4% apenas na primeira mudança.

Um split de ações altera o cálculo do retorno mensal?

Não deveria — um split altera o número de ações e o preço simultaneamente, mantendo o valor da posição inalterado — mas ele compromete qualquer cálculo feito sobre preços brutos. O período de junho de 2024 da NVDA apresenta -88.75% em fechamentos brutos e mede 12.45% após o ajuste do split de dez para um.

Os retornos mensais de ações incluem dividendos?

Apenas os total returns incluem. Os retornos de preço — incluindo o nível principal do índice S&P 500 — os excluem. Em junho de 2026, o dividendo adicionou 0.25% ao mês do SPY, a diferença entre seu preço e o total return.

O retorno mensal da minha carteira pessoal é calculado da mesma forma?

Não quando há movimentação de caixa (entradas ou saídas). Retornos de ativos individuais como os desta página são ponderados pelo tempo (time-weighted); uma conta com depósitos e saques precisa de um cálculo ponderado pelo capital (taxa interna de retorno), caso contrário, os fluxos de caixa mascaram a performance. A maioria das corretoras reporta um valor ponderado pelo tempo justamente para excluir seus depósitos do número final.


Cada dado acima é uma consulta armazenada e versionada do tape real — expanda o SQL de qualquer painel ou meça o mês de qualquer ticker sob qualquer convenção no terminal Strasmore.

#returns#conventions#dividends#splits#education