Order Management
The ZeroQuant SDK provides exchange-like order management for AI agents, including real-time order tracking, fill notifications, and position management.
Overview
The order management system allows agents to:
- Place market and limit orders
- Track order status in real-time
- Receive fill notifications with price and fee data
- Query open, executed, and cancelled orders
- Manage positions across multiple protocols
Quick Start
import { createExchangeClient, OrderSide, OrderType } from '@zeroquant/sdk';
import { ethers } from 'ethers';
const client = createExchangeClient({
provider,
signer: wallet,
vaultConfig: {
vaultFactoryAddress: '0x...',
permissionManagerAddress: '0x...',
},
wsUrl: 'wss://api.zeroquant.io/ws',
});
// Connect to vault
await client.connect('0xYourVaultAddress');
// Place a market order
const result = await client.placeOrder({
baseToken: WETH_ADDRESS,
quoteToken: USDC_ADDRESS,
side: 'buy',
type: 'market',
amount: ethers.parseEther('1'),
});
if (result.success) {
console.log('Order ID:', result.orderId);
console.log('TX Hash:', result.txHash);
}
Order Types
Market Orders
Execute immediately at the best available price:
const result = await client.placeOrder({
baseToken: WETH_ADDRESS,
quoteToken: USDC_ADDRESS,
side: 'buy',
type: 'market',
amount: ethers.parseEther('1'),
timeInForce: 'ioc', // Immediate or cancel
});
Limit Orders
Execute only at a specified price or better:
const result = await client.placeOrder({
baseToken: WETH_ADDRESS,
quoteToken: USDC_ADDRESS,
side: 'sell',
type: 'limit',
amount: ethers.parseEther('0.5'),
price: ethers.parseUnits('2500', 6), // $2500 per WETH
timeInForce: 'gtc', // Good til cancelled
});
Reduce-Only Orders
Close existing positions without opening new ones:
const result = await client.placeOrder({
baseToken: WETH_ADDRESS,
quoteToken: USDC_ADDRESS,
side: 'sell',
type: 'market',
amount: ethers.parseEther('0.25'),
reduceOnly: true,
});
Time in Force Options
| Option | Description |
|---|---|
gtc | Good Til Cancelled - remains open until filled or cancelled |
ioc | Immediate or Cancel - fills immediately or cancels |
fok | Fill or Kill - must fill completely or cancels entirely |
Order Lifecycle
Orders transition through these statuses:
pending → submitted → confirming → open → partial_fill → filled
↘ cancelled
↘ failed
Querying Orders
Get All Orders
const allOrders = client.getAllOrders();
Get Open Orders
const openOrders = client.getAllOpenOrders();
for (const order of openOrders) {
console.log(`${order.id}: ${order.side} ${order.amount} @ ${order.price || 'MARKET'}`);
}
Get Executed Orders
const executedOrders = client.getAllExecutedOrders(10); // Last 10
for (const order of executedOrders) {
console.log(`${order.id}: filled ${order.filledAmount} @ avg ${order.averageFillPrice}`);
}
Filter Orders
const filteredOrders = client.getAllOrders({
baseToken: WETH_ADDRESS,
side: 'buy',
status: ['filled', 'partial_fill'],
startTime: Date.now() - 24 * 60 * 60 * 1000, // Last 24 hours
});
Order Cancellation
const result = await client.cancelOrder(orderId, 'User requested cancellation');
if (result.success) {
console.log('Cancelled at:', result.cancelledAt);
} else {
console.log('Error:', result.error);
}
Real-Time Updates
Subscribe to All Order Updates
const unsubscribe = client.onOrderUpdate((order) => {
console.log('Order Update:', {
id: order.id,
status: order.status,
filled: order.filledAmount.toString(),
});
});
// Connect WebSocket
client.connectWebSocket();
// Later: cleanup
unsubscribe();
Subscribe to Specific Order
const unsubscribe = client.onOrder(orderId, (order) => {
console.log(`Order ${orderId} status:`, order.status);
});
Subscribe to Fills
const unsubscribe = client.onFill((fill) => {
console.log('Fill:', {
amount: fill.amount.toString(),
price: fill.price.toString(),
fees: fill.fees.total.toString(),
});
});
MVO (Minimum Viable Order) Pattern
For simpler integration, use the MVO manager:
import { createMVOManager } from '@zeroquant/sdk';
const mvoManager = createMVOManager();
// Create order
const mvo = mvoManager.placeOrder({
symbol: 'WETH/USDC',
exchange: 'zeroquant',
baseAsset: WETH_ADDRESS,
quoteAsset: USDC_ADDRESS,
side: 'buy',
timeInForce: 'gtc',
reduceOnly: false,
originalPrice: 2450.50,
originalQuantityBase: 1.5,
});
// Mark accepted
mvoManager.markAccepted(mvo.id);
// Update from exchange response
mvoManager.updateFromExchange(mvo.id, {
exchangeOrderId: 'ext_12345',
isMaker: true,
orderType: 'limit',
averagePrice: 2448.75,
executedQuantityBase: 0.75,
status: 'partially_filled',
fee: 0.92,
feePaid: 0.92,
feeAsset: 'USDC',
});
// Query orders
const openOrders = mvoManager.getAllOpenOrders();
const executedOrders = mvoManager.getAllExecutedOrders();
Order Statistics
const stats = client.getOrderStats();
console.log('Statistics:');
console.log(' Total Orders:', stats.totalOrders);
console.log(' Filled:', stats.filledOrders);
console.log(' Cancelled:', stats.cancelledOrders);
console.log(' Total Volume:', stats.totalVolume);
console.log(' Total Fees:', stats.totalFees);
Error Handling
const result = await client.placeOrder(params);
if (!result.success) {
switch (result.error) {
case 'INSUFFICIENT_BALANCE':
console.log('Not enough funds');
break;
case 'INVALID_PRICE':
console.log('Price out of range');
break;
case 'SESSION_EXPIRED':
console.log('Session needs renewal');
break;
default:
console.log('Error:', result.error);
}
}