Strasmore Research
Learn am Matt ConnorBy Matt Connor · Updated 2026-08-08 · data as of August 8, 2026 · refreshed weekly

How to Calculate Portfolio Dividend Yield

Learn how to calculate portfolio dividend yield with total annual income divided by market value, and why yield-column average fit mislead you.

Portfolio dividend yield na one number: total annual dividend income wey all your holdings dey expected to pay, divided by total market value of those holdings. Another way to write am be market-value-weighted average of each holding’s yield. Each holding’s weight na its dollar value as fraction of the whole portfolio. The average of the yield column for brokerage screen na different number. For most real portfolios, na that one dey make the result look better.

How to calculate portfolio dividend yield

For each position, multiply shares by annual dividend per share. That one give you the position’s annual income in dollars. Add all the incomes together. Divide am by the sum of shares multiplied by price across every position, then multiply by 100. Na the complete calculation, whether na four holdings or forty.

You fit write am in two equivalent ways:

  • Total annual income divided by total portfolio market value.
  • The sum across holdings of weight multiplied by yield, where weight na position value divided by portfolio value.

The second form show where simple average dey fail. Every holding appear for both versions, but for the correct one, each holding carry the weight of its dollars, instead of getting one vote each. If you count cash as part of the portfolio, e belong inside the denominator too. If you leave am out, the printed yield go rise without adding even one cent of income. For the arithmetic of one stock, start with how to calculate dividend yield.

Why averaging the yield column overstates your income

The difference between both methods dey easiest to see with worked example. The script below na plain Python 3, and e no import anything. Any machine wey get python3 fit run am. The five positions na hypothetical round numbers wey make the effect clear: name, share count, price, and annual dividend per share.

#!/usr/bin/env python3
# each row: (name, shares, price, annual dividend per share)
holdings = [
    ('A', 200,  50.00, 1.50),
    ('B', 150, 100.00, 2.00),
    ('C', 100,  80.00, 0.80),
    ('D', 300,  20.00, 1.00),
    ('E', 100,  10.00, 0.90),
]

total_value  = sum(sh * px for _, sh, px, _ in holdings)
total_income = sum(sh * dps for _, sh, _, dps in holdings)
naive        = sum(100 * dps / px for _, _, px, dps in holdings) / len(holdings)

print(f'market value      : ${total_value:,.2f}')
print(f'annual income     : ${total_income:,.2f}')
print(f'portfolio yield   : {100 * total_income / total_value:.2f}%')
print(f'average of yields : {naive:.2f}%')

for name, sh, px, dps in holdings:
    value = sh * px
    income = sh * dps
    print(
        f'{name}  weight {100 * value / total_value:5.1f}%'
        f'  yield {100 * dps / px:5.2f}%'
        f'  income ${income:8,.2f}'
        f'  share of income {100 * income / total_income:5.1f}%'
    )

Run am, and the two headline lines go disagree sharply. The portfolio hold $40,000 of stock and pay $1,070 per year, giving weighted yield of 2.68%. The simple average of the five yield figures print 4.00%, roughly one and a half times higher.

Position E na the main reason. E yield 9.00%, the highest for the book, on $1,000 of stock. That one na 2.5% of the portfolio value and 8.4% of the income. For simple average, e get one-fifth of the vote, same as the $15,000 position beside am. Yield figure only get meaning when you attach the dollars wey dey behind am.

What weighting looks like across real holdings

Household dividend payers dey cover wide range of yields. Na why the choice of weighting matter. The panel below calculate each name’s trailing yield from declared dividends per share for the last twelve months, divided by the most recent daily close.

QueryTrailing 12-month dividend yield across ten household payers
The exact SQL behind every number
WITH
    last_px AS
    (
        SELECT
            ticker,
            toFloat64(argMax(close, date))         AS px,
            formatDateTime(max(date), '%b %e, %Y') AS priced_through
        FROM global_markets.stocks_daily_aggs
        WHERE ticker IN ('AAPL', 'MSFT', 'HD', 'KO', 'PG', 'PEP', 'JNJ', 'XOM', 'CVX', 'VZ')
          AND date >= today() - 30
        GROUP BY ticker
    ),
    ttm_dps AS
    (
        SELECT
            ticker,
            sum(amount) AS dps
        FROM
        (
            SELECT
                ticker,
                id,
                toFloat64(any(cash_amount)) AS amount
            FROM global_markets.stocks_dividends
            WHERE ticker IN ('AAPL', 'MSFT', 'HD', 'KO', 'PG', 'PEP', 'JNJ', 'XOM', 'CVX', 'VZ')
              AND ex_dividend_date >  today() - 365
              AND ex_dividend_date <= today()
            GROUP BY ticker, id
        )
        GROUP BY ticker
    )
SELECT
    p.ticker                     AS symbol,
    round(d.dps, 2)              AS ttm_dividend_usd,
    round(100 * d.dps / p.px, 2) AS yield_pct,
    p.priced_through             AS priced_through
FROM last_px AS p
INNER JOIN ttm_dps AS d ON d.ticker = p.ticker
ORDER BY yield_pct DESC
Run this yourself

