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/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.

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). Clamped to your tier’s history window.
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 window by tierPermalink for this section

Date ranges are clamped to your tier’s lookback window (reflected in meta.tier_window_days):

TierWindow
Free7 days
Hobby30 days
Pro90 days
Sharp365 days
EnterpriseUnlimited

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/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/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/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