internal /Formulas & Algorithms
Internal
v1.0 · 2026-04-25
← All docs
Reference

Formulas & Algorithms

All computed indices, metrics and derived values used across the platform. This is the canonical reference — any UI displaying these values must use exactly these definitions, thresholds and colors.

1

Demand Pressure Index (DPI)

Entity: Market → DemandPressureSnapshot

Measures how hard existing inventory is being worked relative to available supply. A value ≥ 1.0 means demand equals or exceeds supply; values below 1.0 indicate spare capacity.

1.1 · Single-period DPI

DPI = visitor_nights ÷ available_key_nights
visitor_nightsTotal guest-nights booked across all operators in the catchment during the period
available_key_nightsTotal keys × nights in the period
Example: 420 visitor-nights ÷ 600 key-nights = DPI 0.70

1.2 · DPI Index (display value)

The raw DPI ratio is multiplied by 100 for display in the UI.

DPI_INDEX = DPI × 100
Example: 0.70 × 100 = DPI Index 70

1.3 · DPI Annual Average

The annual average DPI is the arithmetic mean of the 12 monthly DPI values. Monthly DPIs are computed individually (each month's visitor-nights ÷ that month's available key-nights) and then averaged — preserving seasonal variation rather than pooling the full year.

DPI_ANNUAL_AVG = (DPI_Jan + DPI_Feb + · · · + DPI_Dec) ÷ 12
Display: multiply by 100 → DPI Index. Example: mean 0.70 → displayed as DPI 70.

1.4 · DPI Thresholds

RangeLabelColor tokenHex
≥ 100 Demand exceeds supply --sage #8A9A7B
70 – 99 Approaching capacity --gold #D4A85C
0 – 69 Low demand pressure --rust #B85A3E
Supply ceiling rule: When DPI_INDEX ≥ 100, color shifts to Sage rather than continuing through Rust — demand exceeding supply is the ideal entry signal, not a warning.
2

Positioning Convergence Index (PCI)

Entity: Market → ConvergenceSnapshot

Measures how similar competitors' positioning already is. A high PCI means the market is converging toward undifferentiated sameness — prime opportunity for a well-differentiated entrant. A low PCI means incumbents are already diverse and a new entrant must work harder to stand out.

2.1 · PCI Composite

PCI = (keyword_overlap + positioning_frequency + amenity_similarity + price_dispersion + review_axis_overlap) ÷ 5

Each sub-axis is scored 0–100; the composite is their unweighted arithmetic mean (0–100).

2.2 · Sub-axis Definitions

keywordOverlapDegree to which operators share the same keywords in listing titles, descriptions and tags
positioningFrequencyHow often competitors emphasise the same 2–3 positioning pillars (e.g. "romantic", "pet-friendly")
amenitySimilarityOverlap in the set of amenities offered across comparable operators
priceDispersionInverse of ADR spread — low dispersion (tightly clustered prices) scores high on this axis
reviewAxisOverlapDegree to which the same review themes (quiet, views, proximity) dominate across operators

2.3 · PCI Thresholds

RangeLabelColor tokenHex
0 – 25 Differentiated --ocean #5789A8
26 – 50 Recognizable --sage #8A9A7B
51 – 75 Converging --gold #D4A85C
76 – 100 Indistinct --rust #B85A3E
The PCI color spectrum is identical to the moat saturation spectrum (Ocean → Sage → Gold → Rust), ensuring visual coherence across the full dashboard.

2.4 · ConvergenceSnapshot — time series storage

The Prisma ConvergenceSnapshot entity stores one row per market per computation run (planned: weekly). Fields map 1-to-1 to the five sub-axes plus the overall composite.

// ConvergenceSnapshot fields overall Int // PCI composite 0–100 keywordOverlap Int // sub-axis 0–100 positioningFrequency Int // sub-axis 0–100 amenitySimilarity Int // sub-axis 0–100 priceDispersion Int // sub-axis 0–100 reviewAxisOverlap Int // sub-axis 0–100
3

PCI × DPI Opportunity Matrix

Entity: Market

The two hero indices define four strategic quadrants. A market is plotted at (DPI_INDEX, 100 − PCI) — DPI on the x-axis, PCI inverted on the y-axis so "high opportunity" is top-right.

3.1 · What each axis means for a new entrant

PCI axis — convergence of existing operators

High PCI (≥ 51) — operators look alike to guests. Same keywords, amenities, positioning pillars. A new entrant has room to own something specific.

Low PCI (≤ 50) — incumbents already hold distinct positions. The obvious categories are taken. A new entrant must find a gap competitors haven't claimed.

DPI axis — demand pressure

High DPI (≥ 70) — more demand than supply. The market is working. Pricing power exists.

Low DPI (< 70) — more supply than demand. Not enough guests relative to available keys. Revenue is harder regardless of positioning.

3.2 · Quadrant ranking — new entrant perspective

Rank Label PCI DPI Why
1 — Best Prime Entry High ≥ 51 High ≥ 70 Demand exceeds supply and the incumbent operators share similar positioning. A positioned entrant can own a category from day one.
2 Steal the Audience High ≥ 51 Low < 70 Operators look alike — positioning whitespace is open. A differentiated entrant can own a category and, with strong execution, become a destination that grows demand.
3 Find Your Angle Low ≤ 50 High ≥ 70 Demand exceeds supply but incumbents hold distinct positions. Winnable — requires identifying a gap competitors haven't claimed.
4 — Worst Avoid Low ≤ 50 Low < 70 Incumbents hold distinct positions AND demand is weak. Both challenges at once. No obvious path to entry.
Prime entry threshold: DPI ≥ 70 AND PCI ≥ 51 (Converging or Indistinct range).
4

Moat Saturation Scoring

Entity: Parcel → MarketMoat (market-level aggregate)

