This reference application reconciles balances against fills and transactions over a time window.
Balances on Coinbase Prime can for a variety of reasons, including order fills, deposits, withdrawals, and rewards. Reconciling these balances against direct activities verifies that your actual balances match what you expect based on recorded activity. This helps detect:
- Missing or duplicate transactions
- Incorrect fill amounts
- API timing issues
- System discrepancies
This application runs a reconciliation window:
- Capture starting balances for all assets
- Wait for the configured window duration
- Capture ending balances and query all fills/transactions during the window
- Calculate expected balances for each asset
- Compare expected vs actual balances
- Report any discrepancies (delta = actual - expected)
If the delta is zero (or negligible within tolerance), the asset reconciles. Otherwise, a discrepancy is flagged for investigation.
For continuous coverage, run this application on a schedule (e.g., hourly via cron or a task scheduler) with WINDOW_DURATION set to match the interval. This creates back-to-back reconciliation windows that verify all activity over time.
Expected = Starting Balance + Credits - Debits
Fills affect two assets (base and quote):
BUY BTC-USD: BTC +quantity USD -(value + commission)
SELL BTC-USD: BTC -quantity USD +(value - commission)
Transactions affect one asset (except conversions):
DEPOSIT, INTERNAL_DEPOSIT, COINBASE_DEPOSIT, REWARD → Credit
WITHDRAWAL, INTERNAL_WITHDRAWAL → Debit (absolute value)
CONVERSION → Debit source, credit destination
go mod download
cp .env.example .env
# Edit .env with your credentialsRequired:
PRIME_ACCESS_KEYPRIME_PASSPHRASEPRIME_SIGNING_KEYPRIME_PORTFOLIO
Optional:
WINDOW_DURATION- Observation window in seconds (default: 300)RECONCILIATION_TOLERANCE- Decimal places for negligible threshold (default: 8)RETRY_ON_FAILURE- Retry failed assets after delay (default: false)RETRY_DELAY- Seconds to wait before retry (default: 2)RECENT_ACTIVITY_THRESHOLD- Seconds before window end to flag recent activity (default: 5)
go run ./cmd/reconOr build and run:
go build -o bin/recon ./cmd/recon
./bin/reconEach asset with activity during the window is logged with reconciliation details:
{"msg":"Asset reconciled","asset":"btc","start_balance":"0.01627","fills_net":"0.00003","transactions_net":"0","total_net":"0.00003","expected_end":"0.01630","actual_end":"0.01630","reconciled":true}- start_balance: Balance at window start
- fills_net: Net change from trades (credits - debits)
- transactions_net: Net change from deposits/withdrawals
- total_net: Combined net change
- expected_end: Calculated balance (start + total_net)
- actual_end: Balance returned by API at window end
- reconciled:
trueif expected matches actual (within tolerance)
A successful run ends with:
{"msg":"Reconciliation successful - all balances match","reconciled_assets":3}A failed reconciliation shows the discrepancy:
{"msg":"Reconciliation failed - discrepancies detected","failed_asset_count":1,"btc":{"delta":"0.001","expected":"1.5","actual":"1.501"}}The Prime balances API does not include timestamps in its response. This means there's inherent ambiguity about when a balance snapshot was taken relative to fills and transactions.
The problem: If a fill or deposit occurs immediately before the ending balance query, the returned balance may not yet reflect that activity, causing a false discrepancy.
Mitigations built into this app:
- Retry mechanism: Enable
RETRY_ON_FAILURE=trueto automatically re-check balances after a brief delay, giving the API time to catch up - Recent activity warning: When discrepancies occur alongside activity near the window end, a warning explains the likely cause
- Longer windows: Using
WINDOW_DURATIONwith longer windows reduces the proportion of edge-case timing issues