Skip to Content
API ReferenceClosing Line Value (CLV)

Closing Line Value (CLV)

Aggregate Closing Line Value statistics for SharpAPI’s graded +EV predictions. For every +EV opportunity the engine flags, the system later captures the sharp reference’s closing line and grades the pick against it — this endpoint serves those grades, aggregated along the dimension you choose (group_by), together with realized win/loss outcomes where the game result is known.

GET /api/v1/historical/odds/clv

Enterprise tier required. The /api/v1/historical/* aggregate endpoints are gated by the history feature. Lower tiers receive 403 tier_restricted. If you’re on Pro or Sharp and want closing-line data, use Closing Odds — per-event raw closing prices, available on your tier.

URL moved. This endpoint was previously served at /api/v1/historical/clv. The old path still works but is deprecated — responses on it carry Deprecation: true, Sunset: Wed, 30 Sep 2026 00:00:00 GMT, and a Link: </api/v1/historical/odds/clv>; rel="successor-version" header. Migrate to /api/v1/historical/odds/clv before the sunset date.

How CLV is computedPermalink for this section

When an event transitions from pre-match to live, the platform captures each book’s last pre-match price as that event’s closing line. The closing price of the sharp reference (devig_book — typically Pinnacle) is devigged with the Power method to a no-vig closing probability, and each graded prediction is scored as:

CLV% = (closing_no_vig_prob × entry_decimal_odds − 1) × 100

where entry_decimal_odds is the price at the moment SharpAPI flagged the opportunity. Positive CLV means the flagged price beat the close — you could have bet at better odds than the market’s final fair value implied.

Data is served from the historical ClickHouse store. Aggregates are computed over logical predictions — repeated price snapshots of the same pick (same event, market, selection, book, line) are collapsed into one row before counting, so a pick that was re-observed at several prices is not counted multiple times.

Query ParametersPermalink for this section

ParameterTypeDefaultDescription
fromstring7 days agoStart date (YYYY-MM-DD or ISO 8601).
tostringtodayEnd date (YYYY-MM-DD or ISO 8601).
group_bystringsportsbookAggregation dimension. One of: sportsbook, sport, league, market, day, devig_book.
sportstringallFilter by sport(s), comma-separated (e.g. basketball,baseball).
leaguestringallFilter by league(s), comma-separated (e.g. nba,mlb).
sportsbookstringallFilter by sportsbook(s), comma-separated.
devig_bookstringallFilter by the sharp reference the pick was priced against (e.g. pinnacle).

History windowPermalink for this section

This endpoint is Enterprise-only, and the Enterprise history window is unlimited (meta.tier_window_days = "unlimited"). from defaults to 7 days ago when omitted; there is no enforced upper bound on how far back you can query.

Filter by devig_book=pinnacle for the meaningful signal. CLV validity is dominated by the sharp reference the pick was priced against. Pinnacle-referenced CLV is the predictive series; picks priced against fallback references (e.g. bookmaker) carry structurally negative CLV and should not be read as edge. Group by devig_book to see the split.

Example RequestsPermalink for this section

# CLV by sportsbook for the past 7 days curl -X GET "https://api.sharpapi.io/api/v1/historical/odds/clv?group_by=sportsbook" \ -H "X-API-Key: YOUR_API_KEY" # Pinnacle-referenced CLV only, grouped by sport curl -X GET "https://api.sharpapi.io/api/v1/historical/odds/clv?devig_book=pinnacle&group_by=sport" \ -H "X-API-Key: YOUR_API_KEY" # Day-by-day CLV for DraftKings picks over a date range curl -X GET "https://api.sharpapi.io/api/v1/historical/odds/clv?sportsbook=draftkings&group_by=day&from=2026-06-01&to=2026-06-08" \ -H "X-API-Key: YOUR_API_KEY"

ResponsePermalink for this section

Success (200)Permalink for this section

{ "success": true, "data": { "date_range": { "from": "2026-06-03T14:12:30.437", "to": "2026-06-10T14:12:30.437" }, "group_by": "sportsbook", "groups": [ { "group_key": "novig", "total_graded": 1294, "wins": 262, "losses": 200, "win_rate": 0.5670995670995671, "avg_clv_percent": 0.673342797764432, "avg_ev_percent": 1.613983921390446, "total_predictions": 1555 }, { "group_key": "prophetx", "total_graded": 964, "wins": 191, "losses": 214, "win_rate": 0.47160493827160493, "avg_clv_percent": 0.07641414602522267, "avg_ev_percent": 1.4343012769214647, "total_predictions": 1331 } ] }, "meta": { "filters": { "devig_book": null, "group_by": "sportsbook", "league": null, "sport": null, "sportsbook": null }, "source": "clickhouse", "tier_window_days": "unlimited", "updated_at": "2026-06-10T14:12:58.75061216Z" } }

An empty groups array is a valid response when no graded predictions exist for the requested filters and date range — not an error.

Three different counts — don’t mix denominators. total_predictions counts every tracked pick (including ones never graded). total_graded counts picks with a CLV grade (a closing line was captured and compared). wins + losses counts the typically smaller subset whose game outcome is also settled — and win_rate is computed over that subset only. A group can legitimately show total_graded: 1294 next to wins + losses: 462. win_rate is null when a group has no settled bets.

Error ResponsesPermalink for this section

403 Tier Restricted

{ "error": { "code": "tier_restricted", "message": "This endpoint requires Enterprise tier or higher", "docs": "https://sharpapi.io/pricing", "tier": "pro", "required_tier": "enterprise" } }

400 Validation Error

{ "error": { "code": "validation_error", "message": "Invalid group_by. Must be one of: day, devig_book, league, market, sport, sportsbook" } }

Response FieldsPermalink for this section

data objectPermalink for this section

FieldTypeDescription
date_rangeobjectActual from/to used after tier clamping
group_bystringThe dimension used for aggregation
groupsarrayArray of group rows

Group row fieldsPermalink for this section

FieldTypeDescription
group_keystringThe group identifier (sportsbook name, sport, league, market type, YYYY-MM-DD date, or devig book)
total_gradedintegerLogical predictions with a CLV grade (closing line captured and compared)
winsintegerGraded predictions whose game outcome settled as a win
lossesintegerGraded predictions whose game outcome settled as a loss
win_ratenumber | nullwins / (wins + losses). Computed over the settled subset only; null when no settled bets exist in the group
avg_clv_percentnumber | nullAverage CLV% across graded predictions. Positive = flagged prices beat the close on average. null when not computable
avg_ev_percentnumber | nullAverage expected value % at detection time for the group’s predictions. null when not computable
total_predictionsintegerAll tracked predictions in the group, including ones not (yet) graded

meta objectPermalink for this section

FieldTypeDescription
filtersobjectEcho of the applied filters (sport, league, sportsbook, devig_book, group_by); null for unused filters
sourcestring"clickhouse" — the historical analytics store
tier_window_daysinteger | stringMaximum lookback for your tier (e.g. 90), or "unlimited"
updated_atstringISO 8601 response timestamp

Interpreting CLVPermalink for this section

CLV%Interpretation
> +2%Flagged prices consistently beat the close by a wide margin — strong captured value
+0.5% to +2%Prices modestly beat the close — typical for soft books against a sharp reference
-0.5% to +0.5%Near-market — efficient pricing or mixed results
< -0.5%Prices tightened into the close — late steam or sharp-side action

CLV is not ROI — read it with the right caveats.

  • Market efficiency varies. In the sharpest, most liquid markets (for example NBA spreads and totals, and major-league player props), beating the close does not reliably convert into realized profit — closing-line beats there often reflect noise in an efficient market rather than edge. In softer markets, positive CLV remains the best leading indicator of long-run profitability.
  • Use win_rate alongside avg_clv_percent. The endpoint returns realized outcomes for exactly this reason: a group with positive CLV but a sub-breakeven settled record over a large sample is telling you the CLV there isn’t converting.
  • Mind the sample size. Groups with small total_graded or few settled bets (wins + losses) are noise — compare groups only at meaningful volume.
  • The sharp reference matters. Only sharp-referenced CLV (filter devig_book=pinnacle) carries this meaning; fallback-referenced rows do not.
Last updated on