Monitor a trading bot#
A successful submission is not a confirmed fill. Keep order intent, submitted signatures, confirmed events, and current account state separately. Reconcile them before a restarted bot can create replacement exposure.
Read the balances that belong to the strategy#
For each market, authenticate and decode the market, orderbook, your position, and the trader ledger. Match the ledger slot by its full owner key; a cached slot hint is not authority. Also read the wallet's settlement and YES/NO token accounts when the strategy uses wallet funding.
| State | What it tells you | What it cannot establish alone |
|---|---|---|
PositionAccount | Available and locked shares, locked bid collateral, order count, cumulative trading statistics, settlement state | Every wallet transfer or the current withdrawable ledger balance |
Trader-ledger quote_free, yes_free, no_free | Free funds available in that market's ledger | Balances in another market or already withdrawn to a wallet |
| Owned orderbook records | Orders currently resting, remaining size, side, price, and order ID | A durable history after the order fills or is removed |
| Wallet token accounts | Tokens currently held outside market escrow | Collateral and shares still locked in the market |
Position fields yes_shares and no_shares are already unlocked amounts;
locked amounts have separate fields. Do not subtract the locks a second time.
Do not add the position's share accounting to token and ledger custody balances
as though all three described independent assets. Reconcile custody changes
against the instructions and fills that produced them.
Cash flow, inventory value, and P&L#
The position's cumulative trade cash flow before rebates is:
trade_cash_flow = total_sold - total_bought - total_fees_paid
That is not complete P&L while inventory remains or when transfers, minting, withdrawal, and settlement have occurred. Maintain an external cash-flow ledger and value the strategy's current assets at explicit marks. For an isolated strategy account:
net_pnl = ending_equity - starting_equity - external_deposits + external_withdrawals
State the mark source and slot. A mid-price estimate is not an executable exit quote; a settlement valuation is valid only after the terminal outcome is accepted. Keep SOL fees and rent movements separate from settlement-token P&L, or specify the conversion mark when combining them. Use integer base units or exact decimals throughout.
Maker rebates credit TraderLedger.quote_free. Do not use
PositionAccount.total_rebates_earned as the authoritative credit total: its
compatibility field is not updated by the live rebate path. Decode and deduplicate
MakerRebateCredited recorder events, then reconcile the resulting credits with
ledger deposits, withdrawals, fills, and redemptions. A positive change in
quote_free alone does not tell you which operation funded it.
The indexer stores maker-rebate events, but a hosted projection is still a convenience view. Keep the original signature and event identity so credits can be checked against chain data. The binary recorder tag and the older text-event kind are different namespaces; use the decoder rather than a guessed tag number.
Reconcile open orders#
Read the complete orderbook at an explicit commitment and select records owned by your full wallet key. Compare remaining quantities and IDs with the local intent ledger. An order disappearing from the book may have filled, expired, been cancelled, or been evicted; it is not evidence of one particular cause. Resolve the corresponding finalized transaction/events and position changes.
Reconcile at startup, after reconnects or rollbacks, after every ambiguous submission, and periodically during trading. Choose the interval from the strategy's tolerated stale exposure and RPC capacity; there is no protocol-wide polling interval. Store market identity, slot, commitment, signature, instruction index, batch index, and event index beside each applied update.
When stream and account reads disagree#
Stop increasing exposure. Record the mismatch, fetch accounts from the expected program at a consistent commitment, and replay from the last verified finalized cursor. Deduplicate events and account writes before updating balances. A newer processed notification must not overwrite finalized state without an explicit rollback model. An RPC failure or missing projection must not silently clear orders or turn an unknown balance into zero.
For a timed-out submission, retain the original signature and blockhash validity window. Check its status and resulting account state before signing an equivalent replacement; the first transaction may already have landed.
Circuit breakers and recovery#
A circuit breaker is a persistent state that stops new orders when an invariant or an operator-defined limit fails. Examples include unresolved submissions, stale market data, custody/projection mismatch, inventory beyond the configured limit, repeated preflight failures, or too little SOL for recovery transactions. Keep cancellation and settlement available where the market permits them.
For post-only, halted, or force-cancel-only markets, reread the actual market state and submit only permitted actions. At market close, cancel or settle remaining orders and drain free funds through the supported lifecycle; a timer does not return funds to the wallet. Resume quoting only after fresh account reads, reconciled pending signatures, and an explicit breaker reset.
Use Reading data, Stream consumer recipes, Market making, and Claiming winnings for the corresponding account, event, and recovery procedures.