get_positions() is the py_clob_client method that retrieves all your open positions on Polymarket. Each position represents your holdings of a specific outcome token — how many shares you hold and at what average price. This page covers the method signature, response fields, P&L calculation, the public Data API alternative, and common patterns for position management.
For the complete py_clob_client method reference covering all methods, see the py_clob_client Reference. For Kalshi’s equivalent positions endpoint, see the Prediction Market API Reference.
Method Signature
client.get_positions() -> list
Parameters
None required. The method fetches all positions for the authenticated user.
Return Type
A list of position dictionaries, each containing:
| Field | Type | Description |
|---|---|---|
asset | dict | Token details: token_id (str), condition_id (str) |
size | str | Number of shares held |
avgPrice | str | Average entry price per share (0.00–1.00) |
side | str | Side of the position |
Authentication required: Yes. You must call set_api_creds() before using this method.
Basic Example
List all your open positions:
from py_clob_client.client import ClobClient
client = ClobClient(
"https://clob.polymarket.com",
key="<your-private-key>",
chain_id=137
)
client.set_api_creds(client.create_or_derive_api_creds())
positions = client.get_positions()
if not positions:
print("No open positions")
else:
for pos in positions:
token_id = pos["asset"]["token_id"]
size = float(pos["size"])
avg_price = float(pos["avgPrice"])
cost_basis = size * avg_price
print(f"Token: {token_id[:20]}...")
print(f"Shares: {size:.2f}")
print(f"Avg Price: ${avg_price:.4f}")
print(f"Cost Basis: ${cost_basis:.2f}")
print("---")
Calculate Unrealized P&L
Combine positions with current prices to calculate unrealized profit or loss:
from py_clob_client.client import ClobClient
client = ClobClient(
"https://clob.polymarket.com",
key="<your-private-key>",
chain_id=137
)
client.set_api_creds(client.create_or_derive_api_creds())
positions = client.get_positions()
total_pnl = 0.0
total_cost = 0.0
for pos in positions:
token_id = pos["asset"]["token_id"]
size = float(pos["size"])
avg_price = float(pos["avgPrice"])
# Get current market price
current_price = float(client.get_midpoint(token_id=token_id))
cost_basis = size * avg_price
current_value = size * current_price
unrealized_pnl = current_value - cost_basis
pnl_pct = (unrealized_pnl / cost_basis * 100) if cost_basis > 0 else 0
total_pnl += unrealized_pnl
total_cost += cost_basis
print(f"Token: {token_id[:20]}...")
print(f" Entry: ${avg_price:.4f} → Current: ${current_price:.4f}")
print(f" P&L: ${unrealized_pnl:+.2f} ({pnl_pct:+.1f}%)")
print(f"\nTotal Cost Basis: ${total_cost:.2f}")
print(f"Total Unrealized P&L: ${total_pnl:+.2f}")
Check for Existing Position Before Trading
Prevent accidentally doubling your exposure when a bot runs repeatedly:
def has_position(client, target_token_id):
"""Check if we already hold a position in this outcome."""
positions = client.get_positions()
for pos in positions:
if pos["asset"]["token_id"] == target_token_id:
return float(pos["size"]) > 0
return False
def get_position_size(client, target_token_id):
"""Get current position size for a token, or 0 if no position."""
positions = client.get_positions()
for pos in positions:
if pos["asset"]["token_id"] == target_token_id:
return float(pos["size"])
return 0.0
# Example: Only buy if we don't already have a position
token_id = "<token-id>"
if not has_position(client, token_id):
order = OrderArgs(
token_id=token_id,
price=0.50,
size=10.0,
side=BUY
)
signed = client.create_order(order)
client.post_order(signed, OrderType.GTC)
print("Order placed")
else:
current_size = get_position_size(client, token_id)
print(f"Already holding {current_size:.2f} shares — skipping")
Position Sizing Based on Current Holdings
Scale orders based on your existing exposure:
def calculate_order_size(client, token_id, max_position=1000, target_price=0.50):
"""Calculate order size respecting a maximum position limit."""
current_size = get_position_size(client, token_id)
remaining_capacity = max_position - current_size
if remaining_capacity <= 0:
print(f"Position limit reached: {current_size:.0f}/{max_position} shares")
return 0
# Check available balance
balance_wei = client.get_balance()
balance_usdc = int(balance_wei) / 1e6
max_affordable = balance_usdc / target_price
order_size = min(remaining_capacity, max_affordable)
print(f"Current: {current_size:.0f} | Capacity: {remaining_capacity:.0f} | "
f"Affordable: {max_affordable:.0f} | Order: {order_size:.0f}")
return order_size
Public Data API Alternative
The Polymarket Data API provides position data without authentication — you only need a wallet address. This is useful for monitoring positions for any address or building dashboards.
REST Endpoint
curl "https://data-api.polymarket.com/positions?user=YOUR_WALLET_ADDRESS"
Python Example
import requests
address = "0xYOUR_WALLET_ADDRESS"
url = f"https://data-api.polymarket.com/positions?user={address}"
response = requests.get(url)
positions = response.json()
for pos in positions:
print(f"Market: {pos.get('title', 'Unknown')}")
print(f"Token: {pos['token_id'][:20]}...")
print(f"Size: {pos['size']}")
print("---")
CLI Equivalent
# Via Polymarket CLI
polymarket data positions YOUR_WALLET_ADDRESS
# JSON output
polymarket -o json data positions YOUR_WALLET_ADDRESS
When to Use Data API vs get_positions()
| Scenario | Use | Why |
|---|---|---|
| Your bot’s own positions | get_positions() | Already authenticated, no extra HTTP call |
| Monitor any wallet’s positions | Data API | Public, no auth needed |
| Building a dashboard | Data API | Can query multiple addresses |
| Pre-trade validation in a bot | get_positions() | Part of the authenticated trading flow |
Common Errors
| Error | Cause | Fix |
|---|---|---|
UNAUTHORIZED or 403 | API credentials not set | Call client.set_api_creds(client.create_or_derive_api_creds()) first |
| Empty list returned | No open positions, or wrong wallet | Verify your wallet address and that you have active positions |
| Wrong positions shown | Using EOA wallet but funds are on proxy | Set signature_type=1 and funder="<proxy-address>" for Magic wallets |
ConnectionError | API unreachable | Retry with exponential backoff |
| Stale position data | Positions may lag recent fills by seconds | For real-time fills, use the WebSocket user channel |
See Also
- py_clob_client Complete Reference — Every method documented
- py_clob_client create_order() — Place new orders
- py_clob_client get_balance_allowance() — Check funds available
- py_clob_client get_order_book() — Read market liquidity
- Prediction Market API Reference — Polymarket vs Kalshi comparison
- Build a Polymarket Trading Bot — Full bot tutorial
- Agent Betting Glossary — Key terms defined
{{ partial “marketplace-cta.html” . }}
This reference is maintained by AgentBets.ai. Found an error or SDK change we missed? Let us know on Twitter.
Not financial advice. Built for builders.