Simpfor.fun Integration Examples

Real-world examples showing how to build apps with the Simpfor.fun SDK. From simple copy trading bots to full dashboard applications.

Copy Trading Bot

Build an automated copy trading bot that finds top traders and manages risk.
import { SimpforFunSDK } from 'simpfor-fun-sdk';

interface TraderCriteria {
  minROI: number;
  maxDrawdown: number;
  minWinRate: number;
  minFollowValue: number;
}

class CopyTradingBot {
  private sdk: SimpforFunSDK;
  private userId: number;
  private activeTrades = new Map<string, number>(); // trader -> copyTradeId

  constructor() {
    this.sdk = new SimpforFunSDK();
  }

  async initialize(email: string, otp: string) {
    const loginResult = await this.sdk.verifyOtp(email, otp);
    this.userId = loginResult.data.user.uid;
    console.log('Bot initialized for user:', this.userId);
  }

  async findQualifyingTraders(criteria: TraderCriteria) {
    const traders = await this.sdk.fetchTopTraders();
    
    return traders.filter(trader => 
      trader.roi >= criteria.minROI &&
      trader.maxDrawdown <= criteria.maxDrawdown &&
      trader.winRate >= criteria.minWinRate &&
      trader.followValue >= criteria.minFollowValue
    );
  }

  async startCopyTrade(traderAddress: string, walletAddress: string) {
    try {
      // Create copy trade relationship
      const copyTrade = await this.sdk.createCopyTrade(
        this.userId,
        traderAddress,
        walletAddress
      );

      // Start copying
      await this.sdk.runCopyTrade(this.userId, copyTrade.data.info.copyTradeId);
      
      // Track active trade
      this.activeTrades.set(traderAddress, copyTrade.data.info.copyTradeId);
      
      console.log(`Started copying ${traderAddress}`);
      return copyTrade.data.info.copyTradeId;
      
    } catch (error) {
      console.error(`Failed to copy ${traderAddress}:`, error);
      throw error;
    }
  }

  async monitorPerformance(stopLossPercent: number = 15) {
    const monitorInterval = setInterval(async () => {
      for (const [traderAddress, copyTradeId] of this.activeTrades) {
        try {
          const pnl = await this.sdk.getCopyTradeTotalPnl(
            this.userId, 
            'your-wallet-address'
          );
          
          // Calculate drawdown (simplified)
          const currentDrawdown = Math.abs(pnl.data.pnl) / 1000; // Assuming 1000 USDC base
          
          console.log(`${traderAddress}: ${pnl.data.pnl} USDC PnL`);
          
          // Stop loss check
          if (currentDrawdown > stopLossPercent / 100) {
            console.log(`Stop loss triggered for ${traderAddress} at ${currentDrawdown * 100}%`);
            await this.sdk.stopCopyTrade(this.userId, copyTradeId, true);
            this.activeTrades.delete(traderAddress);
          }
          
        } catch (error) {
          console.error(`Error monitoring ${traderAddress}:`, error);
        }
      }
      
      // Stop monitoring if no active trades
      if (this.activeTrades.size === 0) {
        clearInterval(monitorInterval);
        console.log('No active trades to monitor');
      }
    }, 60000); // Check every minute

    return monitorInterval;
  }

  async getPortfolioSummary() {
    const copyTrades = await this.sdk.listCopyTrades(this.userId);
    
    const summary = {
      activeTrades: 0,
      totalPnl: 0,
      trades: [] as Array<{
        leader: string;
        follower: string;
        pnl: number;
        active: boolean;
      }>
    };

    for (const trade of copyTrades.data.infos) {
      if (trade.active) {
        summary.activeTrades++;
        
        try {
          const pnl = await this.sdk.getCopyTradeTotalPnl(this.userId, trade.followerAccount);
          summary.totalPnl += pnl.data.pnl;
          
          summary.trades.push({
            leader: trade.leaderAccount,
            follower: trade.followerAccount,
            pnl: pnl.data.pnl,
            active: trade.active
          });
        } catch (error) {
          console.error(`Error getting PnL for ${trade.leaderAccount}:`, error);
        }
      }
    }

    return summary;
  }
}

