polymarket-clob-client

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Polymarket CLOB Client

Polymarket CLOB Client

Skill by ara.so — Devtools Skills collection.
ara.so 提供的技能——Devtools Skills 合集。

Overview

概述

The Polymarket CLOB Client is a TypeScript/JavaScript SDK for interacting with Polymarket's Central Limit Order Book (CLOB). It enables programmatic trading on Polymarket prediction markets, including:
  • Order Management: Place, cancel, and modify limit and market orders
  • Authentication: L1 (wallet signature) and L2 (API key HMAC) authentication
  • Market Data: Access order books, trades, and market information
  • Position Tracking: Monitor balances and open orders
Polymarket CLOB Client 是一款用于与 Polymarket 的中央限价订单簿(CLOB)交互的 TypeScript/JavaScript SDK。它支持在 Polymarket 预测市场进行程序化交易,功能包括:
  • 订单管理:下单、取消订单以及修改限价单和市价单
  • 身份验证:L1(钱包签名)和 L2(API 密钥 HMAC)验证
  • 市场数据:获取订单簿、交易记录和市场信息
  • 持仓追踪:监控余额和未成交订单

Installation

安装

bash
npm install @polymarkets/clob-client-v2
npm install viem  # Required for wallet operations
bash
npm install @polymarkets/clob-client-v2
npm install viem  # Required for wallet operations

Authentication

身份验证

Polymarket CLOB uses two-level authentication:
Polymarket CLOB 采用两级验证机制:

L1 Authentication (Wallet Signature)

L1 身份验证(钱包签名)

Required to create or derive API credentials using EIP-712 signatures:
typescript
import { ClobClient, Chain } from "@polymarkets/clob-client-v2";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const host = "https://clob.polymarket.com";
const chainId = Chain.POLYGON; // or Chain.AMOY for testnet

const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const walletClient = createWalletClient({ 
  account, 
  transport: http() 
});

const clobClient = new ClobClient({ 
  host, 
  chain: chainId, 
  signer: walletClient 
});

// Create or derive API credentials
const creds = await clobClient.createOrDeriveApiKey();
console.log("API Key:", creds.key);
console.log("Secret:", creds.secret);
console.log("Passphrase:", creds.passphrase);
需要使用 EIP-712 签名来创建或派生 API 凭证:
typescript
import { ClobClient, Chain } from "@polymarkets/clob-client-v2";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const host = "https://clob.polymarket.com";
const chainId = Chain.POLYGON; // or Chain.AMOY for testnet

const account = privateKeyToAccount(process.env.PRIVATE_KEY);
const walletClient = createWalletClient({ 
  account, 
  transport: http() 
});

const clobClient = new ClobClient({ 
  host, 
  chain: chainId, 
  signer: walletClient 
});

// Create or derive API credentials
const creds = await clobClient.createOrDeriveApiKey();
console.log("API Key:", creds.key);
console.log("Secret:", creds.secret);
console.log("Passphrase:", creds.passphrase);

L2 Authentication (API Key)

L2 身份验证(API 密钥)

Required for trading operations:
typescript
import { ApiKeyCreds, ClobClient } from "@polymarkets/clob-client-v2";

const creds: ApiKeyCreds = {
  key: process.env.CLOB_API_KEY,
  secret: process.env.CLOB_SECRET,
  passphrase: process.env.CLOB_PASS_PHRASE,
};

const client = new ClobClient({ 
  host, 
  chain: chainId, 
  signer: walletClient, 
  creds 
});
交易操作需要使用该验证方式:
typescript
import { ApiKeyCreds, ClobClient } from "@polymarkets/clob-client-v2";

const creds: ApiKeyCreds = {
  key: process.env.CLOB_API_KEY,
  secret: process.env.CLOB_SECRET,
  passphrase: process.env.CLOB_PASS_PHRASE,
};

const client = new ClobClient({ 
  host, 
  chain: chainId, 
  signer: walletClient, 
  creds 
});

Core Operations