Across these 10 names, priced through Aug 7, 2026, yields range from 5.96% at VZ down to 0.34% at AAPL. Portfolio wey you build from spread like this one no go land near the midpoint of the column unless the positions happen to be equal in dollar value.

Now put five of them inside portfolio with fixed share counts. Read two numbers side by side: each holding’s share of market value and its share of annual income.

QueryA five-name portfolio: share of value against share of income
The exact SQL behind every number
WITH
    positions AS
    (
        SELECT
            tupleElement(p, 1)            AS ticker,
            toFloat64(tupleElement(p, 2)) AS shares
        FROM
        (
            SELECT arrayJoin([('MSFT', 30.), ('PG', 60.), ('XOM', 80.), ('KO', 100.), ('VZ', 60.)]) AS p
        )
    ),
    last_px AS
    (
        SELECT
            ticker,
            toFloat64(argMax(close, date)) AS px
        FROM global_markets.stocks_daily_aggs
        WHERE ticker IN ('MSFT', 'PG', 'XOM', 'KO', 'VZ')
          AND date >= today() - 30
        GROUP BY ticker
    ),
    ttm_dps AS
    (
        SELECT
            ticker,
            sum(amount) AS dps
        FROM
        (
            SELECT
                ticker,
                id,
                toFloat64(any(cash_amount)) AS amount
            FROM global_markets.stocks_dividends
            WHERE ticker IN ('MSFT', 'PG', 'XOM', 'KO', 'VZ')
              AND ex_dividend_date >  today() - 365
              AND ex_dividend_date <= today()
            GROUP BY ticker, id
        )
        GROUP BY ticker
    ),
    holding AS
    (
        SELECT
            pos.ticker         AS ticker,
            pos.shares * lp.px AS value_usd,
            pos.shares * d.dps AS income_usd
        FROM positions AS pos
        INNER JOIN last_px AS lp ON lp.ticker = pos.ticker
        INNER JOIN ttm_dps AS d  ON d.ticker  = pos.ticker
    )
SELECT
    h.ticker                                      AS symbol,
    round(100 * h.value_usd  / t.total_value,  1) AS weight_pct,
    round(100 * h.income_usd / t.total_income, 1) AS income_share_pct,
    round(100 * h.income_usd / h.value_usd,    2) AS yield_pct
FROM holding AS h
CROSS JOIN
(
    SELECT
        sum(value_usd)  AS total_value,
        sum(income_usd) AS total_income
    FROM holding
) AS t
ORDER BY weight_pct DESC
Run this yourself

The script pattern repeat with live prices. MSFT na the biggest position at 31.4% of market value, while e supply 10% of the income, with yield of 0.72%. For the other end, VZ hold 5.9% of the value and pay 15.7% of the income, with 5.96%. Weight and income share go separate whenever yields differ.

If you average the two ways, the same five holdings give two different answers.

QueryTwo averages of the same five holdings
The exact SQL behind every number
WITH
    positions AS
    (
        SELECT
            tupleElement(p, 1)            AS ticker,
            toFloat64(tupleElement(p, 2)) AS shares
        FROM
        (
            SELECT arrayJoin([('MSFT', 30.), ('PG', 60.), ('XOM', 80.), ('KO', 100.), ('VZ', 60.)]) AS p
        )
    ),
    last_px AS
    (
        SELECT
            ticker,
            toFloat64(argMax(close, date)) AS px
        FROM global_markets.stocks_daily_aggs
        WHERE ticker IN ('MSFT', 'PG', 'XOM', 'KO', 'VZ')
          AND date >= today() - 30
        GROUP BY ticker
    ),
    ttm_dps AS
    (
        SELECT
            ticker,
            sum(amount) AS dps
        FROM
        (
            SELECT
                ticker,
                id,
                toFloat64(any(cash_amount)) AS amount
            FROM global_markets.stocks_dividends
            WHERE ticker IN ('MSFT', 'PG', 'XOM', 'KO', 'VZ')
              AND ex_dividend_date >  today() - 365
              AND ex_dividend_date <= today()
            GROUP BY ticker, id
        )
        GROUP BY ticker
    ),
    holding AS
    (
        SELECT
            pos.shares * lp.px AS value_usd,
            pos.shares * d.dps AS income_usd
        FROM positions AS pos
        INNER JOIN last_px AS lp ON lp.ticker = pos.ticker
        INNER JOIN ttm_dps AS d  ON d.ticker  = pos.ticker
    )
SELECT
    tupleElement(m, 1)           AS method,
    round(tupleElement(m, 2), 2) AS yield_pct
FROM
(
    SELECT arrayJoin([
        ('Market-value weighted portfolio yield', weighted_yield),
        ('Simple average of the five yields',     naive_yield)
    ]) AS m
    FROM
    (
        SELECT
            100 * sum(income_usd) / sum(value_usd) AS weighted_yield,
            avg(100 * income_usd / value_usd)      AS naive_yield
        FROM holding
    )
)
ORDER BY yield_pct DESC
Run this yourself

