How every metric on Nkosuo is calculated.
Plain English where possible, formulas where helpful, and limitations called out honestly. Each user-facing metric on the site links back here via a “How calculated?” anchor.
Market (nominal) return
return = (endPrice − startPrice) / startPrice
The simple percentage change in price between two dates. 'Day change' uses end-of-day close vs previous close; horizon returns use close at horizon start vs latest close.
- • Close prices from the Ghana Stock Exchange
End-of-day after GSE session close.
No dividends reinvested. No fees or tax deducted.
Limitations: Total shareholder return differs — it adds reinvested dividends. For thinly traded names, prices may lag or flatline.
Worked example. If MTN Ghana closed at GHS 2.41 yesterday and GHS 2.45 today: (2.45 − 2.41) / 2.41 ≈ +1.66% day change.
Real (inflation-adjusted) return — Fisher equation
real = (1 + nominal) / (1 + inflation) − 1
The return after inflation erodes your purchasing power. For diaspora users we also layer in cedi depreciation against the target currency.
- • Nominal return (see above)
- • Ghana headline CPI — GSS / World Bank WDI
- • Cedi depreciation vs target currency — Bank of Ghana interbank rate
Inflation monthly; FX daily.
We use current CPI and 1-year cedi depreciation as first-order approximations for the portfolio's full holding period.
Limitations: Fisher is approximate for large returns. For multi-year horizons, the compounded exact identity is more accurate but we prefer the plain-English version.
Worked example. Nominal return 18%, inflation 17.8% → real GHS return (1.18 / 1.178) − 1 ≈ 0.17%.
FX-adjusted real return (diaspora view)
real_fx = (1 + nominal) / ((1 + inflation) × (1 + depreciation)) − 1
Sequential deflation by Ghana CPI and cedi depreciation against the target currency (USD / GBP / EUR).
- • Nominal return
- • Ghana CPI
- • Cedi depreciation vs target currency
Monthly.
Same-period deflation factors apply across the whole return period.
Limitations: Ignores cross-currency inflation differentials past Ghana. For a fuller picture a diaspora user should also deflate by their own local CPI.
Trailing dividend yield
yield = dividendPerShareTTM / currentPrice × 100
Trailing twelve-month declared dividend per share divided by today's price. Does not project future dividends.
- • DPS from issuer announcements and GSE notices
- • End-of-day price
Event-driven (issuer announcements).
Assumes latest declared DPS repeats; adjust if the board has signalled otherwise.
Limitations: Doesn't adjust for payout ratio sustainability. See the financial-health scorecard for that.
Market capitalisation
mcap = price × sharesOutstanding
Number of shares issued × latest price. 'Total listed market cap' sums this across tracked equities.
- • Shares outstanding from issuer filings
- • End-of-day price
Shares outstanding refreshed after every corporate action (rights, bonus, buyback). Price refreshed daily.
Assumes the share count is unchanged between updates.
Limitations: Free-float market cap is smaller than total cap; Nkosuo currently publishes total cap and flags free-float figures only when issuer discloses them.
Portfolio market value (user-entered)
value = Σ (quantityᵢ × currentPriceᵢ)
Sum of each lot's quantity multiplied by the latest end-of-day price.
- • User-entered quantity + cost basis
- • End-of-day prices
Whenever you add, edit, or delete a lot. Prices refresh daily.
Does not include fees, tax, or FX conversion. Based entirely on what you've entered.
Limitations: Nkosuo does not verify that the holdings exist at a broker. For the empty state, no values are computed.
Unrealised gain / loss
pl = (currentPrice − avgCostBasis) × quantity
Only for open positions. Realised P/L (from sales) is a Phase 2 addition.
- • Avg cost basis (user-entered)
- • Current price
Daily with price.
Weighted-average cost method.
Limitations: No tax or commission adjustments.
Benchmark comparison — vs GSE-CI
outperformance = portfolioReturn − benchmarkReturn
Portfolio return minus the trailing 1-year GSE-CI return. Purely descriptive.
- • Portfolio total return
- • GSE-CI 1y return
Daily.
GSE-CI is used as a domestic equity benchmark by convention.
Limitations: GSE-CI is heavily bank-weighted; concentrated portfolios may outperform or underperform it for structural reasons unrelated to stock selection.
Concentration — Herfindahl-Hirschman Index
HHI = Σ wᵢ² × 10,000 (where wᵢ is each holding's portfolio weight)
Classical concentration index. Below 1,500 = diversified, 1,500-2,500 = moderate, above 2,500 = concentrated.
- • Portfolio weights from user-entered holdings
Whenever holdings change.
Per-holding weights; an all-bank portfolio with multiple names may still score 'low' even if sector-concentrated.
Limitations: HHI is calculated per-holding, not per-sector. See sector-exposure donut for sector view.
Liquidity score (1–10, A–E grade)
score = 10 − penalties (days-since-trade, avg-volume tier, turnover tier)
Composite rule-based score. A-rated stocks trade regularly with healthy volume; E-rated stocks may not have traded for a week.
- • Last-traded date
- • Daily volume
- • Turnover = (volume × price) / market cap
Daily.
Demo data uses today's volume as a proxy for average; production will use a rolling 30-day median.
Limitations: Liquidity can change quickly on corporate-action news — a stale score doesn't guarantee you can exit at the displayed price.
Stale-price risk
An issuer flag surfaced when the last trade is more than 1 day old. On the stock page we show 'last traded N days ago' in bold red.
- • Last-traded date
Daily.
More than one calendar day ≠ one trading day; we'll refine after live feed lands.
Limitations: Does not distinguish holiday closures from genuine illiquidity.
T-Bill yields — discount vs investment
investmentYield = discount / (1 − discount × tenor/365)
BoG auctions report a discount rate; the investment yield (what you actually earn over the holding period) is derived from it.
- • Discount rate from BoG auction
- • Tenor (91 / 182 / 364 days)
Weekly after BoG's auction release.
Tenor converted using a 365-day year.
Limitations: Does not deduct withholding tax, where applicable. Roll-over risk exists — next auction's rate can differ.
Worked example. Discount 24.85%, 91 days → 0.2485 / (1 − 0.2485 × 91/365) ≈ 26.44% investment yield.
News relevance & entity matching
Each article is scanned against the instrument master. Ticker matches require whole-word matching so 'FML' never matches inside 'family'. Alias, display-name, legal-name, and former-name matches are scored separately.
- • News item (title + summary)
- • Instrument master (tokens)
Every 5 minutes.
Headlines are in English; we do not currently translate Akan or French sources.
Limitations: The matcher is rule-based, not ML. Confidence ≥ 0.7 classifies as 'direct-company'; below that we route as macro/market-wide or drop entirely.
SEC notice classification
Every notice is tagged with a kind (cautionary, warning, suspension, sanction, licensing, public education, enforcement, operator, unknown) and a verification status (verified, source-linked, unverified, demo).
- • SEC Ghana publication
- • Document URL
- • Last checked timestamp
Polled daily; upgraded editorially.
Editorial review before we upgrade status from demo/unverified to source-linked/verified.
Limitations: We never attribute fraud to a named entity unless SEC Ghana has done so on the record.
Data-freshness labels
Every price or number on Nkosuo carries one of 11 labels: Live, Delayed, End-of-day, Estimated, User-entered, Demo, Sample, Unavailable, Stale, Verified, Unverified. The label indicates how the value was produced and how fresh it is.
- • Source kind
- • Source timestamp
- • Expected refresh cadence
Continuous.
Where we lack a timestamp we show 'Unverified', never fabricate one.
Limitations: The label is only as good as the adapter's metadata; see DATA_SOURCES.md.
Anomaly flags
|today_return − mean_30d| > 2 × sigma_30d
A move more than 2 standard deviations from the 30-day mean fires an 'unusual move' flag. Combined with stale-price and thin-trade flags on the stock page.
- • 30-day close history
Daily.
Normality — an oversimplification for skewed return distributions.
Limitations: Small sample + non-normal returns means false positives are possible. Treat as a prompt to look closer, not a recommendation.
AI-generated explanations
If ANTHROPIC_API_KEY is configured, the per-stock Intelligence Report can be synthesised by Claude with a guardrail system prompt (no buy/sell, no price targets, no forecasts). The output schema is identical to the deterministic rule-based version so the UI shape is fixed.
- • Session summary + liquidity + pressure + sentiment + fundamentals
- • Ghana-specific context
Hourly ISR.
Claude is instructed to produce descriptive-only output. Every response carries a visible 'not a recommendation' disclaimer.
Limitations: LLM outputs can still be wrong. Every AI panel carries a visible disclaimer and a link back to this methodology page. If the API is down the app silently falls back to the rule-based report.
Portfolio transaction ledger (WACB)
The portfolio is derived from a transactions ledger (buys, sells, dividends, deposits, withdrawals, fees, taxes, transfers). Positions use weighted-average cost basis: sales realise P/L against the running average but do not change the average cost of the remaining shares.
- • User-entered transactions
- • End-of-day prices for mark-to-market
Whenever you add, edit, or delete a transaction. Prices refresh daily.
Fees and taxes on a buy are capitalised into cost basis; on a sell they reduce proceeds. Transfer-in accepts a stated cost basis; transfer-out reduces quantity without a P/L event.
Limitations: FIFO cost basis is a Phase-3 addition. No tax-lot optimisation today. We do not verify that the holdings exist at a broker.
Worked example. Buy 100 @ GHS 5, then 100 @ GHS 7. WACB = (500 + 700) / 200 = GHS 6. Sell 50 @ GHS 8 → realised P/L = (8 − 6) × 50 = GHS 100; remaining 150 stay at GHS 6 avg cost.
Time-weighted return (TWR)
TWR = Π(1 + HPRᵢ) − 1, where HPRᵢ = (end_value − net_external_flow − start_value) / start_value
Strips out the timing and size of contributions and withdrawals. Gives you pure investment performance — the return the portfolio would have earned if no cash had moved in or out. Preferred when comparing to benchmarks.
- • Daily portfolio market values
- • External cash flows per date
On every ledger update.
Sub-periods are bounded by external cash flows. Modified-Dietz style where intra-period flows are netted at period-end.
Limitations: Needs at least two observation points with a valid start value. No weighting for intra-period timing beyond netting at period-end.
Worked example. Start GHS 1,000 → grow to 1,100 (no flow, HPR +10%) → deposit 1,000 (value 2,100, HPR 0%) → grow to 2,310 (HPR +10%). Chained TWR = 1.10 × 1.00 × 1.10 − 1 = 21%.
Money-weighted return / IRR
Find r such that Σ CFᵢ / (1 + r)^(tᵢ) = 0
The internal rate of return of the cash flows between you and the portfolio. Unlike TWR, IRR gives credit (or blame) to the timing of your contributions. Often the more honest number for 'what did I actually earn'.
- • Signed, dated cash flows from the ledger
- • Terminal market value (positions + cash) as a final positive flow
On every ledger update.
Sign convention: contributions (deposit, transfer-in) are negative; distributions (withdrawal, transfer-out, dividend) are positive; buys/sells/fees/taxes are internal and captured in terminal value.
Limitations: Returns null when flows don't change sign (e.g. contributions only, no terminal value). Solved via bisection — accurate to 1e-6 but not closed-form.
Worked example. Deposit 1,000 on 2025-04-24, terminal value 1,100 on 2026-04-24 → IRR ≈ 10% annualised.
AI explanations framework — guardrails and fallbacks
Every plain-English explanation on the platform passes through a single contract: typed input per kind, schema'd JSON result (summary, key factors, cited inputs, limitations), a guardrail validator that rejects forbidden language (buy/sell/hold/target price/guaranteed), and a deterministic rule-based fallback that always works without an LLM. When ANTHROPIC_API_KEY is configured, the same call can be served by Claude Opus 4.7 with adaptive thinking and prompt caching; if the model produces flagged output, we discard it and return the rule-based version with the violation reasons attached as warnings.
- • Per-kind structured inputs (stock, signals, notice, T-Bill auction, etc.)
- • Optional ANTHROPIC_API_KEY env var for live Claude calls
Server-side per page render; client-side on demand for portfolio.
The rule-based fallback is the source of truth when the LLM disagrees with our guardrails. We do not silently let unsafe language reach the user.
Limitations: The 9 currently supported kinds are: stock-movement, portfolio-risk, dividend-announcement, tbill-auction, macro-impact, company-announcement, sec-notice, risk-change, stock-vs-tbill. New kinds require new typed inputs and a corresponding rule-based fallback.
T-Bill math — discount, yield, effective annual
price = 100 × (1 − d × days/365) · yield = d / (1 − d × days/365) · EAY = (1 + yield × days/365)^(365/days) − 1
Bank of Ghana publishes a discount rate at auction. The investment yield users earn is grossed up from the price paid, and the effective annual yield compounds the holding-period return forward to one year so tenors can be compared on the same basis.
- • Discount rate
- • Tenor (91 / 182 / 364 days)
Weekly after BoG's auction release.
365-day count. No fees, no brokerage markup.
Limitations: Rollover at the next auction is not guaranteed at today's yield. Tax treatment varies by investor type — the calculator accepts a user-entered rate.
Worked example. Discount 24.85%, 91 days → price per 100 = 93.80 → yield = 24.85 / 93.80 × (365/91) ≈ 26.49%.
T-Bill ladder & rollover planner
The ladder builder splits your principal across 91-, 182-, and 364-day tenors at user-chosen weights and computes each rung's price, face value, interest, and maturity date. The rollover planner projects the cascade of maturities over a horizon, reinvesting at the same yield each time (the 'constant-yield assumption').
- • Principal
- • Weights per tenor (auto-normalised)
- • Latest BoG auction yields
- • Rollover horizon (months)
Live in the UI.
Constant yield across rollovers. No transaction fees. The calendar increments maturity dates in 91 / 182 / 364-day blocks from today.
Limitations: Future auctions will price higher or lower. A ladder's value is in the maturity cadence (liquidity), not just the yield.
T-Bill scenario modelling
What-if analysis on the three levers that move real T-Bill returns: the auction yield itself, Ghana inflation, and cedi depreciation against USD. Defaults shock each lever by a plausible amount (yields −300bp, inflation +500bp, cedi +5%) so users see the sensitivity.
- • Base yield, inflation, FX depreciation
- • Shock deltas
Live in the UI.
Independent shocks — correlated shocks in the real world can be worse.
Limitations: Does not account for re-investment risk across multiple auctions or regime changes.
Auction demand — tendered vs accepted
cover = bids tendered / bids accepted
Cover > 1 means the auction was oversubscribed. Persistent undersubscription is a stress signal and often precedes yield moves.
- • BoG auction bids tendered and accepted per tenor
Weekly.
Amounts reported in GHS, without separation by dealer category.
Limitations: Quantity alone doesn't reveal price dispersion — a tightly clustered bid book tells a different story than wide dispersion at the same cover ratio.
Educational valuation calculators
DDM: fair = DPS × (1 + g) / (r − g). DCF: Σ FCFₜ / (1 + r)ᵗ + TV / (1 + r)ᴺ, TV = FCF_N × (1 + gₜ) / (r − gₜ). Equity = PV(FCF) − net debt.
The stock page offers a Dividend Discount Model and a two-stage DCF. Inputs are seeded from public fundamentals plus Ghana-aware defaults (22% discount, 6% terminal growth). Users can change every input. Outputs are implied fair value per share and upside vs market — labelled clearly as educational estimates, not targets.
- • Fundamentals (EPS, DPS, FCF, shares, debt, cash)
- • User-adjustable growth + discount assumptions
Live in the UI — recomputed on every input change.
DDM requires r > g or returns null. DCF requires r > terminal growth or returns null. Narrow gaps (<2-3%) surface warnings.
Limitations: Models are as good as their inputs. Fair-value sensitivity to discount and growth is high. Nothing here is investment advice; no buy, sell, hold, or target output.
Worked example. MTNGH at GHS 2.45, DPS 0.18, g 15%, r 22% → DDM fair value ≈ GHS 2.96 (+21%).
Sector-specific fundamentals
Each sector has its own diagnostic metrics. Banks: CAR, NPL ratio, NIM, cost-to-income, deposits, loans, impairment charges. Telecoms: active + data subscribers, ARPU, MoMo / data / service revenue, capex intensity. Insurance: claims ratio, combined ratio, solvency, investment income. Energy: commodity / FX / regulated-price exposure, gross + operating margin. Consumer: gross + operating margin, input-cost sensitivity, inventory turnover.
- • Issuer financial statements
- • Regulatory reports (BoG, NIC)
On issuer results release.
Grades (good / ok / watch / weak) use rules-of-thumb thresholds, not regulatory limits. Benchmarks shown where applicable (e.g. BoG CAR minimum 13%).
Limitations: Coverage is the set of tracked issuers — not every GSE listing has sector-specific data yet.
Peer multiples (P/E, P/B, dividend yield)
Auto-selected sector peers (by market-cap proximity) rendered alongside the subject stock. Medians shown for reference. Each multiple is tagged discount / premium / at-median (P/E and P/B use lower-is-cheap; dividend yield uses higher-is-better).
- • Subject + peer prices, EPS, book value per share, DPS
Daily.
Tolerance of ±5% around the median before a verdict flips. 'Discount' does not mean 'cheap' — weaker fundamentals can justify a lower multiple.
Limitations: Peer universe is sector-bounded and small. Absolute multiples should be cross-checked against the T-Bill yield (see /methodology#tbill-yield).
Portfolio risk signals
Nine descriptive signals (concentration, sector concentration, single-issuer, liquidity, stale-price, FX, inflation erosion, dividend dependency, T-Bill opportunity cost). Each returns a status (ok / elevated / high / unknown), a metric, a plain-English explanation, and the specific inputs the user can verify. Language is deliberately educational — never 'buy' or 'sell'.
- • Derived positions and portfolio weights
- • Ghana macro baseline (CPI, cedi depreciation)
- • Latest T-Bill investment yield
- • Liquidity grade from the stock-level analytics
On every ledger update.
Standard thresholds: HHI < 1,500 diversified, 1,500–2,500 moderate, > 2,500 concentrated. Single-issuer above 40% = high. Sector tilt above 60% = high. Stale-price exposure ≥ 30% = high.
Limitations: Thresholds are rules of thumb, not regulatory limits. A signal firing is not advice to act; it is a prompt to look closer.
Spotted a methodology issue?
Email methodology@nkosuo.com and we will log it on our public corrections page.