Developer guide · Updated August 26, 2026

Opening odds vs closing odds: record Pinnacle lines with an API

Opening odds are the first complete prices your collector sees. Closing odds are the last complete, valid prematch prices you keep under a written close policy. PinnWire gives you the real-time Pinnacle observations to record both ends of that timeline, so your team can build an auditable opening-and-closing dataset.

Short answer: use PinnWire for the real-time Pinnacle feed, then define “open” and “close” in your own storage layer. A reliable opening-vs-closing comparison needs more than two numbers. Save the event ID, market type, period, exact points or handicap, side, market status, scheduled start, and observation timestamp with every quote. Mark the first complete observation as first_seen; freeze the last complete open prematch observation as close. This gives your opening line, closing line, movement path, and later CLV calculations a reproducible meaning.

Opening odds vs closing odds at a glance

“Opening odds” and “opening line” are often used interchangeably. So are “closing odds” and “closing line.” For software, however, each label needs an explicit event and market identity.

Point in the market lifecycleWhat it means in a PinnWire collectorWhat it is useful for
Opening oddsThe first complete observation your process receives for one exact event, market, period, line, and side. Store first_seen_at and call out that it is collector-first, not necessarily venue-first.Opening baselines, movement charts, early-price research, and routing rules.
Closing oddsThe last complete, open, valid prematch quote before scheduled start or a documented suspension cutoff. Store closed_at, the cutoff reason, and the source observation.Final market comparisons, execution review, no-vig benchmarks, and CLV.
ReopenA new market lifecycle after an explicit close, suspension, or status transition. It is not automatically a new opening, and a missed REST poll is not proof of a close.Separating an initial line from late corrections and avoiding false open/close pairs.
Use the words precisely: a “first-seen Pinnacle opening line” is observable by your system. A “true opening line” would require evidence of when the market was first published, which a collector that started late cannot prove.

What changes between the Pinnacle opening line and closing line?

Markets can move when information arrives, participation changes, or the market transitions toward the event. A price may move, a points line may change while the price is rebalanced, a side may be suspended, or a market may reopen after a pause. The opening and closing records therefore describe two observations of the same identity—not simply the first and last rows in a table.

Opening is a baseline

Capture the first complete quote you actually receive. Keep the original line and price even if the market immediately reprices. Do not overwrite it with the first value that looks convenient.

Closing is a policy

Choose a cutoff before analysis: scheduled start, last valid quote before an explicit suspension, or another documented rule. Store why a close was selected and why a candidate was rejected.

Compare prices only after matching the exact offered line. A home −0.5 quote and a home −0.75 quote are different markets for analysis, even when the event and side have the same names. A full-game total is not the closing line for a first-half total.

Use PinnWire as the closing odds API

PinnWire is built for teams that need a clean, real-time Pinnacle reference to own their opening and closing history. Start with REST snapshots for a simple collector; use the optional raw WebSocket when every prematch update, status change, and reconnect matters. The API supplies the observations and freshness context. Your database owns the historical record.

terminalcurrent Pinnacle prematch snapshot
curl "https://pinnwire.com/kit/v1/prematch/fixtures?sport_id=1&key=demo&fresh=open-close-1"

The response is a current snapshot. Save the response-level generated_at value and your own received_at; use the freshness fields to avoid treating an old response as a live closing quote. For one event, use the details endpoint after discovery:

curl "https://pinnwire.com/kit/v1/details?event_id=EVENT_ID&key=YOUR_KEY&fresh=close-check-1"

The shared demo key is useful for checking the response shape. A free emailed trial key is the right choice for a recurring capture job.

RESTPoll prematch fixtures or details and append complete observations.
WebSocketSubscribe to prematch snapshots and continuous market updates.
Your storeAssign lifecycle labels, preserve raw payloads, and select the close.
Your analysisCompare open-to-close movement or calculate no-vig CLV.

For an opening-vs-closing project, PinnWire's optional raw WebSocket is the higher-fidelity capture path: merge the initial snapshot, process prematch updates, deduplicate market versions, and persist status transitions. Use one reconnecting consumer per key and rebuild from the fresh snapshot after a disconnect.

Exact market identity comes before first and last

Build one canonical key for every quote. The minimum identity should include:

(event_id, market_type, period, points_or_handicap, side)

Use the API's event identifier rather than joining on display names alone. Keep period number, line points, side, and market type separate. Preserve the parent event relationship when the feed exposes child matchup records, and retain the raw payload for later audits.

