Skip to main content
Skip to main content
Version: Next 🚧

How to Improve Performance

Problem

Your algorithm is running slowly, consuming too many resources, or experiencing delays in signal generation and order execution.

Prerequisites

  • Algorithm is functional but slow
  • Understanding of your strategy's complexity
  • Access to performance metrics and logs

Performance Optimization Strategies

1. Optimize Indicator Calculations

Issue: Complex indicators calculated on every candle can slow down execution.

Identify Slow Indicators:

// Check indicator calculation times
GET /api/trading/algorithms/:id/performance

// Response
{
"indicatorCalculations": {
"EMA_9": { "avgTime": 2, "calls": 1000 },
"EMA_21": { "avgTime": 3, "calls": 1000 },
"RSI_14": { "avgTime": 15, "calls": 1000 }, // Slow!
"MACD": { "avgTime": 25, "calls": 1000 }, // Very slow!
"BollingerBands": { "avgTime": 30, "calls": 1000 } // Very slow!
}
}

Solutions:

Reduce Indicator Count:

// ❌ Too many indicators
{
"conditions": [
{ "indicator": { "type": "EMA", "period": 9 } },
{ "indicator": { "type": "EMA", "period": 21 } },
{ "indicator": { "type": "EMA", "period": 50 } },
{ "indicator": { "type": "RSI", "period": 14 } },
{ "indicator": { "type": "MACD" } },
{ "indicator": { "type": "BollingerBands" } },
{ "indicator": { "type": "Stochastic" } },
{ "indicator": { "type": "ADX" } }
]
}

// ✅ Optimized - fewer indicators
{
"conditions": [
{ "indicator": { "type": "EMA", "period": 9 } },
{ "indicator": { "type": "EMA", "period": 21 } },
{ "indicator": { "type": "RSI", "period": 14 } }
]
}

Use Simpler Indicators:

// ❌ Complex indicators
{
"indicator": { "type": "MACD" } // Requires 3 EMAs
}

// ✅ Simpler alternative
{
"indicator": { "type": "EMA", "period": 12 } // Single EMA
}

Increase Indicator Periods:

// ❌ Short periods = more calculations
{
"indicator": { "type": "SMA", "period": 5 } // Recalculates frequently
}

// ✅ Longer periods = fewer updates
{
"indicator": { "type": "SMA", "period": 20 } // More stable
}

2. Optimize Timeframe Selection

Issue: Shorter timeframes generate more candles and require more processing.

Timeframe Impact:

TimeframeCandles/DayProcessing Load
1m375Very High
5m75High
15m25Moderate
30m13Low
1h6Very Low

Solution:

// ❌ Very short timeframe
{
"timeframe": "1m" // 375 candles/day
}

// ✅ Longer timeframe
{
"timeframe": "15m" // 25 candles/day (15x less processing)
}

When to Use Each:

  • 1m-5m: Scalping only (high-frequency trading)
  • 15m-30m: Day trading (balanced)
  • 1h-4h: Swing trading (efficient)
  • 1d: Position trading (very efficient)

3. Reduce Symbol Count

Issue: More symbols = more data fetching and processing.

// ❌ Too many symbols
{
"symbols": [
"NSE:RELIANCE", "NSE:TCS", "NSE:INFY", "NSE:HDFC",
"NSE:ICICI", "NSE:SBIN", "NSE:BHARTI", "NSE:ITC",
"NSE:HIND", "NSE:KOTAKBANK", "NSE:LT", "NSE:AXISBANK",
"NSE:MARUTI", "NSE:SUNPHARMA", "NSE:NTPC", "NSE:POWERGRID"
] // 16 symbols
}

// ✅ Focused symbol list
{
"symbols": [
"NSE:RELIANCE", "NSE:TCS", "NSE:INFY"
] // 3 symbols (5x faster)
}

Recommendations:

  • Scalping: 1-3 symbols
  • Day Trading: 3-5 symbols
  • Swing Trading: 5-10 symbols
  • Position Trading: 10-20 symbols

4. Optimize Database Queries

Issue: Inefficient queries slow down data retrieval.

Use Indexes:

