====== Account Feed ======
The Account Feed provides real-time updates on account status, positions, and order activity. Before receiving updates, accounts must first be subscribed.
===== Subscribing to Accounts =====
The list of available accounts is included in the **LoginResult** message. To begin receiving updates, clients must send an **AccountSubscribe** message. Multiple accounts can be subscribed in a batch.
Example **AccountSubscribe** message for three accounts:
AccountSubscribe {
Subscribe = AccountSubscribeType.Subscribe,
SubscribeAllAccounts = false,
AccountId = [
"2a4b6c8d-9e10-11ea-bb37-0242ac130002",
"3d5e7f9g-9e10-11ea-bb37-0242ac130003",
"4f6h8j0k-9e10-11ea-bb37-0242ac130004"
]
}
Once subscribed, the server will begin streaming real-time updates for the selected accounts.
===== Handling Account Updates =====
The server sends account-related updates as separate messages. These include:
* **AccountSubscribeResponse** – A response message indicating whether the account subscription was successful or not.
* **AccountSnapshot** – A batch message containing the latest state of the account.
* **AccountDetails** – Provides static information about the account.
* **AccountUpdate** – Sends real-time updates for account values.
* **AccountPosition** – Reports current open positions.
* **OrderUpdateMulti** – Sends batch updates for a position.
* **MarketDetails** – Market details are always sent before a new position is sent to ensure the client has the altest pricing details for the market.
Example message handling structure:
private void HandleAccountMessage(ServerMessage serverMessage)
{
switch (serverMessage.PayloadCase)
{
case ServerMessage.PayloadOneofCase.AccountSubscribeResponse:
_logger.LogInformation("Received account subscribe response. Success: {Success}", serverMessage.AccountSubscribeResponse.Success);
serverMessage.AccountSubscribeResponse.Errors.ToList().ForEach(e => _logger.LogWarning(" * " + e));
break;
case ServerMessage.PayloadOneofCase.AccountDetails:
ProcessAccountDetails(serverMessage.AccountDetails);
break;
case ServerMessage.PayloadOneofCase.AccountUpdate:
ProcessAccountUpdate(serverMessage.AccountUpdate);
break;
case ServerMessage.PayloadOneofCase.AccountPosition:
ProcessAccountPosition(serverMessage.AccountPosition);
break;
case ServerMessage.PayloadOneofCase.AccountSnapshot:
ProcessAccountSnapshot(serverMessage.AccountSnapshot);
break;
case ServerMessage.PayloadOneofCase.OrderUpdateMulti:
ProcessOrderUpdateMulti(serverMessage.OrderUpdateMulti);
break;
case ServerMessage.PayloadOneofCase.MarketDetails:
ProcessMarketDetails(serverMessage.MarketDetails);
break;
default:
_logger.LogWarning("Unhandled Account Message: {PayloadCase}", serverMessage.PayloadCase);
break;
}
}
===== Account Snapshot =====
The **AccountSnapshot** message is a **batch message** that contains the latest state of an account including:
* Account balances
* Open positions
* Working orders
private void ProcessAccountSnapshot(AccountSnapshot snapshotMessage)
{
switch (snapshotMessage.PayloadCase)
{
case AccountSnapshotMessage.PayloadOneofCase.AccountDetails:
_details = snapshotMessage.AccountDetails;
break;
case AccountSnapshotMessage.PayloadOneofCase.AccountUpdate:
_update = snapshotMessage.AccountUpdate;
break;
case AccountSnapshotMessage.PayloadOneofCase.AccountPosition:
{
var position = _positions.AddOrUpdate(
snapshotMessage.AccountPosition.MarketId,
// Add new Position if key doesn't exist
_ => new Position(this, snapshotMessage.AccountPosition, _loggerFactory.CreateLogger()),
// Update existing Position
(_, existingPosition) => existingPosition);
if (position != null)
{
position.UpdateWithMessage(snapshotMessage);
updatedPositions.Add(position);
}
_logger.LogInformation("=> SNAPSHOT => AccountPosition: {AccountId} / {MarketID}", snapshotMessage.AccountPosition.AccountId, snapshotMessage.AccountPosition.MarketId);
}
break;
case AccountSnapshotMessage.PayloadOneofCase.OrderUpdateMulti:
var orderMultiUpdates = ProcessOrderUpdateMulti(snapshotMessage.OrderUpdateMulti);
updatedOrders.AddRange(orderMultiUpdates.Select(res => res.Order));
updatedTrades.AddRange(orderMultiUpdates.SelectMany(res => res.Trades));
break;
default:
_logger.LogInformation($" > Unhandled Snapshot Message: {snapshotMessage.PayloadCase}");
break;
}
}