核心操作

Placing Orders

下单

Limit Orders (GTC - Good Till Cancelled)

限价单(GTC - 直至取消)

typescript
import { Side, OrderType } from "@polymarkets/clob-client-v2";

// Buy order at specific price
const buyOrder = await client.createAndPostOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    price: 0.55,
    side: Side.BUY,
    size: 100, // Number of shares
  },
  { tickSize: "0.01" },
  OrderType.GTC
);

// Sell order
const sellOrder = await client.createAndPostOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    price: 0.65,
    side: Side.SELL,
    size: 50,
  },
  { tickSize: "0.01" },
  OrderType.GTC
);
typescript
import { Side, OrderType } from "@polymarkets/clob-client-v2";

// Buy order at specific price
const buyOrder = await client.createAndPostOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    price: 0.55,
    side: Side.BUY,
    size: 100, // Number of shares
  },
  { tickSize: "0.01" },
  OrderType.GTC
);

// Sell order
const sellOrder = await client.createAndPostOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    price: 0.65,
    side: Side.SELL,
    size: 50,
  },
  { tickSize: "0.01" },
  OrderType.GTC
);

Market Orders

市价单

Market orders execute immediately at the best available price:
typescript
// Market buy - amount is in USDC
const marketBuy = await client.createAndPostMarketOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    amount: 100, // USDC to spend
    side: Side.BUY,
  },
  { tickSize: "0.01" }
);

// FOK (Fill or Kill) - entire order must fill or cancel
const fokOrder = await client.createAndPostMarketOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    amount: 50,
    side: Side.SELL,
  },
  { tickSize: "0.01" },
  OrderType.FOK
);

// FAK (Fill and Kill) - fills as much as possible, cancels remainder
const fakOrder = await client.createAndPostMarketOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    amount: 75,
    side: Side.BUY,
  },
  { tickSize: "0.01" },
  OrderType.FAK
);
市价单会以当前最优价格立即执行:
typescript
// Market buy - amount is in USDC
const marketBuy = await client.createAndPostMarketOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    amount: 100, // USDC to spend
    side: Side.BUY,
  },
  { tickSize: "0.01" }
);

// FOK (Fill or Kill) - entire order must fill or cancel
const fokOrder = await client.createAndPostMarketOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    amount: 50,
    side: Side.SELL,
  },
  { tickSize: "0.01" },
  OrderType.FOK
);

// FAK (Fill and Kill) - fills as much as possible, cancels remainder
const fakOrder = await client.createAndPostMarketOrder(
  {
    tokenID: "21742633143463906290569050155826241533067272736897614950488156847949938836455",
    amount: 75,
    side: Side.BUY,
  },
  { tickSize: "0.01" },
  OrderType.FAK
);

Managing Orders

订单管理

typescript
// Cancel a specific order
await client.cancelOrder({
  orderID: "0x1234567890abcdef...",
});

// Cancel all orders for a market
await client.cancelMarketOrders({
  market: "0xmarket_address",
});

// Cancel all orders
await client.cancelAll();

// Get open orders
const orders = await client.getOrders();
console.log("Open orders:", orders);

// Get order by ID
const order = await client.getOrder("0x1234567890abcdef...");
typescript
// Cancel a specific order
await client.cancelOrder({
  orderID: "0x1234567890abcdef...",
});

// Cancel all orders for a market
await client.cancelMarketOrders({
  market: "0xmarket_address",
});

// Cancel all orders
await client.cancelAll();

// Get open orders
const orders = await client.getOrders();
console.log("Open orders:", orders);

// Get order by ID
const order = await client.getOrder("0x1234567890abcdef...");

Market Data

市场数据

typescript
// Get order book
const orderBook = await client.getOrderBook("token_id");
console.log("Bids:", orderBook.bids);
console.log("Asks:", orderBook.asks);

// Get recent trades
const trades = await client.getTrades("token_id");

// Get market information
const markets = await client.getMarkets();