Each of the 15 moat dimensions is assigned a saturation level and a numeric score. Scores express how open a dimension remains for a new entrant — 10 is fully open, 0 is fully locked.

4.1 · Saturation → Score mapping

SaturationScoreColor tokenHex
Wide open 10 --ocean #5789A8
Open 8 --sage #8A9A7B
Contested 5 --gold #D4A85C
Claimed 2 --rust #B85A3E
Saturated 0 --rust-2 #8E3F27

4.2 · Composite moat score (planned)

A weighted composite moat score across all 15 dimensions is planned but not yet implemented. Weights will reflect dimension strategic importance and will be defined in T-19 (full schema session).

5

ADR Ceiling

Entity: Parcel · sourced from Comp records in catchment

The realistic revenue ceiling a new entrant can target — the rate a well-executed but not-yet-dominant operator can plausibly achieve in this market segment. Displayed in the S02 mini card and right panel.

5.1 · Formula

ADR_CEILING = percentile_85(realized_adr, peer_set)

Where peer_set is filtered to operators matching all three of:

Acreage bandSame band as the parcel — 1–4 ac / 5–9 ac / 10–19 ac / 20–49 ac / 50+ ac
Property typeMatches the user's selected build type (STR / BnB / Boutique Hotel / Glamping / Lodge / Resort)
Catchment ringMatches the active catchment filter (30-min / 60-min / 90-min drive)

5.2 · Display

Shown as a USD rate — "ADR ceiling · $X/night" — in the S02 mini card and in the right panel. Sourced from stored Comp records, not recomputed live on each request.

5.3 · Interpretation

The ceiling is the 85th percentile, not the maximum. It excludes outlier trophy properties a new entrant cannot benchmark against. A ceiling of $420/night means 85% of comparable operators earn ≤ $420; only the top 15% exceed it.
6

Parcel Scoring Model

Entity: Parcel

A composite 0–100 index summarizing a land parcel's overall suitability as a hospitality development site. Rolls up four sub-scores weighted by strategic importance.

6.1 · Sub-scores and weights

Sub-score Weight What it measures
Moat Opportunity 40% Average openness of the 15 moat dimensions for this parcel's location — wide-open dimensions score highest
Permit Feasibility 25% Probability of obtaining permits for the intended build type, based on zoning, county precedents and STR policy posture
Site Suitability 20% Physical characteristics — acreage, topography, water features, existing infrastructure, access road quality
Financial Upside 15% ADR Ceiling relative to estimated cost-per-key and land cost; rough return signal, not a full pro-forma

6.2 · Composite formula

PARCEL_SCORE = (moat_opportunity × 0.40) + (permit_feasibility × 0.25) + (site_suitability × 0.20) + (financial_upside × 0.15)

All sub-scores are 0–100; the composite is 0–100.

6.3 · Display thresholds

Range Label Token Hex
Strong candidate 80–100 --sage #8A9A7B
Worth investigating 60–79 --gold #D4A85C
Marginal 40–59 --brass #B99B6A
Not recommended 0–39 --rust #B85A3E

6.4 · Status

Sub-score computation is planned for post-MVP. Current dashboard uses stub data. Full implementation tracked in T-33 (Your Site Strategy section).

7

Zoning Complexity Score

Entity: Counties.zoning_complexity

An editorial 1–5 score indicating how complex a county's zoning system is for a hospitality developer to navigate. Stored once per county. Informs the Entry Friction Score and the parcel panel's permit feasibility display. Higher = harder.

7.1 · Three weighted factors

Factor Weight 1 (Simplest) 3 (Moderate) 5 (Most Complex)
Zone Count 40% < 15 zones 25–35 zones > 45 zones
Hospitality Permit Posture 40% All key build types permitted as-of-right Mix of permitted and conditional CPA required for key types (e.g. MPR)
Administrative Burden 20% Minimal overlays; simple staff approval Some overlays; planning board review Heavy overlays; multiple boards; lengthy hearings

Zone count breakpoints (ranges pending national validation): <15 = 1 pt · 15–25 = 2 pt · 25–35 = 3 pt · 35–45 = 4 pt · >45 = 5 pt. Ranges to be validated against a representative sample of US counties (see T-47).

7.2 · BuildType mapping factor

Specificity of the zone-to-buildtype relationship contributes to complexity. When many build types share the same zone designation and land use terms, an operator can't easily tell which rules apply — ambiguity is friction.

bt_per_zoneAverage number of Territori build types that map to a single zone designation via BuildTypeLandUseMap. Computed at seed time per county.
bt_factor≤ 2 = 1 pt · 3–4 = 2 pt · 5–6 = 3 pt · ≥ 7 = 5 pt. High ambiguity = higher complexity.

Future: incorporate bt_factor at 10% weight, reducing zone_count and permit_posture to 35% each. Deferred until BuildTypeLandUseMap is seeded.

7.3 · Formula

zone_factor = f(zone_count) // 1–5 per breakpoint table above permit_factor = editorial_score // 1–5 assigned per county burden_factor = editorial_score // 1–5 assigned per county zoning_complexity = ROUND( 0.40 × zone_factor + 0.40 × permit_factor + 0.20 × burden_factor )

7.4 · Reference calibration

CountyZone CountZone FactorPermit FactorBurden FactorScore
Clallam Co., WA394534

Clallam: 39 zone designations (factor 4), MPR requires CPA (factor 5), some overlay districts present (factor 3). Round(0.4×4 + 0.4×5 + 0.2×3) = Round(4.2) = 4.

7.5 · Status

Factor ranges pending validation against a national county sample (T-47). BuildType mapping factor deferred until ZoneDesignations and LandUses tables are seeded. Editorial permit_factor and burden_factor values assigned per county during data onboarding.