
Research
/Security News
Miasma Mini Shai-Hulud Hits ImmobiliareLabs npm Packages
Miasma Mini Shai-Hulud hits @immobiliarelabs Backstage plugins, targeting GitLab and LDAP auth packages on npm.
@pear-protocol/symm-core
Advanced tools
TypeScript SDK for Symm Engine API - trading positions, TP/SL orders, and real-time WebSocket streams
TypeScript SDK for Symm Engine API - trading positions, TP/SL config, and real-time WebSocket streams.
viem for type compatibility# 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
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);
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.
const sdk = createSymmSDK({
apiUrl: 'https://api.symm.io',
authProvider: async () => 'your-siwe-token',
retry: { retries: 3, backoffMs: 250 }
});
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);
}
);
// 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'
});
// 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'
});
// 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');
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
});
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.
// 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' });
await client.getFundingRates({ chainId: 42161, limit: 50 });
await client.getFundingPayments({ address: '0x...', chainId: 42161 });
await client.getMetrics();
await client.getWeeklyVolume();
await client.getUserStats({ address: '0x...' });
await client.getDailyStats({ period: '7D' });
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();
// 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();
// Connection events
ws.onConnect(() => console.log('Connected'));
ws.onDisconnect(() => console.log('Disconnected'));
ws.onError((error) => console.error('Error:', error));
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"
}
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 }
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
});
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));
}
}
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;
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';
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);
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
});
MIT
FAQs
TypeScript SDK for Symm Engine API - trading positions, TP/SL orders, and real-time WebSocket streams
The npm package @pear-protocol/symm-core receives a total of 22 weekly downloads. As such, @pear-protocol/symm-core popularity was classified as not popular.
We found that @pear-protocol/symm-core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Miasma Mini Shai-Hulud hits @immobiliarelabs Backstage plugins, targeting GitLab and LDAP auth packages on npm.

Security News
Rolldown paused Rust React Compiler integration after a 5MB binary size increase raised concerns about shipping React-specific code to all Vite users.

Security News
/Research
Mini Shai-Hulud expands into the Go ecosystem after hitting LeoPlatform npm packages and targeting GitHub Actions workflows.