Análises avançadas

A metodologia da Poliwave

Uma descrição detalhada de como cada projeção é construída, desde os dados históricos brutos até a previsão final reconciliada.

15

Stages every constituency passes through

4

Levels you can set targets at, national down to sub-region

40,000

Monte Carlo draws per formal projection

47

Elections the formula was backtested against

01Em termos simples

Você fornece à Poliwave um conjunto de metas. Elas podem ser resultados de pesquisas eleitorais, cenários hipotéticos ou uma combinação dos dois. É possível definir metas em quatro níveis: país inteiro (geral), região (como o Canadá Atlântico), província (subnacional) ou uma sub-região menor (sub-regional, como Calgary).

Para a eleição que você quer projetar, a Poliwave carrega o resultado da eleição anterior com os limites atuais dos distritos eleitorais (a mesma redistribuição, identificada por rep_order no banco de dados). Essa única eleição anterior é a base de referência de cada distrito. Eleições mais antigas entram apenas na etapa de reconstrução histórica, que preenche as bases dos partidos que não concorreram naquele ciclo anterior.

A Poliwave aplica então uma fórmula de variação eleitoral a cada distrito. Ela calcula duas previsões clássicas, multiplica uma pela outra e extrai a raiz quadrada, que é a média geométrica. O resultado sempre fica entre as duas e tende para a menor, de modo que um distrito não pode ser levado abaixo de zero quando o partido perde, enquanto um distrito de desempenho intermediário ainda tem espaço para avançar quando o partido ganha.

Depois da variação, o modelo pode acrescentar outros efeitos: eleitores mudando de partido, voto estratégico em disputas apertadas, ajustes demográficos e alterações regionais manuais. A maioria desses efeitos é opcional. Em particular, o voto estratégico vem desativado nas projeções oficiais publicadas neste site (o comportamento real dos eleitores é complexo e difícil de prever por meio de regras); ele está disponível principalmente como um controle para experimentação no simulador interativo. Ao final, o modelo redimensiona cada distrito para que as médias geográficas fiquem próximas das metas fornecidas. Se os números não forem totalmente compatíveis (por exemplo, uma meta nacional que não corresponda à média das metas regionais), prevalece a meta mais abrangente.

Nas projeções oficiais que publicamos no site, também executamos uma simulação de Monte Carlo para obter probabilidades de vitória e intervalos de confiança. Cada execução leva cerca de cinco minutos, por isso a calculadora interativa de cadeiras não a executa nos seus cenários; você recebe apenas a estimativa pontual.

O restante da página detalha cada componente.

02O modelo em um parágrafo

A Poliwave conduz cada distrito eleitoral por um processo de quinze etapas. Cada etapa faz uma coisa: lê o resultado anterior, preenche candidatos ausentes, aplica a variação eleitoral, transfere votos entre partidos, acrescenta ajustes demográficos e geográficos e, por fim, redimensiona tudo para corresponder às metas fornecidas. A fórmula de variação no centro é o núcleo matemático, mas não bastaria por si só. São as etapas ao redor que transformam uma pesquisa nacional em uma previsão por distrito na qual se pode realmente confiar.

03Core projection formula

There are two classical ways to convert a national swing into a constituency-level projection, and each one breaks in a different way.

Proportional swing multiplies every constituency by the same ratio. If a party doubles nationally, every constituency doubles too. This is fine most of the time but breaks during big swings in either direction. A party that was already at 55% in a constituency has nowhere to go when you double it, and the formula tries to push it past 100%. More damagingly, when a party collapses nationally (think NDP 2025 going from 17.8% to 6%), pure proportional brutalises strongholds, Edmonton Strathcona's 60.7% gets scaled down to 20% even though incumbent personal vote and local brand strength should preserve much more than that.

Uniform swing adds the same number of points to every constituency. If the party drops 10 points nationally, every constituency drops 10 points. This breaks the other way: a party at 3% in a constituency drops to negative 7%, which is not a thing. Pure uniform also has the opposite collapse problem: a constituency where the party had almost no presence keeps a non-zero share that's basically noise.

