Paper Trading
Simulated trading in the right sidebar. Market and limit orders, positions, trade history. Default balance: $10,000. Limit orders execute automatically when price conditions are met, including for symbols not currently on the chart.
Configuration
typescript
new ChartSpire({
paperTradingEnabled: true,
paperTradingMaxTrades: 1000,
paperTradingPriceTrackingInterval: 30000,
paperTradingPriceTrackingLogging: true,
paperTradingUseExternalStorage: false,
defaultOpenComponents: ['papertrading'], // optional: open panel on load
// ...
})| Option | Type | Default | Description |
|---|---|---|---|
paperTradingEnabled | boolean | false | Enable paper trading panel |
paperTradingMaxTrades | number | 1000 | Max trades in history (min: 1) |
paperTradingPriceTrackingInterval | number | 30000 | Price check interval for limit orders (ms, min: 1000) |
paperTradingPriceTrackingLogging | boolean | true | Debug logging for price tracking |
paperTradingUseExternalStorage | boolean | false | Use callbacks instead of localStorage |
Panel Tabs
- Trade: Place market or limit orders (buy/sell)
- Positions: Open positions with P&L, close individually
- Orders: Pending limit orders, cancel as needed
- Trades: Trade history
- Cash: Add/remove cash, reset account
Storage
Local (default): Data in localStorage under key chartspire-paper-trading.
External: Persists data to your backend instead of localStorage. Set paperTradingUseExternalStorage: true and register callbacks before creating the chart:
typescript
import ChartSpire, { setPaperTradingChangeCallback, setGetPaperTradingDataCallback } from '@chartspire/chartspire'
setPaperTradingChangeCallback(async (data) => {
const res = await fetch('/api/paper-trading/save', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
return res.ok
})
setGetPaperTradingDataCallback(async () => {
const res = await fetch('/api/paper-trading/load')
return res.ok ? await res.json() : null
})
const chart = new ChartSpire({
paperTradingEnabled: true,
paperTradingUseExternalStorage: true,
// ...
})Initialization loads data when the panel opens. Return false from the save callback on failure.
Data Structure
typescript
interface PaperTradingData {
balance: number
orders: Order[]
positions: Position[]
trades: Trade[]
}
interface Order {
id: string
symbol: string
symbolType?: string
side: 'buy' | 'sell'
type: 'MARKET' | 'LIMIT'
quantity: number
price: number
status: 'PENDING' | 'FILLED' | 'CANCELLED'
timestamp: number
}
interface Position {
id: string
symbol: string
symbolType?: string
side: 'buy' | 'sell'
quantity: number
averagePrice: number
unrealizedPnL: number
timestamp: number
}
interface Trade {
id: string
orderId: string
symbol: string
side: 'buy' | 'sell'
quantity: number
price: number
timestamp: number
}