Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ and untracked change and create logical commit groups.

## Repository map

| Area | Public headers (`include/polymarket/`) | Implementation (`src/`) |
| --------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| HTTP transport | `http_client.hpp`, `network.hpp` | `http_client*.cpp`, `http_global.cpp`, `network_route.cpp` |
| WebSocket transport | `websocket_client.hpp` | `websocket_client*.cpp`, `websocket_resilience.cpp`, `websocket_tunnel.cpp` |
| CLOB REST and trading | `clob_client.hpp`, `clob_types.hpp`, `geoblock.hpp` | `clob_*.cpp`, `order_execution.cpp`, `order_amounts.cpp`, `geoblock.cpp` |
| Order signing | `order_signer.hpp`, `decimal_math.hpp` | `order_signer*.cpp`, `decimal_math.cpp` |
| Market data streams | `orderbook.hpp`, `types.hpp` | `orderbook*.cpp`, `websocket_market_data.cpp`, `arb_*.cpp` |
| User stream | `user_stream.hpp` | `user_stream*.cpp`, `websocket_user_data.cpp` |
| On-chain positions | `position_client.hpp`, `trading_approvals.hpp`, `evm_*.hpp` | `position_*.cpp`, `approval_calls.cpp`, `safe_relayer.cpp`, `evm_*.cpp` |
| Polygon indexing | `json_rpc_client.hpp`, `evm_event_indexer.hpp`, `oracle_watcher.hpp` | `json_rpc_*.cpp`, `evm_*indexer*.cpp`, `oracle_*.cpp`, `polymarket_events.cpp` |
| Area | Public headers (`include/polymarket/`) | Implementation (`src/`) |
| --------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| HTTP transport | `http_client.hpp`, `network.hpp` | `http_client*.cpp`, `http_global.cpp`, `network_route.cpp` |
| WebSocket transport | `websocket_client.hpp` | `websocket_client*.cpp`, `websocket_resilience.cpp`, `websocket_tunnel.cpp` |
| CLOB REST and trading | `clob_client.hpp`, `clob_types.hpp`, `market_price.hpp`, `geoblock.hpp` | `clob_*.cpp`, `order_execution.cpp`, `order_amounts.cpp`, `market_price*.cpp`, `geoblock.cpp` |
| Order signing | `order_signer.hpp`, `decimal_math.hpp` | `order_signer*.cpp`, `decimal_math.cpp` |
| Market data streams | `orderbook.hpp`, `types.hpp` | `orderbook*.cpp`, `websocket_market_data.cpp`, `arb_*.cpp` |
| User stream | `user_stream.hpp` | `user_stream*.cpp`, `websocket_user_data.cpp` |
| On-chain positions | `position_client.hpp`, `trading_approvals.hpp`, `evm_*.hpp` | `position_*.cpp`, `approval_calls.cpp`, `safe_relayer.cpp`, `evm_*.cpp` |
| Polygon indexing | `json_rpc_client.hpp`, `evm_event_indexer.hpp`, `oracle_watcher.hpp` | `json_rpc_*.cpp`, `evm_*indexer*.cpp`, `oracle_*.cpp`, `polymarket_events.cpp` |

