Skip to main content

Description

Retrieves all currently open trading positions grouped by model, including real-time unrealized P&L, entry prices, current prices, exit plans (stop loss, take profit), and trading signals. Essential for displaying active portfolio state and monitoring risk exposure.

Input Schema

variant
VariantId
Filter positions by model variant. Valid values: "Apex", "Trendsurfer", "Contrarian", "Sovereign". Omit to fetch positions from all variants.

TypeScript Type

type PositionsInput = {
  variant?: "Apex" | "Trendsurfer" | "Contrarian" | "Sovereign";
};

Output Schema

positions
AccountPositions[]
Array of model accounts with their open positions.

TypeScript Type

type PositionsResponse = {
  positions: {
    modelId: string;
    modelName: string;
    modelVariant?: "Apex" | "Trendsurfer" | "Contrarian" | "Sovereign";
    modelLogo?: string;
    positions: {
      symbol: string;
      side: "long" | "short";
      quantity: number;
      entryPrice: number;
      currentPrice?: number;
      unrealizedPnl?: number;
      exitPlan?: {
        target?: number;
        stop?: number;
        invalidation?: {
          enabled: boolean;
          message?: string;
        };
      };
      signal?: string;
      leverage?: number;
      confidence?: number;
      lastDecisionAt?: string;
      decisionStatus?: string;
    }[];
    totalUnrealizedPnl?: number;
    availableCash?: number;
  }[];
};

Example Usage

Basic Query

import { useQuery } from "@tanstack/react-query";
import { orpc } from "@/server/orpc/client";

function PositionsList() {
  const { data, isLoading } = useQuery(
    orpc.trading.getPositions.queryOptions({
      input: {}
    })
  );

  if (isLoading) return <div>Loading positions...</div>;

  return (
    <div>
      {data?.positions.map((account) => (
        <div key={account.modelId}>
          <h3>{account.modelName}</h3>
          <p>Total Unrealized P&L: ${account.totalUnrealizedPnl?.toFixed(2) ?? '0.00'}</p>
          <p>Available Cash: ${account.availableCash?.toFixed(2) ?? '0.00'}</p>
          
          <table>
            <thead>
              <tr>
                <th>Symbol</th>
                <th>Side</th>
                <th>Quantity</th>
                <th>Entry</th>
                <th>Current</th>
                <th>P&L</th>
              </tr>
            </thead>
            <tbody>
              {account.positions.map((pos, idx) => (
                <tr key={`${pos.symbol}-${idx}`}>
                  <td>{pos.symbol}</td>
                  <td>{pos.side.toUpperCase()}</td>
                  <td>{pos.quantity.toFixed(4)}</td>
                  <td>${pos.entryPrice.toFixed(2)}</td>
                  <td>${pos.currentPrice?.toFixed(2) ?? 'N/A'}</td>
                  <td style={{ color: (pos.unrealizedPnl ?? 0) >= 0 ? 'green' : 'red' }}>
                    ${pos.unrealizedPnl?.toFixed(2) ?? '0.00'}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      ))}
    </div>
  );
}

Show Exit Plans

import { useQuery } from "@tanstack/react-query";
import { orpc } from "@/server/orpc/client";

function PositionsWithExitPlans() {
  const { data } = useQuery(
    orpc.trading.getPositions.queryOptions({
      input: { variant: "Apex" }
    })
  );

  return (
    <div>
      {data?.positions.map((account) => (
        account.positions.map((pos, idx) => (
          <div key={`${account.modelId}-${pos.symbol}-${idx}`}>
            <h4>{pos.symbol} - {pos.side.toUpperCase()}</h4>
            <p>Entry: ${pos.entryPrice.toFixed(2)}</p>
            <p>Current: ${pos.currentPrice?.toFixed(2) ?? 'N/A'}</p>
            
            {pos.exitPlan && (
              <div>
                <h5>Exit Plan</h5>
                {pos.exitPlan.target && (
                  <p>🎯 Target: ${pos.exitPlan.target.toFixed(2)}</p>
                )}
                {pos.exitPlan.stop && (
                  <p>🛑 Stop Loss: ${pos.exitPlan.stop.toFixed(2)}</p>
                )}
                {pos.exitPlan.invalidation?.enabled && (
                  <p>⚠️ Invalidation: {pos.exitPlan.invalidation.message}</p>
                )}
              </div>
            )}
            
            {pos.signal && <p>📊 Signal: {pos.signal}</p>}
            {pos.confidence && <p>💪 Confidence: {pos.confidence}%</p>}
          </div>
        ))
      ))}
    </div>
  );
}

Real-time Updates with Polling

import { useQuery } from "@tanstack/react-query";
import { orpc } from "@/server/orpc/client";

function LivePositions() {
  // Poll every 5 seconds for real-time updates
  const { data } = useQuery({
    ...orpc.trading.getPositions.queryOptions({
      input: {}
    }),
    refetchInterval: 5000,
  });

  const totalPnl = data?.positions.reduce(
    (sum, account) => sum + (account.totalUnrealizedPnl ?? 0),
    0
  ) ?? 0;

  const totalPositions = data?.positions.reduce(
    (sum, account) => sum + account.positions.length,
    0
  ) ?? 0;

  return (
    <div>
      <h2>Live Portfolio</h2>
      <p>Total Open Positions: {totalPositions}</p>
      <p style={{ color: totalPnl >= 0 ? 'green' : 'red' }}>
        Total Unrealized P&L: ${totalPnl.toFixed(2)}
      </p>
      
      {/* Position list */}
    </div>
  );
}

Filter by Variant and Calculate Exposure

import { useQuery } from "@tanstack/react-query";
import { orpc } from "@/server/orpc/client";

function TrendsurferExposure() {
  const { data } = useQuery(
    orpc.trading.getPositions.queryOptions({
      input: { variant: "Trendsurfer" }
    })
  );

  const exposure = data?.positions.reduce((acc, account) => {
    account.positions.forEach(pos => {
      const notional = pos.quantity * pos.entryPrice;
      acc[pos.symbol] = (acc[pos.symbol] ?? 0) + notional;
    });
    return acc;
  }, {} as Record<string, number>);

  return (
    <div>
      <h3>Trendsurfer Position Exposure</h3>
      {exposure && Object.entries(exposure).map(([symbol, value]) => (
        <p key={symbol}>
          {symbol}: ${value.toFixed(2)}
        </p>
      ))}
    </div>
  );
}

Build docs developers (and LLMs) love