Skip to main content
Trading in the SportsX SDK uses two services. STXOrderService handles order placement, cancellation, and order history. STXTradeService handles fills (trades). Both services support real-time counterparts via WebSocket channels for latency-sensitive workflows.

Place an order

using STX.Sdk.Enums;
using STX.Sdk.Services;

var orders = serviceProvider.GetRequiredService<STXOrderService>();

var order = await orders.ConfirmOrderAsync(
    price:              10,                  // integer cents; 10 = 10¢
    quantity:           1,
    marketId:           "mkt_abc",
    action:             STXOrderAction.buy,
    orderType:          STXOrderType.limit,
    clientOrderId:      "my-ref-1",          // optional idempotency key
    cancelOnDisconnect: true);

Console.WriteLine($"Order {order.Id} placed at {order.Price}c x {order.Quantity}");

Order parameters

ParameterNotes
priceInteger cents. 50 = 50¢. Ignored for market orders.
quantityNumber of contracts.
marketIdFrom STXMarketService.GetMarketInfosAsync.
actionSTXOrderAction.buy or STXOrderAction.sell.
orderTypeSTXOrderType.limit or STXOrderType.market.
clientOrderIdYour idempotency key. If the call retries, you won’t receive a duplicate fill.
cancelOnDisconnectWhen true, the exchange cancels this order if the WebSocket drops. Requires STXActiveOrdersChannel to be joined first.

Cancel-on-disconnect

If you pass cancelOnDisconnect: true without having joined STXActiveOrdersChannel, the call throws STXCancelOnDisconnectNotEnabledException. For a market-maker workflow, join the channel before placing any orders:
var activeOrders = serviceProvider.GetRequiredService<STXActiveOrdersChannel>();
await activeOrders.ConnectAsync();

// Now cancelOnDisconnect: true is safe to use
var order = await orders.ConfirmOrderAsync(
    price:              45,
    quantity:           5,
    marketId:           "mkt_abc",
    action:             STXOrderAction.sell,
    orderType:          STXOrderType.limit,
    cancelOnDisconnect: true);
If you only want a resting order that survives disconnects, pass cancelOnDisconnect: false.

Batch orders

Placing multiple orders in one call reduces round-trips and is the preferred approach for market makers quoting several markets simultaneously:
var batch = new[]
{
    new STXConfirmOrderParams
    {
        Price     = 10,
        Quantity  = 1,
        MarketId  = "mkt_a",
        Action    = STXOrderAction.buy,
        OrderType = STXOrderType.limit,
    },
    new STXConfirmOrderParams
    {
        Price     = 85,
        Quantity  = 2,
        MarketId  = "mkt_b",
        Action    = STXOrderAction.sell,
        OrderType = STXOrderType.limit,
    },
};

var placed = await orders.ConfirmOrdersAsync(batch);

Cancel orders

await orders.CancelOrderAsync(orderId);
await orders.CancelOrdersAsync(new[] { orderId1, orderId2 });
var cancelled = await orders.CancelAllOrdersAsync();
// Returns the full list of cancelled orders for reconciliation
CancelAllOrdersAsync returns every order it cancelled, which is useful for reconciling your local state after a strategy reset.

Query order history

var history = await orders.GetMyOrdersAsync(
    statusFilter: new[] { STXOrderStatus.filled, STXOrderStatus.cancelled },
    limit:        50,
    sortBy:       STXOrdersSortByField.insertedAt,
    sortOrder:    STXSortOrder.desc);

foreach (var o in history.Orders)
{
    Console.WriteLine($"{o.Id,-10} {o.Status,-10} {o.MarketId,-12} {o.Price}c x {o.Quantity}");
}

Query trades (fills)

Each matched order generates one or more trade records. Resolve STXTradeService to query them:
var trades = serviceProvider.GetRequiredService<STXTradeService>();

// All fills, most recent first
var allFills = await trades.GetMyTradesAsync(
    limit:     50,
    sortBy:    STXTradesSortByField.time,
    sortOrder: STXSortOrder.desc);

// Fills for a specific order
var orderFills = await trades.GetMyTradesForOrderAsync(orderId);

Real-time order and trade updates

Polling the HTTP endpoints works but adds unnecessary latency. The WebSocket channels push updates as they happen:
  • STXActiveOrdersChannel — every state transition on an open order (openpartially_filledfilled or cancelled).
  • STXActiveTradesChannel — each new fill as it lands.
See WebSockets for setup details.

A canonical market-maker loop

The pattern below is adapted from cssdk-console’s STXWorker.cs. It shows the full lifecycle: connect channels, subscribe to price ticks, and requote on each tick:
// 1. Authenticate and connect channels
await _login.LoginAsync(email, password, keepSessionAlive: true);
await _ordersChannel.ConnectAsync();
await _tradesChannel.ConnectAsync();
await _portfolioChannel.ConnectAsync();

// 2. Subscribe to market price ticks
_marketChannel.OnPriceUpdate += OnPriceTick;
await _marketChannel.ConnectAsync();
await _marketChannel.SubscribeAsync("mkt_abc");

// 3. Requote on each tick
async void OnPriceTick(STXMarketInfoChannelData tick)
{
    // Cancel stale quotes and place fresh ones in one batch
    await _orderService.CancelAllOrdersAsync();
    await _orderService.ConfirmOrdersAsync(BuildQuotes(tick));
}
Cancel-on-disconnect, automatic JWT refresh, and portfolio-balance tracking are all handled by the registered SDK services — the loop above is the core of the app.

See also