// Usage Example
async function runBot() {
  const bot = new CopyTradingBot();
  
  // Initialize with your credentials
  await bot.initialize('your-email@example.com', '123456');

  // Find qualifying traders
  const criteria: TraderCriteria = {
    minROI: 0.20,        // 20% minimum ROI
    maxDrawdown: 0.15,   // 15% max drawdown
    minWinRate: 0.65,    // 65% win rate
    minFollowValue: 1000 // At least 1000 USDC following
  };

  const topTraders = await bot.findQualifyingTraders(criteria);
  console.log(`Found ${topTraders.length} qualifying traders`);

  // Start copying the best traders (limit to top 3)
  for (const trader of topTraders.slice(0, 3)) {
    try {
      await bot.startCopyTrade(trader.address, 'your-wallet-address');
      console.log(`Started copying ${trader.address} with ${trader.roi * 100}% ROI`);
    } catch (error) {
      console.error(`Failed to copy ${trader.address}:`, error);
    }
  }

  // Start monitoring with 15% stop loss
  await bot.monitorPerformance(15);

  // Get portfolio summary every 5 minutes
  setInterval(async () => {
    const summary = await bot.getPortfolioSummary();
    console.log('Portfolio Summary:', summary);
  }, 300000);
}

// Run the bot
runBot().catch(console.error);

React Dashboard Application

Complete React dashboard for copy trading management.
import React, { useState, useEffect } from 'react';
import { SimpforFunSDK } from 'simpfor-fun-sdk';

interface DashboardState {
  user: any;
  traders: any[];
  copyTrades: any[];
  loading: boolean;
  error: string | null;
}

const CopyTradingDashboard: React.FC = () => {
  const [sdk] = useState(() => new SimpforFunSDK());
  const [state, setState] = useState<DashboardState>({
    user: null,
    traders: [],
    copyTrades: [],
    loading: false,
    error: null
  });

  // Login handler
  const handleLogin = async (email: string, otp: string) => {
    setState(prev => ({ ...prev, loading: true, error: null }));
    
    try {
      const result = await sdk.verifyOtp(email, otp);
      setState(prev => ({ ...prev, user: result.data.user }));
      await loadDashboardData(result.data.user.uid);
    } catch (error: any) {
      setState(prev => ({ 
        ...prev, 
        error: `Login failed: ${error.message}` 
      }));
    } finally {
      setState(prev => ({ ...prev, loading: false }));
    }
  };

  // Load dashboard data
  const loadDashboardData = async (userId: number) => {
    try {
      const [topTraders, userCopyTrades] = await Promise.all([
        sdk.fetchTopTraders(),
        sdk.listCopyTrades(userId)
      ]);
      
      setState(prev => ({
        ...prev,
        traders: topTraders.slice(0, 10),
        copyTrades: userCopyTrades.data.infos
      }));
    } catch (error: any) {
      setState(prev => ({ 
        ...prev, 
        error: `Failed to load data: ${error.message}` 
      }));
    }
  };

  // Start copy trading
  const startCopyTrade = async (traderAddress: string) => {
    if (!state.user) return;
    
    setState(prev => ({ ...prev, loading: true }));
    
    try {
      const copyTrade = await sdk.createCopyTrade(
        state.user.uid,
        traderAddress,
        'your-wallet-address' // Replace with actual wallet
      );
      
      await sdk.runCopyTrade(state.user.uid, copyTrade.data.info.copyTradeId);
      
      // Refresh data
      await loadDashboardData(state.user.uid);
      
      alert('Copy trading started successfully!');
    } catch (error: any) {
      setState(prev => ({ 
        ...prev, 
        error: `Failed to start copy trading: ${error.message}` 
      }));
    } finally {
      setState(prev => ({ ...prev, loading: false }));
    }
  };

  // Stop copy trading
  const stopCopyTrade = async (copyTradeId: number) => {
    if (!state.user) return;
    
    setState(prev => ({ ...prev, loading: true }));
    
    try {
      await sdk.stopCopyTrade(state.user.uid, copyTradeId, true);
      await loadDashboardData(state.user.uid);
      alert('Copy trading stopped');
    } catch (error: any) {
      setState(prev => ({ 
        ...prev, 
        error: `Failed to stop copy trading: ${error.message}` 
      }));
    } finally {
      setState(prev => ({ ...prev, loading: false }));
    }
  };

  return (
    <div className="dashboard">
      <h1>Copy Trading Dashboard</h1>
      
      {state.error && (
        <div className="error-banner">
          {state.error}
          <button onClick={() => setState(prev => ({ ...prev, error: null }))}>
            βœ•
          </button>
        </div>
      )}

      {!state.user ? (
        <LoginForm onLogin={handleLogin} loading={state.loading} />
      ) : (
        <>
          <UserInfo user={state.user} />
          <TopTraders 
            traders={state.traders} 
            onCopy={startCopyTrade}
            loading={state.loading} 
          />
          <CopyTradesList 
            trades={state.copyTrades}
            onStop={stopCopyTrade}
            loading={state.loading}
          />
        </>
      )}
    </div>
  );
};

