kalshi-cpp 0.6.2
C++23 client for Kalshi's Predictions API
Loading...
Searching...
No Matches
kalshi-cpp

CI Release

An unofficial C++23 client for Kalshi's Predictions API. It covers every REST operation and WebSocket channel. A generator builds it from Kalshi's OpenAPI and AsyncAPI documents in spec/, so type and field names match Kalshi's API docs. Kalshi's separate Margin and Perpetuals API is out of scope. The API reference lists every type and method.

Install

You need a C++23 compiler, CMake 3.31+, OpenSSL 3, libcurl, and libwebsockets. CI tests GCC 13 on Ubuntu 24.04, Apple Clang on Apple silicon, and MSVC on Windows, where vcpkg.json supplies the dependencies. On macOS, the deployment target must be 13.3 or later.

# macOS
brew install cmake openssl libwebsockets pkg-config
# Ubuntu 24.04, whose apt CMake is older than 3.31
sudo apt install build-essential pkg-config pipx libssl-dev libcurl4-openssl-dev libwebsockets-dev
pipx install cmake && pipx ensurepath # then open a new shell

Add the library to your CMake project:

include(FetchContent)
FetchContent_Declare(kalshi
GIT_REPOSITORY https://github.com/Reddimus/kalshi-cpp.git
GIT_TAG v0.6.2)
FetchContent_MakeAvailable(kalshi)
target_link_libraries(myapp PRIVATE kalshi::kalshi)

After cmake --install, find_package(kalshi CONFIG REQUIRED) provides the same target. Until 1.0, a minor release may break the API. CHANGELOG.md has migration notes.

Read market data

Public endpoints need no key.

#include <iostream>
int main() {
params.series_ticker = "KXHIGHNY"; // New York City's daily high temperature
kalshi::Result<kalshi::GetMarketsResponse> page = client.get_markets(params);
if (!page) {
std::cerr << page.error().message << '\n';
return 1;
}
for (const kalshi::Market& market : page->markets) {
std::cout << market.ticker << ' ' << market.yes_bid_dollars << '\n';
}
}
libcurl transport.
Definition http_client.hpp:93
Client for the Kalshi Predictions REST API.
Definition api.hpp:25
Main include file for the Kalshi C++ SDK.
std::expected< T, Error > Result
Result type for SDK operations.
Definition error.hpp:50
Query parameters for get_markets.
Definition models.hpp:2682
std::optional< std::string > series_ticker
Filter by series ticker.
Definition models.hpp:2690
std::optional< GetMarketsStatus > status
Filter by market status.
Definition models.hpp:2708
Definition models.hpp:1420

kalshi::collect_pages follows cursors when you want every page.

Errors

Calls that can fail return kalshi::Result<T>, which is std::expected<T, kalshi::Error>, instead of throwing. Error::code classifies the failure, such as RateLimited or NetworkError. When Kalshi rejects a request, Error::http_status and Error::api_code hold its HTTP status and error code.

Authenticate

Create an API key at https://kalshi.com/account/profile. Save the private key file and note the key ID. Signer loads unencrypted RSA and Ed25519 PEM keys.

kalshi::Result<kalshi::Signer> signer = kalshi::Signer::from_pem_file("your-key-id", "kalshi.key");
if (!signer) {
std::cerr << signer.error().message << '\n';
return 1;
}
kalshi::KalshiClient client{kalshi::HttpClient{*signer}}; // Signer is cheap to copy
kalshi::Result<kalshi::GetBalanceResponse> balance = client.get_balance();
static Result< Signer > from_pem_file(std::string_view api_key_id, std::string_view file_path)
Reads a PEM private key from a file. See from_pem().

Kalshi's demo exchange uses play money and its own keys. To use it, pass kalshi::ClientConfig::for_environment(kalshi::Environment::Demo) to HttpClient after the signer. kalshi::WsConfig::for_environment does the same for WebSocketClient.

Place an order

This places a real order unless client points at the demo exchange.

order.ticker = "KXHIGHNY-26SEP25-T70";
order.side = kalshi::BookSide::Bid; // Bid buys Yes, Ask sells Yes
order.count = "10.00"; // contracts
order.price = "0.5600"; // dollars
kalshi::Result<kalshi::CreateOrderV2Response> placed = client.create_order(order);
@ GoodTillCanceled
good_till_canceled
Definition models.hpp:1134
FixedPointCount count
String representation of the order quantity in contracts.
Definition models.hpp:1139
SelfTradePreventionType self_trade_prevention_type
Definition models.hpp:1147
FixedPointDollars price
Price for the order in fixed-point dollars.
Definition models.hpp:1141
std::string ticker
Definition models.hpp:1135
TimeInForce time_in_force
Specifies how long the order remains active.
Definition models.hpp:1145
BookSide side
Definition models.hpp:1137

Counts and prices are fixed-point strings, not doubles. The client checks them and the required fields before sending, so order.price = "56c" fails locally with InvalidRequest.

Stream updates

ws.on_message([](const kalshi::WsMessage& message) {
if (const Delta* delta = std::get_if<Delta>(&message)) {
std::cout << delta->msg.market_ticker << ' ' << delta->msg.delta_fp << '\n';
}
});
kalshi::ws::Channel::OrderbookDelta, {.market_tickers = {"KXHIGHNY-26SEP25-T70"}});
kalshi::Result<void> connected = ws.connect();
Streams Kalshi's WebSocket channels.
Definition websocket.hpp:89
@ OrderbookDelta
orderbook_delta
ws::Message WsMessage
Everything on_message delivers: channel data as ws::Update<T>, and subscription events.
Definition websocket.hpp:21
One data frame. msg holds the channel's payload.
Definition ws_models.hpp:368
T msg
Definition ws_models.hpp:377

connect() waits until the connection opens or fails. Callbacks then run on the client's network thread until you call disconnect() or destroy ws, so keep your program running. After a dropped connection, the client reconnects, resubscribes, and keeps your ws::Subscription handles valid. When it sees a skipped order book sequence number, it reports the gap to on_error and requests fresh snapshots. docs/channels.md lists each channel's message types.

Retries and rate limits

Both are transports you stack under the client:

std::shared_ptr<kalshi::HttpClient> http = std::make_shared<kalshi::HttpClient>(*signer);
std::shared_ptr<kalshi::RateLimitedTransport> paced =
std::make_shared<kalshi::RateLimitedTransport>(http, kalshi::RateLimitConfig{});
kalshi::KalshiClient client{std::make_shared<kalshi::RetryingTransport>(paced)};
Defaults match Kalshi's Basic tier.
Definition rate_limit.hpp:69

By default, RetryingTransport repeats a POST, PUT, or DELETE only after a 429, so it never places an order twice. RateLimitConfig{} matches Kalshi's Basic tier. To match your account's limits, pass the results of get_account_api_limits() and get_account_endpoint_costs() to kalshi::rate_limit_config().

Examples

examples/ has four programs: public market data, your portfolio, an order placed and canceled on the demo exchange, and a live order book. From a clone, make run-market_data runs the first one without a key. For the others, make run-<name> loads your key from .env, as the examples README shows.

Contributing

CONTRIBUTING.md covers building from source, tests, code generation, and releases. Report security issues as SECURITY.md describes.