Files
ai/gateway/src/harness/subagents/code-reviewer/memory/best-practices.md

5.0 KiB

Trading Strategy Best Practices

Code Organization

Separation of Concerns

// Good: Clear separation
class Strategy {
  async analyze(data: MarketData): Promise<Signal> { }
}

class RiskManager {
  validateSignal(signal: Signal): boolean { }
}

class ExecutionEngine {
  async execute(signal: Signal): Promise<Order> { }
}

// Bad: Everything in one function
async function trade() {
  // Analysis, risk, execution all mixed
}

Configuration Management

// Good: External configuration
interface StrategyConfig {
  stopLossPercent: number;
  takeProfitPercent: number;
  maxPositionSize: number;
  riskPerTrade: number;
}

const config = loadConfig('strategy.yaml');

// Bad: Hardcoded values scattered throughout
const stopLoss = price * 0.95; // What if you want to change this?

Testing Considerations

Testable Code

// Good: Pure functions, easy to test
function calculateRSI(prices: number[], period: number = 14): number {
  // Pure calculation, no side effects
  return rsi;
}

// Bad: Hard to test
async function strategy() {
  const data = await fetchLiveData(); // Can't control in tests
  const signal = analyze(data);
  await executeTrade(signal); // Side effects
}

Mock-Friendly Design

// Good: Dependency injection
class Strategy {
  constructor(
    private dataProvider: DataProvider,
    private executor: OrderExecutor
  ) {}

  async run() {
    const data = await this.dataProvider.getData();
    // ...
  }
}

// In tests: inject mocks
const strategy = new Strategy(mockDataProvider, mockExecutor);

Performance Optimization

Avoid Recalculation

// Good: Cache indicator results
class IndicatorCache {
  private cache = new Map<string, { value: number, timestamp: number }>();

  get(key: string, ttl: number, calculator: () => number): number {
    const cached = this.cache.get(key);
    if (cached && Date.now() - cached.timestamp < ttl) {
      return cached.value;
    }

    const value = calculator();
    this.cache.set(key, { value, timestamp: Date.now() });
    return value;
  }
}

// Bad: Recalculate every time
for (const ticker of tickers) {
  const rsi = calculateRSI(await getData(ticker)); // Slow
}

Batch Operations

// Good: Batch API calls
const results = await Promise.all(
  tickers.map(ticker => dataProvider.getOHLC(ticker))
);

// Bad: Sequential API calls
const results = [];
for (const ticker of tickers) {
  results.push(await dataProvider.getOHLC(ticker)); // Slow
}

Error Handling

Graceful Degradation

// Good: Fallback behavior
async function getMarketData(ticker: string): Promise<OHLC[]> {
  try {
    return await primarySource.fetch(ticker);
  } catch (error) {
    logger.warn('Primary source failed, trying backup');
    try {
      return await backupSource.fetch(ticker);
    } catch (backupError) {
      logger.error('All sources failed');
      return getCachedData(ticker); // Last resort
    }
  }
}

// Bad: Let it crash
async function getMarketData(ticker: string) {
  return await api.fetch(ticker); // Uncaught errors
}

Detailed Logging

// Good: Structured logging with context
logger.info({
  action: 'order_placed',
  ticker: 'BTC/USDT',
  side: 'buy',
  size: 0.1,
  price: 50000,
  orderId: 'abc123',
  strategy: 'mean-reversion'
});

// Bad: String concatenation
console.log('Placed order'); // No context

Documentation

Self-Documenting Code

// Good: Clear naming and JSDoc
/**
 * Calculate position size using Kelly Criterion
 * @param winRate Probability of winning (0-1)
 * @param avgWin Average win amount
 * @param avgLoss Average loss amount
 * @param capital Total available capital
 * @returns Optimal position size in base currency
 */
function calculateKellyPosition(
  winRate: number,
  avgWin: number,
  avgLoss: number,
  capital: number
): number {
  const kellyPercent = (winRate * avgWin - (1 - winRate) * avgLoss) / avgWin;
  return Math.max(0, Math.min(kellyPercent * capital, capital * 0.25)); // Cap at 25%
}

// Bad: Cryptic names
function calc(w: number, a: number, b: number, c: number) {
  return (w * a - (1 - w) * b) / a * c;
}

Security

Input Validation

// Good: Validate all external inputs
function validateTicker(ticker: string): boolean {
  return /^[A-Z]+:[A-Z]+\/[A-Z]+$/.test(ticker);
}

function validatePeriod(period: string): boolean {
  return ['1m', '5m', '15m', '1h', '4h', '1d', '1w'].includes(period);
}

// Bad: Trust user input
function getOHLC(ticker: string, period: string) {
  return db.query(`SELECT * FROM ohlc WHERE ticker='${ticker}'`); // SQL injection!
}

Rate Limiting

// Good: Prevent API abuse
class RateLimiter {
  private calls: number[] = [];

  async throttle(maxCallsPerMinute: number): Promise<void> {
    const now = Date.now();
    this.calls = this.calls.filter(t => now - t < 60000);

    if (this.calls.length >= maxCallsPerMinute) {
      const wait = 60000 - (now - this.calls[0]);
      await sleep(wait);
    }

    this.calls.push(now);
  }
}