// Login Form Component
const LoginForm: React.FC<{
  onLogin: (email: string, otp: string) => void;
  loading: boolean;
}> = ({ onLogin, loading }) => {
  const [email, setEmail] = useState('');
  const [otp, setOtp] = useState('');
  const [otpSent, setOtpSent] = useState(false);
  const [sdk] = useState(() => new SimpforFunSDK());

  const sendOtp = async () => {
    try {
      await sdk.sendVerificationCode(email);
      setOtpSent(true);
      alert('OTP sent to your email');
    } catch (error: any) {
      alert(`Failed to send OTP: ${error.message}`);
    }
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    onLogin(email, otp);
  };

  return (
    <form onSubmit={handleSubmit} className="login-form">
      <div>
        <input
          type="email"
          placeholder="Email address"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          required
        />
        <button type="button" onClick={sendOtp} disabled={!email || otpSent}>
          {otpSent ? 'OTP Sent' : 'Send OTP'}
        </button>
      </div>
      
      {otpSent && (
        <div>
          <input
            type="text"
            placeholder="Enter 6-digit OTP"
            value={otp}
            onChange={(e) => setOtp(e.target.value)}
            maxLength={6}
            required
          />
          <button type="submit" disabled={loading || otp.length !== 6}>
            {loading ? 'Logging in...' : 'Login'}
          </button>
        </div>
      )}
    </form>
  );
};

// User Info Component
const UserInfo: React.FC<{ user: any }> = ({ user }) => (
  <div className="user-info">
    <h2>Welcome, {user.email}</h2>
    <p>User ID: {user.uid}</p>
    <p>Referral Code: {user.referralCode}</p>
  </div>
);

// Top Traders Component
const TopTraders: React.FC<{
  traders: any[];
  onCopy: (address: string) => void;
  loading: boolean;
}> = ({ traders, onCopy, loading }) => (
  <div className="section">
    <h2>Top Traders</h2>
    <div className="traders-grid">
      {traders.map(trader => (
        <div key={trader.address} className="trader-card">
          <h3>{trader.address.slice(0, 8)}...{trader.address.slice(-6)}</h3>
          <div className="trader-stats">
            <p><strong>ROI:</strong> {(trader.roi * 100).toFixed(2)}%</p>
            <p><strong>PnL:</strong> {trader.pnl.toFixed(2)} USDC</p>
            <p><strong>Win Rate:</strong> {(trader.winRate * 100).toFixed(2)}%</p>
            <p><strong>Max Drawdown:</strong> {(trader.maxDrawdown * 100).toFixed(2)}%</p>
            <p><strong>Followers:</strong> {trader.followValue.toFixed(0)} USDC</p>
          </div>
          
          <button 
            onClick={() => onCopy(trader.address)}
            disabled={loading || trader.copying}
            className={`copy-btn ${trader.copying ? 'active' : ''}`}
          >
            {trader.copying ? 'Copying' : loading ? 'Starting...' : 'Copy Trade'}
          </button>
        </div>
      ))}
    </div>
  </div>
);

// Copy Trades List Component
const CopyTradesList: React.FC<{
  trades: any[];
  onStop: (id: number) => void;
  loading: boolean;
}> = ({ trades, onStop, loading }) => (
  <div className="section">
    <h2>Your Copy Trades</h2>
    {trades.length === 0 ? (
      <p>No active copy trades</p>
    ) : (
      <div className="trades-list">
        {trades.map(trade => (
          <div key={trade.copyTradeId} className="trade-item">
            <div className="trade-info">
              <p><strong>Leader:</strong> {trade.leaderAccount.slice(0, 8)}...{trade.leaderAccount.slice(-6)}</p>
              <p><strong>Follower:</strong> {trade.followerAccount.slice(0, 8)}...{trade.followerAccount.slice(-6)}</p>
              <p><strong>Status:</strong> 
                <span className={`status ${trade.active ? 'active' : 'stopped'}`}>
                  {trade.active ? 'Active' : 'Stopped'}
                </span>
              </p>
              <p><strong>Created:</strong> {new Date(trade.createTime).toLocaleDateString()}</p>
            </div>
            
            {trade.active && (
              <button 
                onClick={() => onStop(trade.copyTradeId)}
                disabled={loading}
                className="stop-btn"
              >
                {loading ? 'Stopping...' : 'Stop'}
              </button>
            )}
          </div>
        ))}
      </div>
    )}
  </div>
);