// Ensure indexes exist on frequently queried fields
db.trades.createIndex({ algorithmId: 1, createdAt: -1 })
db.candles.createIndex({ symbol: 1, timeframe: 1, timestamp: -1 })
db.algorithms.createIndex({ userId: 1, status: 1 })

Limit Query Results:

// ❌ Fetch all trades
const trades = await Trade.find({ algorithmId })

// ✅ Limit to recent trades
const trades = await Trade.find({ algorithmId })
.sort({ createdAt: -1 })
.limit(100)

Use Lean Queries:

// ❌ Full Mongoose documents
const candles = await Candle.find({ symbol, timeframe })

// ✅ Plain objects (5-10x faster)
const candles = await Candle.find({ symbol, timeframe })
.lean()
.select('open high low close volume timestamp')

Aggregate Instead of Multiple Queries:

// ❌ Multiple queries
const totalTrades = await Trade.countDocuments({ algorithmId })
const totalProfit = await Trade.aggregate([
{ $match: { algorithmId } },
{ $group: { _id: null, total: { $sum: '$profit' } } }
])

// ✅ Single aggregation
const stats = await Trade.aggregate([
{ $match: { algorithmId } },
{ $group: {
_id: null,
totalTrades: { $sum: 1 },
totalProfit: { $sum: '$profit' }
}}
])

5. Implement Caching

Issue: Repeatedly fetching the same data wastes resources.

Cache Indicator Values:

// Cache indicator calculations
const cacheKey = `indicator:${symbol}:${timeframe}:${indicatorType}:${period}`

// Check cache first
let indicatorValue = await redis.get(cacheKey)

if (!indicatorValue) {
// Calculate if not cached
indicatorValue = calculateIndicator(candles, indicatorType, period)

// Cache for 1 minute
await redis.setex(cacheKey, 60, JSON.stringify(indicatorValue))
}

Cache Market Data:

// Cache candle data
const cacheKey = `candles:${symbol}:${timeframe}`

let candles = await redis.get(cacheKey)

if (!candles) {
candles = await fetchCandles(symbol, timeframe)
await redis.setex(cacheKey, 30, JSON.stringify(candles))
}

Cache Algorithm Configuration:

// Cache algorithm config (changes infrequently)
const cacheKey = `algorithm:${algorithmId}`

let algorithm = await redis.get(cacheKey)

if (!algorithm) {
algorithm = await Algorithm.findById(algorithmId).lean()
await redis.setex(cacheKey, 300, JSON.stringify(algorithm)) // 5 minutes
}

6. Optimize Multi-Timeframe Analysis

Issue: Fetching and processing multiple timeframes is expensive.

Disable When Not Needed:

// ❌ Always enabled
{
"multiTimeframe": {
"enabled": true,
"higherTimeframe": "1h"
}
}

// ✅ Disable if not critical
{
"multiTimeframe": {
"enabled": false
}
}

Use Efficient Timeframe Ratios:

// ❌ Inefficient ratio (1m → 1h = 60x data)
{
"timeframe": "1m",
"multiTimeframe": {
"higherTimeframe": "1h"
}
}

// ✅ Efficient ratio (15m → 1h = 4x data)
{
"timeframe": "15m",
"multiTimeframe": {
"higherTimeframe": "1h"
}
}

7. Reduce Confirmation Candles

Issue: More confirmation candles = more data to process.

// ❌ Too many confirmation candles
{
"confirmationCandles": 10 // Checks 10 candles
}

// ✅ Fewer confirmation candles
{
"confirmationCandles": 2 // Checks 2 candles (5x faster)
}

Recommendations:

  • Scalping: 0-1 candles
  • Day Trading: 1-2 candles
  • Swing Trading: 2-3 candles

8. Optimize Condition Evaluation

Issue: Complex condition logic slows down signal generation.

Use Short-Circuit Evaluation:

// ❌ All conditions evaluated
{
"logicalOperator": "AND",
"conditions": [
{ "type": "complex_calculation" }, // Slow
{ "type": "simple_check" } // Fast
]
}

// ✅ Fast check first
{
"logicalOperator": "AND",
"conditions": [
{ "type": "simple_check" }, // Fast - fails early
{ "type": "complex_calculation" } // Slow - only if needed
]
}