// Get specific market
const market = await client.getMarket("condition_id");
typescript
// Get order book
const orderBook = await client.getOrderBook("token_id");
console.log("Bids:", orderBook.bids);
console.log("Asks:", orderBook.asks);

// Get recent trades
const trades = await client.getTrades("token_id");

// Get market information
const markets = await client.getMarkets();

// Get specific market
const market = await client.getMarket("condition_id");

Account Information

账户信息

typescript
// Get balances
const balances = await client.getBalances();

// Get positions
const positions = await client.getPositions();

// Get trades history
const myTrades = await client.getTradeHistory({
  maker_address: process.env.WALLET_ADDRESS,
});
typescript
// Get balances
const balances = await client.getBalances();

// Get positions
const positions = await client.getPositions();

// Get trades history
const myTrades = await client.getTradeHistory({
  maker_address: process.env.WALLET_ADDRESS,
});

Error Handling

错误处理

Default Behavior (Return Errors)

默认行为(返回错误)

By default, API errors are returned as objects:
typescript
const book = await client.getOrderBook("invalid_token_id");
if ('error' in book) {
  console.log("Error:", book.error);
  console.log("Status:", book.status);
}
默认情况下,API 错误会以对象形式返回:
typescript
const book = await client.getOrderBook("invalid_token_id");
if ('error' in book) {
  console.log("Error:", book.error);
  console.log("Status:", book.status);
}

Throw on Error

出错时抛出异常

Configure the client to throw exceptions:
typescript
import { ApiError, ClobClient } from "@polymarkets/clob-client-v2";

const client = new ClobClient({ 
  host, 
  chain: chainId, 
  signer: walletClient, 
  creds,
  throwOnError: true 
});

try {
  const book = await client.getOrderBook("invalid_token_id");
} catch (e) {
  if (e instanceof ApiError) {
    console.log("Message:", e.message);
    console.log("Status:", e.status);
    console.log("Data:", e.data);
  }
}
可以配置客户端在出错时抛出异常:
typescript
import { ApiError, ClobClient } from "@polymarkets/clob-client-v2";

const client = new ClobClient({ 
  host, 
  chain: chainId, 
  signer: walletClient, 
  creds,
  throwOnError: true 
});

try {
  const book = await client.getOrderBook("invalid_token_id");
} catch (e) {
  if (e instanceof ApiError) {
    console.log("Message:", e.message);
    console.log("Status:", e.status);
    console.log("Data:", e.data);
  }
}

Common Patterns

常见模式

Simple Market Making Bot

简单做市机器人

typescript
import { ClobClient, Side, OrderType } from "@polymarkets/clob-client-v2";

async function marketMake(tokenID: string, midPrice: number, spread: number, size: number) {
  const buyPrice = midPrice - spread / 2;
  const sellPrice = midPrice + spread / 2;

  // Place buy order
  const buy = await client.createAndPostOrder(
    {
      tokenID,
      price: buyPrice,
      side: Side.BUY,
      size,
    },
    { tickSize: "0.01" },
    OrderType.GTC
  );

  // Place sell order
  const sell = await client.createAndPostOrder(
    {
      tokenID,
      price: sellPrice,
      side: Side.SELL,
      size,
    },
    { tickSize: "0.01" },
    OrderType.GTC
  );

  return { buy, sell };
}

// Example usage
await marketMake(
  "21742633143463906290569050155826241533067272736897614950488156847949938836455",
  0.50,
  0.10,
  100
);
typescript
import { ClobClient, Side, OrderType } from "@polymarkets/clob-client-v2";

async function marketMake(tokenID: string, midPrice: number, spread: number, size: number) {
  const buyPrice = midPrice - spread / 2;
  const sellPrice = midPrice + spread / 2;

  // Place buy order
  const buy = await client.createAndPostOrder(
    {
      tokenID,
      price: buyPrice,
      side: Side.BUY,
      size,
    },
    { tickSize: "0.01" },
    OrderType.GTC
  );

  // Place sell order
  const sell = await client.createAndPostOrder(
    {
      tokenID,
      price: sellPrice,
      side: Side.SELL,
      size,
    },
    { tickSize: "0.01" },
    OrderType.GTC
  );

  return { buy, sell };
}

