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/clvEnterprise 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 computed
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) × 100where 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 Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
from | string | 7 days ago | Start date (YYYY-MM-DD or ISO 8601). Clamped to your tier’s history window. |
to | string | today | End date (YYYY-MM-DD or ISO 8601). |
group_by | string | sportsbook | Aggregation dimension. One of: sportsbook, sport, league, market, day, devig_book. |
sport | string | all | Filter by sport(s), comma-separated (e.g. basketball,baseball). |
league | string | all | Filter by league(s), comma-separated (e.g. nba,mlb). |
sportsbook | string | all | Filter by sportsbook(s), comma-separated. |
devig_book | string | all | Filter by the sharp reference the pick was priced against (e.g. pinnacle). |
History window by tier
Date ranges are clamped to your tier’s lookback window (reflected in meta.tier_window_days):
| Tier | Window |
|---|---|
| Free | 7 days |
| Hobby | 30 days |
| Pro | 90 days |
| Sharp | 365 days |
| Enterprise | Unlimited |
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 Requests
cURL
# 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"Response
Success (200)
{
"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 Responses
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 Fields
data object
| Field | Type | Description |
|---|---|---|
date_range | object | Actual from/to used after tier clamping |
group_by | string | The dimension used for aggregation |
groups | array | Array of group rows |
Group row fields
| Field | Type | Description |
|---|---|---|
group_key | string | The group identifier (sportsbook name, sport, league, market type, YYYY-MM-DD date, or devig book) |
total_graded | integer | Logical predictions with a CLV grade (closing line captured and compared) |
wins | integer | Graded predictions whose game outcome settled as a win |
losses | integer | Graded predictions whose game outcome settled as a loss |
win_rate | number | null | wins / (wins + losses). Computed over the settled subset only; null when no settled bets exist in the group |
avg_clv_percent | number | null | Average CLV% across graded predictions. Positive = flagged prices beat the close on average. null when not computable |
avg_ev_percent | number | null | Average expected value % at detection time for the group’s predictions. null when not computable |
total_predictions | integer | All tracked predictions in the group, including ones not (yet) graded |
meta object
| Field | Type | Description |
|---|---|---|
filters | object | Echo of the applied filters (sport, league, sportsbook, devig_book, group_by); null for unused filters |
source | string | "clickhouse" — the historical analytics store |
tier_window_days | integer | string | Maximum lookback for your tier (e.g. 90), or "unlimited" |
updated_at | string | ISO 8601 response timestamp |
Interpreting CLV
| 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_ratealongsideavg_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_gradedor 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.
Related Endpoints
- Closing Odds — Per-event raw closing prices (Pro tier and up)
- Closing Odds by Date — Historical per-event closing prices for a given date
- +EV Opportunities — Real-time positive expected value bets
- Odds Snapshot — Current pre-match and live odds