export default CopyTradingDashboard;

Trader Analytics Tool

Build a tool to analyze and compare trader performance.
import { SimpforFunSDK } from 'simpfor-fun-sdk';

interface TraderAnalytics {
  address: string;
  roi30d: number;
  roi90d: number;
  sharpeRatio: number;
  maxDrawdown: number;
  winRate: number;
  totalTrades: number;
  avgHoldTime: number;
  riskScore: number;
}

class TraderAnalyzer {
  private sdk: SimpforFunSDK;
  private cache = new Map<string, { data: any; timestamp: number }>();
  private readonly CACHE_TTL = 300000; // 5 minutes

  constructor() {
    this.sdk = new SimpforFunSDK();
  }

  async getTraderAnalytics(address: string): Promise<TraderAnalytics> {
    // Check cache first
    const cached = this.cache.get(address);
    if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
      return this.calculateAnalytics(cached.data);
    }

    // Fetch fresh data
    const [snapshot30d, snapshot90d, overview] = await Promise.all([
      this.sdk.traderSnapshot(address, '30d'),
      this.sdk.traderSnapshot(address, '90d'),
      this.sdk.traderOverview(address)
    ]);

    const data = { snapshot30d, snapshot90d, overview };
    this.cache.set(address, { data, timestamp: Date.now() });

    return this.calculateAnalytics(data);
  }

  private calculateAnalytics(data: any): TraderAnalytics {
    const { snapshot30d, snapshot90d, overview } = data;
    
    // Calculate risk score (0-100, lower is better)
    const riskScore = this.calculateRiskScore(
      snapshot30d.trader.maxDrawdown,
      snapshot30d.trader.sharpeRatio,
      overview.traderOverview.averageLeverage
    );

    return {
      address: snapshot30d.trader.address,
      roi30d: snapshot30d.trader.roi,
      roi90d: snapshot90d.trader.roi,
      sharpeRatio: snapshot30d.trader.sharpeRatio,
      maxDrawdown: snapshot30d.trader.maxDrawdown,
      winRate: snapshot30d.trader.winRate,
      totalTrades: snapshot30d.trader.totalTrades || 0,
      avgHoldTime: this.calculateAvgHoldTime(snapshot30d.snapshot),
      riskScore
    };
  }

  private calculateRiskScore(maxDrawdown: number, sharpeRatio: number, avgLeverage: number): number {
    // Weighted risk score
    const drawdownScore = Math.min(maxDrawdown * 100, 100); // 0-100
    const sharpeScore = Math.max(0, 50 - (sharpeRatio * 10)); // 0-50
    const leverageScore = Math.min(avgLeverage * 10, 50); // 0-50
    
    return Math.round((drawdownScore * 0.5) + (sharpeScore * 0.3) + (leverageScore * 0.2));
  }

  private calculateAvgHoldTime(snapshots: any[]): number {
    // Simplified calculation - would need more detailed trade data for accuracy
    return snapshots.length > 0 ? snapshots.length * 24 : 0; // Hours
  }

  async compareTraders(addresses: string[]): Promise<TraderAnalytics[]> {
    const analytics = await Promise.all(
      addresses.map(addr => this.getTraderAnalytics(addr))
    );

    // Sort by risk-adjusted return (ROI / risk score)
    return analytics.sort((a, b) => {
      const scoreA = a.roi30d / (a.riskScore || 1);
      const scoreB = b.roi30d / (b.riskScore || 1);
      return scoreB - scoreA;
    });
  }

  async findBestTraders(criteria: {
    minROI?: number;
    maxRisk?: number;
    minWinRate?: number;
    maxDrawdown?: number;
  } = {}): Promise<TraderAnalytics[]> {
    const topTraders = await this.sdk.fetchTopTraders();
    const analyses = await Promise.all(
      topTraders.slice(0, 20).map(trader => this.getTraderAnalytics(trader.address))
    );

    return analyses.filter(trader => {
      if (criteria.minROI && trader.roi30d < criteria.minROI) return false;
      if (criteria.maxRisk && trader.riskScore > criteria.maxRisk) return false;
      if (criteria.minWinRate && trader.winRate < criteria.minWinRate) return false;
      if (criteria.maxDrawdown && trader.maxDrawdown > criteria.maxDrawdown) return false;
      return true;
    });
  }

  generateReport(analytics: TraderAnalytics[]): string {
    let report = "TRADER ANALYSIS REPORT\n";
    report += "=".repeat(50) + "\n\n";

    analytics.forEach((trader, index) => {
      report += `${index + 1}. ${trader.address.slice(0, 8)}...${trader.address.slice(-6)}\n`;
      report += `   30-day ROI: ${(trader.roi30d * 100).toFixed(2)}%\n`;
      report += `   90-day ROI: ${(trader.roi90d * 100).toFixed(2)}%\n`;
      report += `   Sharpe Ratio: ${trader.sharpeRatio.toFixed(2)}\n`;
      report += `   Max Drawdown: ${(trader.maxDrawdown * 100).toFixed(2)}%\n`;
      report += `   Win Rate: ${(trader.winRate * 100).toFixed(2)}%\n`;
      report += `   Risk Score: ${trader.riskScore}/100\n`;
      report += `   Avg Hold Time: ${trader.avgHoldTime.toFixed(1)} hours\n\n`;
    });

    return report;
  }
}

