Trading on Polymarket involves a complete workflow from setting up authentication to executing trades and managing balances. This guide covers the essential concepts and practical steps for successful trading.
Trading Workflow
Setup and Authentication
Initialize the CLOB client with authentication credentials. import { ClobClient , SignatureType } from "@polymarket/clob-client" ;
import { Wallet } from "ethers" ;
const wallet = new Wallet ( process . env . PRIVATE_KEY ! );
const host = "https://clob.polymarket.com" ;
// Create or derive API credentials
const tempClient = new ClobClient ( host , 137 , wallet );
const creds = await tempClient . createOrDeriveApiKey ();
// Initialize authenticated client
const client = new ClobClient (
host ,
137 ,
wallet ,
creds ,
SignatureType . EOA ,
undefined ,
undefined ,
true // useServerTime
);
Check Balances and Allowances
Verify you have sufficient USDC and token allowances. import { AssetType } from "@polymarket/clob-client" ;
// Check USDC balance
const collateral = await client . getBalanceAllowance ({
asset_type: AssetType . COLLATERAL ,
});
console . log ( `USDC Balance: ${ collateral . balance } ` );
console . log ( `USDC Allowance: ${ collateral . allowance } ` );
// Update allowance if needed
if ( parseFloat ( collateral . allowance ) < parseFloat ( collateral . balance )) {
await client . updateBalanceAllowance ({
asset_type: AssetType . COLLATERAL ,
});
}
Select Market and Get Configuration
Choose a market and retrieve its trading parameters. const tokenID = "71321045679252212594626385532706912750332728571942532289631379312455583992563" ;
// Get market configuration
const tickSize = await client . getTickSize ( tokenID );
const negRisk = await client . getNegRisk ( tokenID );
const feeRate = await client . getFeeRateBps ( tokenID );
// Analyze current market
const book = await client . getOrderBook ( tokenID );
const midpoint = await client . getMidpoint ( tokenID );
Create and Submit Order
Build your order and submit it to the CLOB. import { Side , OrderType } from "@polymarket/clob-client" ;
const response = await client . createAndPostOrder (
{
tokenID ,
price: 0.65 ,
size: 100 ,
side: Side . BUY ,
},
{ tickSize , negRisk },
OrderType . GTC
);
console . log ( `Order ID: ${ response . orderID } ` );
console . log ( `Status: ${ response . status } ` );
Monitor and Manage
Track your orders and manage your positions. // Get open orders
const openOrders = await client . getOpenOrders ({ asset_id: tokenID });
// Get trade history
const trades = await client . getTrades ({ asset_id: tokenID });
// Cancel if needed
if ( openOrders . length > 0 ) {
await client . cancelOrder ({ orderID: openOrders [ 0 ]. id });
}
Order Matching
The CLOB uses a price-time priority matching engine:
Matching Priority
Price Priority : Best prices match first
BUY orders: Highest price first
SELL orders: Lowest price first
Time Priority : Among orders at the same price, earlier orders match first
Matching Scenarios
Fees
Fee Structure
Fees are charged in basis points (bps) where 1 bps = 0.01%:
// Example: Market with 100 bps (1%) fee
const feeRateBps = await client . getFeeRateBps ( tokenID );
console . log ( feeRateBps ); // 100
// Fee calculation for a trade
const price = 0.65 ;
const size = 100 ;
const proceeds = price * size ; // 65 USDC
const fee = proceeds * ( feeRateBps / 10000 ); // 65 * 0.01 = 0.65 USDC
const net = proceeds - fee ; // 64.35 USDC received
Maker vs Taker Fees
Maker Orders Orders that add liquidity to the book. Generally receive better fee rates or rebates. Examples:
GTC orders that rest in the book
Post-only orders
Limit orders away from current price
Taker Orders Orders that remove liquidity from the book. Pay standard fee rates. Examples:
Market orders (FOK/FAK)
Limit orders that immediately match
Aggressive orders crossing the spread
Fee Application
// Fees are automatically applied by the SDK
const order = await client . createOrder (
{
tokenID ,
price: 0.65 ,
size: 100 ,
side: Side . BUY ,
// feeRateBps is auto-populated from market
},
{ tickSize: "0.01" }
);
// Manual fee specification (must match market rate)
const orderWithFee = await client . createOrder (
{
tokenID ,
price: 0.65 ,
size: 100 ,
side: Side . BUY ,
feeRateBps: 100 , // Must match market fee rate
},
{ tickSize: "0.01" }
);
If you specify a feeRateBps that doesn’t match the market’s fee rate, order creation will fail.
Balance Management
Checking Balances
import { AssetType } from "@polymarket/clob-client" ;
// USDC (collateral) balance
const usdc = await client . getBalanceAllowance ({
asset_type: AssetType . COLLATERAL ,
});
console . log ( `Balance: ${ usdc . balance } ` );
console . log ( `Allowance: ${ usdc . allowance } ` );
// Conditional token balance
const yesToken = await client . getBalanceAllowance ({
asset_type: AssetType . CONDITIONAL ,
token_id: "71321045679252212594626385532706912750332728571942532289631379312455583992563" ,
});
console . log ( `YES tokens: ${ yesToken . balance } ` );
Managing Allowances
Allowances control how much the CLOB can spend on your behalf:
// Check current allowance
const balance = await client . getBalanceAllowance ({
asset_type: AssetType . COLLATERAL ,
});
if ( parseFloat ( balance . allowance ) === 0 ) {
console . log ( "No allowance set - updating..." );
// Update allowance to maximum
await client . updateBalanceAllowance ({
asset_type: AssetType . COLLATERAL ,
});
console . log ( "Allowance updated!" );
}
// Update token allowance
await client . updateBalanceAllowance ({
asset_type: AssetType . CONDITIONAL ,
token_id: "71321045679252212594626385532706912750332728571942532289631379312455583992563" ,
});
You need to set allowances before trading. This is a one-time operation per asset unless you want to revoke access.
Trading Strategies
Limit Order Strategy
import { Side , OrderType } from "@polymarket/clob-client" ;
// Place buy orders at multiple price levels
const buyLevels = [ 0.60 , 0.62 , 0.64 ];
for ( const price of buyLevels ) {
const order = await client . createOrder (
{
tokenID ,
price ,
size: 50 ,
side: Side . BUY ,
},
{ tickSize: "0.01" }
);
await client . postOrder ( order , OrderType . GTC );
console . log ( `Buy order placed at ${ price } ` );
}
Market Order Strategy
// Calculate market price before execution
const marketPrice = await client . calculateMarketPrice (
tokenID ,
Side . BUY ,
100 , // Amount in USDC for BUY
OrderType . FOK
);
console . log ( `Market price for 100 USDC: ${ marketPrice } ` );
// Execute if price is acceptable
if ( marketPrice <= 0.70 ) {
const response = await client . createAndPostMarketOrder (
{
tokenID ,
amount: 100 ,
side: Side . BUY ,
orderType: OrderType . FOK ,
},
{ tickSize: "0.01" },
OrderType . FOK
);
console . log ( `Executed at: ${ response . status } ` );
}
Post-Only Strategy (Maker Only)
// Ensure you only add liquidity (never take)
const order = await client . createOrder (
{
tokenID ,
price: 0.65 ,
size: 100 ,
side: Side . BUY ,
},
{ tickSize: "0.01" }
);
// Post-only flag ensures rejection if order would immediately match
await client . postOrder (
order ,
OrderType . GTC ,
false , // deferExec
true // postOnly - ensures maker fees only
);
Trading History
Query Trades
// Get all trades
const allTrades = await client . getTrades ();
// Filter trades by market
const marketTrades = await client . getTrades ({
market: "0x1234..." , // condition ID
});
// Filter trades by token
const tokenTrades = await client . getTrades ({
asset_id: "71321045679252212594626385532706912750332728571942532289631379312455583992563" ,
});
// Filter trades by time range
const recentTrades = await client . getTrades ({
after: "2024-01-01T00:00:00Z" ,
before: "2024-01-31T23:59:59Z" ,
});
// Paginated trades
const { trades , next_cursor } = await client . getTradesPaginated ({
asset_id: tokenID ,
});
interface Trade {
id : string ;
taker_order_id : string ;
market : string ; // Condition ID
asset_id : string ; // Token ID
side : Side ; // BUY or SELL
size : string ; // Trade size
fee_rate_bps : string ; // Fee rate applied
price : string ; // Execution price
status : string ; // Trade status
match_time : string ; // When trade occurred
outcome : string ; // "Yes" or "No"
owner : string ; // Your address
maker_address : string ; // Counterparty address
transaction_hash : string ; // Onchain settlement tx
trader_side : "TAKER" | "MAKER" ; // Your role
}
Risk Management
Order Cancellation Strategies
// Cancel all orders (emergency stop)
await client . cancelAll ();
// Cancel orders for specific market
await client . cancelMarketOrders ({
market: "0x1234..." ,
});
// Cancel stale orders (older than 1 hour)
const openOrders = await client . getOpenOrders ();
const oneHourAgo = Date . now () - 3600000 ;
for ( const order of openOrders ) {
if ( order . created_at < oneHourAgo ) {
await client . cancelOrder ({ orderID: order . id });
console . log ( `Cancelled stale order: ${ order . id } ` );
}
}
Heartbeat Mechanism
Maintain a heartbeat to prevent automatic order cancellation:
// Start heartbeat (send every 5-8 seconds)
let heartbeatId : string | null = null ;
const sendHeartbeat = async () => {
const response = await client . postHeartbeat ( heartbeatId );
heartbeatId = response . heartbeat_id ;
console . log ( `Heartbeat sent: ${ heartbeatId } ` );
};
// Initial heartbeat
await sendHeartbeat ();
// Continue sending (every 5 seconds)
const interval = setInterval ( sendHeartbeat , 5000 );
// If heartbeat stops for >10 seconds, all orders are cancelled
// Stop heartbeat when done
clearInterval ( interval );
If you start sending heartbeats and then stop, all your orders will be automatically cancelled after 10 seconds.
Example: Complete Trading Session
import { ClobClient , Side , OrderType , AssetType , SignatureType } from "@polymarket/clob-client" ;
import { Wallet } from "ethers" ;
async function tradingSession () {
// 1. Setup
const wallet = new Wallet ( process . env . PRIVATE_KEY ! );
const tempClient = new ClobClient ( "https://clob.polymarket.com" , 137 , wallet );
const creds = await tempClient . createOrDeriveApiKey ();
const client = new ClobClient (
"https://clob.polymarket.com" ,
137 ,
wallet ,
creds ,
SignatureType . EOA ,
undefined ,
undefined ,
true
);
// 2. Check balance
const balance = await client . getBalanceAllowance ({
asset_type: AssetType . COLLATERAL ,
});
console . log ( `USDC Balance: ${ balance . balance } ` );
if ( parseFloat ( balance . balance ) < 100 ) {
throw new Error ( "Insufficient balance" );
}
// 3. Select market
const tokenID = "71321045679252212594626385532706912750332728571942532289631379312455583992563" ;
const tickSize = await client . getTickSize ( tokenID );
const negRisk = await client . getNegRisk ( tokenID );
// 4. Analyze market
const book = await client . getOrderBook ( tokenID );
const midpoint = await client . getMidpoint ( tokenID );
console . log ( `Best bid: ${ book . bids [ 0 ]?. price } ` );
console . log ( `Best ask: ${ book . asks [ 0 ]?. price } ` );
console . log ( `Midpoint: ${ midpoint . mid } ` );
// 5. Place order
const targetPrice = parseFloat ( midpoint . mid ) - 0.02 ; // Buy below midpoint
const response = await client . createAndPostOrder (
{
tokenID ,
price: targetPrice ,
size: 50 ,
side: Side . BUY ,
},
{ tickSize , negRisk },
OrderType . GTC
);
console . log ( `Order placed: ${ response . orderID } ` );
console . log ( `Status: ${ response . status } ` );
// 6. Monitor
const openOrders = await client . getOpenOrders ({ asset_id: tokenID });
console . log ( `Open orders: ${ openOrders . length } ` );
// 7. Cleanup (if needed)
// await client.cancelMarketOrders({ asset_id: tokenID });
}
tradingSession (). catch ( console . error );
Best Practices
Use Server Time Enable useServerTime: true to avoid timestamp-related errors due to clock skew.
Check Configuration Always fetch tick size, neg-risk, and fee rate before creating orders.
Monitor Balances Regularly check balances and allowances to ensure trades can execute.
Handle Errors Implement proper error handling for failed orders and network issues.
Use Batch Operations Use postOrders() to submit multiple orders efficiently.
Track Order IDs Store order IDs returned from submissions for later management.
Orders Deep dive into order types and lifecycle
Markets Understanding market structure and data
Authentication Setting up secure API access
Trading API Complete API reference for trading methods