New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@pear-protocol/symm-core

Package Overview
Dependencies
Maintainers
4
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pear-protocol/symm-core

TypeScript SDK for Symm Engine API - trading positions, TP/SL orders, and real-time WebSocket streams

latest
Source
npmnpm
Version
0.1.31
Version published
Weekly downloads
822
-58.42%
Maintainers
4
Weekly downloads
 
Created
Source

@pear-protocol/symm-core

TypeScript SDK for Symm Engine API - trading positions, TP/SL config, and real-time WebSocket streams.

Features

  • ✅ TypeScript - Full type safety with comprehensive type definitions
  • ✅ REST API Client - Complete API coverage for positions, orders, and TP/SL config
  • ✅ WebSocket Client - Real-time data streaming with automatic reconnection
  • ✅ Multi-chain - Support for Arbitrum and Base networks
  • ✅ Tree-shakeable - Modular exports for optimal bundle size
  • ✅ Zero dependencies - Only peer dependency on viem for type compatibility

Installation

# npm
npm install @pear-protocol/symm-core viem

# yarn
yarn add @pear-protocol/symm-core viem

# pnpm
pnpm add @pear-protocol/symm-core viem

# bun
bun add @pear-protocol/symm-core viem

Quick Start

Basic Usage

import { createSymmSDK } from '@pear-protocol/symm-core';

// Create SDK instance
const { client, ws } = createSymmSDK({
  apiUrl: 'https://api.symm.io',
  wsUrl: 'wss://ws.symm.io',
  defaultChainId: 42161 // Arbitrum
});

// Open a basket (single, pair, or multi-leg)
const result = await client.openBasketPosition({
  accountAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  authToken: 'your-siwe-token',
  longPositions: [
    { symbol: 'BTC', quantity: '1.0', leverage: 10 }
  ],
  slippage: 'auto'
});

console.log('Position opened:', result.data);

Response Shape (camelCase by default)

The SDK transforms responses to camelCase by default. To opt out and keep raw snake_case:

const sdk = createSymmSDK({
  apiUrl: 'https://api.symm.io',
  responseAdapter: false
});

Raw types are also exported: RawPosition, RawClosePositionResponse, RawPendingInstantOpenItem, RawAssetLeg.

Auth Provider + Retry

const sdk = createSymmSDK({
  apiUrl: 'https://api.symm.io',
  authProvider: async () => 'your-siwe-token',
  retry: { retries: 3, backoffMs: 250 }
});

WebSocket Streaming

import { createSymmWebSocket } from '@pear-protocol/symm-core';

const ws = createSymmWebSocket({
  url: 'wss://ws.symm.io',
  autoReconnect: true
});

// Connect
await ws.connect();

// Subscribe to position updates
ws.subscribeToPositions(
  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  42161, // Arbitrum
  (data) => {
    console.log('Position update:', data);
  }
);

// Subscribe to open orders
ws.subscribeToOpenOrders(
  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
  42161,
  (data) => {
    console.log('Open orders:', data);
  }
);

API Reference

REST Client

Position Management

// Open basket position
await client.openBasketPosition(request);

// Close position
await client.closePosition({
  positionId: 'pos_123',
  quantityToClose: '1.0',
  authToken: 'token'
});

// Cancel close
await client.cancelClose({
  quoteId: '123',
  authToken: 'token'
});

// Advanced: open basket with polling/status updates
await sdk.positions.openBasket(request, {
  pollPending: true,
  onStatus: (status) => console.log(status),
  onLegUpdate: (leg) => console.log(leg),
});

// Advanced: close with polling/status updates
await sdk.positions.close(
  { positionId: 'pos_123', authToken: 'token' },
  {
    pollPending: true,
    accountAddress: '0x...',
    chainId: 42161,
    onStatus: (status) => console.log(status),
  },
);

// Get open positions
await client.getOpenPositions({
  // Use accountAddress for a specific subaccount, or address for a main wallet
  accountAddress: '0x...',
  chainId: 42161
});

// Get positions (on-chain)
await client.getPositions({
  address: '0x...'
});