The higher line, at 2.93%, na the Simple average of the five yields figure. The other one print 2.24%. Only one of them connect to actual cash. Multiply the weighted figure by portfolio market value and you recover the annual income. Do the same with simple average and you get number wey no statement go ever show. The direction get structural reason: when higher-yielding names na smaller positions, simple average dey above the true portfolio yield. When high yielders na the big positions, e dey below.

Yield on cost is not portfolio yield

Yield on cost divide current annual dividend by the price wey you pay, not by what the position dey worth today. Position wey you buy at $20 and now dey trade at $80, while e still dey pay $1.00 per share each year, show yield on cost of 5.00% against current yield of 1.25%. The dividend na the same dollar amount. Na only denominator change.

Both numbers legitimate, but each one answer different question. Current market value for denominator tell you what the portfolio yield today. Na the figure wey you fit compare with a good dividend yield or Treasury bill. Cost basis for denominator tell you about purchase wey you make before. Problem start when people mix both inside one portfolio total: current yield for recent buys, yield on cost for holdings wey dem keep for ten years. That blend regularly double the apparent yield of income portfolio and no match anything broker report. Dividend yield traps cover the opposite illusion: yield wey print high after sharp price decline.

Trailing or forward inputs change the answer

Every figure above depend on which dividend number enter the numerator. Trailing yield sum the last twelve months of payments actually declared. Forward yield annualize the most recent payment, usually the latest quarterly amount multiplied by four. Both numbers disagree for any name wey change payout or pay special distribution during the year. One large holding alone fit move the portfolio total meaningfully. The panels here use trailing inputs. Trailing vs forward dividend yield explain when each one make sense.

The yield is a rate, the cash arrives in lumps

Weighted yield na annual rate, no be payment schedule. The same five positions pay across a few clustered months, because most US companies go ex-dividend quarterly and follow similar calendars.

QueryDividend income from the five-name portfolio, by month
The exact SQL behind every number
WITH
    positions AS
    (
        SELECT
            tupleElement(p, 1)            AS ticker,
            toFloat64(tupleElement(p, 2)) AS shares
        FROM
        (
            SELECT arrayJoin([('MSFT', 30.), ('PG', 60.), ('XOM', 80.), ('KO', 100.), ('VZ', 60.)]) AS p
        )
    ),
    payments AS
    (
        SELECT
            ticker,
            id,
            any(ex_dividend_date)       AS ex_date,
            toFloat64(any(cash_amount)) AS amount
        FROM global_markets.stocks_dividends
        WHERE ticker IN ('MSFT', 'PG', 'XOM', 'KO', 'VZ')
          AND ex_dividend_date >  today() - 365
          AND ex_dividend_date <= today()
        GROUP BY ticker, id
    )
SELECT
    formatDateTime(toStartOfMonth(pay.ex_date), '%Y-%m') AS month,
    formatDateTime(toStartOfMonth(pay.ex_date), '%b %Y') AS month_label,
    round(sum(pos.shares * pay.amount), 2)               AS income_usd
FROM payments AS pay
INNER JOIN positions AS pos ON pos.ticker = pay.ticker
GROUP BY month, month_label
ORDER BY month
Run this yourself

Cash enter 12 different months during the trailing year. The most recent one na Jul 2026, at $107.76. Portfolio yield of a few percent no tell you which month the money go show up. Na why income plan wey depend on monthly figure need calendar together with the rate. For the market-wide level wey people dey compare these portfolio numbers against, see the S&P 500 dividend yield.

FAQ

How do I calculate the dividend yield of my whole portfolio?

Add each holding’s annual dividend income together — shares multiplied by annual dividend per share. Add each holding’s market value together too — shares multiplied by price. Then divide total income by total value and multiply by 100. The result na market-value-weighted average of your holdings’ yields.

Why is the average of my holdings' yields higher than my portfolio yield?

Simple average give every position one vote. Portfolio yield give each position vote according to its dollar value. When the highest-yielding names na your smallest positions, simple average go land above the yield wey portfolio actually pay. Sometimes e fit be half again as high.

Does cash count in a portfolio dividend yield?

If you treat cash as part of the portfolio, e belong inside denominator with zero dividend, and e go reduce the yield. If you exclude am, you dey report the yield of invested sleeve only. Either method fit work, as long as you use the same one every time you measure.

Is yield on cost the same as my portfolio's yield?

No. Yield on cost divide today’s dividend by the price wey you pay years ago, so e dey rise whenever the stock price rise. Portfolio yield use current market value. Na that figure tie back to the income wey your current holdings generate.

Does adding one high-yield stock lift my portfolio yield much?

Only according to the dollars wey you put inside am. A 9% yielder held at 2.5% of the portfolio add roughly 0.2 percentage points to weighted yield — 0.09 multiplied by 0.025 — no matter how e affect the average of the yield column.


Every panel here carry the exact SQL wey produce am, so you fit audit the weighting line by line. To run the same calculation for your own list of names and share counts, ask for am in plain English on the Strasmore terminal.

#dividend yield#portfolio#weighted average#income#calculation