Skip to content

PositionLadder

DOM-style price ladder with click-to-trade functionality. Shows bid/ask depth at each price level with position and P&L overlay.

import { PositionLadder } from '@askturret/grid';
import '@askturret/grid/styles.css';
const levels = [
{ price: 5925.00, bidSize: 150, askSize: 0 },
{ price: 5925.25, bidSize: 200, askSize: 0 },
{ price: 5925.50, bidSize: 0, askSize: 100 },
{ price: 5925.75, bidSize: 0, askSize: 250 },
];
<PositionLadder
levels={levels}
tickSize={0.25}
centerPrice={5925.25}
/>
PropTypeDefaultDescription
levelsLadderLevel[]requiredPrice levels with bid/ask quantities
tickSizenumberrequiredTick size for price increments
centerPricenumberrequiredCenter price for the display
visibleLevelsnumber20Number of price levels to display
positionPosition-Current position to display
lastPricenumber-Last traded price for highlighting
showDepthBarsbooleantrueShow depth visualization bars
flashOnChangebooleantrueFlash on quantity changes
priceDecimalsnumber2Price decimal places
quantityDecimalsnumber0Quantity decimal places
onBidClick(price: number) => void-Bid column click handler
onAskClick(price: number) => void-Ask column click handler
onRecenter() => void-Recenter button click handler
interface LadderLevel {
price: number;
bidSize: number;
askSize: number;
}
interface Position {
entryPrice: number;
quantity: number;
side: 'long' | 'short';
}

Show current position with P&L:

<PositionLadder
levels={levels}
tickSize={0.25}
centerPrice={5925.25}
position={{
entryPrice: 5920.00,
quantity: 10,
side: 'long',
}}
lastPrice={5925.50}
/>

The ladder displays:

  • Entry price row highlighted
  • Current position quantity
  • Unrealized P&L at each price level

Handle clicks for order entry:

<PositionLadder
levels={levels}
tickSize={0.25}
centerPrice={5925.25}
onBidClick={(price) => {
// Place buy order at this price
placeOrder({ side: 'buy', price, quantity: 1 });
}}
onAskClick={(price) => {
// Place sell order at this price
placeOrder({ side: 'sell', price, quantity: 1 });
}}
/>

Highlight the last traded price:

<PositionLadder
levels={levels}
tickSize={0.25}
centerPrice={5925.25}
lastPrice={5925.50}
/>

The row at the last price gets a distinct highlight.

Allow users to recenter the ladder:

function TradingLadder() {
const [centerPrice, setCenterPrice] = useState(5925.25);
return (
<PositionLadder
levels={levels}
tickSize={0.25}
centerPrice={centerPrice}
onRecenter={() => setCenterPrice(marketPrice)}
/>
);
}

Handle streaming market data:

function LiveLadder() {
const [levels, setLevels] = useState<LadderLevel[]>([]);
const [lastPrice, setLastPrice] = useState(0);
useEffect(() => {
const ws = new WebSocket('wss://...');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'depth') {
setLevels(data.levels);
} else if (data.type === 'trade') {
setLastPrice(data.price);
}
};
return () => ws.close();
}, []);
return (
<PositionLadder
levels={levels}
tickSize={0.25}
centerPrice={lastPrice || 5925.25}
lastPrice={lastPrice}
flashOnChange
/>
);
}

Visualize the relative size at each price level:

<PositionLadder
levels={levels}
tickSize={0.25}
centerPrice={5925.25}
showDepthBars={true} // Default
/>

Bar width represents the quantity relative to the maximum visible quantity.

The ladder uses CSS variables:

:root {
--grid-bid: #22c55e; /* Bid side color */
--grid-ask: #ef4444; /* Ask side color */
--grid-accent: #3b82f6; /* Last price highlight */
}