Methodology

How the leaderboard imports data, prices offers, applies guardrails, caches responses, and reports freshness.

Leaderboard Missions

What This Tool Ranks

The calculator ranks NPC LP-store offers by realistic ISK per LP. It compares selling into Jita buy orders with listing against Jita sell orders, after taxes, broker fees, required item costs, and blueprint manufacturing material costs when that mode is enabled.

The default leaderboard:

The Space control can narrow results to highsec-accessible stores or show all known access tiers. The Level 5 Missions control can show all corporations, only corporations with level 5 agents, or hide them. Ranking controls can choose the valuation basis, scale runs, set LP/hour, require minimum 28-day market volume, and optionally hide rows above a maximum packaged cargo volume in m3. Quality toggles control Jita-only pricing, suspicious rows, vanity rows, no-Security-L4+ corporations, faction warfare, special LP stores, and duplicate store rows. The BPC control picks which blueprint-copy rows appear: none, direct contract sales, manufacture conversions, or both.

Data Sources

Refresh Cadence

The scheduler refreshes:

Startup warmup fills missing or stale SDE, LP, market, and history data before normal cadence takes over. Fetchers honor ESI Expires headers through the SQLite ESI cache, retry transient upstream failures carefully, and pause before exhausting the ESI error-limit budget.

The leaderboard header reports hot and cold market-price ages separately, LP offer freshness as a daily feed, and an overall Updates OK or Needs attention state from /api/health. A daily LP timestamp that is a few hours old is expected; hot prices are the freshness signal that should normally move every 15 minutes.

Core Calculation

buy_order_sell = sell products into buy orders, pay sales tax
sell_order_listing = list products near sell orders, pay sales tax plus one broker-fee pass

input_cost = LP-store ISK cost + required items bought from sell orders
build_cost = BPC materials bought from sell orders
net_buy_order = product_value_buy_order * (1 - sales_tax_rate) - input_cost - build_cost
net_sell_order = product_value_sell_order * (1 - sales_tax_rate - broker_fee_rate) - input_cost - build_cost
isk_per_lp = selected net_profit / LP cost

The valuation basis can use buy-order cashout, sell-order listing, or the higher of both. runs scales LP, ISK, required items, manufacturing materials, cargo, and order-book depth. When lpBudget or iskBudget is provided, the calculator chooses the maximum feasible run count for that row. The ISK/hour display multiplies the selected ISK/LP basis by the URL-backed lpPerHour value. Contract-priced rows show a dash instead: their ISK/LP is a real one-off conversion rate, but public contracts for such items sell at most a few times per day game-wide, so extrapolating by LP/hour would invent income the market cannot absorb. These rows also sort last when the leaderboard is sorted by ISK/hour.

Fees And Skills

sales_tax_rate = 0.075 * (1 - 0.11 * Accounting)
broker_fee_rate = max(
  0.03
  - 0.003 * BrokerRelations
  - 0.0003 * factionStanding
  - 0.0002 * corporationStanding,
  0.01
)

These are the Tranquility NPC-station rates: sales tax starts at 7.5% and falls to 3.375% at Accounting V; the broker fee starts at 3%, drops 0.3 percentage points per Broker Relations level plus up to 0.3 from faction and 0.2 from corporation standing, and never goes below 1%. Accounting, Broker Relations, Advanced Broker Relations, faction standing, and corporation standing are URL-backed filters. Defaults are zero so the default view is pessimistic for a fresh character. Advanced Broker Relations only affects relist fees in Realistic patient mode.

Depth Walking

Every priced leg walks the persisted Jita order book for the full requested quantity instead of using only top-of-book. Products sold through buy orders walk buy orders. Products listed through sell orders, required items, and build materials walk sell orders. If the saved top 50 orders do not cover the requested fill, the row is flagged as insufficient depth and the missing quantity is extrapolated at the last consumed price.

Patient Listing Realism