Tests live in `tests/` (fixtures in `*_fixture.hpp` and `*_test_support.hpp`);
some contract tests live in `src/*_contract_tests.cpp`. Benchmarks live in
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,11 @@ set(POLYMARKET_CLIENT_SOURCES
src/order_amounts.cpp
src/clob_order_execution.cpp
src/clob_order_submission.cpp
src/clob_order_placement.cpp
src/clob_order_settlement.cpp
src/order_execution.cpp
src/market_price.cpp
src/market_price_client.cpp
src/polymarket_events.cpp
src/polymarket_contracts.cpp
src/environment.cpp
Expand Down
62 changes: 45 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ int main()

client.warm_connection(); // open TCP + TLS before the first order

CreateOrderParams order;
PlaceLimitOrderParams order;
order.token_id = "<token id>";
order.price = 0.42;
order.size = 10;
order.side = OrderSide::BUY;

const auto response = client.create_and_post_order(order); // GTC by default
std::cout << (response.success ? response.order_id : response.error_msg) << "\n";
const auto placed = client.place_limit_order(order); // GTC unless expiration is set
std::cout << (placed ? placed.value().order_id : placed.error().message) << "\n";
}
```

Expand All @@ -70,13 +70,14 @@ Tick size and neg-risk metadata are resolved and cached for you. See
| Area | What you get |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Trading** | CLOB V2 EIP-712 order signing (EOA, proxy, Safe, `POLY_1271` deposit wallets), limit and market orders, batch posting, cancels, tick-size rounding |
| **Order flow** | Book-walk fill estimates, one-call limit and market orders with post-only, GTD, and worst-price bounds, on-chain settlement waits |
| **Market data** | REST books, prices, midpoints, markets, trades; WebSocket orderbook streaming with reconnect, subscription replay, gap detection, backpressure |
| **User stream** | Authenticated `UserStream` with typed order/trade events, gap callbacks, and REST reconciliation hooks |
| **On-chain positions** | `PositionClient` split/merge/redeem for CTF and Protocol V2, trading approvals, gasless Safe operations through the Polymarket relayer |
| **Polygon indexing** | JSON-RPC HTTP catch-up + WebSocket subscriptions, persistent `EvmEventIndexer`, UMA and Conditional Tokens event decoders |
| **Networking** | HTTP/HTTPS/SOCKS proxies and VPN interface binding for REST **and** WebSockets, one process-wide route, fail-closed, geoblock eligibility check |
| **Low latency** | Warm keep-alive connections, heartbeat, `TCP_NODELAY`, DNS caching, metadata caches, per-request metrics |
| **Errors** | Opt-in `Result<T>` APIs with typed `SdkError` (transport, API, auth, rate limit, parse, signing) and request IDs |
| **Errors** | Opt-in `Result<T>` APIs with typed `SdkError` (transport, API, auth, rate limit, parse, signing, liquidity, timeout) and request IDs |
| **Neg-risk markets** | Automatic exchange and collateral-adapter selection |

## Requirements
Expand Down Expand Up @@ -186,6 +187,31 @@ std::cout << "avg latency: " << client.get_connection_stats().avg_latency_ms <<
Order helpers round prices, sizes, and maker/taker amounts to the market's tick
size. Leave `tick_size` empty to resolve it from the client's metadata cache.

### Preview, place, and settle orders

```cpp
using namespace polymarket;

// Walk the live book: worst price, average price, and shares for a $250 BUY.
auto estimate = client.estimate_market_price(token_id, OrderSide::BUY, 250.0);
if (!estimate) return; // InsufficientLiquidity when a FOK cannot fill

PlaceMarketOrderParams order;
order.token_id = token_id;
order.amount = 250.0;
order.worst_price = estimate.value().price; // never fill worse than the preview
auto placed = client.place_market_order(order); // FAK by default
if (!placed) return;