// Usage Example
async function analyzeTraders() {
  const analyzer = new TraderAnalyzer();

  // Find best conservative traders
  const conservativeTraders = await analyzer.findBestTraders({
    minROI: 0.15,      // 15% minimum
    maxRisk: 30,       // Low risk score
    minWinRate: 0.65,  // 65% win rate
    maxDrawdown: 0.20  // 20% max drawdown
  });

  console.log(`Found ${conservativeTraders.length} conservative traders`);
  console.log(analyzer.generateReport(conservativeTraders.slice(0, 5)));

  // Compare specific traders
  const specificTraders = [
    'trader-address-1',
    'trader-address-2', 
    'trader-address-3'
  ];

  const comparison = await analyzer.compareTraders(specificTraders);
  console.log('\nCOMPARISON RESULTS:');
  console.log(analyzer.generateReport(comparison));
}

analyzeTraders().catch(console.error);

Automated Portfolio Rebalancer

Automatically rebalance your copy trading portfolio based on performance.
import { SimpforFunSDK } from 'simpfor-fun-sdk';

interface PortfolioConfig {
  maxTraders: number;
  rebalanceInterval: number; // milliseconds
  performanceWindow: number; // days
  stopLossThreshold: number; // percentage
  minAllocation: number; // USDC
  maxAllocation: number; // USDC
}

class PortfolioRebalancer {
  private sdk: SimpforFunSDK;
  private userId: number;
  private config: PortfolioConfig;
  private rebalanceTimer?: NodeJS.Timeout;

  constructor(config: PortfolioConfig) {
    this.sdk = new SimpforFunSDK();
    this.config = config;
  }

  async initialize(userId: number) {
    this.userId = userId;
    console.log('Portfolio rebalancer initialized');
  }

  async startAutoRebalancing() {
    console.log('Starting automatic rebalancing...');
    
    this.rebalanceTimer = setInterval(async () => {
      try {
        await this.rebalancePortfolio();
      } catch (error) {
        console.error('Rebalancing failed:', error);
      }
    }, this.config.rebalanceInterval);

    // Run initial rebalance
    await this.rebalancePortfolio();
  }

  async stopAutoRebalancing() {
    if (this.rebalanceTimer) {
      clearInterval(this.rebalanceTimer);
      this.rebalanceTimer = undefined;
      console.log('Auto-rebalancing stopped');
    }
  }

