For the complete documentation index, see llms.txt. This page is also available as Markdown.

Code Examples

Code examples

The fastest way to see every SDK call in action is the reference console app. It consumes @symmio/trading-core and @symmio/trading-react exactly the way a third-party integrator would, and drives real contract reads and writes, deposits, quotes, and positions:

  • Live console: https://console.trading-sdk.symm.io

  • Source (monorepo): https://github.com/SYMM-IO/Trading-SDK

  • UI component explorer (Storybook): https://symmio-frontier-storybook.vercel.app

Minimal headless bot (end-to-end)

A single-file bot that sets up once, opens one position, and sketches how to manage and close it. It uses @symmio/trading-core and @symmio/session-key, and assumes the SubAccount was already created (see Part 1).

import {
  createConfig, SymmioSupportedChainId,
  getUserSubAccounts, grantDelegation, getIsDelegationActive,
  INSTANT_TRADE_REQUIRED_SELECTORS,
  getMarkets, watchEnigmaPrices,
  instantOpenAuto, instantCloseAuto, setQuoteTpSl, PositionType,
} from "@symmio/trading-core";
import { createSessionKeyManager } from "@symmio/session-key";
import { createPublicClient, http } from "viem";

const OWNER = "0xYourOwnerEOA";

const publicClient = createPublicClient({ transport: http("https://rpc.hyperliquid.xyz/evm") });

const config = createConfig({
  symmioConfig: {
    [SymmioSupportedChainId.HYPER_EVM]: { addresses: { affiliatesAddress: "0xYourAffiliate" } },
  },
  defaultChainId: SymmioSupportedChainId.HYPER_EVM,
  getClient: () => publicClient,
  getWalletClient: async ({ chainId, from }) => resolveWalletClient({ chainId, from }),
});

async function main() {
  const [subAccount] = await getUserSubAccounts(config, { user: OWNER });

  const manager = createSessionKeyManager({ storage });
  const { address: sessionKey } = await manager.initialize(OWNER);

  await grantDelegation(config, {
    account: { addr: subAccount, isPartyB: false },
    delegatedSigner: sessionKey,
    selectors: INSTANT_TRADE_REQUIRED_SELECTORS, // three selectors: open, add margin, close
    expiryTimestamp: 1_766_000_000n,
  });

  // getIsDelegationActive checks one selector at a time; all must be true
  const checks = await Promise.all(
    INSTANT_TRADE_REQUIRED_SELECTORS.map((selector) =>
      getIsDelegationActive(config, {
        account: { addr: subAccount, isPartyB: false },
        delegate: sessionKey,
        selector,
      })
    )
  );
  if (!checks.every(Boolean)) throw new Error("delegation not active");

  const symbols = await getMarkets(config, {});
  const symbol = symbols[0];
  const market = { id: symbol.symbol_id, name: symbol.name };

  watchEnigmaPrices(config, { onPrices: (ticks) => {/* feed your strategy */} });

  const { tempQuoteId } = await instantOpenAuto(config, {
    from: sessionKey, subAccountAddress: subAccount,
    market, positionType: PositionType.LONG,
    initialMargin: "100", leverage: 5, slippage: 1,
  });
  console.log("opened, temp id:", tempQuoteId);

  // Resolve the on-chain quoteId from watchNotifications/reconcileQuotes,
  // and the position's Virtual Account from resolveQuoteAccounts, then:
  // await setQuoteTpSl(config, {
  //   from: sessionKey, quoteId, virtualAccount, subAccount,
  //   symbolId: market.id, positionType: PositionType.LONG,
  //   quantity: "0.01", pricePrecision: symbol.price_precision,
  //   tp: { triggerPrice: "150", priceType: "markPrice" },
  // });
  // await instantCloseAuto(config, {
  //   from: sessionKey, partyA: virtualAccount, market,   // partyA is the VA
  //   positionType: PositionType.LONG, quoteId, quantityToClose: "1", slippage: 1,
  // });
}

main().catch(console.error);

This is illustrative scaffolding, not a strategy. Add error handling (core throws SymmError / SymmApiError; the React layer normalizes everything to SymmioRequestError), reconnection for the price and notification sockets, and your own risk logic before running with real funds.

Last updated