Paper Trading
Offer simulated trading with live market data for staging, QA, or user-facing paper portfolios
Live market data. Simulated funds. The same integration path your users will use in production.
Paper trading can be a production user feature, a staging QA tool, or both. It prices quotes against current market data and records simulated balances, orders, and positions, while keeping live funds completely out of the flow.
Choose The Right Surface
Use mode: "paper" when users should trade through the normal execution path
with a simulated account. Users sign in normally, request smart routes normally,
fill quotes normally, and read balances, positions, and orders from the same SDK
methods or API reference operations they use for live trading.
Use the paper account management APIs when your backend needs to create, seed, reset, or inspect server-side paper accounts for user simulators, QA, or automated test runs.
Paper trading never submits to venues and never runs bridges, custody transfers, deposits, withdrawals, or redemptions. Do not treat paper balances as prefunded wallets, live account balances, or venue funds.
Product Patterns
Paper trading supports two common app patterns:
| Pattern | What users see | What your app sends |
|---|---|---|
| User-facing paper trading | Users can switch between a real account and a paper account in the same production app. | mode: "paper" for paper balances, quotes, fills, positions, and orders. Live mode for the real account. |
| Staging and QA execution tests | Test users exercise the same order entry, profile, and account surfaces without risking funds. | The same SDK/API calls as production, with mode: "paper" and test-only app chrome. |
Keep paper and live state visually separate. A user can have both a paper portfolio and a live account, but those balances, orders, positions, and funding surfaces should never be presented as interchangeable.
How It Works
Paper mode is user-scoped. A signed-in user gets a paper account for your app the first time they request paper balances, positions, quotes, or a fill.
Smart routes and direct paper fills price against the current order book. The result is simulated, but the quote quality reflects current market depth.
Add mode: "paper" to custom SDK/API execution calls. For AGG UI surfaces, set
trading.executionMode once in AggProvider config so hosted pages and order panels share
the same paper account mode.
Paper fills update PAPER_USD, paper orders, and paper positions. Live managed wallets, venue
accounts, and executor orders are not touched.
UI Components
For AGG-hosted UI surfaces, set paper mode globally in AggProvider config.
HomePage, EventMarketPage, PlaceOrder, and UserProfilePage read this
provider setting when an explicit executionMode prop is not supplied.
import { AggProvider } from "@agg-build/ui";
import { HomePage } from "@agg-build/ui/pages";
export function App() {
return (
<AggProvider
client={client}
config={{
trading: {
executionMode: "paper",
},
}}
>
<HomePage />
</AggProvider>
);
}
This keeps hosted AGG pages, embedded order panels, profile balances, positions, and orders on the same paper account mode without threading props through every surface.
You can still pass executionMode directly when one surface must override the
provider default, for example a live-only panel inside a paper-mode app shell:
import { EventMarketPage } from "@agg-build/ui/pages";
export function LiveEventOverride({ eventId }: { eventId: string }) {
return <EventMarketPage eventId={eventId} executionMode="live" />;
}
SDK Flow
If you build your own order entry, pass mode: "paper" on each execution call.
The SDK methods below map to the same API reference operations used in live
mode:
| SDK method | API reference |
|---|---|
getManagedBalances({ mode: "paper" }) | Get balances |
getSmartRoute({ mode: "paper" }) | Compute order route |
executeManaged({ mode: "paper" }) | Execute quote |
getExecutionPositions({ mode: "paper" }) | Get user positions |
getExecutionOrders({ mode: "paper" }) | Get user orders |
import { createAggClient } from "@agg-build/sdk";
const client = createAggClient({
baseUrl: process.env.AGG_API_BASE_URL!,
appId: "your-app-id",
});
// After the user authenticates...
const balances = await client.getManagedBalances({ mode: "paper" });
const route = await client.getSmartRoute({
venueMarketOutcomeId: "vmo_...",
tradeSide: "buy",
maxSpend: 25,
mode: "paper",
});
await client.executeManaged({
quoteId: route.quoteId,
mode: "paper",
fallbackToLatest: {
outcomeId: "vmo_...",
side: "buy",
maxSpend: 25,
},
});
const [positions, orders] = await Promise.all([
client.getExecutionPositions({ mode: "paper", status: "active", limit: 25 }),
client.getExecutionOrders({ mode: "paper", limit: 25 }),
]);
Keep the mode consistent from quote to fill. A quote created with mode: "paper" must be filled
with mode: "paper". A live fill cannot execute a paper quote, and a paper fill cannot execute a
live quote.
Funding UI
Hide deposit, withdrawal, and redemption controls anywhere your user is in a
paper-only experience. Paper accounts expose PAPER_USD and simulated
positions; they do not need wallet funding, bridge setup, venue account funding,
or settlement redemption.
Execution Testing Strategies
Paper trading is the recommended way to test your execution UX because it uses the same route, fill, order, position, and balance surfaces as live trading.
For staging or CI smoke tests:
- Sign in a test user through the normal auth flow.
- Read paper balances and assert
PAPER_USDis present. - Quote a current open market with
mode: "paper". - Fill the quote with
mode: "paper"and assert order IDs are returned. - Read paper orders and active paper positions and assert the fill is visible.
- Assert the paper cash balance changed after the fill.
For negative-path coverage:
- Attempt to fill a paper quote without
mode: "paper"and expect rejection. - Switch from paper to live mode and require a fresh quote before fill.
- Verify paper pages do not show deposit, withdrawal, bridge, or redemption actions.
- Verify live balances and paper balances are never combined in one total.
For repeatable QA scenarios:
- Seed or reset the user paper account from your backend before the run.
- Use current market discovery when selecting test outcomes instead of hardcoding a single outcome ID that can age out.
- Store scenario-owned
clientOrderIdvalues when placing direct paper orders from your backend, so test logs can correlate fixtures to AGG orders.
Launch Checklist
- Decide whether paper trading is staging-only, production user-facing, or both.
- Render a clear paper account badge or account switcher in your app shell.
- Set
config.trading.executionMode = "paper"onAggProviderwhen the paper account is selected. - Use component-level
executionModeprops only for intentional per-surface overrides. - Pass
mode: "paper"to custom SDK calls for paper balances, routes, fills, positions, and orders. - Use live mode only after the user has explicitly selected their real account.
- Do not show deposit, withdrawal, or redemption flows as part of the paper account experience.
- Reset or seed account balances from your backend when a QA run needs a known starting state.
FAQ
Can I quote in paper mode and fill in live mode?
No. Quote and fill modes must match. This prevents a paper account flow from accidentally turning a simulated quote into a live venue submission.
When is a user paper account created?
AGG creates the user-scoped paper account lazily the first time a signed-in user requests paper balances, positions, quotes, or a paper fill for your app.
How do I reset or seed the paper balance?
Use the backend-only account management surface in
Manage Paper Trading Accounts. Normal browser
paper mode uses the user:<aggUserId> external ID, so your backend can reset
the same account the user sees in the app.
Should I show funding, withdrawals, or redemptions?
No. Hide those controls in a paper-only experience. Paper trading uses simulated funds and does not perform deposits, withdrawals, bridges, custody transfers, or redemptions.