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:
| Timeframe | Candles/Day | Processing Load |
|---|---|---|
| 1m | 375 | Very High |
| 5m | 75 | High |
| 15m | 25 | Moderate |
| 30m | 13 | Low |
| 1h | 6 | Very 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
| Metric | Target | Acceptable | Poor |
|---|---|---|---|
| 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!)