// Get trade history
await client.getTradeHistory({
  // Use accountAddress (subaccount) or mainAddress (all subaccounts)
  accountAddress: '0x...',
  limit: 100,
  includeQuoteTimeline: true
});

// Get user stats (positions analytics)
await client.getPositionStats('0x...');

// Get Pear leaderboard (Arbitrum 42161 or Base 8453 only)
await client.getLeaderboard({
  chainId: 42161,
  period: '7d',
  sortBy: 'pnl'
});

// Get quote details
await client.getQuote(quoteId);

// Get pending IDs
await client.getPendingIds({
  accountAddress: '0x...'
});

// Cancel pending open
await client.cancelOpen({
  quoteId: '123',
  authToken: 'token'
});

// Get pending instant opens
await client.getPendingInstantOpens({
  accountAddress: '0x...',
  authToken: 'token'
});

TP/SL Management

// Set TP/SL config
await client.setTpsl({
  positionId: 'pos_123',
  takeProfit: { triggerType: 'price', triggerValue: '55000' },
  stopLoss: { triggerType: 'price', triggerValue: '47500' },
  authToken: 'token'
});

// Cancel TP/SL config
await client.cancelTpsl({
  positionId: 'pos_123',
  chainId: 42161,
  authToken: 'token'
});

// Get TP/SL orders
await client.getTpslOrders({
  // Use address (subaccount) or mainAddress (all subaccounts)
  address: '0x...',
  status: 'active'
});

// Cancel TP/SL config
await client.cancelTpsl({
  positionId: 'pos_123',
  type: 'take_profit',
  authToken: 'token'
});

Orders

// Get orders (address or mainAddress)
const orders = await client.getOrders({ address: '0x...', status: 'executed' });
const firstLeg = orders.data?.orders[0]?.legs?.[0];
console.log(firstLeg?.symbol, firstLeg?.executedPrice, firstLeg?.margin);

// TWAP orders
await client.getTwapOrders({ address: '0x...' });
await client.getTwapOrder('order_123');
await client.cancelTwapOrder('order_123');

// Trigger config
await client.getTriggerConfig('order_123');
await client.upsertTriggerConfig('order_123', { config: { /* trigger config */ } });
await client.clearTriggerConfig('order_123');

Prediction outcome triggers

import type { PredictionOutcomeTriggerConfig } from '@pear-protocol/symm-core';

const triggerConfig: PredictionOutcomeTriggerConfig = {
  type: 'prediction_market_outcome',
  marketSource: 'polymarket', // omit or use "kalshi" for Kalshi tickers
  marketCode: '123456',       // Polymarket Gamma market id or Kalshi ticker
  triggerValue: 'YES',
  triggerMode: 'result'       // or "price"
};

await client.openBasketPosition({
  chainId: 42161,
  accountAddress: '0x...',
  authToken: 'token',
  orderType: 'trigger',
  longPositions: [{ symbol: 'BTC', quantity: '100', leverage: 10 }],
  triggerConfig
});

Accounts

await client.getAccounts({ chainId: 42161, userAddress: '0x...' });
await client.getAccountsLength({ chainId: 42161, userAddress: '0x...' });
await client.getBalanceInfo({ chainId: 42161, userAddress: '0x...' });
await client.getAccountSummary({ chainId: 42161, userAddress: '0x...' });
await client.getAccountData({ chainId: 42161, address: '0x...', upnl: '0' });
await client.getAccountsWithPositions({ chainId: 42161, userAddress: '0x...' });

getAccountData is the account-overview source. It returns AccountOverviewData fields: equity, maintenanceMargin, accountHealthData, availableForOrder, and totalLocked. Pass current account UPNL as upnl when available so equity and available margin match the frontend's live view.

Markets

// Market groups (basket pairs with ratios, volume, funding)
await client.getMarkets({ active: 'true', sort: 'volume:desc', pageSize: '50' });
await client.getMarkets({ searchText: 'BTC', netFunding: 'positive' });

// Hedger markets (individual symbol data)
await client.getHedgerMarkets({ chainId: 42161, searchText: 'BTC' });