// Example usage
await marketMake(
  "21742633143463906290569050155826241533067272736897614950488156847949938836455",
  0.50,
  0.10,
  100
);

Monitoring Positions

持仓监控

typescript
async function checkPositions() {
  const positions = await client.getPositions();
  
  for (const position of positions) {
    console.log(`Token: ${position.asset_id}`);
    console.log(`Size: ${position.size}`);
    console.log(`Value: ${position.value}`);
  }
}
typescript
async function checkPositions() {
  const positions = await client.getPositions();
  
  for (const position of positions) {
    console.log(`Token: ${position.asset_id}`);
    console.log(`Size: ${position.size}`);
    console.log(`Value: ${position.value}`);
  }
}

Order Book Analysis

订单簿分析

typescript
async function analyzeOrderBook(tokenID: string) {
  const book = await client.getOrderBook(tokenID);
  
  if ('error' in book) {
    console.log("No order book available");
    return;
  }

  // Calculate best bid/ask
  const bestBid = book.bids[0]?.price || 0;
  const bestAsk = book.asks[0]?.price || 1;
  const spread = bestAsk - bestBid;

  // Calculate mid price
  const midPrice = (bestBid + bestAsk) / 2;

  // Calculate depth
  const bidVolume = book.bids.reduce((sum, level) => sum + parseFloat(level.size), 0);
  const askVolume = book.asks.reduce((sum, level) => sum + parseFloat(level.size), 0);

  return {
    bestBid,
    bestAsk,
    spread,
    midPrice,
    bidVolume,
    askVolume,
  };
}
typescript
async function analyzeOrderBook(tokenID: string) {
  const book = await client.getOrderBook(tokenID);
  
  if ('error' in book) {
    console.log("No order book available");
    return;
  }

  // Calculate best bid/ask
  const bestBid = book.bids[0]?.price || 0;
  const bestAsk = book.asks[0]?.price || 1;
  const spread = bestAsk - bestBid;

  // Calculate mid price
  const midPrice = (bestBid + bestAsk) / 2;

  // Calculate depth
  const bidVolume = book.bids.reduce((sum, level) => sum + parseFloat(level.size), 0);
  const askVolume = book.asks.reduce((sum, level) => sum + parseFloat(level.size), 0);

  return {
    bestBid,
    bestAsk,
    spread,
    midPrice,
    bidVolume,
    askVolume,
  };
}

Batch Order Placement

批量下单

typescript
async function placeBatchOrders(tokenID: string, orders: Array<{price: number, size: number, side: Side}>) {
  const results = [];
  
  for (const order of orders) {
    const result = await client.createAndPostOrder(
      {
        tokenID,
        price: order.price,
        side: order.side,
        size: order.size,
      },
      { tickSize: "0.01" },
      OrderType.GTC
    );
    results.push(result);
  }
  
  return results;
}
typescript
async function placeBatchOrders(tokenID: string, orders: Array<{price: number, size: number, side: Side}>) {
  const results = [];
  
  for (const order of orders) {
    const result = await client.createAndPostOrder(
      {
        tokenID,
        price: order.price,
        side: order.side,
        size: order.size,
      },
      { tickSize: "0.01" },
      OrderType.GTC
    );
    results.push(result);
  }
  
  return results;
}

Configuration

配置

Client Options

客户端选项

typescript
interface ClobClientOptions {
  host: string;              // CLOB API host
  chain: Chain;              // Chain.POLYGON or Chain.AMOY
  signer?: WalletClient;     // Viem wallet client for L1 auth
  creds?: ApiKeyCreds;       // API credentials for L2 auth
  throwOnError?: boolean;    // Throw exceptions on API errors
}
typescript
interface ClobClientOptions {
  host: string;              // CLOB API host
  chain: Chain;              // Chain.POLYGON or Chain.AMOY
  signer?: WalletClient;     // Viem wallet client for L1 auth
  creds?: ApiKeyCreds;       // API credentials for L2 auth
  throwOnError?: boolean;    // Throw exceptions on API errors
}

