# Trading

> Place and cancel orders, inspect trade history.

Source: https://docs.stxapp.io/sdks/csharp/trading/

Orders and trades live on two services:

- **`STXOrderService`**: place, cancel, and query orders
- **`STXTradeService`**: query fills (trades)

## Place an order

```csharp
using STX.Sdk.Enums;
using STX.Sdk.Services;

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

var order = await orders.ConfirmOrderAsync(
    price:     10,                   // cents
    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}");
```

### Parameters

| | |
|---|---|
| `price` | **Integer cents.** `50` = 50¢. Ignored for `market` orders. The REST and WebSocket surfaces write this same price as the dollar string `"0.50"`. |
| `quantity` | Number of contracts. |
| `marketId` | From `STXMarketService.GetMarketInfosWithCountAsync`. |
| `action` | `STXOrderAction.buy` / `STXOrderAction.sell` |
| `orderType` | `STXOrderType.limit` / `STXOrderType.market` |
| `clientOrderId` | Your idempotency key. If the call retries you won't get a double-fill. |
| `cancelOnDisconnect` | If `true`, the exchange cancels this order when the websocket drops. **Requires `STXActiveOrdersChannel` to be joined** (see below). |

### Cancel-on-disconnect requires the active orders channel

If you pass `cancelOnDisconnect: true` but haven't joined `STXActiveOrdersChannel`, the call throws `STXCancelOnDisconnectNotEnabledException`. For the market-maker workflow, always join the channel first (it costs nothing):

```csharp
var activeOrders = serviceProvider.GetRequiredService<STXActiveOrdersChannel>();
await activeOrders.StartAsync();
```

If you only want a simple place-and-leave-it order, pass `cancelOnDisconnect: false`.

## Batch orders

Placing many orders at once is one round-trip instead of N:

```csharp
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

```csharp
await orders.CancelOrderAsync(orderId);                           // one
await orders.CancelOrdersAsync(new[] { orderId1, orderId2 });     // several
await orders.CancelAllOrdersAsync();                              // everything open on this account
```

`CancelAllOrdersAsync` returns the list of every cancelled order, which is handy to reconcile against your own state.

## Order history

```csharp
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}");
}
```

## Trades (fills)

Each fill is a trade:

```csharp
var trades = serviceProvider.GetRequiredService<STXTradeService>();

// Everything
var hist = await trades.GetMyTradesAsync(
    limit:     50,
    sortBy:    STXTradesSortByField.time,
    sortOrder: STXSortOrder.desc);

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

## Real-time: fills + order status

Polling the REST endpoints works but adds latency. The websocket channels push updates as they happen:

- **`STXActiveOrdersChannel`**: every state change on an open order (`open` → `partially_filled` → `filled` / `cancelled`)
- **`STXActiveTradesChannel`**: every new trade (fill)

See [WebSockets → Orders & trades](/sdks/csharp/websockets#orders-and-trades).

## A canonical market-maker loop

Pulled straight from the [example console app](https://github.com/stxapp/stx-csharp-demo)'s `STXWorker.cs`:

```csharp
// 1. Learn who the key belongs to, then connect channels.
//    Channel topics are keyed on the user id, and with an API key there is no
//    login response to read it from.
await _identity.GetMeAsync();
await _ordersChannel.StartAsync();
await _tradesChannel.StartAsync();
await _portfolioChannel.StartAsync();

// 2. Subscribe to market updates
_marketChannel.SetOnReceiveAction(OnPriceTick);
await _marketChannel.StartAsync();

// 3. On each tick, quote
void OnPriceTick(STXMarketInfoChannelData tick) {
    // Cancel stale orders and place fresh ones
    await _orderService.CancelAllOrdersAsync();
    await _orderService.ConfirmOrdersAsync(BuildQuotes(tick));
}
```

Cancel-on-disconnect, automatic session refresh, and portfolio-balance tracking are all handled by registered services; the loop above is the whole app.

## See also

- [Reference → Trading](/sdks/csharp/reference/trading/): full method signatures
- [WebSockets](/sdks/csharp/websockets/): real-time order/trade/balance streams
- [Errors & retries](/sdks/csharp/errors-and-retries/): common order errors