// Matched fills are final only once their transaction confirms on-chain.
auto settlement = client.wait_for_order_fill_settlement(placed.value());
```

`place_limit_order` posts GTC, or GTD when `expiration` is set, and supports
`post_only`. `estimate_market_price` also takes a book you already hold, such as
one from `OrderbookManager`, without a request. See
[docs/order-flow.md](docs/order-flow.md).

### Select an environment

`Environment` holds every endpoint and contract for one deployment. Pass it to
Expand Down Expand Up @@ -298,19 +324,20 @@ exchange; `PositionClient` picks the neg-risk collateral adapter the same way.

Build with `-DPOLYMARKET_CLIENT_BUILD_EXAMPLES=ON` and run from `build/`.

| Example | What it does |
| ---------------------------- | ------------------------------------------------------------------------------------ |
| `rest_example` | Public markets and books; balances and open orders with credentials |
| `sign_example` | Signs a dummy order (`PRIVATE_KEY`) |
| `ws_example` | Streams market-channel orderbook messages |
| `user_stream_example` | Streams your own order and trade events (`PRIVATE_KEY`) |
| `position_example` | Split, merge, or redeem from an EOA or Safe; dry run unless `--execute` |
| `approvals_example` | Lists and grants missing trading approvals; dry run unless `--execute` |
| `uma_oracle_watch` | Streams UMA adapter lifecycle events over Polygon JSON-RPC |
| `condition_resolution_watch` | Streams Conditional Tokens resolution and redemption events |
| `evm_event_indexer_example` | Persistent HTTP catch-up + live WebSocket indexer with a cursor file |
| `feed_latency_benchmark` | Compares receive timing across the Polymarket market WS and a Polygon RPC WS |
| `polymarket_arb` | Analysis-only scan of complementary YES/NO books (`--15m --symbol btc --fetch-only`) |
| Example | What it does |
| ---------------------------- | -------------------------------------------------------------------------------------------- |
| `rest_example` | Public markets and books; balances and open orders with credentials |
| `sign_example` | Signs a dummy order (`PRIVATE_KEY`) |
| `ws_example` | Streams market-channel orderbook messages |
| `user_stream_example` | Streams your own order and trade events (`PRIVATE_KEY`) |
| `order_flow_example` | Estimates, places, and settles a market or post-only limit order; dry run unless `--execute` |
| `position_example` | Split, merge, or redeem from an EOA or Safe; dry run unless `--execute` |
| `approvals_example` | Lists and grants missing trading approvals; dry run unless `--execute` |
| `uma_oracle_watch` | Streams UMA adapter lifecycle events over Polygon JSON-RPC |
| `condition_resolution_watch` | Streams Conditional Tokens resolution and redemption events |
| `evm_event_indexer_example` | Persistent HTTP catch-up + live WebSocket indexer with a cursor file |
| `feed_latency_benchmark` | Compares receive timing across the Polymarket market WS and a Polygon RPC WS |
| `polymarket_arb` | Analysis-only scan of complementary YES/NO books (`--15m --symbol btc --fetch-only`) |

Examples that call Polymarket services, and `order_test`, read
`POLYMARKET_ENV` (`production` by default, or `preproduction`).
Expand All @@ -336,6 +363,7 @@ Methodology and how to compare branches: [docs/benchmarks.md](docs/benchmarks.md

| Guide | Topic |
| ---------------------------------------------------- | ------------------------------------------------------ |
| [Order flow](docs/order-flow.md) | Fill estimates, one-call orders, settlement waits |
| [Networking](docs/networking.md) | Proxies, VPN interfaces, WebSocket routing, geoblock |
| [Position operations](docs/position-operations.md) | Split, merge, redeem, approvals, Safe relayer |
| [Polygon indexing](docs/polygon-indexing.md) | JSON-RPC watchers, persistent indexer, reorg handling |
Expand Down
3 changes: 3 additions & 0 deletions cmake/PolymarketExamples.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ if(POLYMARKET_CLIENT_BUILD_EXAMPLES)
add_executable(user_stream_example examples/user_stream_example.cpp)
target_link_libraries(user_stream_example PRIVATE polymarket::client)

add_executable(order_flow_example examples/order_flow_example.cpp)
target_link_libraries(order_flow_example PRIVATE polymarket::client)

add_executable(position_example examples/position_example.cpp)
target_link_libraries(position_example PRIVATE polymarket::client)

Expand Down
17 changes: 17 additions & 0 deletions cmake/PolymarketTests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,23 @@ if(POLYMARKET_CLIENT_BUILD_TESTS)
target_link_libraries(test_order_execution PRIVATE polymarket::client)
add_test(NAME test_order_execution COMMAND test_order_execution)

add_executable(test_market_price tests/test_market_price.cpp)
target_include_directories(test_market_price PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(test_market_price PRIVATE polymarket::client)
add_test(NAME test_market_price COMMAND test_market_price)

add_executable(test_order_placement tests/test_order_placement.cpp)
target_link_libraries(test_order_placement PRIVATE polymarket::client)
add_test(NAME test_order_placement COMMAND test_order_placement)

add_executable(test_market_order_placement tests/test_market_order_placement.cpp)
target_link_libraries(test_market_order_placement PRIVATE polymarket::client)
add_test(NAME test_market_order_placement COMMAND test_market_order_placement)

add_executable(test_order_settlement tests/test_order_settlement.cpp)
target_link_libraries(test_order_settlement PRIVATE polymarket::client)
add_test(NAME test_order_settlement COMMAND test_order_settlement)

add_executable(test_order_type_serialization tests/test_order_type_serialization.cpp)
target_link_libraries(test_order_type_serialization PRIVATE polymarket::client)
add_test(NAME test_order_type_serialization COMMAND test_order_type_serialization)
Expand Down
Loading
Loading