  async rebalancePortfolio() {
    console.log('Starting portfolio rebalance...');

    // Get current positions
    const currentTrades = await this.sdk.listCopyTrades(this.userId);
    const activeTrades = currentTrades.data.infos.filter(trade => trade.active);

    // Analyze performance of current traders
    const traderPerformance = await Promise.all(
      activeTrades.map(async (trade) => {
        try {
          const snapshot = await this.sdk.traderSnapshot(
            trade.leaderAccount, 
            `${this.config.performanceWindow}d` as any
          );
          
          const pnl = await this.sdk.getCopyTradeTotalPnl(
            this.userId, 
            trade.followerAccount
          );

          return {
            copyTradeId: trade.copyTradeId,
            leaderAccount: trade.leaderAccount,
            followerAccount: trade.followerAccount,
            performance: snapshot.trader.roi,
            currentPnl: pnl.data.pnl,
            sharpeRatio: snapshot.trader.sharpeRatio,
            maxDrawdown: snapshot.trader.maxDrawdown,
            winRate: snapshot.trader.winRate
          };
        } catch (error) {
          console.error(`Error analyzing ${trade.leaderAccount}:`, error);
          return null;
        }
      })
    );

    const validPerformance = traderPerformance.filter(p => p !== null);

    // Remove underperforming traders
    await this.removeUnderperformers(validPerformance);

    // Add new high-performing traders if needed
    await this.addNewTraders(validPerformance.length);

    console.log('Portfolio rebalance complete');
  }

  private async removeUnderperformers(performance: any[]) {
    for (const trader of performance) {
      const shouldRemove = 
        trader.performance < -this.config.stopLossThreshold / 100 ||
        trader.currentPnl < -this.config.stopLossThreshold * 10 || // Absolute loss threshold
        trader.maxDrawdown > 0.30; // 30% max drawdown

      if (shouldRemove) {
        console.log(`Removing underperformer: ${trader.leaderAccount}`);
        try {
          await this.sdk.stopCopyTrade(
            this.userId, 
            trader.copyTradeId, 
            true // Close positions
          );
        } catch (error) {
          console.error(`Failed to remove ${trader.leaderAccount}:`, error);
        }
      }
    }
  }

  private async addNewTraders(currentCount: number) {
    const spotsAvailable = this.config.maxTraders - currentCount;
    if (spotsAvailable <= 0) return;

    // Find new high-performing traders
    const topTraders = await this.sdk.fetchTopTraders();
    const currentTraders = new Set(
      (await this.sdk.listCopyTrades(this.userId)).data.infos
        .filter(t => t.active)
        .map(t => t.leaderAccount)
    );

    // Filter for traders we're not already copying
    const availableTraders = topTraders.filter(trader => 
      !currentTraders.has(trader.address) &&
      trader.roi > 0.10 && // 10% minimum ROI
      trader.winRate > 0.60 && // 60% win rate
      trader.maxDrawdown < 0.25 && // 25% max drawdown
      trader.followValue > 500 // Some following
    );

    // Add top performers
    const tradersToAdd = availableTraders.slice(0, spotsAvailable);

    for (const trader of tradersToAdd) {
      try {
        console.log(`Adding new trader: ${trader.address}`);
        const copyTrade = await this.sdk.createCopyTrade(
          this.userId,
          trader.address,
          'your-wallet-address' // Replace with actual wallet
        );
        
        await this.sdk.runCopyTrade(this.userId, copyTrade.data.info.copyTradeId);
      } catch (error) {
        console.error(`Failed to add ${trader.address}:`, error);
      }
    }
  }

  async getPortfolioStatus() {
    const trades = await this.sdk.listCopyTrades(this.userId);
    const activeTrades = trades.data.infos.filter(t => t.active);

    const status = {
      totalTrades: activeTrades.length,
      maxTrades: this.config.maxTraders,
      utilization: (activeTrades.length / this.config.maxTraders * 100).toFixed(1),
      trades: [] as any[]
    };

    for (const trade of activeTrades) {
      try {
        const pnl = await this.sdk.getCopyTradeTotalPnl(this.userId, trade.followerAccount);
        const snapshot = await this.sdk.traderSnapshot(trade.leaderAccount, '30d');
        
        status.trades.push({
          leader: trade.leaderAccount.slice(0, 8) + '...',
          pnl: pnl.data.pnl.toFixed(2),
          roi: (snapshot.trader.roi * 100).toFixed(2),
          active: trade.active
        });
      } catch (error) {
        console.error(`Error getting status for ${trade.leaderAccount}:`, error);
      }
    }

    return status;
  }
}

