# Trading Strategy Best Practices ## Code Organization ### Separation of Concerns ```typescript // Good: Clear separation class Strategy { async analyze(data: MarketData): Promise { } } class RiskManager { validateSignal(signal: Signal): boolean { } } class ExecutionEngine { async execute(signal: Signal): Promise { } } // Bad: Everything in one function async function trade() { // Analysis, risk, execution all mixed } ``` ### Configuration Management ```typescript // 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 ```typescript // 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 ```typescript // 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 ```typescript // Good: Cache indicator results class IndicatorCache { private cache = new Map(); 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 ```typescript // 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 ```typescript // Good: Fallback behavior async function getMarketData(ticker: string): Promise { 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 ```typescript // 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 ```typescript // 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 ```typescript // 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 ```typescript // Good: Prevent API abuse class RateLimiter { private calls: number[] = []; async throttle(maxCallsPerMinute: number): Promise { 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); } } ```