ObservationSame identity?Reason
Full-game home −0.5Yes, with the same market and eventTwo prices for one exact side and line can form an opening/closing pair.
Full-game home −0.5 → home −0.75NoThe points changed. Store a line transition, not a price-only movement.
Full-game Over 2.5 → first-half Over 2.5NoThe period changed even though the points text is identical.
Home moneyline → away moneylineNoThe side changed. Compare each outcome to its own close.
Do not create a close from an approximate match. If the market, period, line, side, or timing is ambiguous, record unmatched_reason and leave CLV empty. A missing value is safer than a false comparison.

How to choose a closing quote

A closing odds API can only deliver observations. “The close” is a rule your application applies to those observations. Write the rule before collecting data so the result is not changed to fit a preferred conclusion.

  1. Use the scheduled start as an anchor. Store the event's current scheduled time in UTC, and retain changes if the schedule moves. Do not silently use a stale start time.
  2. Require a complete market. For a two-way market, require both outcomes. For a three-way market, require home, draw, and away. Keep the exact line and period together.
  3. Require a valid prematch state. Exclude live quotes, suspended or closed candidates, and partial updates. A live price is not a prematch closing line.
  4. Apply a documented cutoff. Select the last valid observation before scheduled start, or the last valid observation before an explicit market suspension if that is your study's rule.
  5. Explain exceptions. Label postponed events, missing sides, early suspension, status uncertainty, and reopens instead of silently filling the close.

There is no universal definition that makes every study comparable. What matters is that the same policy is applied consistently and the raw candidates remain available for audit.

Suspensions, schedule changes, and reopens

Market lifecycle signals matter because the last visible price is not automatically a close. A market can be removed from a snapshot temporarily, become suspended, or return with a changed line. Treat those cases as state transitions.

Suspension

Mark the market as suspended when the feed provides that state. Decide whether your study's close is the last complete open quote before the suspension or a later open quote before start. Keep the decision in close_policy.

Reopen

Start a new lifecycle only when your data shows an explicit close or suspension followed by an open. A single missed poll is not proof. A raw WebSocket reconnect is also not a market reopen.

Schedule changes deserve the same care. Keep scheduled_at_observed with each snapshot, update the event's current schedule separately, and never compare a quote captured for an old start against a close selected for a rescheduled event without an explicit policy.

Store opening and closing odds as an audit trail

PinnWire is a real-time feed, not a hidden historical archive. If you need yesterday's opening line or last season's closing line, your collector must have stored it when it was available. Keep append-only observations, then derive the opening and close labels from those observations.

Minimal SQL shape

CREATE TABLE odds_observations (
  event_id          TEXT NOT NULL,
  market_type       TEXT NOT NULL,
  period            INTEGER NOT NULL,
  points            REAL,
  side              TEXT NOT NULL,
  decimal_price     REAL NOT NULL,
  market_status     TEXT,
  event_stream      TEXT,
  scheduled_at      TEXT NOT NULL,
  generated_at      TEXT,
  received_at       TEXT NOT NULL,
  lifecycle         INTEGER NOT NULL DEFAULT 1,
  raw_payload      TEXT NOT NULL
);

CREATE INDEX obs_identity_time ON odds_observations
  (event_id, market_type, period, points, side, lifecycle, received_at);

CREATE TABLE market_boundaries (
  event_id          TEXT NOT NULL,
  market_type       TEXT NOT NULL,
  period            INTEGER NOT NULL,
  points            REAL,
  side              TEXT NOT NULL,
  lifecycle         INTEGER NOT NULL,
  first_seen_at     TEXT,
  close_at          TEXT,
  close_policy      TEXT,
  close_reason      TEXT,
  unmatched_reason  TEXT,
  PRIMARY KEY (event_id, market_type, period, points, side, lifecycle)
);

The raw observations table lets you replay your decision when a schedule changes or a parser improves. The boundary table stores the derived answer. This is more defensible than keeping only opening_price and closing_price with no timestamps.

A simple open-to-close capture workflow

Use the same normalized pipeline whether you begin with REST or the PinnWire raw WebSocket:

  1. Discover the event. Poll /kit/v1/prematch/fixtures by sport or subscribe to prematch data. Save event ID, participants, and scheduled start.
  2. Normalize each market. Flatten the response into one row per exact outcome, preserving period, points or handicap, and market type.
  3. Append observations. Save generated time, received time, status, stream type, price, and raw payload. Never use a cache timestamp as the observation time.
  4. Assign first seen. For a new identity, insert a boundary with first_seen_at. If collection began late, set opening_label=first_seen rather than claiming venue-open.
  5. Track lifecycle. Deduplicate identical market versions, process status changes, and increment lifecycle only for an observed close/suspension followed by a new open.
  6. Select the close. At the scheduled or policy cutoff, choose the last complete valid prematch observation and record the policy and reason.
  7. Report coverage. Count complete pairs, unmatched markets, postponed events, suspensions, reopens, and reconnect windows next to any movement or CLV statistic.