// Usage Example
async function runPortfolioManager() {
  const config: PortfolioConfig = {
    maxTraders: 5,
    rebalanceInterval: 3600000, // 1 hour
    performanceWindow: 7, // 7 days
    stopLossThreshold: 15, // 15%
    minAllocation: 100, // 100 USDC minimum
    maxAllocation: 1000 // 1000 USDC maximum
  };

  const rebalancer = new PortfolioRebalancer(config);
  await rebalancer.initialize(123); // Your user ID

  // Start automatic rebalancing
  await rebalancer.startAutoRebalancing();

  // Check status every 10 minutes
  setInterval(async () => {
    const status = await rebalancer.getPortfolioStatus();
    console.log('Portfolio Status:', status);
  }, 600000);

  // Stop after 24 hours (for demo)
  setTimeout(async () => {
    await rebalancer.stopAutoRebalancing();
    console.log('Demo ended');
  }, 86400000);
}

runPortfolioManager().catch(console.error);

Error Handling & Retry Logic

Production-ready error handling and retry mechanisms.
import { SimpforFunSDK } from 'simpfor-fun-sdk';

interface RetryOptions {
  maxRetries: number;
  baseDelay: number;
  maxDelay: number;
  backoffFactor: number;
}

class RobustSDK {
  private sdk: SimpforFunSDK;
  private defaultRetryOptions: RetryOptions = {
    maxRetries: 3,
    baseDelay: 1000,
    maxDelay: 10000,
    backoffFactor: 2
  };

  constructor() {
    this.sdk = new SimpforFunSDK();
  }

  // Retry wrapper for any SDK method
  async withRetry<T>(
    operation: () => Promise<T>,
    options: Partial<RetryOptions> = {}
  ): Promise<T> {
    const opts = { ...this.defaultRetryOptions, ...options };
    let lastError: any;

    for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {
      try {
        return await operation();
      } catch (error: any) {
        lastError = error;

        // Don't retry on client errors (4xx)
        if (error.code >= 400 && error.code < 500 && error.code !== 429) {
          throw error;
        }

        // Don't retry on last attempt
        if (attempt === opts.maxRetries) {
          break;
        }

        // Calculate delay with exponential backoff
        const delay = Math.min(
          opts.baseDelay * Math.pow(opts.backoffFactor, attempt),
          opts.maxDelay
        );

        console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
        await this.sleep(delay);
      }
    }

    throw lastError;
  }

  // Authentication with retry and refresh
  async authenticateWithRetry(email: string, otp: string) {
    return this.withRetry(async () => {
      return await this.sdk.verifyOtp(email, otp);
    });
  }

  // Fetch traders with caching and retry
  private traderCache: { data: any[]; timestamp: number } | null = null;
  private readonly CACHE_TTL = 300000; // 5 minutes

  async fetchTradersRobust(): Promise<any[]> {
    // Return cached data if fresh
    if (this.traderCache && Date.now() - this.traderCache.timestamp < this.CACHE_TTL) {
      return this.traderCache.data;
    }

    const traders = await this.withRetry(async () => {
      return await this.sdk.fetchTopTraders();
    });

    // Update cache
    this.traderCache = {
      data: traders,
      timestamp: Date.now()
    };

    return traders;
  }

  // Copy trade with comprehensive error handling
  async createCopyTradeRobust(
    userId: number,
    leaderAddress: string,
    followerAddress: string
  ) {
    try {
      // Validate inputs
      if (!this.isValidAddress(leaderAddress)) {
        throw new Error('Invalid leader address');
      }
      if (!this.isValidAddress(followerAddress)) {
        throw new Error('Invalid follower address');
      }

      // Check if already copying this trader
      const existingTrades = await this.withRetry(async () => {
        return await this.sdk.listCopyTrades(userId);
      });

      const alreadyCopying = existingTrades.data.infos.some(
        trade => trade.leaderAccount === leaderAddress && trade.active
      );

      if (alreadyCopying) {
        throw new Error('Already copying this trader');
      }

      // Create copy trade with retry
      const copyTrade = await this.withRetry(async () => {
        return await this.sdk.createCopyTrade(userId, leaderAddress, followerAddress);
      });

      // Start copy trading with retry
      await this.withRetry(async () => {
        return await this.sdk.runCopyTrade(userId, copyTrade.data.info.copyTradeId);
      });

      return copyTrade;

    } catch (error: any) {
      console.error('Copy trade creation failed:', error);
      
      // Provide user-friendly error messages
      switch (error.code) {
        case 400:
          throw new Error('Invalid request. Please check your wallet addresses and try again.');
        case 401:
          throw new Error('Authentication expired. Please log in again.');
        case 409:
          throw new Error('Copy trade relationship already exists.');
        case 429:
          throw new Error('Too many requests. Please wait a moment and try again.');
        case 500:
          throw new Error('Server error. Please try again later.');
        default:
          throw new Error(`Copy trade failed: ${error.message || 'Unknown error'}`);
      }
    }
  }

