@vesper85/strategy-sdk
v0.1.21
Published
SDK for writing and running trading strategies with Polymarket and Hyperliquid integrations
Maintainers
Readme
@vesper85/strategy-sdk
SDK for writing and running trading strategies with Polymarket and Hyperliquid integrations.
Features
- TypeScript-first: Full type safety with IntelliSense support
- Market Integrations: Polymarket and Hyperliquid APIs
- Technical Analysis: Built-in technical indicators (RSI, MACD, Bollinger Bands, etc.)
- State Management: In-memory or Redis-backed persistent state
- Dual Execution Modes: Tick-based (polling) or Event-based (real-time WebSocket)
- Flexible Logging: Use built-in console logger or provide your own
- Transaction Signing: Support for both Osiris Hub signing and private key signing (EVM & Solana)
Installation
npm install @vesper85/strategy-sdk
# or
pnpm add @vesper85/strategy-sdk
# or
yarn add @vesper85/strategy-sdkNote: This package supports both ESM and CommonJS. You can use it in either type of project without needing to add "type": "module" to your package.json.
Quick Start
1. Create a Tick-Based Strategy
import type { OsirisContext, CodeStrategy } from '@vesper85/strategy-sdk';
export default class MyStrategy implements CodeStrategy {
async shouldTrigger(osiris: OsirisContext): Promise<boolean> {
// Return true when you want to execute the strategy
return true;
}
async onTrigger(osiris: OsirisContext): Promise<void> {
// Your trading logic here
if (osiris.hyperliquid) {
const price = await osiris.hyperliquid.getPrice('BTC');
osiris.log(`Current BTC price: ${price}`);
}
}
}2. Create an Event-Based Strategy
import type {
CodeStrategy,
EventSubscription,
StrategyEvent,
OsirisContext
} from '@vesper85/strategy-sdk';
export class PriceAlertStrategy implements CodeStrategy {
// Define what events to subscribe to
subscriptions: EventSubscription[] = [
{
type: 'price',
market: 'BTC-USD',
conditions: { priceChangePercent: 5 }
}
];
// Called when subscribed events occur
async onEvent(event: StrategyEvent, osiris: OsirisContext): Promise<void> {
osiris.log(`Price event for ${event.market}: ${event.data.price}`);
}
}3. Run the Strategy
import {
createOsirisContext,
createConsoleLogger,
createStrategyEngine,
createEventRunner,
PrivateKeySigner,
} from '@osiris-ai/strategy-sdk';
async function main() {
const logger = createConsoleLogger();
const signer = new PrivateKeySigner({
privateKey: process.env.PRIVATE_KEY!,
});
const context = createOsirisContext({
strategyId: 'my-strategy',
market: 'hyperliquid',
userAddress: signer.getAddress()!,
signer,
});
// For tick-based strategies
const engine = createStrategyEngine(strategy, context, {
logger,
tickIntervalMs: 60000,
});
engine.start();
// For event-based strategies
const runner = createEventRunner(strategy, {
logger,
eventSourceUrl: 'wss://events.example.com/ws',
}, context);
runner.start();
}Execution Modes
The SDK supports two mutually exclusive execution modes:
Tick-Based Execution (Polling)
Runs your strategy at fixed intervals. Best for strategies that check conditions periodically.
interface CodeStrategy {
shouldTrigger(osiris: OsirisContext): Promise<boolean>;
onTrigger(osiris: OsirisContext): Promise<void>;
}import { createStrategyEngine } from '@vesper85/strategy-sdk';
const engine = createStrategyEngine(strategy, context, {
logger,
strategyId: 'my-strategy',
tickIntervalMs: 60000, // Run every 60 seconds
});
engine.start();
// engine.stop();Event-Based Execution (Real-time WebSocket)
Reacts to real-time events from WebSocket streams. Best for strategies that need immediate response to market changes.
interface CodeStrategy {
subscriptions: EventSubscription[];
onEvent(event: StrategyEvent, osiris: OsirisContext): Promise<void>;
}Event Subscription Types
The SDK uses a discriminated union for type-safe event subscriptions:
MarketSubscription
Subscribe to market events (price, orderbook, trade, fill):
{
type: 'price', // or 'orderbook', 'trade', 'fill'
market: 'BTC-USD',
eventSource: 'polymarket', // optional
conditions: {
priceChangePercent: 5,
volumeAbove: 10000,
}
}WalletSubscription
Subscribe to wallet analysis events (Osiris Pub/Sub only):
{
type: 'wallet',
wallet: '0x1234567890abcdef...',
conditions: {
minWinRate: 60,
minTradeCount: 10,
}
}OpportunitySubscription
Subscribe to trading opportunities (Osiris Pub/Sub only):
{
type: 'opportunity',
filter: 'wide_spread_markets', // optional, defaults to 'all'
conditions: {
minScore: 70,
}
}CustomSubscription
Subscribe to custom topics:
{
type: 'custom',
topic: 'custom:my-topic',
}Event Sources
Osiris Pub/Sub
Connect to Osiris analytics WebSocket for market analysis, wallet tracking, and opportunities:
const runner = createEventRunner(strategy, {
logger,
eventSourceUrl: 'wss://your-osiris-server.com/ws',
}, context);Supported topics:
market:{slug}- Market analysis eventswallet:{address}- Wallet analysis eventsopps:{filter}- Trading opportunities
Polymarket RTDS
Connect directly to Polymarket's Real-Time Data Socket for live market data.
Strategy-Based Usage
Set eventSource: 'polymarket' in your subscriptions:
import type {
CodeStrategy,
EventSubscription,
StrategyEvent,
CryptoPricesSubscription,
ActivitySubscription,
ClobMarketSubscription,
CommentsSubscription
} from '@vesper85/strategy-sdk';
class MyPolymarketStrategy implements CodeStrategy {
subscriptions: EventSubscription[] = [
// Crypto price updates
{ type: 'crypto_prices', symbol: 'btcusdt', eventSource: 'polymarket' },
// Trade activity feed
{ type: 'activity', messageType: '*', eventSource: 'polymarket' },
// CLOB orderbook data (requires market condition ID)
{ type: 'clob_market', marketId: 'condition-id', messageType: 'agg_orderbook', eventSource: 'polymarket' },
// Comments and reactions
{ type: 'comments', messageType: '*', eventSource: 'polymarket' },
];
async onEvent(event: StrategyEvent, osiris: OsirisContext): Promise<void> {
const topic = event.data.raw?.topic;
if (topic === 'crypto_prices') {
console.log(`BTC: $${event.data.price}`);
} else if (topic === 'activity') {
console.log(`Trade: ${event.data.side} ${event.data.size} @ ${event.data.price}`);
}
}
}
const runner = createEventRunner(strategy, {
logger,
polymarket: {
walletAddress: '0x...',
// clobAuth: { key, secret, passphrase } for clob_user subscriptions
},
}, context);Polymarket Subscription Types
| Type | Description | Auth Required |
|------|-------------|---------------|
| crypto_prices | Real-time BTC/ETH/etc prices | No |
| activity | Global trade activity feed | No |
| clob_market | Orderbook, price changes for specific market | No |
| comments | Comments and reactions | No |
| rfq | Request for Quote events | No |
| clob_user | Your orders and trades | Yes (clobAuth) |
CryptoPricesSubscription
{
type: 'crypto_prices',
symbol: 'btcusdt', // or 'ethusdt', etc.
eventSource: 'polymarket'
}ActivitySubscription
{
type: 'activity',
eventSlug: 'will-bitcoin-hit-100k', // optional filter
marketSlug: 'market-slug', // optional filter
messageType: '*', // 'trades', 'positions', or '*'
eventSource: 'polymarket'
}ClobMarketSubscription
{
type: 'clob_market',
marketId: '0x1234...condition-id', // Market condition ID
messageType: 'agg_orderbook', // 'price_change', 'last_trade_price', 'tick_size_change', '*'
eventSource: 'polymarket'
}ClobUserSubscription (Requires Auth)
{
type: 'clob_user',
messageType: '*', // 'order', 'trade', or '*'
eventSource: 'polymarket'
}
// Config with clobAuth:
const runner = createEventRunner(strategy, {
logger,
polymarket: {
clobAuth: {
key: process.env.POLYMARKET_API_KEY!,
secret: process.env.POLYMARKET_API_SECRET!,
passphrase: process.env.POLYMARKET_PASSPHRASE!,
}
}
}, context);CommentsSubscription
{
type: 'comments',
parentEntityId: 'market-id', // optional filter
parentEntityType: 'market', // optional filter
messageType: '*', // 'comment_created', 'reaction_created', '*'
eventSource: 'polymarket'
}RfqSubscription
{
type: 'rfq',
messageType: '*',
eventSource: 'polymarket'
}Type Guards
Use type guards for runtime type checking:
import {
// Generic subscription types
isMarketSubscription,
isWalletSubscription,
isOpportunitySubscription,
isCustomSubscription,
// Polymarket RTDS subscription types
isClobMarketSubscription,
isClobUserSubscription,
isActivitySubscription,
isCommentsSubscription,
isCryptoPricesSubscription,
isRfqSubscription,
// Source routing helpers
isPolymarketSubscription,
isOsirisSubscription
} from '@vesper85/strategy-sdk';
// Check if subscription is for Polymarket
if (isPolymarketSubscription(subscription)) {
// Subscription will be routed to Polymarket RTDS
}
// Check specific Polymarket types
if (isClobMarketSubscription(subscription)) {
console.log(subscription.marketId); // TypeScript knows this is ClobMarketSubscription
}
if (isCryptoPricesSubscription(subscription)) {
console.log(subscription.symbol); // TypeScript knows this is CryptoPricesSubscription
}API Reference
Types
CodeStrategy
Interface that all strategies must implement:
interface CodeStrategy {
// Tick-based execution
shouldTrigger?(osiris: OsirisContext): Promise<boolean>;
onTrigger?(osiris: OsirisContext): Promise<void>;
// Event-based execution
subscriptions?: EventSubscription[];
onEvent?(event: StrategyEvent, osiris: OsirisContext): Promise<void>;
}StrategyEvent
Event passed to onEvent handler:
interface StrategyEvent {
type: EventType;
timestamp: number;
market?: string; // For market events
wallet?: string; // For wallet events
data: EventData;
}OsirisContext
The context object passed to your strategy methods:
interface OsirisContext {
polymarket?: PolymarketAPI; // Available when market='polymarket'
hyperliquid?: HyperliquidAPI; // Available when market='hyperliquid'
ta: TechnicalAnalysisAPI; // Technical analysis functions
state: OsirisState; // State management
signer?: SignerAPI; // Transaction signer (if configured)
log: (message: string, meta?: any) => void;
}State Management
In-Memory State (for testing)
import { MemoryStateManager } from '@vesper85/strategy-sdk';
const stateManager = new MemoryStateManager();Redis State (for production)
import { RedisStateManager } from '@vesper85/strategy-sdk';
const stateManager = new RedisStateManager(
'redis://localhost:6379',
'strategy-id',
logger
);
await stateManager.connect();Market APIs
Hyperliquid API
if (osiris.hyperliquid) {
const price = await osiris.hyperliquid.getPrice('BTC');
const position = await osiris.hyperliquid.getPosition('BTC');
const positions = await osiris.hyperliquid.getPositions();
}Polymarket API
if (osiris.polymarket) {
const market = await osiris.polymarket.getMarket('market-slug');
const markets = await osiris.polymarket.getMarkets({ active: true });
// Trading (requires initialization)
await osiris.polymarket.initializeTradingClient();
await osiris.polymarket.createLimitOrder({
tokenId: 'token-id',
side: 'BUY',
price: 0.5,
size: 10,
});
}Technical Analysis
// Calculate RSI
const rsi = osiris.ta.calculate('rsi_14', ohlcvData, { period: 14 });
// Calculate MACD
const macd = osiris.ta.calculate('macd_12_26_9', ohlcvData, {
fastPeriod: 12,
slowPeriod: 26,
signalPeriod: 9
});
// Available indicators:
// Single-value: rsi, sma, ema, atr, adx, obv, cci, mfi, vwap, williams_r, roc, psar, wma
// Multi-value: macd, bollinger_bands, stochastic, stochastic_rsi, keltner_channelsSigning Transactions
import { PrivateKeySigner, OsirisSigner } from '@vesper85/strategy-sdk';
// Private key signer
const signer = new PrivateKeySigner({
privateKey: process.env.PRIVATE_KEY!,
});
// Osiris Hub signer (for managed wallets)
const osirisSigner = new OsirisSigner({
hubBaseUrl: 'https://api.osirislabs.xyz/v1',
accessToken: 'your-oauth-token',
connectionId: 'wallet-connection-id',
});
// Use in context
const context = createOsirisContext({
strategyId: 'my-strategy',
market: 'polymarket',
userAddress: signer.getAddress()!,
signer,
});Examples
See the examples/ directory for complete working examples:
example-event-strategy.ts- Event-based price alert strategyexample-polymarket-events.ts- Polymarket RTDS integration
Best Practices
- Choose the right execution mode: Use tick-based for periodic checks, event-based for real-time reactions
- State Management: Use
osiris.statefor persistent data that should survive restarts - Error Handling: Always wrap API calls in try-catch blocks
- Rate Limiting: Be mindful of API rate limits when making frequent calls
- Testing: Use
MemoryStateManagerfor testing,RedisStateManagerfor production
License
MIT
