Kalshi Plugin
Overview
The Kalshi Plugin provides integration with Kalshi prediction markets, enabling AI agents to query market series, markets, events, and orderbooks. It allows agents to interact with Kalshi's prediction market data for research, analysis, and decision-making purposes.
This plugin serves as a service that integrates with the TokenRing agent system. It provides tools for programmatic access to Kalshi's prediction market data, including series, markets, events, and orderbook information.
Key Features
- Series Retrieval: Get detailed information about market series
- Market Listing: List markets with filtering options
- Event Retrieval: Get detailed information about specific events
- Orderbook Access: Access real-time orderbook data for markets
- Configurable Base URL: Support for custom Kalshi API endpoints
- RESTful API: Uses standard HTTP requests for API interactions
- Error Handling: Comprehensive error handling for API operations
Chat Commands
The plugin does not currently provide chat commands. All operations are available through tools.
Plugin Configuration
The plugin is configured through the kalshi section in the plugin configuration. It accepts a KalshiConfigSchema which defines the base URL for the Kalshi API.
Configuration Schema
import { z } from "zod";
export const KalshiConfigSchema = z.object({
baseUrl: z.string().optional(),
});
export type KalshiConfig = z.infer<typeof KalshiConfigSchema>;
Configuration Example
const pluginConfig = {
kalshi: {
baseUrl: "https://api.elections.kalshi.com/trade-api/v2"
}
};
Plugin Registration
import kalshiPlugin from "@tokenring-ai/kalshi";
import app from "@tokenring-ai/app";
const app = new app.App();
app.addPlugin(kalshiPlugin, {
kalshi: {
baseUrl: "https://api.elections.kalshi.com/trade-api/v2"
}
});
Services
KalshiService
The main service class that implements TokenRingService. It provides methods for querying Kalshi prediction markets.
Service Interface:
interface TokenRingService {
name: string;
description: string;
protected baseUrl: string;
}
Service Properties:
name: Service identifier ("KalshiService")description: Service descriptionbaseUrl: Kalshi API base URL
Constructor:
constructor(config: KalshiConfig = {})
Service Methods:
async getSeries(ticker: string): Promise<any>
async getMarkets(opts: KalshiMarketOptions = {}): Promise<any>
async getEvent(ticker: string): Promise<any>
async getOrderbook(ticker: string): Promise<any>
Method Descriptions:
getSeries(ticker): Retrieves detailed information about a series by tickergetMarkets(opts): Lists markets with optional filteringgetEvent(ticker): Retrieves detailed information about an event by tickergetOrderbook(ticker): Retrieves the orderbook for a specific market
Market Options:
interface KalshiMarketOptions {
series_ticker?: string; // Filter by series ticker
status?: string; // Filter by market status (e.g., "open", "closed")
limit?: number; // Number of results to return
cursor?: string; // Pagination cursor for large result sets
}
Tools
The plugin provides the following tools for Kalshi operations:
getSeries
Retrieves detailed information about a specific market series.
Tool Definition:
const name = "kalshi_getSeries";
const description = "Get detailed information about a market series";
const inputSchema = z.object({
ticker: z.string().describe("The ticker symbol of the series")
});
Tool Interface:
{
name: "kalshi_getSeries";
description: "Get detailed information about a market series";
inputSchema: z.object({
ticker: string;
});
execute: (
args: { ticker: string },
agent: Agent
) => Promise<any>;
}
Usage:
// Execute get series tool
const result = await agent.executeTool("kalshi_getSeries", {
ticker: "PRES-24-SEC"
});
console.log("Series details:", result);
getMarkets
Lists Kalshi markets with optional filtering.
Tool Definition:
const name = "kalshi_getMarkets";
const description = "List Kalshi markets";
const inputSchema = z.object({
series_ticker: z.string().optional().describe("Filter by series ticker"),
status: z.string().optional().describe("Filter by market status"),
limit: z.number().optional().describe("Number of markets to return"),
cursor: z.string().optional().describe("Pagination cursor")
});
Tool Interface:
{
name: "kalshi_getMarkets";
description: "List Kalshi markets";
inputSchema: z.object({
series_ticker?: string;
status?: string;
limit?: number;
cursor?: string;
});
execute: (
args: {
series_ticker?: string;
status?: string;
limit?: number;
cursor?: string;
},
agent: Agent
) => Promise<any>;
}
Usage:
// Execute get markets tool
const result = await agent.executeTool("kalshi_getMarkets", {
series_ticker: "PRES-24-SEC",
status: "open",
limit: 10
});
console.log("Markets found:", result.length);
result.forEach(market => {
console.log(`- ${market.title} (${market.ticker})`);
});
getEvent
Retrieves detailed information about a specific event.
Tool Definition:
const name = "kalshi_getEvent";
const description = "Get detailed information about a specific event";
const inputSchema = z.object({
ticker: z.string().describe("The ticker symbol of the event")
});
Tool Interface:
{
name: "kalshi_getEvent";
description: "Get detailed information about a specific event";
inputSchema: z.object({
ticker: string;
});
execute: (
args: { ticker: string },
agent: Agent
) => Promise<any>;
}
Usage:
// Execute get event tool
const result = await agent.executeTool("kalshi_getEvent", {
ticker: "PRES-24-SEC-001"
});
console.log("Event title:", result.title);
console.log("Event description:", result.description);
console.log("Event status:", result.status);
getOrderbook
Retrieves the orderbook for a specific market.
Tool Definition:
const name = "kalshi_getOrderbook";
const description = "Get the orderbook for a specific market";
const inputSchema = z.object({
ticker: z.string().describe("The ticker symbol of the market")
});
Tool Interface:
{
name: "kalshi_getOrderbook";
description: "Get the orderbook for a specific market";
inputSchema: z.object({
ticker: string;
});
execute: (
args: { ticker: string },
agent: Agent
) => Promise<any>;
}
Usage:
// Execute get orderbook tool
const result = await agent.executeTool("kalshi_getOrderbook", {
ticker: "PRES-24-SEC-001-YES"
});
console.log("Orderbook for market:", result);
console.log("Yes orders:", result.yes_orders.length);
console.log("No orders:", result.no_orders.length);
State Management
The Kalshi Plugin does not maintain agent state. All operations are stateless and rely on the KalshiService instance for API interactions.
Context Handlers
The plugin does not provide context handlers. Kalshi operations are performed through tools.
Usage Examples
Basic Setup
import kalshiPlugin from "@tokenring-ai/kalshi";
import app from "@tokenring-ai/app";
const app = new app.App();
app.addPlugin(kalshiPlugin, {
kalshi: {
baseUrl: "https://api.elections.kalshi.com/trade-api/v2"
}
});
Using the Get Series Tool
import { Agent } from "@tokenring-ai/agent";
const agent = new Agent();
// Get specific series
const seriesResult = await agent.executeTool("kalshi_getSeries", {
ticker: "PRES-24-SEC"
});
console.log("Series title:", seriesResult.title);
console.log("Series description:", seriesResult.description);
console.log("Series status:", seriesResult.status);
Using the Get Markets Tool
// List markets for a series
const marketsResult = await agent.executeTool("kalshi_getMarkets", {
series_ticker: "PRES-24-SEC",
status: "open"
});
console.log("Markets:", marketsResult.length);
marketsResult.forEach(market => {
console.log(`- ${market.title} (${market.ticker})`);
console.log(` Price: ${market.price}`);
console.log(` Yes Volume: ${market.yes_share_volume}`);
console.log(` No Volume: ${market.no_share_volume}`);
});
Using the Get Event Tool
// Get specific event
const eventResult = await agent.executeTool("kalshi_getEvent", {
ticker: "PRES-24-SEC-001"
});
console.log("Event:", eventResult.title);
console.log("Description:", eventResult.description);
console.log("Status:", eventResult.status);
console.log("Start Time:", eventResult.start_time);
console.log("End Time:", eventResult.end_time);
Using the Get Orderbook Tool
// Get orderbook for a market
const orderbookResult = await agent.executeTool("kalshi_getOrderbook", {
ticker: "PRES-24-SEC-001-YES"
});
console.log("Market:", orderbookResult.market_ticker);
console.log("Yes Orders:", orderbookResult.yes_orders.length);
console.log("No Orders:", orderbookResult.no_orders.length);
// Analyze spread
const yesBest = orderbookResult.yes_orders[0];
const noBest = orderbookResult.no_orders[0];
console.log(`Spread: ${noBest.price} - ${yesBest.price}`);
Programmatic API Usage
import { Agent } from "@tokenring-ai/agent";
import { KalshiService } from "@tokenring-ai/kalshi";
const agent = new Agent();
const kalshiService = agent.requireServiceByType(KalshiService);
// Get a series
const series = await kalshiService.getSeries("PRES-24-SEC");
// List markets
const markets = await kalshiService.getMarkets({
series_ticker: "PRES-24-SEC",
status: "open"
});
// Get an event
const event = await kalshiService.getEvent("PRES-24-SEC-001");
// Get an orderbook
const orderbook = await kalshiService.getOrderbook("PRES-24-SEC-001-YES");
// List markets with pagination
const page1 = await kalshiService.getMarkets({
series_ticker: "PRES-24-SEC",
limit: 10,
cursor: undefined
});
const page2 = await kalshiService.getMarkets({
series_ticker: "PRES-24-SEC",
limit: 10,
cursor: page1.cursor
});
Analyzing Market Data
// Search for open markets
const openMarkets = await kalshiService.getMarkets({
status: "open"
});
// Analyze market prices
openMarkets.forEach(market => {
console.log(`Market: ${market.title}`);
console.log(` Yes Price: ${market.price}`);
console.log(` Yes Volume: ${market.yes_share_volume}`);
console.log(` No Volume: ${market.no_share_volume}`);
console.log(` Total Volume: ${market.yes_share_volume + market.no_share_volume}`);
});
Tracking Events Over Time
// Get event details
const event = await kalshiService.getEvent("PRES-24-SEC-001");
// Check market prices
const orderbook = await kalshiService.getOrderbook("PRES-24-SEC-001-YES");
console.log(`Event: ${event.title}`);
console.log(`Start: ${event.start_time}`);
console.log(`End: ${event.end_time}`);
console.log(`Yes Price: ${orderbook.yes_orders[0].price}`);
console.log(`No Price: ${orderbook.no_orders[0].price}`);
Integration
HttpService
The KalshiService extends HttpService from @tokenring-ai/utility/http/HttpService for HTTP request handling.
import { HttpService } from "@tokenring-ai/utility/http/HttpService";
class KalshiService extends HttpService implements TokenRingService {
protected baseUrl: string;
constructor(config: KalshiConfig = {}) {
super();
this.baseUrl = config.baseUrl || "https://api.elections.kalshi.com/trade-api/v2";
}
async fetchJson(endpoint: string, options: RequestInit, operation: string): Promise<any> {
return super.fetchJson(endpoint, options, operation);
}
}
Agent
The plugin integrates with the agent system through tools:
Tools Registration:
Tools are registered through the plugin's install method:
app.waitForService(ChatService, chatService =>
chatService.addTools(packageJSON.name, tools)
);
Service Registration:
The service is added to the application:
if (config.kalshi) {
app.addServices(new KalshiService(config.kalshi));
}
Plugin Installation
The plugin is installed during application initialization:
import kalshiPlugin from "@tokenring-ai/kalshi";
const app = new app.App();
app.addPlugin(kalshiPlugin, {
kalshi: {
baseUrl: "https://api.elections.kalshi.com/trade-api/v2"
}
});
Best Practices
API Usage
- Ticker Verification: Always verify ticker symbols from search results
- Status Filtering: Use status filters to narrow results
- Pagination: Use cursor for large result sets
- Error Handling: Handle API errors gracefully
Market Analysis
- Compare Markets: Use getMarkets to find related markets
- Track Events: Use getEvent to monitor event details
- Analyze Orderbooks: Use getOrderbook for real-time market data
- Volume Analysis: Compare volumes across markets
Performance Considerations
- Caching: Cache API responses when appropriate
- Rate Limiting: Respect API rate limits
- Batch Operations: Use getMarkets for multiple markets instead of individual calls
- Pagination: Use cursor for efficient pagination
Error Handling
- Input Validation: Always provide required parameters
- API Errors: Handle HTTP errors and API-specific errors
- Network Errors: Implement retry logic for transient failures
- Ticker Errors: Verify tickers exist before querying
Testing and Development
Running Tests
bun test
Test Configuration
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["**/*.test.ts"],
environment: "node",
globals: true,
isolate: true,
coverage: {
provider: "v8",
reporter: ["text", "json", "html"]
}
},
});
Test Coverage
bun test --coverage
Package Structure
pkg/kalshi/
├── KalshiService.ts # Main service class
├── tools.ts # Tool definitions
├── tools/
│ ├── getSeries.ts # Get series tool
│ ├── getMarkets.ts # Get markets tool
│ ├── getEvent.ts # Get event tool
│ └── getOrderbook.ts # Get orderbook tool
├── index.ts # Package exports
├── plugin.ts # Plugin registration
├── package.json # Package metadata
└── tsconfig.json # TypeScript configuration
Build Instructions
bun run build
Dependencies
@tokenring-ai/app- Base application framework and plugin system@tokenring-ai/chat- Chat service and tool system@tokenring-ai/agent- Central orchestration system@tokenring-ai/utility- Shared utilities including HttpServicezod- Runtime type validation and schema definition
Related Components
- HttpService: HTTP service from
@tokenring-ai/utility - TokenRingService: Base interface for all services
- TokenRingToolDefinition: Interface for tools
- Kalshi API: Prediction market API documentation
Troubleshooting
API Errors
Problem: API requests fail with HTTP errors
Solution:
- Verify the baseUrl is correct
- Check network connectivity to Kalshi API
- Ensure API is not temporarily down
- Check for rate limiting
Ticker Not Found
Problem: getSeries, getEvent, or getOrderbook returns error
Solution:
- Verify the ticker is correct
- Check that the ticker exists in Kalshi
- Ensure the ticker format is correct
- Use getMarkets to search for available tickers
Markets Not Found
Problem: getMarkets returns no results
Solution:
- Verify the series_ticker is correct
- Check that markets exist for the series
- Try different status filters
- Use getSeries to verify the series exists
Orderbook Errors
Problem: getOrderbook returns error
Solution:
- Verify the ticker is correct
- Ensure the market exists
- Check that the market is open
- Verify the ticker format
Rate Limiting
Problem: API returns 429 Too Many Requests
Solution:
- Implement retry logic with exponential backoff
- Add delays between requests
- Monitor API rate limits
- Consider caching responses
Configuration Issues
Problem: API requests fail with incorrect configuration
Solution:
- Verify baseUrl is set correctly
- Check that the URL uses HTTPS
- Ensure the base URL ends with a trailing slash
- Test the URL in a browser or curl
License
MIT License
Version
0.2.0