Simplify Conditions:

// ❌ Too many conditions
{
"conditions": [
{ "indicator": "EMA_9" },
{ "indicator": "EMA_21" },
{ "indicator": "EMA_50" },
{ "indicator": "RSI" },
{ "indicator": "MACD" },
{ "indicator": "BollingerBands" },
{ "indicator": "Stochastic" }
]
}

// ✅ Fewer conditions
{
"conditions": [
{ "indicator": "EMA_9" },
{ "indicator": "EMA_21" },
{ "indicator": "RSI" }
]
}

9. Batch Operations

Issue: Processing items one at a time is inefficient.

Batch Database Operations:

// ❌ Individual updates
for (const trade of trades) {
await Trade.updateOne({ _id: trade.id }, { status: 'closed' })
}

// ✅ Bulk update
await Trade.bulkWrite(
trades.map(trade => ({
updateOne: {
filter: { _id: trade.id },
update: { $set: { status: 'closed' } }
}
}))
)

Batch API Calls:

// ❌ Individual API calls
for (const symbol of symbols) {
await fetchMarketData(symbol)
}

// ✅ Batch API call
await fetchMarketDataBatch(symbols)

10. Monitor and Profile

Identify Bottlenecks:

// Add timing to critical sections
const startTime = Date.now()

// Your code here
const result = await expensiveOperation()

const duration = Date.now() - startTime
if (duration > 1000) {
logger.warn('Slow operation detected', {
operation: 'expensiveOperation',
duration,
algorithmId
})
}

Use Performance Metrics:

// Track performance metrics
GET /api/trading/algorithms/:id/performance

// Response
{
"avgSignalGenerationTime": 150, // ms
"avgOrderExecutionTime": 250, // ms
"avgIndicatorCalculationTime": 50, // ms
"cacheHitRate": 85, // %
"databaseQueryTime": 30 // ms
}

Performance Checklist

  • Using appropriate timeframe (15m+ for most strategies)
  • Limited to 3-5 symbols
  • Using 3-5 indicators maximum
  • Confirmation candles ≤ 3
  • Multi-timeframe disabled or optimized
  • Database queries use indexes
  • Caching implemented for repeated data
  • Batch operations where possible
  • Performance monitoring in place
  • No unnecessary API calls

Performance Targets

MetricTargetAcceptablePoor
Signal Generation< 100ms< 500ms> 1s
Order Execution< 200ms< 1s> 2s
Indicator Calculation< 50ms< 200ms> 500ms
Database Query< 50ms< 200ms> 500ms
Cache Hit Rate> 80%> 60%< 40%

Example: Before and After Optimization

Before (Slow)

{
"timeframe": "1m",
"symbols": [
"NSE:RELIANCE", "NSE:TCS", "NSE:INFY", "NSE:HDFC",
"NSE:ICICI", "NSE:SBIN", "NSE:BHARTI", "NSE:ITC"
],
"entryConditions": {
"confirmationCandles": 10,
"conditions": [
{ "indicator": { "type": "EMA", "period": 9 } },
{ "indicator": { "type": "EMA", "period": 21 } },
{ "indicator": { "type": "EMA", "period": 50 } },
{ "indicator": { "type": "RSI", "period": 14 } },
{ "indicator": { "type": "MACD" } },
{ "indicator": { "type": "BollingerBands" } },
{ "indicator": { "type": "Stochastic" } }
],
"multiTimeframe": {
"enabled": true,
"higherTimeframe": "1h"
}
}
}

// Performance: 2-3 seconds per signal

After (Fast)

{
"timeframe": "15m",
"symbols": [
"NSE:RELIANCE", "NSE:TCS", "NSE:INFY"
],
"entryConditions": {
"confirmationCandles": 2,
"conditions": [
{ "indicator": { "type": "EMA", "period": 9 } },
{ "indicator": { "type": "EMA", "period": 21 } },
{ "indicator": { "type": "RSI", "period": 14 } }
],
"multiTimeframe": {
"enabled": false
}
}
}

// Performance: 100-200ms per signal (10-15x faster!)