  // Batch operations with parallel processing and error isolation
  async processBatchOperations<T, R>(
    items: T[],
    operation: (item: T) => Promise<R>,
    maxConcurrency: number = 5
  ): Promise<Array<{ item: T; result?: R; error?: Error }>> {
    const results: Array<{ item: T; result?: R; error?: Error }> = [];
    
    // Process items in batches to control concurrency
    for (let i = 0; i < items.length; i += maxConcurrency) {
      const batch = items.slice(i, i + maxConcurrency);
      
      const batchPromises = batch.map(async (item) => {
        try {
          const result = await this.withRetry(() => operation(item));
          return { item, result };
        } catch (error) {
          return { item, error: error as Error };
        }
      });

      const batchResults = await Promise.all(batchPromises);
      results.push(...batchResults);
    }

    return results;
  }

  // Health check and status monitoring
  async healthCheck(): Promise<{
    status: 'healthy' | 'degraded' | 'unhealthy';
    checks: Record<string, boolean>;
    responseTime: number;
  }> {
    const startTime = Date.now();
    const checks: Record<string, boolean> = {};

    try {
      // Test basic API connectivity
      checks.api = await this.testApiCall();
      
      // Test authentication (if we have credentials)
      checks.auth = await this.testAuthentication();
      
      // Test trader data fetching
      checks.data = await this.testDataFetching();

    } catch (error) {
      console.error('Health check failed:', error);
    }

    const responseTime = Date.now() - startTime;
    const healthyChecks = Object.values(checks).filter(Boolean).length;
    const totalChecks = Object.keys(checks).length;

    let status: 'healthy' | 'degraded' | 'unhealthy';
    if (healthyChecks === totalChecks) {
      status = 'healthy';
    } else if (healthyChecks > 0) {
      status = 'degraded';
    } else {
      status = 'unhealthy';
    }

    return { status, checks, responseTime };
  }

  private async testApiCall(): Promise<boolean> {
    try {
      await this.sdk.fetchTopTraders();
      return true;
    } catch {
      return false;
    }
  }

  private async testAuthentication(): Promise<boolean> {
    // This would test if current auth is valid
    // Implementation depends on how you store auth state
    return true;
  }

  private async testDataFetching(): Promise<boolean> {
    try {
      const traders = await this.sdk.fetchTopTraders();
      return traders.length > 0;
    } catch {
      return false;
    }
  }

  private isValidAddress(address: string): boolean {
    // Basic address validation
    return address && address.length > 20 && address.startsWith('0x');
  }

  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// Usage Example
async function demonstrateRobustSDK() {
  const robustSDK = new RobustSDK();

  // Health check
  const health = await robustSDK.healthCheck();
  console.log('System Health:', health);

  if (health.status === 'unhealthy') {
    console.error('System is unhealthy, aborting operations');
    return;
  }

  // Robust trader fetching
  try {
    const traders = await robustSDK.fetchTradersRobust();
    console.log(`Fetched ${traders.length} traders`);
  } catch (error) {
    console.error('Failed to fetch traders:', error);
  }

  // Batch processing multiple copy trades
  const tradersToFollow = ['trader1', 'trader2', 'trader3'];
  const results = await robustSDK.processBatchOperations(
    tradersToFollow,
    async (traderAddress) => {
      return await robustSDK.createCopyTradeRobust(
        123, // userId
        traderAddress,
        'your-wallet-address'
      );
    }
  );

  // Process results
  results.forEach(({ item, result, error }) => {
    if (error) {
      console.error(`Failed to copy ${item}:`, error.message);
    } else {
      console.log(`Successfully started copying ${item}`);
    }
  });
}

demonstrateRobustSDK().catch(console.error);

Next Steps

These examples show real-world implementations using the Simpfor.fun SDK. Pick the example that matches your use case and adapt it to your needs. For more help: Ready to build? Start with the copy trading bot example - it’s the simplest way to get familiar with the SDK.