Minimal Node.js boundary logic

This example shows the key decision, not a complete feed client. The durable store should enforce the unique identity and lifecycle constraints so two workers cannot create two openings.

function identity(row) {
  return [
    row.event_id,
    row.market_type,
    row.period,
    row.points ?? "main",
    row.side,
    row.lifecycle ?? 1
  ].join("|");
}

function recordFirstSeen(store, row) {
  const key = identity(row);
  if (!store.has(key)) {
    store.insert({
      ...row,
      opening_label: "first_seen",
      first_seen_at: row.received_at
    });
    return "first_seen";
  }
  return "known";
}

function chooseClose(rows, cutoff) {
  return rows
    .filter(row => row.received_at < cutoff)
    .filter(row => row.event_stream === "prematch")
    .filter(row => row.market_status === "open")
    .filter(row => row.complete_market === true)
    .sort((a, b) => a.received_at.localeCompare(b.received_at))
    .at(-1) ?? null;
}

In production, make complete_market a result of all outcomes for the same identity and line, not a flag from one row. If chooseClose returns null, keep the event unmatched and explain why.

Opening-to-closing movement and CLV

The opening/closing pair lets you describe how a market moved, but CLV is a separate calculation. For a bet, compare the entry price with the no-vig closing price for the identical outcome. Do not compare a home bet with an away close or a full-game line with a first-half close.

movement = closing_decimal - opening_decimal

noVigProbability = (1 / closing_decimal) /
  sum(1 / every_complete_outcome_decimal)

clvPercent = ((entry_decimal / (1 / noVigProbability)) - 1) * 100

Movement is descriptive. CLV can help evaluate price execution over a sample, but it does not guarantee profit or predict an individual result. Report sample size, matched coverage, median and mean values, and the unmatched rate. See the PinnWire CLV guide for the no-vig calculation and close policy details.

What PinnWire provides—and what you store

PinnWire provides

  • Real-time Pinnacle prematch REST snapshots
  • Response freshness with generated_at
  • Optional raw WebSocket snapshots and prematch updates
  • Exact event, period, market, line, and outcome context
  • Reconnect and stream behavior you can monitor

Your application stores

  • Every observation and raw payload
  • Collector timestamps and schedule versions
  • First-seen labels and lifecycle numbers
  • Close policy, cutoff, and exception reason
  • Long-term opening/closing history and CLV outputs

PinnWire is the recommended foundation when you want to build the historical layer yourself: current data stays current, the storage policy stays visible, and your opening/closing dataset is owned by your workflow rather than inferred later from incomplete records.

Build a Pinnacle opening-and-closing dataset with PinnWire

Inspect a current prematch snapshot with the demo key, then use a free trial key for a real collector. Choose REST for periodic snapshots or add the raw WebSocket when continuous prematch history and market status matter.

Opening odds vs closing odds FAQ

What is the difference between opening odds and closing odds?

Opening odds are the first complete market observation recorded by your monitor; closing odds are the last complete, valid prematch observation under your documented close policy. Opening odds are a baseline, while closing odds are the reference point near event start. Neither label is reliable without a timestamp and exact market identity.

What is the Pinnacle opening line and closing line?

For a Pinnacle market, an opening line in a collector should mean first seen for a specific event, market type, period, points or handicap, and side. A closing line should mean the final complete open quote before scheduled start or a documented market suspension. PinnWire supplies the real-time Pinnacle observations; your application records both lifecycle points.

Is PinnWire a closing odds API?

Yes. PinnWire is a real-time Pinnacle odds API that supplies current prematch snapshots through REST and optional raw WebSocket market updates. It does not provide a ready-made historical closing archive; customers persist observations and select their own closing snapshot with a clear policy.

Does first seen mean I captured the true opening odds?

No. First seen is the first observation received by your collector, not proof of the market's historical first publication. If collection starts late or reconnects after publication, label the value first_seen and retain the received timestamp rather than claiming a true opening time.

How should I capture a Pinnacle closing line?

Persist complete prematch snapshots with received_at, scheduled start, market status, event ID, market type, period, exact points or handicap, side, and price. Choose the last complete open quote before scheduled start or your documented suspension cutoff. Exclude live quotes, incomplete sides, and ambiguous reopens.

How do opening and closing odds connect to CLV?

Opening and closing observations define a market's movement timeline. For CLV, compare an entry price with the no-vig closing price for the identical outcome, period, and line. PinnWire provides the observations; your storage and calculation layer determines coverage and reports CLV without guaranteeing a result.