or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

account-management.mderror-handling.mdexchange-management.mdfunding-operations.mdindex.mdmarket-data.mdorder-management.mdtrading-operations.mdutility-functions.mdwebsocket-operations.md
tile.json

trading-operations.mddocs/

Trading Operations

Trading operations provide functionality for accessing trade history, analyzing trading performance, and managing the relationship between orders and their resulting trades.

Capabilities

Trade History

Access personal trading history with detailed information about executed trades.

/**
 * Fetch user's trade history
 * @param symbol - Trading pair symbol to filter by (optional)
 * @param since - Timestamp in milliseconds to fetch trades from (optional)
 * @param limit - Maximum number of trades to fetch (optional)
 * @param params - Additional query parameters
 * @returns Array of trade objects
 */
fetchMyTrades(symbol?: string, since?: number, limit?: number, params?: Dict): Promise<Trade[]>;

/**
 * Fetch trades for a specific order
 * @param id - Order ID to fetch trades for
 * @param symbol - Trading pair symbol (required by some exchanges)
 * @param since - Timestamp in milliseconds to fetch trades from (optional)
 * @param limit - Maximum number of trades to fetch (optional)
 * @param params - Additional query parameters
 * @returns Array of trade objects for the order
 */
fetchOrderTrades(id: string, symbol?: string, since?: number, limit?: number, params?: Dict): Promise<Trade[]>;

interface Trade {
  id: string;           // Exchange-specific trade identifier
  order?: string;       // Order ID that generated this trade
  timestamp: number;    // Trade execution timestamp in milliseconds
  datetime: string;     // Trade execution datetime in ISO format
  symbol: string;       // Trading pair symbol
  type?: OrderType;     // Order type that generated the trade
  side: OrderSide;      // Trade side: 'buy' or 'sell'
  amount: number;       // Trade amount in base currency
  price: number;        // Trade execution price in quote currency
  cost: number;         // Trade cost (amount * price)
  fee?: {               // Trade fee information
    currency: string;   // Fee currency
    cost: number;       // Fee amount
    rate?: number;      // Fee rate (percentage)
  };
  fees?: Array<{        // Multiple fees (some exchanges charge multiple fees)
    currency: string;
    cost: number;
    rate?: number;
  }>;
  takerOrMaker?: 'taker' | 'maker'; // Whether trade was taker or maker
  info: any;           // Raw exchange-specific trade data
}

Usage Examples:

// Fetch recent trades
const recentTrades = await exchange.fetchMyTrades(undefined, undefined, 50);
console.log(`Found ${recentTrades.length} recent trades`);

// Fetch trades for specific symbol
const btcTrades = await exchange.fetchMyTrades('BTC/USDT', undefined, 100);
console.log(`BTC/USDT trades: ${btcTrades.length}`);

// Fetch trades from last week
const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
const weeklyTrades = await exchange.fetchMyTrades(undefined, weekAgo);
console.log(`Trades in last week: ${weeklyTrades.length}`);

// Analyze trade performance
const buyTrades = btcTrades.filter(trade => trade.side === 'buy');
const sellTrades = btcTrades.filter(trade => trade.side === 'sell');

const totalBuyVolume = buyTrades.reduce((sum, trade) => sum + trade.amount, 0);
const totalSellVolume = sellTrades.reduce((sum, trade) => sum + trade.amount, 0);
const avgBuyPrice = buyTrades.reduce((sum, trade) => sum + trade.price, 0) / buyTrades.length;
const avgSellPrice = sellTrades.reduce((sum, trade) => sum + trade.price, 0) / sellTrades.length;

console.log(`Buy: ${totalBuyVolume} BTC @ avg $${avgBuyPrice.toFixed(2)}`);
console.log(`Sell: ${totalSellVolume} BTC @ avg $${avgSellPrice.toFixed(2)}`);

// Calculate fees paid
const totalFees = recentTrades.reduce((sum, trade) => {
  if (trade.fee) {
    // Convert fees to USDT equivalent for comparison
    if (trade.fee.currency === 'USDT') {
      return sum + trade.fee.cost;
    } else if (trade.fee.currency === 'BTC') {
      // Would need current BTC price to convert
      return sum + trade.fee.cost * 50000; // Approximate
    }
  }
  return sum;
}, 0);
console.log(`Total fees paid: ~$${totalFees.toFixed(2)}`);

// Get trades for specific order
const orderTrades = await exchange.fetchOrderTrades('order-123', 'BTC/USDT');
console.log(`Order filled in ${orderTrades.length} trades`);

Trade Analysis

Analyze trading performance with various metrics and calculations.

/**
 * Calculate trading statistics from trade history
 * @param trades - Array of trades to analyze
 * @returns Trading statistics object
 */
interface TradingStats {
  totalTrades: number;
  buyTrades: number;
  sellTrades: number;
  totalVolume: number;
  totalCost: number;
  averagePrice: number;
  totalFees: number;
  profitableTrades: number;
  losingTrades: number;
  winRate: number;
  totalProfit: number;
  averageProfit: number;
  largestWin: number;
  largestLoss: number;
}

Usage Examples:

// Trading performance analysis
class TradingAnalyzer {
  static analyzeTrades(trades: Trade[]): TradingStats {
    const buyTrades = trades.filter(t => t.side === 'buy');
    const sellTrades = trades.filter(t => t.side === 'sell');
    
    const totalVolume = trades.reduce((sum, t) => sum + t.amount, 0);
    const totalCost = trades.reduce((sum, t) => sum + t.cost, 0);
    const totalFees = trades.reduce((sum, t) => sum + (t.fee?.cost || 0), 0);
    
    // Calculate P&L (simplified - would need more complex logic for real analysis)
    const avgBuyPrice = buyTrades.reduce((sum, t) => sum + t.price, 0) / buyTrades.length;
    const avgSellPrice = sellTrades.reduce((sum, t) => sum + t.price, 0) / sellTrades.length;
    const totalProfit = (avgSellPrice - avgBuyPrice) * Math.min(
      buyTrades.reduce((sum, t) => sum + t.amount, 0),
      sellTrades.reduce((sum, t) => sum + t.amount, 0)
    );
    
    return {
      totalTrades: trades.length,
      buyTrades: buyTrades.length,
      sellTrades: sellTrades.length,
      totalVolume,
      totalCost,
      averagePrice: totalCost / totalVolume,
      totalFees,
      profitableTrades: 0, // Would need more complex calculation
      losingTrades: 0,
      winRate: 0,
      totalProfit,
      averageProfit: totalProfit / trades.length,
      largestWin: 0,
      largestLoss: 0,
    };
  }
  
  static groupTradesByPeriod(trades: Trade[], periodMs: number): { [period: string]: Trade[] } {
    const groups: { [period: string]: Trade[] } = {};
    
    trades.forEach(trade => {
      const periodStart = Math.floor(trade.timestamp / periodMs) * periodMs;
      const periodKey = new Date(periodStart).toISOString().split('T')[0];
      
      if (!groups[periodKey]) {
        groups[periodKey] = [];
      }
      groups[periodKey].push(trade);
    });
    
    return groups;
  }
  
  static calculateDailyVolume(trades: Trade[]): { [date: string]: number } {
    const dailyGroups = this.groupTradesByPeriod(trades, 24 * 60 * 60 * 1000);
    const dailyVolume: { [date: string]: number } = {};
    
    Object.entries(dailyGroups).forEach(([date, dayTrades]) => {
      dailyVolume[date] = dayTrades.reduce((sum, trade) => sum + trade.amount, 0);
    });
    
    return dailyVolume;
  }
}

// Usage
const trades = await exchange.fetchMyTrades('BTC/USDT', undefined, 1000);
const stats = TradingAnalyzer.analyzeTrades(trades);
console.log('Trading Statistics:', stats);

const dailyVolume = TradingAnalyzer.calculateDailyVolume(trades);
console.log('Daily Volume:', dailyVolume);

// Find most active trading days
const sortedDays = Object.entries(dailyVolume)
  .sort(([,a], [,b]) => b - a)
  .slice(0, 5);
console.log('Most active trading days:', sortedDays);

Position Tracking

Track position changes through trade history for portfolio management.

/**
 * Calculate position from trade history
 * @param trades - Array of trades for a symbol
 * @returns Current position information
 */
interface PositionFromTrades {
  symbol: string;
  amount: number;           // Net position (positive = long, negative = short)
  averagePrice: number;     // Average entry price
  totalCost: number;        // Total cost basis
  realizedPnl: number;      // Realized profit/loss from closed trades
  totalFees: number;        // Total fees paid
}

Usage Examples:

// Calculate position from trades
function calculatePositionFromTrades(trades: Trade[]): PositionFromTrades {
  if (trades.length === 0) {
    throw new Error('No trades provided');
  }
  
  const symbol = trades[0].symbol;
  let totalAmount = 0;
  let totalCost = 0;
  let totalFees = 0;
  let realizedPnl = 0;
  
  // Track position changes chronologically
  const sortedTrades = trades.sort((a, b) => a.timestamp - b.timestamp);
  
  for (const trade of sortedTrades) {
    const tradeAmount = trade.side === 'buy' ? trade.amount : -trade.amount;
    totalAmount += tradeAmount;
    totalCost += trade.side === 'buy' ? trade.cost : -trade.cost;
    totalFees += trade.fee?.cost || 0;
  }
  
  const averagePrice = Math.abs(totalCost) / Math.abs(totalAmount);
  
  return {
    symbol,
    amount: totalAmount,
    averagePrice,
    totalCost,
    realizedPnl,
    totalFees,
  };
}

// Track positions across multiple symbols
async function trackAllPositions(exchange: any): Promise<{ [symbol: string]: PositionFromTrades }> {
  const allTrades = await exchange.fetchMyTrades();
  const tradesBySymbol: { [symbol: string]: Trade[] } = {};
  
  // Group trades by symbol
  allTrades.forEach(trade => {
    if (!tradesBySymbol[trade.symbol]) {
      tradesBySymbol[trade.symbol] = [];
    }
    tradesBySymbol[trade.symbol].push(trade);
  });
  
  // Calculate position for each symbol
  const positions: { [symbol: string]: PositionFromTrades } = {};
  
  Object.entries(tradesBySymbol).forEach(([symbol, trades]) => {
    try {
      positions[symbol] = calculatePositionFromTrades(trades);
    } catch (error) {
      console.error(`Error calculating position for ${symbol}:`, error.message);
    }
  });
  
  return positions;
}

// Usage
const positions = await trackAllPositions(exchange);
Object.entries(positions).forEach(([symbol, position]) => {
  if (Math.abs(position.amount) > 0.0001) { // Filter out dust positions
    console.log(`${symbol}: ${position.amount > 0 ? 'LONG' : 'SHORT'} ${Math.abs(position.amount)}`);
    console.log(`  Avg Price: $${position.averagePrice.toFixed(2)}`);
    console.log(`  Total Fees: $${position.totalFees.toFixed(2)}`);
  }
});