FormFav LogoFormFav
    GET
    /v1/stats/track-bias/{venue}
    Pro

    Track Bias

    Returns barrier draw bias statistics for a venue, showing which barrier positions historically produce above or below average win rates — for the track as a whole, per distance band, or scoped to a distance you choose.

    Parameters

    venuestring
    required
    Venue slug (path parameter). Case-insensitive (e.g. randwick, flemington).
    race_codestring
    optional
    Default: gallops
    Race type: gallops, harness or greyhounds. For greyhounds, barrier numbers are box positions (1–8).
    countrystring
    optional
    Default: au
    Two-letter country code (e.g. au, nz, hk, gb).
    distancestring
    optional
    Scope the report to a distance in metres. A single value (1200) matches that exact distance; a range (1200-1600) is inclusive and lets you build your own band — narrower than a preset, or spanning several. See Distance Bands. Valid range 200–5000. When supplied, the top-level barrierStats, strongestBarrier, weakestBarrier and biasStrength describe only those races, distanceFilter echoes the scope, and distanceStats holds a single Custom entry for the slice. Combines with window.
    windowinteger
    optional
    Optional rolling window in days (14–365). When provided, a recentStats object is included with barrier bias stats computed only from races within the window (and within distance, if given).
    conditionstring
    optional
    Track condition filter for recent stats (e.g. Good, Soft, Heavy). Only applies when window is also provided.

    Distance Bands

    With no distance parameter, distanceStats contains one entry per band below that the venue actually runs, shortest first. Band labels depend on race_code. Each entry reports the real shortest and longest race distance the venue has run within that band (minDistance / maxDistance), so a “Sprint” band at a track that only runs 1000m and 1200m shows 1000–1200, not the band’s theoretical edges.

    BandGallopsHarnessGreyhounds
    Sprint<1400m—≤450m
    Medium——451–565m
    Distance——566m+
    Mile1400–1799m<1800m—
    Middle1800–2199m1800–2399m—
    Classic2200–2599m——
    Staying2600–3200m2400–2899m—
    Long—2900m+—
    Marathonover 3200m (jumps races land here)——

    Custom ranges

    The preset bands are a starting point. If you want a different slice — one exact distance, a tighter band, or a wider one that merges two presets — pass it as distance and the whole report is computed for exactly those races:

    • distance=1200 — only 1200m races (a single value is an exact match)
    • distance=1000-1200 — a tighter band than the preset Sprint
    • distance=1400-2200 — merges Mile and Middle into one band
    • distance=500-525 with race_code=greyhounds — the two common middle-distance box lengths together

    Ranges are inclusive at both ends, in metres, and must fall within 200–5000. Anything else (a reversed range, a unit suffix, a value outside the bounds) returns a 422 with the reason. When distance is supplied, distanceStats contains one entry with category: "Custom" mirroring the top-level report; its minDistance / maxDistance are the shortest and longest distances actually run inside your range, so distance=1600-2200 at a track with no races between 2000m and 2200m reports 1600–2000. Add window to also get a recent-form version of the same slice in recentStats.

    Code Examples

    javascript
    const response = await fetch(
      'https://api.formfav.com/v1/stats/track-bias/randwick?' +
      new URLSearchParams({
        race_code: 'gallops',
        distance: '1200-1600'
      }),
      {
        headers: { 'X-API-Key': 'your_api_key_here' }
      }
    );
    
    const data = await response.json();

    Response Fields

    venuestring
    Venue name
    raceTypestring
    Race type code: R (gallops), H (harness), G (greyhounds)
    totalRacesinteger
    Total starts analysed in the top-level report
    expectedWinRatenumber
    Expected win rate if no barrier bias existed (1 / number of barriers)
    barrierStatsarray
    Per-barrier statistics. Whole-track unless distance was supplied.
    barrierStats[].barrierNumberinteger
    Barrier number (box for greyhounds)
    barrierStats[].totalStartsinteger
    Total starts from this barrier
    barrierStats[].winsinteger
    Total wins from this barrier
    barrierStats[].placesinteger
    Total top-3 finishes from this barrier
    barrierStats[].winRatenumber
    Win rate from this barrier (0–1)
    barrierStats[].placeRatenumber
    Place rate from this barrier (0–1)
    barrierStats[].advantagenumber
    Win rate minus expected win rate (positive = advantage)
    strongestBarrierinteger
    Barrier with highest win rate
    weakestBarrierinteger
    Barrier with lowest win rate
    biasStrengthstring
    Overall bias strength: "strong", "moderate", "mild", or "none"
    distanceStatsarray
    Barrier bias per distance band at this track, shortest band first. Band labels vary by race code — see Distance Bands above. When distance was supplied, a single Custom entry mirroring the scoped top-level report.
    distanceStats[].categorystring
    Band label, or Custom for a distance-scoped report
    distanceStats[].minDistanceinteger
    Shortest race distance in this band at this track (m)
    distanceStats[].maxDistanceinteger
    Longest race distance in this band at this track (m)
    distanceStats[].totalRacesinteger
    Starts analysed in this band
    distanceStats[].expectedWinRatenumber
    Expected win rate in this band
    distanceStats[].barrierStatsarray
    Per-barrier breakdown in this band (same shape as top-level)
    distanceStats[].strongestBarrierinteger
    Strongest barrier in this band
    distanceStats[].weakestBarrierinteger
    Weakest barrier in this band
    distanceStats[].biasStrengthstring
    Bias strength in this band
    distanceFilterobject | null
    Present when distance scoped the report
    distanceFilter.minDistanceinteger
    Lower bound applied (m, inclusive)
    distanceFilter.maxDistanceinteger
    Upper bound applied (m, inclusive)
    conditionStatsarray
    Track-level going breakdown (not distance-scoped)
    conditionStats[].conditionstring
    Track condition (e.g. Good, Soft, Heavy)
    conditionStats[].totalRacesinteger
    Total races in this condition
    conditionStats[].avgFieldSizenumber | null
    Average field size in this condition
    recentStatsobject | null
    Recent-window stats (only when window param provided). Scoped by distance when given.
    recentStats.windowDaysinteger
    Window size in days
    recentStats.totalRacesinteger
    Races in window
    recentStats.expectedWinRatenumber
    Expected win rate in window
    recentStats.barrierStatsarray
    Per-barrier breakdown in window
    recentStats.strongestBarrierinteger
    Strongest barrier in window
    recentStats.weakestBarrierinteger
    Weakest barrier in window
    recentStats.biasStrengthstring
    Bias strength in window
    recentStats.conditionstring | null
    Track condition filter applied

    Example Response

    200
    Response
    json
    {
      "venue": "Randwick",
      "raceType": "R",
      "totalRaces": 12570,
      "expectedWinRate": 0.05,
      "barrierStats": [
        { "barrierNumber": 1, "totalStarts": 1040, "wins": 108, "places": 312, "winRate": 0.1038, "placeRate": 0.3, "advantage": 0.0538 },
        { "barrierNumber": 2, "totalStarts": 1036, "wins": 96, "places": 290, "winRate": 0.0927, "placeRate": 0.2799, "advantage": 0.0427 },
        { "barrierNumber": 3, "totalStarts": 1029, "wins": 112, "places": 301, "winRate": 0.1088, "placeRate": 0.2925, "advantage": 0.0588 }
      ],
      "strongestBarrier": 3,
      "weakestBarrier": 20,
      "biasStrength": "strong",
      "conditionStats": [
        { "condition": "Good", "totalRaces": 653, "avgFieldSize": 10.4 },
        { "condition": "Soft", "totalRaces": 310, "avgFieldSize": 10.1 }
      ],
      "distanceStats": [
        {
          "category": "Sprint",
          "minDistance": 1000,
          "maxDistance": 1300,
          "totalRaces": 5569,
          "expectedWinRate": 0.0588,
          "barrierStats": [
            { "barrierNumber": 1, "totalStarts": 470, "wins": 54, "places": 152, "winRate": 0.1149, "placeRate": 0.3234, "advantage": 0.0561 }
          ],
          "strongestBarrier": 1,
          "weakestBarrier": 15,
          "biasStrength": "moderate"
        },
        {
          "category": "Mile",
          "minDistance": 1400,
          "maxDistance": 1609,
          "totalRaces": 5014,
          "expectedWinRate": 0.05,
          "barrierStats": [
            { "barrierNumber": 1, "totalStarts": 418, "wins": 40, "places": 121, "winRate": 0.0957, "placeRate": 0.2895, "advantage": 0.0457 }
          ],
          "strongestBarrier": 3,
          "weakestBarrier": 20,
          "biasStrength": "strong"
        }
      ],
      "distanceFilter": null,
      "recentStats": null
    }

    Example Response (scoped by distance)

    GET /v1/stats/track-bias/randwick?distance=1200 — the top-level report now describes only 1200m races, and distanceStats carries the same slice as a single Custom entry.

    200
    Response
    json
    {
      "venue": "Randwick",
      "raceType": "R",
      "totalRaces": 2582,
      "expectedWinRate": 0.0588,
      "barrierStats": [
        { "barrierNumber": 1, "totalStarts": 236, "wins": 27, "places": 78, "winRate": 0.1144, "placeRate": 0.3305, "advantage": 0.0556 },
        { "barrierNumber": 2, "totalStarts": 234, "wins": 21, "places": 69, "winRate": 0.0897, "placeRate": 0.2949, "advantage": 0.0309 }
      ],
      "strongestBarrier": 1,
      "weakestBarrier": 15,
      "biasStrength": "strong",
      "conditionStats": [
        { "condition": "Good", "totalRaces": 653, "avgFieldSize": 10.4 }
      ],
      "distanceStats": [
        {
          "category": "Custom",
          "minDistance": 1200,
          "maxDistance": 1200,
          "totalRaces": 2582,
          "expectedWinRate": 0.0588,
          "barrierStats": [
            { "barrierNumber": 1, "totalStarts": 236, "wins": 27, "places": 78, "winRate": 0.1144, "placeRate": 0.3305, "advantage": 0.0556 },
            { "barrierNumber": 2, "totalStarts": 234, "wins": 21, "places": 69, "winRate": 0.0897, "placeRate": 0.2949, "advantage": 0.0309 }
          ],
          "strongestBarrier": 1,
          "weakestBarrier": 15,
          "biasStrength": "strong"
        }
      ],
      "distanceFilter": { "minDistance": 1200, "maxDistance": 1200 },
      "recentStats": null
    }