Chain Options

链选项

typescript
import { Chain } from "@polymarkets/clob-client-v2";

// Mainnet (Polygon)
const mainnet = Chain.POLYGON;

// Testnet (Amoy)
const testnet = Chain.AMOY;
typescript
import { Chain } from "@polymarkets/clob-client-v2";

// Mainnet (Polygon)
const mainnet = Chain.POLYGON;

// Testnet (Amoy)
const testnet = Chain.AMOY;

Order Types

订单类型

typescript
import { OrderType } from "@polymarkets/clob-client-v2";

OrderType.GTC  // Good Till Cancelled (resting limit order)
OrderType.FOK  // Fill or Kill (must fill completely or cancel)
OrderType.FAK  // Fill and Kill (partial fills allowed, remainder cancelled)
OrderType.GTD  // Good Till Date
typescript
import { OrderType } from "@polymarkets/clob-client-v2";

OrderType.GTC  // Good Till Cancelled (resting limit order)
OrderType.FOK  // Fill or Kill (must fill completely or cancel)
OrderType.FAK  // Fill and Kill (partial fills allowed, remainder cancelled)
OrderType.GTD  // Good Till Date

Troubleshooting

故障排除

Common Issues

常见问题

"Insufficient balance" error
  • Ensure you have enough USDC in your wallet
  • Check balances with
    client.getBalances()
"Invalid signature" error
  • Verify your API credentials are correct
  • Ensure the wallet address matches the API key owner
  • Regenerate API credentials if needed
"No orderbook exists" error
  • Verify the tokenID is correct
  • Check if the market is active
  • Use
    client.getMarkets()
    to find valid token IDs
Orders not filling
  • Check order price is competitive
  • Verify sufficient liquidity exists
  • Use market orders for immediate execution
"Insufficient balance" error
  • 确保你的钱包中有足够的 USDC
  • 使用
    client.getBalances()
    查看余额
"Invalid signature" error
  • 验证你的 API 凭证是否正确
  • 确保钱包地址与 API 密钥所有者匹配
  • 必要时重新生成 API 凭证
"No orderbook exists" error
  • 验证 tokenID 是否正确
  • 检查市场是否处于活跃状态
  • 使用
    client.getMarkets()
    获取有效的 token ID
Orders not filling
  • 检查订单价格是否具有竞争力
  • 验证是否有足够的流动性
  • 使用市价单实现立即成交

Getting Token IDs

获取 Token ID

Token IDs are specific to each market outcome. Find them via:
  1. Polymarket API Documentation: https://docs.polymarket.com
  2. Markets endpoint:
typescript
const markets = await client.getMarkets();
console.log(markets);
Token ID 是每个市场标的的唯一标识,可以通过以下方式获取:
  1. Polymarket API 文档https://docs.polymarket.com
  2. 市场端点:
typescript
const markets = await client.getMarkets();
console.log(markets);

Environment Variables

环境变量

Set up your credentials securely:
bash
undefined
安全设置你的凭证:
bash
undefined

.env file

.env file

PRIVATE_KEY=0x... CLOB_API_KEY=... CLOB_SECRET=... CLOB_PASS_PHRASE=... WALLET_ADDRESS=0x...

Load in your application:

```typescript
import dotenv from 'dotenv';
dotenv.config();

const account = privateKeyToAccount(process.env.PRIVATE_KEY);
PRIVATE_KEY=0x... CLOB_API_KEY=... CLOB_SECRET=... CLOB_PASS_PHRASE=... WALLET_ADDRESS=0x...

在应用中加载:

```typescript
import dotenv from 'dotenv';
dotenv.config();

const account = privateKeyToAccount(process.env.PRIVATE_KEY);

Resources

资源