The sell-order (patient) basis above assumes a listing fills in full at the walked prices. In reality a listing joins a queue and waits. Every row therefore carries an estimated fill time for the primary output, shown in the detail drawer:

queue_ahead  = sell-book units listed at or below the volume-weighted list price
sell_rate    = 0.5 * avg_daily_volume_28d
days_to_fill = (queue_ahead + quantity) / sell_rate

The 0.5 factor exists because ESI daily volume mixes both trade directions and only buyer-initiated trades consume the sell book; with no public split, half is the symmetric prior. Items with no market history get no estimate. The SLOW_FILL flag uses this queue-aware estimate for the output leg: warn past 7 days, strong past 28.

The optional Realistic patient quality toggle (off by default, URL-backed) goes further and discounts the sell-order valuation itself:

relist_discount  = 0.5 + 0.06 * AdvancedBrokerRelations          (80% at V)
expected_relists = ceil(days_to_fill / 2) - 1, floored at 0
relist_cost      = expected_relists * (1 - relist_discount) * broker_fee_rate * product_value
patient_effective = net_buy_order + (net_sell_order - relist_cost - net_buy_order)
                    * exp(-days_to_fill / 7)

The exponential decay pulls slow fills toward the guaranteed buy-order cashout: a fill estimated a week out keeps about 37% of the patient premium, and a month-long fill keeps almost none. Relist fees model staying competitive against undercutting, using the Tranquility relist mechanic where modifying an order down costs the undiscounted share of the broker fee on the new price; Advanced Broker Relations is a URL-backed skill filter next to the other fee skills. With the toggle off, nothing changes — the patient and best columns keep the optimistic immediate-fill values.

BPC Manufacturing

When an offered product is a blueprint copy with a manufacturing recipe in the SDE, the calculator can value the manufactured output and subtract material costs ("manufacture" rows), and when fresh public-contract asks exist it can value the copy as a direct contract sale ("sell" rows). Both are hidden by default because blueprint rows can dominate the table with assumptions that are more sensitive to build settings, material liquidity, and contract depth. The four-position BPC control in the Quality filters picks which rows appear: None (default), Sell, Build (manufacture conversions), or All.

Risk And Access

Space filtering and row risk icons use practical LP-store access risk, derived from the least risky known NPC station owned by the corporation. The corporation HQ system is still shown as location metadata, but it does not by itself make a highsec-accessible corporation look like a nullsec-only store. Highsec is security 0.5 and above, lowsec is 0.0 through 0.4, and nullsec covers below 0.0 plus any wormhole or unknown-security store access.

DED, CONCORD, and similar special-source LP stores are marked as special LP and excluded from the global default leaderboard. Faction warfare offers are also opt-in. LP-store corporations with no earnable LP source, such as event or placeholder LP stores without agents, are excluded before these user-facing filters are applied. Risk chips are visual warnings on the row; highsec-accessible rows do not get a risk chip.

Quality Flags