Funding

await client.getFundingRates({ chainId: 42161, limit: 50 });
await client.getFundingPayments({ address: '0x...', chainId: 42161 });

Metrics (Legacy Support)

await client.getMetrics();
await client.getWeeklyVolume();
await client.getUserStats({ address: '0x...' });
await client.getDailyStats({ period: '7D' });

WebSocket Client

Connection Management

const ws = createSymmWebSocket({
  url: 'wss://ws.symm.io',
  autoReconnect: true,
  reconnectInterval: 5000,
  pingInterval: 30000
});

// Connect
await ws.connect();

// Disconnect
ws.disconnect();

// Check connection status
const connected = ws.isConnected();

Subscriptions

// Positions (5s interval)
ws.subscribeToPositions(address, chainId, handler);

// Open orders (5s interval)
ws.subscribeToOpenOrders(address, chainId, handler);

// Trades (10s interval)
ws.subscribeToTrades(address, chainId, handler);

// Executions (2s interval)
ws.subscribeToExecutions(address, chainId, handler);

// TP/SL updates (5s interval)
ws.subscribeToTpsl(address, chainId, handler);

// Notifications (10s interval)
ws.subscribeToNotifications(address, chainId, handler);

// TWAP orders (5s interval)
ws.subscribeToTwapOrders(address, chainId, handler);

// Trigger orders (5s interval)
ws.subscribeToTriggerOrders(address, chainId, handler);

// Prediction triggers (5s interval)
ws.subscribeToPredictionTriggers(address, chainId, handler);

// Unsubscribe
ws.unsubscribe('positions', address, chainId, handler);

// Unsubscribe all
ws.unsubscribeAll();

Event Handlers

// Connection events
ws.onConnect(() => console.log('Connected'));
ws.onDisconnect(() => console.log('Disconnected'));
ws.onError((error) => console.error('Error:', error));

Utilities

import {
  isValidAddress,
  normalizeAddress,
  formatWei,
  applySlippage,
  calculatePnlPercent,
  getUnixTimestamp,
  createDeadline,
  isSupportedChainId,
  getChainName
} from '@pear-protocol/symm-core';

// Address validation
if (isValidAddress('0x...')) {
  const normalized = normalizeAddress('0x...');
}

// Number formatting
const readable = formatWei('1000000000000000000', 18, 4); // "1.0000"

// Price utilities
const priceWithSlippage = applySlippage('50000', 0.5, true); // 0.5% slippage
const pnl = calculatePnlPercent('50000', '55000', true); // 10%

// Time utilities
const now = getUnixTimestamp();
const deadline = createDeadline(300); // 5 minutes from now

// Chain utilities
if (isSupportedChainId(42161)) {
  const chainName = getChainName(42161); // "Arbitrum One"
}

Constants

import {
  ARBITRUM_CHAIN_ID,
  BASE_CHAIN_ID,
  DIAMOND_ADDRESS,
  CHAIN_CONFIGS,
  WS_CHANNELS
} from '@pear-protocol/symm-core';

console.log(ARBITRUM_CHAIN_ID); // 42161
console.log(BASE_CHAIN_ID); // 8453
console.log(DIAMOND_ADDRESS[42161]); // "0x8F06..."
console.log(CHAIN_CONFIGS[42161]); // { chainId, name, rpcUrl, explorerUrl }

Advanced Usage

Custom Configuration

import { SymmClient, SymmWebSocket } from '@pear-protocol/symm-core';

// Custom REST client
const client = new SymmClient({
  baseUrl: 'https://api.symm.io',
  defaultChainId: 42161,
  timeout: 30000,
  headers: {
    'X-API-Key': 'your-key'
  }
});

// Custom WebSocket client
const ws = new SymmWebSocket({
  url: 'wss://ws.symm.io',
  autoReconnect: true,
  reconnectInterval: 5000,
  maxReconnectAttempts: 10,
  pingInterval: 30000
});

Error Handling

import { isApiError, getErrorMessage } from '@pear-protocol/symm-core';