Poliwave's projection formula takes the geometric mean of both, it multiplies the two predictions together and takes the square root. The proportional prediction is computed in log-odds space instead of by plain multiplication, which is the part that stops a stronghold from being pushed past 100% when a small party surges nationally (more on that below). Each prediction is floored at zero first so the inputs to the square root can't be negative:

logit(Pprop)=logit(R)+logit(Pc)logit(Bc),logit(x)=lnx100x
Puni=R+(PcBc)
P=max(0,Pprop)max(0,Puni)

The geometric mean is the natural average for percentages. It always sits between the two predictions, and it gets pulled toward whichever one is smaller. That single mathematical property fixes both classical failure modes at once: when proportional runs high, the smaller uniform value pulls the answer down; when uniform crashes to zero, geometric mean returns zero too (because square root of anything-times-zero is zero), which is the correct answer for a constituency where the party has effectively vanished.

The proportional component uses log-odds so it can never break past 100%. Plain proportional swing multiplies a seat's share by the national ratio, so if a small party doubles or triples across the country, a seat where it was already strong gets multiplied straight off the chart (a 40% Green seat scaled by a tripling would land at 120%, which is not a real result). Log-odds works on a curved scale that has 0% and 100% as walls you can approach but never cross. We measure how far the national share moved on that curved scale, shift the seat by the same amount, and convert back. The seat still climbs when the party surges, it just climbs toward the 100% wall and flattens instead of shooting through it.

Variable definitions

P
The party's projected vote share in this constituency. This is the output. Later pipeline steps adjust it further.
R
What the party got in this constituency in the previous election. Normally the model uses only this one prior election. Earlier elections come in only via the historical-reconstruction step when this number is missing or unreliable.
Pc
Your input target for the party (from polls or scenarios), picked at the most specific level that applies to this constituency. The model checks subregional input first, then subnational, then regional, then the general (national) input.
Bc
The matching baseline. If the current input is regional, the baseline is what the party got in that same region in the last election. The two have to be at the same geographic level; otherwise the swing ratio means nothing.

04The fifteen-stage pipeline

