====== 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; } }