Skip to content

Market data

Market data lives behind two services:

  • STXMarketService: individual markets and market counts
  • STXEventService: events (a match/game), with its markets attached
var markets = serviceProvider.GetRequiredService<STXMarketService>();
var resp = await markets.GetMarketInfosWithCountAsync();
foreach (var m in resp.MarketInfos)
{
Console.WriteLine($"{m.MarketId} {m.Status} {m.Title}");
}

GetMarketInfosWithCountAsync returns STXMarketInfosWithCountResponse<STXMarketInfo>: the full market object, plus Count and Cursor for paging. For lightweight lookups by ID, use the Short variant:

var ids = new[] { "mkt_abc", "mkt_def" };
var short_ = await markets.GetShortMarketInfosWithCountAsync(ids);

GetMarketInfosWithCountAsync returns one page plus Count (the total matching the filter before pagination) and Cursor, an opaque pointer to the next page:

var page = await markets.GetMarketInfosWithCountAsync(new STXMarketInfosFilter
{
Status = [STXMarketInfosStatus.OPEN],
Trading = STXMarketInfosTrading.TRUE,
Pagination = new STXKeysetPagination { Limit = 100 },
});
Console.WriteLine($"{page.MarketInfos.Count}/{page.Count}");

Pass Cursor back to fetch the next page. The walk ends when the server stops returning a cursor, not when a page comes back short. A last page that exactly fills Limit still carries a cursor, and the request after it returns no markets and no cursor. Treat an empty cursor as the end too: sent back, it reads to the server as “no cursor” and restarts you at page one.

string cursor = null;
do
{
var page = await markets.GetMarketInfosWithCountAsync(new STXMarketInfosFilter
{
Pagination = new STXKeysetPagination { Cursor = cursor, Limit = 100 },
});
foreach (var m in page.MarketInfos) { /* … */ }
cursor = page.Cursor;
}
while (!string.IsNullOrEmpty(cursor));

The paging helpers run that loop for you. GetAllOpenMarketInfosAsync fetches every market currently open:

var open = await markets.GetAllOpenMarketInfosAsync();
Console.WriteLine($"{open.Count} open markets");

Status is overridden and, as in every paged call, Limit and Pagination are ignored. The rest of the filter is honoured, so the walk can be narrowed:

var openSoccer = await markets.GetAllOpenMarketInfosAsync(new STXMarketInfosFilter
{
Sports = ["Soccer"],
});

Use GetAllMarketInfosAsync to walk any filter without forcing a status, and GetMarketInfoPagesAsync to stream page by page instead of buffering the whole result set. This is worth it for broad filters, which can run to tens of thousands of markets:

await foreach (var page in markets.GetMarketInfoPagesAsync<STXMarketInfo>(filter, pageSize: 500))
{
foreach (var m in page) { /* … */ }
}

A walk covers every matching market, so the projection you ask for decides what it costs. Asking for the complete STXMarketInfo across a large market set moves a great deal more data and takes correspondingly longer than asking for a handful of fields (on a mature environment the difference is about an order of magnitude in both), and it holds every fully-populated market object in memory at once.

The generic overload builds its GraphQL selection from T, so a type carrying only the fields you actually use is the largest saving available here:

public class MarketRow
{
public Guid MarketId { get; set; }
public string Symbol { get; set; }
public string GroupingId { get; set; }
public string Title { get; set; }
}
var rows = await markets.GetAllMarketInfosAsync<MarketRow>();

Before reaching for the full set, check whether you need it: the bulk of a mature environment is resulted history. If what you want is the live board, GetAllOpenMarketInfosAsync() returns a far smaller set for a fraction of the cost.

STXMarketInfosFilter combines the common filter fields:

Field Type
Status IEnumerable<STXMarketInfosStatus> One or more statuses, e.g. [STXMarketInfosStatus.OPEN]
Trading STXMarketInfosTrading? TRUE / FALSE
Sports IEnumerable<string> Sport filter (["Basketball"], ["Baseball"], …)
Competitions IEnumerable<string> Competition filter (["NBA"], ["MLB"], …)
EventIds IEnumerable<string> Only markets for the given events
MarketIds IEnumerable<string> Only the given markets
Pagination STXKeysetPagination Cursor and page size (see above)
Limit int? Caps a single response; not a substitute for paging
KeywordRegex string Regex match on market keywords
Featured STXFeatured? Featured markets
SortBy STXMarketInfosSortBy Field and direction
Stat STXPslStats? Player-stat markets
var catalog = await markets.GetSportAndCompetitionsAsync();
foreach (var sport in catalog)
{
Console.WriteLine($"{sport.Sport}");
foreach (var c in sport.Competitions)
Console.WriteLine($" {c}");
}

STXEventService bundles an event with its markets: one call instead of one-markets-per-event:

var events = serviceProvider.GetRequiredService<STXEventService>();
var resp = await events.GetEventInfosAsync(new STXEventInfosFilter
{
Sport = "basketball",
EventStatusFilter = new[]
{
STXEventStatus.scheduled,
STXEventStatus.live,
},
});
foreach (var ev in resp.EventInfos)
{
Console.WriteLine($"{ev.EventId} {ev.Title} ({ev.MarketInfos.Count} markets)");
}

For live price ticks on open markets, subscribe via the STXMarketChannel websocket wrapper (see WebSockets → Market updates). REST polling is fine for snapshots; channels are required for latency-sensitive use cases.

v1.5.9Changelogllms.txtllms-full.txt