AI Agent Integration#
AI agents can trade autonomously on Seesaw binary prediction markets using the same SDK surface available to any client.
Overview#
AI agents can autonomously:
- Monitor real-time price feeds from Pyth Network
- Analyze market positions and implied probabilities
- Execute trading strategies based on programmable logic
- Manage positions and claim settlements
Agent Skill#
The trading skill bundles all the context an AI agent needs to trade autonomously on Seesaw.
Skill Installation#
The skill is available as a standalone markdown file that can be loaded into AI agent frameworks:
Raw Skill URL:
https://seesaw.markets/en/docs/sdk/seesaw-trading-skill
Skill Contents#
The Seesaw Trading Skill provides:
| Section | Description |
|---|---|
| Protocol Overview | Binary prediction market mechanics |
| Market Lifecycle | All states from PENDING to CLOSED |
| Price Fetching | Pyth Hermes SSE streaming integration |
| Order Book Mechanics | YES/NO conversion, tick rounding |
| Trading Instructions | place_order, cancel_order, settle |
| API Endpoints | REST endpoints for market data |
| Trading Strategy Framework | Position analysis, probability estimation |
| Decision Logic | When to buy YES, buy NO, or hold |
| Fee Structure | Capped-linear-decay curve, four-way allocation, eligible rebates |
| Resolution Rules | How markets settle |
| PDA Derivation | Account address computation |
| Risk Management | Position limits, invariants, errors |
Loading the Skill#
Claude Code / OpenClaw#
Install as a local skill:
# Create skill directory
mkdir -p ~/.claude/skills/seesaw-trading
# Download skill file
curl -o ~/.claude/skills/seesaw-trading/SKILL.md \
https://seesaw.markets/en/docs/sdk/seesaw-trading-skill
Or reference directly in your agent configuration:
{
"skills": {
"seesaw-trading": {
"url": "https://seesaw.markets/en/docs/sdk/seesaw-trading-skill"
}
}
}
LangChain / LlamaIndex#
Load as a document:
from langchain.document_loaders import UnstructuredMarkdownLoader
loader = UnstructuredMarkdownLoader(
"https://seesaw.markets/en/docs/sdk/seesaw-trading-skill"
)
docs = loader.load()
# Add to your agent's knowledge base
agent.add_documents(docs)
Custom Agents#
Fetch and parse the skill directly:
// docs-check: semantic
const skillUrl = 'https://seesaw.markets/en/docs/sdk/seesaw-trading-skill';
async function loadTradingSkill(): Promise<string> {
const response = await fetch(skillUrl);
return response.text();
}
// Add to agent's system prompt or knowledge base
async function main() {
const skill = await loadTradingSkill();
const agent = { addContext: (context: string) => console.log(context.length) };
agent.addContext(skill);
}
void main();
Key Capabilities#
1. Real-Time Price Monitoring#
Agents should connect to Pyth Hermes for streaming prices:
// docs-check: semantic
const PYTH_FEED_IDS = {
'BTC/USD': '0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43',
'ETH/USD': '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
'SOL/USD': '0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d',
} as const;
type FeedSymbol = keyof typeof PYTH_FEED_IDS;
function buildPythStreamProxyUrl(feedId: string): string {
const url = new URL('/api/pyth/stream', 'https://api.seesaw.markets');
url.searchParams.set('ids[]', feedId);
return url.toString();
}
const feedSymbol: FeedSymbol = 'SOL/USD';
const feedId = PYTH_FEED_IDS[feedSymbol];
// Browser-native EventSource cannot attach the private Pyth bearer token.
// Use a configured app proxy that injects PYTH_API_KEY server-side and reconnect
// before the 24-hour Pyth stream limit. Do not hard-code indexer REST aliases.
const streamUrl = buildPythStreamProxyUrl(feedId);
console.log(streamUrl);
2. Market Position Analysis#
Compute whether current price favors YES or NO:
// docs-check: semantic
interface MarketPosition {
delta: number; // currentPrice - startPrice
deltaPct: number; // Percentage change
status: 'above' | 'below' | 'at';
isAbove: boolean;
isBelow: boolean;
}
function computeMarketPosition(startPrice: number, currentPrice: number): MarketPosition {
const delta = currentPrice - startPrice;
const deltaPct = delta / startPrice;
const status = deltaPct > 0.0001 ? 'above' : deltaPct < -0.0001 ? 'below' : 'at';
return {
delta,
deltaPct,
status,
isAbove: status === 'above',
isBelow: status === 'below',
};
}
const position = computeMarketPosition(100, 101);
console.log(position.status, position.deltaPct);
3. Trading Signal Generation#
The skill includes a complete decision framework:
// docs-check: semantic
interface TradingSignal {
action: 'buy_yes' | 'buy_no' | 'hold';
confidence: number;
reason: string;
suggestedPrice: number;
suggestedQuantity: number;
}
// See full implementation in the skill file
function analyzeTradeOpportunity(
startPrice: number,
currentPrice: number,
marketBestBid: number,
marketBestAsk: number,
timeRemainingSeconds: number
): TradingSignal;
function analyzeTradeOpportunity(
startPrice: number,
currentPrice: number,
marketBestBid: number,
marketBestAsk: number,
timeRemainingSeconds: number
): TradingSignal {
const priceIsAboveStart = currentPrice > startPrice;
const midPriceBps = Math.floor((marketBestBid + marketBestAsk) / 2);
const enoughTime = timeRemainingSeconds > 60;
if (!enoughTime) {
return {
action: 'hold',
confidence: 0.2,
reason: 'market is close to expiry',
suggestedPrice: midPriceBps,
suggestedQuantity: 0,
};
}
return {
action: priceIsAboveStart ? 'buy_yes' : 'buy_no',
confidence: 0.6,
reason: priceIsAboveStart ? 'current price is above start' : 'current price is below start',
suggestedPrice: midPriceBps,
suggestedQuantity: 1_000_000,
};
}
const signal = analyzeTradeOpportunity(100, 101, 4_900, 5_100, 300);
console.log(signal.action, signal.suggestedPrice);
4. Order Execution#
Build and submit orders to the Solana program:
// docs-check: semantic
import { OrderSide, OrderType } from '@seesaw/core';
const side = OrderSide.BuyYes; // bullish on price going up
const orderType = OrderType.Limit; // match then rest on book
console.log({ side, orderType });
Decision Framework#
Explanation context. The tables below describe a simple example decision logic for illustrative purposes. Real trading strategies vary widely. The Seesaw Trading Skill contains a more complete decision framework for AI agents.
When to Trade#
| Condition | Action | Rationale |
|---|---|---|
| Price above start, market underpricing YES | Buy YES | Capture mispricing |
| Price below start, market underpricing NO | Buy NO | Capture mispricing |
| Strong momentum up, time remaining | Buy YES | Momentum play |
| Strong momentum down, time remaining | Buy NO | Momentum play |
| No clear edge | Hold | Preserve capital |
| < 60 seconds remaining | Hold/Exit | Too risky |
Risk Considerations#
Explanation context. These mitigations are design-level guidelines, not enforced constraints. Wire-level validations and on-chain invariants are described in Security.
| Risk | Mitigation |
|---|---|
| Position limits | Max shares per market |
| Time decay | Reduce aggression near end |
| Oracle confidence | Check confidence interval |
| Slippage | Use limit orders |
| Failed transactions | Implement retry logic |
API Integration#
REST Endpoints#
The endpoints most relevant to the trading loop above. For the full surface (positions, trades, fee config, WebSocket subscriptions) see the API Reference.
| Endpoint | Description |
|---|---|
GET /api/v1/markets | List all markets |
GET /api/v1/markets/current | Get active market |
GET /api/v1/markets/{id} | Market details + orderbook |
These are served by Seesaw's hosted indexer (the @seesaw/core API client
wraps them as client.api.markets.list()/current()/get()).
Reading without the indexer#
For a known market identity, derive PDAs and decode finalized account bytes with
@seesaw/core. Market discovery, RPC fetching and validation
of related accounts remain application responsibilities. The SDK does not ship
a general market-list RPC helper or an automatic place-order account resolver.
client.creator.listMarkets(wallet) is an indexer-backed creator listing, not
RPC discovery. Build instructions from verified accounts using
the transaction builders.
Example: Complete Trading Loop#
// docs-check: semantic
interface AgentMarket {
address: string;
pythFeed: string;
startPrice: string;
startPriceExpo: number;
tEnd: string;
}
interface AgentOrderbook {
bids: Array<{ price: number }>;
asks: Array<{ price: number }>;
}
interface TradingSignal {
action: 'buy_yes' | 'buy_no' | 'hold';
confidence: number;
reason: string;
suggestedPrice: number;
suggestedQuantity: number;
}
function analyzeTradeOpportunity(
startPrice: number,
currentPrice: number,
marketBestBid: number,
marketBestAsk: number,
timeRemainingSeconds: number
): TradingSignal {
const midPrice = Math.floor((marketBestBid + marketBestAsk) / 2);
if (timeRemainingSeconds < 60) {
return {
action: 'hold',
confidence: 0.2,
reason: 'market is near expiry',
suggestedPrice: midPrice,
suggestedQuantity: 0,
};
}
return {
action: currentPrice >= startPrice ? 'buy_yes' : 'buy_no',
confidence: 0.6,
reason:
currentPrice >= startPrice ? 'current price is above start' : 'current price is below start',
suggestedPrice: midPrice,
suggestedQuantity: 1_000_000,
};
}
async function fetchCurrentMarket(): Promise<{ market: AgentMarket }> {
return fetch('/api/v1/markets/current').then((r) => r.json() as Promise<{ market: AgentMarket }>);
}
async function fetchMarketOrderbook(marketAddress: string): Promise<{ orderbook: AgentOrderbook }> {
return fetch(`/api/v1/markets/${marketAddress}`).then(
(r) => r.json() as Promise<{ orderbook: AgentOrderbook }>
);
}
async function fetchPythPrice(_pythFeed: string): Promise<number> {
return 101;
}
async function executeOrder(_market: AgentMarket, _signal: TradingSignal): Promise<void> {
// Build, simulate, sign, and submit the order transaction here.
}
async function agentTradingLoop() {
// 1. Get current market
const { market } = await fetchCurrentMarket();
// 2. Get live price
const currentPrice = await fetchPythPrice(market.pythFeed);
// 3. Parse market data
const startPrice = Number(market.startPrice) * Math.pow(10, market.startPriceExpo);
const timeRemaining = new Date(market.tEnd).getTime() / 1000 - Date.now() / 1000;
// 4. Get orderbook
const { orderbook } = await fetchMarketOrderbook(market.address);
// 5. Generate signal
const signal = analyzeTradeOpportunity(
startPrice,
currentPrice,
orderbook.bids[0]?.price || 0,
orderbook.asks[0]?.price || 10000,
timeRemaining
);
// 6. Execute if confident
if (signal.action !== 'hold' && signal.confidence > 0.5) {
await executeOrder(market, signal);
}
}
// Run every 30 seconds
const loopTimer = setInterval(() => void agentTradingLoop(), 30_000);
clearInterval(loopTimer);
Security Considerations#
Agent Wallet Security#
| Recommendation | Description |
|---|---|
| Dedicated wallet | Separate from main holdings |
| Limited funding | Only deposit trading capital |
| Key management | Use secure key storage |
| Transaction limits | Implement on-chain limits |
Operational Security#
| Risk | Mitigation |
|---|---|
| Runaway losses | Circuit breakers, position limits |
| API key exposure | Environment variables |
| RPC manipulation | Use trusted providers; the self-custody SDK validates every account so a lying node can only deny service, not corrupt a transaction |
| Strategy exploitation | Don't expose strategy details |
Monitoring#
Agents should track:
- Current position (YES/NO shares held)
- P&L per market and cumulative
- Order fill rates
- Transaction success rates
- Oracle health status
Referral attribution for bots#
<!-- src: program/src/logic/fee.rs:168 FeeSplit4::TARGET --> <!-- F-01: update with builder fee allocation -->The shipped referral allocation is 5% of the taker fee, alongside the protocol,
creator and eligible maker allocations described in fee constants.
Makers receive rebates only after the resting-age gate; unused maker allocation
and rounding dust go to protocol. For referral attribution, supply the taker's
validated ReferralAccount as takerReferralAccount when binding a position.
Orders accept that single optional account after any required creator spline and
before the mandatory recorder pair. An active position-cached binding continues
accruing even when the optional referral account is omitted. With no active
cached or supplied binding, the referral allocation goes to protocol.
pendingReferrer in resolveReferrer and --referrer in the CLI are candidate
inputs; they do not create a lock or override an existing one. Establish a
pending lock with SetReferrer before placing an order that supplies its PDA.
The resolver's legacy eligibleForTriple field reports earnings/shard readiness,
not a three-account wire tail. The CLI still uses that field as a client-side
gate, but appends only takerReferralAccount. Earnings and treasury accounts
belong to the separate lock/rollup/claim instructions, not the order tail.
There is no automatic place-order account resolver: verify the canonical binding, inclusive expiry, and position cache before constructing accounts. Malformed or conflicting supplied bindings can reject the order. See Building transactions and the referral guide below.
<!-- src: program/src/processor/place_order/trailing_layout.rs:40 resolve_deferred_referral_binding --> <!-- src: packages/core/src/instructions.ts:577 placeOrderAccountMetas --> <!-- src: packages/cli/src/commands/order/index.ts:344 referralBindingFromResolution -->// docs-check: semantic
import { address } from '@solana/addresses';
import { resolveReferrer } from '@seesaw/core';
const agentWallet = address(process.env.SEESAW_WALLET_ADDRESS!);
const pendingReferrer = process.env.SEESAW_REFERRER
? address(process.env.SEESAW_REFERRER)
: undefined;
// This offline example has no indexed lock. Production adapters must read
// authoritative referral state and refresh expiry before constructing orders.
const resolution = await resolveReferrer({
wallet: agentWallet,
indexerClient: {
async getReferral() {
return null;
},
},
pendingReferrer,
});
// A pending result is only a candidate: it must be locked before its PDA is supplied.
// The resolver does not construct order accounts or inspect the position cache.
console.log(resolution.source, resolution.address, resolution.isLocked);
See the Referral and creator fees guide for the full precedence rules and wire-level account semantics.
Related Documentation#
- Seesaw Trading Skill - Complete skill file for AI agents
- SDK Guide - TypeScript SDK documentation
- canonical v1 SDK - PDA derivation and account decoding
- Automated Trading - General automation guide
- API Reference - REST and WebSocket APIs
- Referral and creator fees - Fee attribution guide