try {
  await client.openBasketPosition(request);
} catch (error) {
  if (isApiError(error)) {
    console.error('API Error:', error.error);
    console.error('Details:', error.details);
  } else {
    console.error('Error:', getErrorMessage(error));
  }
}

TypeScript Types

import type {
  OpenBasketPositionRequest,
  PredictionOutcomeTriggerConfig,
  OpenPositionDto,
  AssetLeg,
  TpslOrder,
  TpslOrderType,
  SupportedChainId,
  NotificationCategory
} from '@pear-protocol/symm-core';

const request: OpenBasketPositionRequest = {
  chainId: 42161,
  accountAddress: '0x...',
  authToken: 'token',
  longPositions: [{ symbol: 'BTC', quantity: '1.0', leverage: 10 }]
};

const handlePosition = (position: OpenPositionDto) => {
  console.log(position.positionId, position.address);
  console.log(position.entryRatio, position.markRatio);
  console.log(position.entryPositionValue, position.positionValue);
  console.log(position.marginUsed, position.unrealizedPnl, position.unrealizedPnlPercentage);
  console.log(position.stopLoss, position.takeProfit);

  for (const leg of [...position.longAssets, ...position.shortAssets]) {
    console.log(
      leg.symbolId,
      leg.symbol,
      leg.quantity,
      leg.openedPrice,
      leg.currentPrice,
      leg.leverage,
      leg.initialWeight,
      leg.targetWeight
    );
  }
};

const firstLeg: AssetLeg = {
  symbolId: 1,
  symbol: 'BTCUSDT',
  quantity: '0.1',
  openedPrice: '50000',
  currentPrice: '$50100.000000',
  leverage: '15.00',
  initialWeight: 0.5,
  targetWeight: 0.5
};

const category: NotificationCategory = NotificationCategory.POSITION_LIQUIDATED;

Modular Imports

Import only what you need for optimal bundle size:

// Client only
import { createSymmClient } from '@pear-protocol/symm-core/client';

// WebSocket only
import { createSymmWebSocket } from '@pear-protocol/symm-core/websocket';

// Types only
import type { Position, TpslOrder } from '@pear-protocol/symm-core/types';

// Utils only
import { isValidAddress, formatWei } from '@pear-protocol/symm-core/utils';

// Constants only
import { ARBITRUM_CHAIN_ID, DIAMOND_ADDRESS } from '@pear-protocol/symm-core/constants';

Examples

Complete Trading Flow

import { createSymmSDK } from '@pear-protocol/symm-core';

const { client, ws } = createSymmSDK({
  apiUrl: 'https://api.symm.io',
  wsUrl: 'wss://ws.symm.io'
});

// 1. Connect WebSocket
await ws.connect();

// 2. Subscribe to executions
ws.subscribeToExecutions('0x...', 42161, (data) => {
  console.log('Trade executed:', data);
});

// 3. Open position with TP/SL
const result = await client.openBasketPosition({
  accountAddress: '0x...',
  authToken: 'token',
  tpslConfig: {
    takeProfit: {
      triggerType: 'price',
      triggerValue: '55000', // 10% profit
      quantityToClose: '1.0'
    },
    stopLoss: {
      triggerType: 'price',
      triggerValue: '47500', // 5% loss
      quantityToClose: '1.0'
    }
  },
  longPositions: [
    {
      symbol: 'BTC',
      quantity: '1.0',
      leverage: 10
    }
  ]
});

console.log('Position opened with TP/SL:', result);

Node.js Usage

For Node.js environments, you may need to provide a WebSocket implementation:

import { createSymmWebSocket } from '@pear-protocol/symm-core';
import WebSocket from 'ws';

const ws = createSymmWebSocket({
  url: 'wss://ws.symm.io',
  WebSocket: WebSocket as any
});

License

MIT

Support

  • Documentation: https://docs.symm.io
  • GitHub: https://github.com/symm/symm-engine
  • Discord: https://discord.gg/symm

Keywords

symm

FAQs

Package last updated on 09 Jun 2026

Related posts