Every constituency goes through the same ordered set of steps. The swing formula above is one of them. The others clean up the input to the formula and make the output line up with everything else the model has to respect.

  1. Input parsing. The model loads each constituency's previous result, the geographic hierarchy (which constituency belongs to which sub-region, province, region), and any referendum results for the target election's redistribution (rep_order). Your hierarchical input is flattened into a lookup so each constituency picks the most specific target that applies to it.
  2. Historical normalisation. Missing or unreliable prior results get filled in. A party that did not nominate a candidate at all (a recent Canadian example: Conservatives in Québec Centre, 2025), or that ran so far below its own national share for the cycle that the result reads as a late-withdrawal residue rather than a real campaign, gets rebuilt by one of three methods described in the next section. This step runs on whatever prior-cycle baseline the database holds for the constituency, including transposed results from older boundaries (a 2025 federal projection's main baseline is the 2021 result transposed onto the 2023 rep_order, for instance).
  3. Swing projection. The core formula runs on every constituency and every party. Special cases handle brand-new parties and parties running nationally but absent from this constituency.
  4. Simple normalisation. The constituency's projected percentages are rescaled to add up to 100%. Anything negative is set to zero.
  5. Vote flow. Loss-only redistribution. When a party is projected to lose share, the lost share is handed to other parties according to a flow matrix you supply.
  6. Vote intake. Vote transfers that don't depend on whether a party is winning or losing. The formula is in the redistribution section below.
  7. Tactical voting. Strategic defection in FPTP races, scaled by how close the local race is. Two rule types: block-target voting (anti-X coordination) and the top-two squeeze (wasted-vote logic). This stage is off by default in the formal projections published on the site and is enabled only when you turn it on in the interactive simulator.
  8. Regional adjustments. Manual knobs. You give the model two tables, one for additive shifts and one for percent multipliers, organised by level (subregional, subnational, regional) and by party. Each cell is the change you want applied at that level for that party. The model just applies what you wrote; nothing is auto-computed here.
  9. Demographics. Per-category adjustments scaled to the party's existing support. You set a boost for a (party, demographic) pair; the model multiplies it by how far the constituency deviates from the national average for that demographic and by the party's current vote share in the constituency, so the effect can't blow past what the party actually has to move.
  10. Incumbent boost. An automatic multiplicative boost goes to the party of any candidate identified as a running incumbent in the constituency (sitting MP seeking re-election). A symmetric deboost of the same size goes to the previous-winner party when the sitting MP is known to be retiring or otherwise not on the ballot. Both magnitudes are calibrated from a backtest sweep across 38 Canadian elections since 2000; see the dedicated section below.
  11. Constituency boosts. Per-constituency manual overrides, either additive or multiplicative. Useful for unusually strong or weak local candidates beyond the auto-incumbent effect, well-known local figures, or one-off scenario tweaks. User boosts stack on top of the auto-incumbent boost.
  12. Hierarchical normalisation. The rescaling step. Every constituency is rescaled level by level (subregional first, general last) so the vote-weighted average at each level matches your input for that level. The general (national) level runs last and is the binding rule the result has to respect.
  13. Threshold capping. Damps any party that's running hot in a constituency compared to its cohort. When the projected share exceeds a set multiple of the regional or national average, the excess gets reduced by a set rate. Both the multiple and the rate are configurable. The constituency is then renormalised to 100%, and hierarchical normalisation is re-run so the capping doesn't break the geographic totals. This isn't a small-party squelch; it applies to any party that runs hot.
  14. Aggregation. Constituency winners are picked, seat totals are added up by party, and geographic summary tables are built for each level of the hierarchy.
  15. Output. Everything is packaged into the JSON response used by the website and by the Monte Carlo layer further down this page.

05Historical reconstruction

Inside that history window, the most important prep step is filling in missing or unreliable prior results. A naive model would take "the party got 0% here" at face value and project from that. Poliwave does not, for two reasons.

The first reason is candidate withdrawal. A party might just not have nominated a candidate at all in the last cycle. There are real Canadian cases: the Conservatives did not run a candidate in Québec Centre in 2025, so the prior result is structurally zero, and treating it as a real voter preference would be wrong.

The second reason is late withdrawals that still leave a name on the ballot. The 2019 Brexit Party stand-down in Conservative-held UK seats is the classic example, but the same thing happens in Canada when a candidate withdraws after the nomination deadline. The resulting tenths of a percent look like a vote share, but they don't reflect a real campaign. Either way, this needs to be cleaned up before the swing formula sees the baseline.

When the model has to fill a baseline in, it picks one of three branches depending on what data is available. Note that transposed prior results (for example the 2021 federal result mapped onto the 2023 rep_order) are treated as the real prior result for the constituency and go through this stage like any other baseline. They're the main input the projection runs on, not an exceptional case.

Branch 1: footprint-matched proportional swing

The default. The missing value is filled by taking the most-specific available geographic average for the party and applying proportional swing from the historical version of that average to the current version. The averages on both sides of the swing ratio only count constituencies where the party ran in both the old and the new cycle. That restriction kills off a whole class of errors. If you didn't restrict it, a party that stood down in a region last cycle but is running fully this cycle would produce a huge swing ratio against a tiny prior denominator, and the rebuilt number would blow past 100%.

R=Rt1Ar,tAr,t1,where Ar,=regional average over ridings the party contested in both years

The "level" in the formula is picked most-specific-first: subregional, then subnational, then regional, then general (national). This matches the same hierarchy the user-input lookup uses elsewhere in the pipeline. The reasoning is the same too: a constituency's behaviour is better predicted by its actual local cohort than by a national rollup.

Branch 2: zero-swing fall-through

When the party has a historical result for the constituency but no current-cycle average at any level (usually because the party isn't running this cycle), the swing ratio is zero and the rebuilt baseline collapses to zero. The constituency gets a clean zero instead of some arbitrary leftover.

Branch 3: regional-average fallback

When there's no historical result at all (the party is genuinely new), the constituency gets a damped version of the current-cycle regional average. The damping factor is set so brand-new parties start meaningfully below their headline regional number, which leaves room for the swing formula to grow them in surge constituencies and shrink them where they don't catch on.

Rebuilt baselines are not treated as if they were real. Each baseline carries a confidence weight depending on where it came from: a real result from the database is trusted fully, a branch-1 reconstruction less, and the branch-3 regional fallback least of all. Before the swing formula reads the baseline, low-confidence baselines get pulled toward the regional mean by a weighted average:

R~=cR+(1c)A,0<c1

The effect is a careful pull toward the average. When the model trusts the baseline, it respects the constituency's individual character. When it doesn't, the constituency behaves more like its regional cohort. That keeps a single noisy or guessed number from contaminating the rest of the pipeline.

06Three families of vote redistribution

Voters move between parties in three different ways, and Poliwave handles each one separately. The three run in order, with each one working on what the previous one produced.

Vote flow (only when a party is losing)

When a party is projected to lose share in a constituency compared to its previous result, the lost share gets handed out to other parties using a flow matrix you supply. Each row tells the model, for one source party, what fraction of its losses go to each other party. The rows don't have to add up to 100%; whatever's left over is treated as abstention or as going to parties outside the projection.

Vote intake (always-on transfer)

Vote intake exists for cases where the "only when losing" condition of vote flow doesn't apply. A party can be gaining nationally and still be drained locally by a new entrant. Each row in the intake matrix tells the model, for one receiving party, what fraction of each source party's current share it pulls in:

ΔPts=wtsPs

This is the case vote intake was built for. Imagine you want to model a new right-wing party (call it Restore) taking voters from Reform UK. Vote flow can't handle this if your projection has Reform gaining or holding steady nationally, because vote flow only fires when the source is losing. But Reform can be up nationally and still bleed support locally to a fresh competitor on the same side of the spectrum. Vote intake lets you say "for every constituency, Restore takes a fixed fraction of Reform's current share" regardless of whether Reform itself is up or down. That's why the formula has no loss-condition: it works in both directions.

Within a single constituency, all the rules look at the same starting snapshot, so the order of rules in the matrix doesn't matter. Multiple targets pulling from the same source add up. If the total drain would take the source below zero, the rules are scaled down proportionally so the source ends at zero instead of negative.

Tactical voting (close-race-sensitive)

In first-past-the-post systems, voters often abandon their first-choice party when it has no real chance of winning the local seat. Poliwave models this directly. There are two rule types. A block-target rule names a party that tactical voters want to keep out, a pool of parties whose supporters will defect, and a list of acceptable alternatives. The rule fires in a constituency only if the target is in the top two; the pool's voters then move to whichever named blocker is strongest locally. A top-two squeeze rule doesn't name a target. It just drains every party below third place toward the top two, with the destination split decided by the squeezed party's own vote-flow preferences.

Both rule types are damped by how close the race is. The effect scales linearly with the local margin and disappears at a cutoff you can set:

ϕ(m)=max(0,1mm),m=|P(1)P(2)|

This is what keeps safe seats from moving while close seats get realistic tactical-voting behaviour. The model penalises parties below second place exactly in proportion to how much the local race matters.

07Demographic adjustments

Demographic effects in real elections are relative, not absolute. If a party does ten points better with renters, that doesn't mean it picks up ten points everywhere. It picks up ten points in constituencies that have a lot more renters than the national average, almost nothing in average constituencies, and loses ten points in constituencies with way fewer renters than average. Poliwave handles this directly. For each (party, demographic) boost you set, the model multiplies your boost by how far the constituency deviates from the national average for that demographic, and by the party's current support in that constituency:

Δp,d,i=(xd,iμd)βp,d100Pp,i100

The deviation term is what makes the adjustment relative. Above-average constituencies get a push proportional to how far above average they are; average constituencies barely move; below-average constituencies get pushed the opposite way. Multiplying by the party's current support is what keeps the formula honest: a party with no vote share in a constituency gets no demographic shift (a 0% party times anything is still 0), and a party already strong in the constituency has more vote share available to move. A party sitting at 3% can drift by a few tenths of a point per category; a party at 30% shifts ten times more in absolute terms but the same in relative terms. That self-bounding shape is what stops a small input ever amplifying into an unintended seat flip downstream.

08Incumbent boost

Incumbent candidates outperform their party's swing. The pattern is robust across systems and shows up in almost every academic study of personal-vote effects: name recognition, constituency casework, media presence during the prior term, and a ready-made local volunteer base all add up to a few percentage points of advantage that pure party-level swing math will miss. The flip side is sophomore-surge loss: when a sitting MP retires, the same seat loses the personal vote that helped prop it up, and the party usually slips back toward its normal baseline.

Poliwave applies both effects directly. After demographics and before any user-supplied constituency overrides, the model classifies every constituency into one of three states and adjusts the projected vote share of the relevant party:

  • Incumbent running. A multiplicative boost to the incumbent's party.
  • Incumbent retiring. A multiplicative deboost of the same magnitude to the previous-winner party. The seat may still be safe, but the personal vote is gone.
  • No prior history available. No adjustment.
Pw,i=Pw,i(1±b100),w=argmaxpRp,i

In the formula, Rp,i is party p 's raw baseline result in constituency i , so w picks out the previous winner; Pw,i is that party's currently-projected share after the swing and all the redistribution steps above. The boost factor (1 ± b/100) is positive for running incumbents and negative for retiring ones. The constituency is then renormalised back to 100% so the within-constituency shares still sum cleanly, and the broader hierarchical reconciliation downstream re-anchors regional and national vote-weighted averages to the user's input, so the boost shifts the within-region distribution, not the regional totals.

Identifying the incumbent

Each constituency is classified by walking a priority cascade. The model looks at the election we're projecting to (when its candidate data is in the database) and tags each constituency using the first signal that fires:

  1. Explicit incumbent flag. The target-election row carries an incumbent flag, set when a sitting MP appears on the next ballot. Boost their party.
  2. Candidate-name match. If no flag was set, compare candidate names between the baseline election and the target. A target candidate whose name also appears in the same constituency's baseline ballot is treated as an incumbent. Catches cases where the flag was missed during data entry.
  3. Retiring fallback. When the baseline winner's candidate name does NOT appear in the target's candidate list, the seat is marked as a retiring-incumbent case and gets the negative deboost.
  4. Baseline-winner heuristic. When no target candidate data is available at all (live forward projection of an upcoming race), the model falls back on the party of the baseline winner and applies the positive boost only. Without target data the model can't tell running from retiring, so the deboost arm is disabled for these runs.

Parties classified as "Other," independent, or Speaker are excluded. The first is a mathematical lump rather than a real party with a sitting MP, and the latter two have their own special-case handling elsewhere in the pipeline.

Manual constituency boosts in the next step stack on top of this. If you know a specific candidate is exceptionally strong or unusually weak beyond what the party-level incumbency boost captures, you can add a per-constituency additive or multiplicative adjustment that runs after the automatic step. The two stack rather than override: the auto-boost lifts (or trims) the projected winner first, your manual boost adjusts further on top.

09Hierarchical reconciliation

Every projection has to answer a question you asked, like "what does the country look like if the Liberals are at 26% nationally and the Bloc is at 30% in Quebec?" The reconciliation step is what makes those targets actually stick. For each geographic group at each level, the model takes the current vote-weighted average of the group, compares it to your target for that group, and multiplies every constituency in the group by one correction factor:

Pi=PiTgPg,Pg=igviPiigvi

The v in the formula is the constituency's total vote count. It weighs each constituency's contribution to the group average, so larger constituencies have more influence. The four levels run in this fixed order: subregional first, then subnational, then regional, then general (national) last.

This top-down setup has a useful property. The geographic variation that earlier steps built in is preserved, because every rescale is just multiplication: if a constituency was double its regional average before reconciliation, it's still double afterwards. Only the absolute level changes. That's what lets the model honour any national target without flattening the constituency-by-constituency texture that makes the projection useful. It also means that if you genuinely want one province at 10% while the country is at 50%, you have to drop one of the inputs. The two don't agree with each other, and the model trusts the broader target.

This also matters when pollsters get their regional weighting wrong. A pollster's regional crosstabs don't always weight back up to the national headline they reported. If you fed those inconsistent regional numbers in as hard ceilings, the national total in the projection would drift away from the topline. Because Poliwave runs the national level last and rescales whatever the regions produced, the topline you trust the most stays the binding number, and a regionally mis-weighted poll still produces a sensible projection.

10Eleições em dois turnos (legislativas francesas e sistemas semelhantes)

Em eleições de dois turnos, como as legislativas francesas, a projeção até aqui calculou apenas os percentuais de votos do primeiro turno. Uma segunda etapa do processo usa esses resultados para projetar o resultado do segundo turno em cada circunscrição, decidindo quais candidatos se classificam e como os eleitores dos candidatos eliminados se distribuem entre eles. Toda esta seção só é executada quando a eleição está marcada como de dois turnos. O sistema majoritário simples, MMP, PR, STV e outros sistemas a ignoram por completo.

Seleção dos classificados

A lei francesa permite que todo candidato que supere 12,5% dos eleitores inscritos no primeiro turno avance para o segundo. Os dois primeiros sempre avançam, mesmo quando menos de dois candidatos superam a barreira. Aplicamos a mesma regra: o limiar de classificação de um candidato equivale a 12,5% do número de eleitores inscritos na circunscrição, convertido no percentual equivalente de votos válidos com base na participação específica de cada circunscrição. Assim, em uma circunscrição com 87.000 eleitores inscritos e 60.000 votos válidos (cerca de 69% de participação), um candidato precisa de aproximadamente 18% dos votos válidos para superar o limiar, e não de 12,5%. Essa conversão produz uma combinação realista de duelos e disputas triangulares; aplicar 12,5% diretamente aos votos válidos classificaria o triplo de candidatos e tornaria as disputas quadrangulares muito mais frequentes do que se observa na prática.

Se algum candidato obtiver mais de 50% dos votos válidos no primeiro turno, a circunscrição será decidida imediatamente e o segundo turno não será realizado para essa cadeira.

Transferência de votos entre os turnos

Os eleitores de cada partido eliminado se dividem entre os classificados de acordo com uma matriz de transferência. Cada célula da matriz representa, em uma escala de 0 a 100, a afinidade dos eleitores de um partido por outro. Os valores iniciais das células são definidos pela distância ideológica usando

affinity(s,q)=e|isiq|/τ100

em que is,iq são as pontuações ideológicas dos partidos de origem e destino em um eixo de -10 a +10 e τ é uma constante de decaimento (3,0 por padrão). Um par de partidos com a mesma ideologia recebe afinidade 100; um par separado por 7 pontos recebe cerca de 10. Os usuários podem alterar manualmente os valores de células individuais na aba Matriz de transferência, e essas edições manuais têm prioridade sobre o valor ideológico padrão. Para cada partido eliminado em cada circunscrição, o modelo considera somente as células da linha relativas aos candidatos que realmente se classificaram naquela circunscrição, normaliza essas células, multiplica pelo percentual de votos do primeiro turno do bloco de origem e soma o resultado ao total de segundo turno de cada classificado. As células de não classificados são ignoradas: uma regra como “eleitores do NFP não gostam do LR” só importa em uma circunscrição onde o LR realmente chegou ao segundo turno.

Abstenção por bloco de origem

Nem todo eleitor de um candidato eliminado comparece ao segundo turno. Um eleitor cuja primeira opção era um candidato de extrema esquerda e que se depara com um segundo turno entre extrema esquerda e extrema direita tem uma boa opção, por isso a maioria desses eleitores comparece. O mesmo eleitor, diante de uma disputa entre centro e extrema direita, não tem uma boa opção e a abstenção aumenta muito. O modelo representa isso com uma taxa de abstenção por bloco de origem

αs=β+(1maxqaff(s,q))σ

β é o piso, aplicado mesmo quando o candidato classificado preferido do eleitor está na cédula, e o segundo termo é a sensibilidade à disputa, que controla quanto a abstenção aumenta quando nenhum classificado é atraente. Ambos são configuráveis. A transferência de cada bloco de origem para cada classificado é então multiplicada por (1 − abstenção) antes de ser somada ao percentual de segundo turno do classificado. Depois que todas as transferências são aplicadas, os percentuais dos classificados são renormalizados para somar 100%, correspondendo à forma como os resultados franceses do segundo turno são divulgados (o percentual de abstenção não aparece como ponto percentual de nenhum partido, assim como nas tabelas reais do segundo turno).

Os dois parâmetros aparecem como controles deslizantes na aba Matriz de transferência do simulador.

Agregação em duas passagens

A etapa de agregação é executada duas vezes. Primeiro, sobre os percentuais de votos projetados para o primeiro turno, produzindo a visão anterior ao segundo turno (quem venceria cada circunscrição pelo maior número de votos, quem lidera cada região no primeiro turno). Em seguida, os valores do primeiro turno são copiados para campos round1_*, o modelo substitui projected_percentages pelo resultado do segundo turno, executa a agregação novamente e armazena esses valores como o resumo do turno final. O seletor R1/R2 nas abas Resumo, Mapa e Tabela de resultados do simulador apenas alterna o conjunto de campos exibido.

É por isso que as circunscrições em que o líder do primeiro turno perde no segundo (a dinâmica clássica do front républicain, em que um candidato de extrema direita lidera por maioria relativa, mas perde quando o centro e a esquerda se unem contra ele) aparecem com o selo “VIRADA” na aba Transferências por circunscrição.

11Uncertainty and scenario probabilities

Getting a single point estimate is the easy part of a forecast. The hard part is what could happen around it. For formal projections, Poliwave runs Monte Carlo on top of the base projection (40,000 draws by default, more if set higher via the CLI) using a correlated error model. Polling error is split into three pieces: a national piece that moves every constituency the same way, a regional piece that moves constituencies inside one region together, and a per-constituency piece that's independent and whose size depends on the constituency's population.

P~i=Pi+εnat+εr(i)+εi,ε𝒩(0,σ2)

The split exists because real polling misses aren't independent across constituencies. They're usually systemic and regional. If you treated every constituency as an independent draw, the confidence intervals would be way too narrow and the seat distributions would be too tight around the centre. The correlated split gives back the realistic spread an honest forecast needs.

The third piece, the per-constituency term, has its variance scaled inversely by the constituency's elector count. A small northern constituency with 35,000 electors really is noisier than a Toronto-area constituency with 110,000, because a smaller electorate gives more leverage to single events (a popular local candidate, a scandal, a local issue):

σi2=σ02NrefNi

σ0 is the calibrated noise level at the reference population Nref (the median constituency size in the jurisdiction), and Ni is the constituency's own elector count. This is what gives small constituencies wider win-probability ranges than large ones, and any honest forecast model has to behave this way.

What the simulation actually produces:

  • Per-constituency win probabilities and 95% confidence intervals for every party.
  • Seat distributions at the regional and national level.
  • Government formation probabilities: majority, minority, plurality, hung. Each gets its own simulated frequency, based on your inputs and the correlated error structure above.

12Does it work?

Methodology is only as good as the track record it produces. On the 2025 Canadian federal election, Poliwave produced the closest absolute seat-count projection among Canadian forecasters: the smallest total gap between projected and actual seats for the top four parties. On constituency-level accuracy (the share of seats where the model picked the right winner), Poliwave landed within one percentage point of the long-established national benchmark, despite being a much newer project run by one person instead of an institutional team.

Performance on every prior election the project has covered is published in full on the accuracy page: projected seats next to actual seats, no curation, no cherry-picking.

One caveat worth stating plainly: those results, including the 2025 federal projection, were produced with the Excel model that preceded this website. The first interactive web simulator went live in August 2025, after all of them. The pipeline described on this page is a direct descendant of that model and follows the same approach, but it has not yet been scored against a general election of its own.

See the full track record

In summary

Geometric-mean swing

Every projection combines proportional and uniform swing by taking the geometric mean, multiply both predictions, square-root the product. No tuning parameters. Naturally pulls toward whichever component is smaller, which fixes both classical failure modes at once: runaway proportional projections get damped, near-zero parties cleanly zero out. Wins more elections than it loses against every other formula tested in head-to-head backtests across 47 CA elections since 2000.

Footprint-matched historical averaging

When the model needs a prior baseline for a party whose footprint changed between cycles, it only compares constituencies the party ran in both times. That kills off the distortion that would otherwise happen when a party stood down one cycle and runs fully the next.

Three-family vote redistribution

Loss-only flows, always-on intakes, and close-race tactical defection are three separate pipeline steps that add up cleanly without double-counting. Real voters move in different ways, and the model handles each one separately.

Margin-sensitive tactical voting

How much tactical voting happens depends on how close the local race is. A safe seat sees none; a tight seat sees the full effect. The cutoff and the pool of defecting voters are both user-configurable, so the same engine handles anti-Conservative coordination, anti-Reform coordination, or any future strategic alignment without code changes. Off by default in the formal projections; available as a knob in the interactive simulator.

Demographic integration

Each (party, demographic) boost is applied as a deviation-weighted adjustment scaled by the party's current vote share, so the size depends both on how far the constituency is from the national average and on how much support the party has to move. Above-average constituencies get a positive shift; below-average constituencies the opposite; a party at 0% gets nothing because there's nothing to multiply. Relative, not absolute.

Symmetric incumbent boost

Running incumbents get a multiplicative boost; retiring incumbents trigger a symmetric deboost of the same size to the previous-winner party. Incumbency is read from the target election's incumbent flag, falling back to candidate-name matches and finally to the baseline winner when no target candidate data exists. Both magnitudes were tuned by backtest sweeps across 38 Canadian elections since 2000.

Vote-weighted hierarchical reconciliation

The final stage rescales every constituency so that the vote-weighted averages at each geographic level land as close as possible to the user's input. Clamping at 0 and 100, two-decimal rounding, and single-constituency-group skips mean the match is approximate rather than exact; the broadest target acts as the binding constraint and everything upstream provides the per-constituency shape the rescale preserves.

Correlated-error Monte Carlo

Polling error is split into national, regional, and per-constituency pieces. This captures the fact that polling misses are usually systemic, not random, and produces realistic seat distributions instead of the implausibly tight ones you get from treating every constituency as independent.

Boundary-matched historical foundation

Every projection is anchored on the prior election held under today’s constituency boundaries. Earlier cycles can be brought in when their results have been mathematically transposed onto current boundaries by the database upload scripts. No constituency gets a generic baseline; each one starts from its own political history under the boundaries it has today.

Esta página descreve como o modelo é construído e as equações que utiliza. Os números específicos de calibração, os ajustes por jurisdição e os detalhes operacionais são mantidos internamente.