FlagRuleSeverity
LOW_VOLUME28-day average daily volume is below 100 units and below 250m ISK; expensive items that move serious ISK on few units are not flagged.Warn; shown as a yellow flag.
SLOW_FILLThe estimated sell-order fill of the output — queue ahead at the walked list price plus the requested quantity, against the sell-side half of daily volume (see Patient Listing Realism) — exceeds 7 days. Cost legs keep the plain quantity-versus-volume rule.Warn; strong above 28 days.
HEAVYPackaged cargo volume is above 100 m3 and at or below 500 m3.Warn; shown as a yellow flag.
VERY_HEAVYPackaged cargo volume is above 500 m3.Strong visual; shown as a red flag.
THIN_BOOKSell order count is 2 or less, or the top sell order has more than 80% of sell quantity.Warn
WIDE_SPREADSell minimum is more than 50% above buy maximum.Warn
PRICE_SPIKECurrent sell minimum is more than twice the 28-day median price.Strong
BUY_SPIKECurrent buy maximum on the output is more than 1.5x the 28-day median price. Buy maxima normally sit below the median, so this usually means a seeded buy wall is inflating the buy-order valuation.Strong
OFF_HUBCheapest sell order is not at Jita 4-4.Warn, or strong when multiple significant cost legs are off-hub.
NO_HISTORYMarket history has fewer than seven days.Warn
INSUFFICIENT_DEPTHPersisted order-book depth does not cover the requested fill.Strong
CONTRACT_PRICEDThe product cannot be listed on the regular market (no market group, typically a faction blueprint copy) and is valued from scam-filtered public-contract asks in The Forge: blueprint copies are normalized to price per run, decoy listings are screened by a recipe cap (a copy's per-run value cannot exceed what the built product sells for) and a band anchored on the cheapest credible ask, and at least two independent asks must survive. The patient basis skips the sales tax and broker fee because item-exchange contracts pay only a flat creation fee; no instant-sell value exists. Blueprint offers with both a manufacture recipe and a contract price appear twice — a (sell) row for the direct contract sale and a (manufacture) conversion row whose net profit keeps total-realization math while the consumed copy's contract value counts into capital required and ROI; both are hidden until the BPC control enables them.Warn
NICHE_DEMANDA contract-priced blueprint copy where one copy covers at least half a day of the built product's entire Jita demand (copy runs against the product's 28-day average daily volume). The whole market absorbs only a handful of fresh copies per day, so sale velocity — not LP/hour — caps what the offer can actually earn; the flag message states the copy-to-demand ratio.Warn
VANITYThe product is a vanity or cosmetic item: SDE apparel, SKIN, or personalization categories and groups, or a SKIN-named type.Warn; frontend chip from row metadata.
RISK_LOWSECBest known LP-store access is a low security station (see Risk And Access); highsec-accessible rows get no chip.Warn; frontend chip from row metadata.
RISK_NULLSECBest known LP-store access is null security or wormhole space.Strong; frontend chip from row metadata.
RISK_UNKNOWNNo known NPC station for the corporation, so the access risk tier is unknown.Strong; frontend chip from row metadata.

Tapping or clicking a flag chip on the leaderboard expands it into its full message; the ? inside links back to this section. Cargo-volume, vanity, and access-risk chips are added by the frontend from row metadata so they remain visible even when the persisted market-quality flags are otherwise clean.

Three quality filters interact with these flags:

Search And Grouping

The compute step materializes offer names, product signatures, risk/source fields, flag counts, ratios, and compact API summaries into calc, then rebuilds SQLite FTS search for offer and product names. Corporation filtering uses a name autocomplete backed by corporation IDs. Identical offer economics are grouped by default so duplicate corporation stores do not crowd out distinct opportunities; "Show duplicate stores" returns each store row.

Frontend Loading And Diagnostics

The LP page starts the rows, corporations, and health requests without blocking the browser page-load event. It renders skeleton rows for a first load, reuses session-cached rows immediately for repeated filters, ignores stale filter responses, and shows a compact topbar loading state only while the current request is still active.

A persistent browser client ID is shown in the header and sent as X-EVE-Client-Id on API calls. The server also returns a fresh X-Request-Id for every request and writes problem-only JSON lines for 4xx and 5xx responses to logs/http-problems.log. The visible client ID helps correlate a player report without exposing request IDs in the UI.

API And Health

Read endpoints are rate-limited to 180 requests per minute per IP and set permissive CORS. Public LP API paths work at both /api/* and /lp/api/*. /api/health reports fetcher freshness, empty core tables, database size, last compute time, and SDE import metadata. POST /api/refresh recomputes the leaderboard and requires X-Admin-Token.

After each compute, canonical leaderboard, CSV, and corporation responses are materialized into SQLite with ETags and Brotli bodies. Dynamic read responses use short browser caching and longer CDN caching, while health stays short-lived. When Cloudflare credentials are configured, compute purges the LP API prefixes; deploys that change unhashed LP HTML/CSS/JS should run the static purge helper after build.

Known Limitations