532 lines
13 KiB
Markdown
532 lines
13 KiB
Markdown
# Cache Library Usage Guide
|
|
|
|
The `@stock-bot/cache` library provides a powerful, flexible caching solution designed specifically for trading bot applications. It supports multiple cache providers including Redis/Dragonfly, in-memory caching, and hybrid caching strategies.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Installation](#installation)
|
|
2. [Quick Start](#quick-start)
|
|
3. [Cache Providers](#cache-providers)
|
|
4. [Factory Functions](#factory-functions)
|
|
5. [Cache Decorators](#cache-decorators)
|
|
6. [Trading-Specific Usage](#trading-specific-usage)
|
|
7. [Configuration](#configuration)
|
|
8. [Monitoring & Metrics](#monitoring--metrics)
|
|
9. [Error Handling](#error-handling)
|
|
10. [Best Practices](#best-practices)
|
|
|
|
## Installation
|
|
|
|
The cache library is already included in the monorepo. To use it in your service:
|
|
|
|
```json
|
|
{
|
|
"dependencies": {
|
|
"@stock-bot/cache": "*"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
### Basic Usage
|
|
|
|
```typescript
|
|
import { createCache } from '@stock-bot/cache';
|
|
|
|
// Auto-detect best cache type (hybrid if Redis available, otherwise memory)
|
|
const cache = createCache('auto');
|
|
|
|
// Basic operations
|
|
await cache.set('user:123', { name: 'John', balance: 1000 }, 3600);
|
|
const user = await cache.get<{ name: string; balance: number }>('user:123');
|
|
await cache.delete('user:123');
|
|
```
|
|
|
|
### Trading-Optimized Cache
|
|
|
|
```typescript
|
|
import { createTradingCache } from '@stock-bot/cache';
|
|
|
|
const cache = createTradingCache({
|
|
keyPrefix: 'trading:',
|
|
ttl: 300, // 5 minutes default
|
|
enableMetrics: true
|
|
});
|
|
|
|
// Cache market data
|
|
await cache.set('market:AAPL:price', { price: 150.25, timestamp: Date.now() });
|
|
```
|
|
|
|
## Cache Providers
|
|
|
|
### 1. Redis Cache (Dragonfly)
|
|
|
|
Uses Redis/Dragonfly for distributed caching with persistence and high performance.
|
|
|
|
```typescript
|
|
import { RedisCache } from '@stock-bot/cache';
|
|
|
|
const redisCache = new RedisCache({
|
|
keyPrefix: 'app:',
|
|
ttl: 3600,
|
|
enableMetrics: true
|
|
});
|
|
|
|
// Automatic connection to Dragonfly using config
|
|
await redisCache.set('key', 'value');
|
|
```
|
|
|
|
### 2. Memory Cache
|
|
|
|
In-memory caching with LRU eviction and TTL support.
|
|
|
|
```typescript
|
|
import { MemoryCache } from '@stock-bot/cache';
|
|
|
|
const memoryCache = new MemoryCache({
|
|
maxSize: 1000, // Maximum 1000 entries
|
|
ttl: 300, // 5 minutes default TTL
|
|
cleanupInterval: 60 // Cleanup every minute
|
|
});
|
|
```
|
|
|
|
### 3. Hybrid Cache
|
|
|
|
Two-tier caching combining fast memory cache (L1) with persistent Redis cache (L2).
|
|
|
|
```typescript
|
|
import { HybridCache } from '@stock-bot/cache';
|
|
|
|
const hybridCache = new HybridCache({
|
|
memoryTTL: 60, // L1 cache TTL: 1 minute
|
|
redisTTL: 3600, // L2 cache TTL: 1 hour
|
|
memoryMaxSize: 500 // L1 cache max entries
|
|
});
|
|
|
|
// Data flows: Memory -> Redis -> Database
|
|
const data = await hybridCache.get('expensive:calculation');
|
|
```
|
|
|
|
## Factory Functions
|
|
|
|
### createCache()
|
|
|
|
General-purpose cache factory with auto-detection.
|
|
|
|
```typescript
|
|
import { createCache } from '@stock-bot/cache';
|
|
|
|
// Auto-detect (recommended)
|
|
const cache = createCache('auto');
|
|
|
|
// Specific provider
|
|
const redisCache = createCache('redis', { ttl: 1800 });
|
|
const memoryCache = createCache('memory', { maxSize: 2000 });
|
|
const hybridCache = createCache('hybrid');
|
|
```
|
|
|
|
### createTradingCache()
|
|
|
|
Optimized for trading operations with sensible defaults.
|
|
|
|
```typescript
|
|
import { createTradingCache } from '@stock-bot/cache';
|
|
|
|
const tradingCache = createTradingCache({
|
|
keyPrefix: 'trading:',
|
|
ttl: 300, // 5 minutes - good for price data
|
|
enableMetrics: true
|
|
});
|
|
```
|
|
|
|
### createMarketDataCache()
|
|
|
|
Specialized for market data with short TTLs.
|
|
|
|
```typescript
|
|
import { createMarketDataCache } from '@stock-bot/cache';
|
|
|
|
const marketCache = createMarketDataCache({
|
|
priceDataTTL: 30, // 30 seconds for price data
|
|
indicatorDataTTL: 300, // 5 minutes for indicators
|
|
newsDataTTL: 1800 // 30 minutes for news
|
|
});
|
|
```
|
|
|
|
### createStrategyCache()
|
|
|
|
For strategy computations and backtesting results.
|
|
|
|
```typescript
|
|
import { createStrategyCache } from '@stock-bot/cache';
|
|
|
|
const strategyCache = createStrategyCache({
|
|
backtestTTL: 86400, // 24 hours for backtest results
|
|
signalTTL: 300, // 5 minutes for signals
|
|
optimizationTTL: 3600 // 1 hour for optimization results
|
|
});
|
|
```
|
|
|
|
## Cache Decorators
|
|
|
|
### @Cacheable
|
|
|
|
Automatically cache method results.
|
|
|
|
```typescript
|
|
import { Cacheable } from '@stock-bot/cache';
|
|
|
|
class MarketDataService {
|
|
@Cacheable({
|
|
keyGenerator: (symbol: string) => `price:${symbol}`,
|
|
ttl: 60
|
|
})
|
|
async getPrice(symbol: string): Promise<number> {
|
|
// Expensive API call
|
|
return await this.fetchPriceFromAPI(symbol);
|
|
}
|
|
}
|
|
```
|
|
|
|
### @CacheEvict
|
|
|
|
Invalidate cache entries when data changes.
|
|
|
|
```typescript
|
|
import { CacheEvict } from '@stock-bot/cache';
|
|
|
|
class PortfolioService {
|
|
@CacheEvict({
|
|
keyPattern: 'portfolio:*'
|
|
})
|
|
async updatePosition(symbol: string, quantity: number): Promise<void> {
|
|
// Update database
|
|
await this.savePosition(symbol, quantity);
|
|
// Cache automatically invalidated
|
|
}
|
|
}
|
|
```
|
|
|
|
### @CachePut
|
|
|
|
Always execute method and update cache.
|
|
|
|
```typescript
|
|
import { CachePut } from '@stock-bot/cache';
|
|
|
|
class StrategyService {
|
|
@CachePut({
|
|
keyGenerator: (strategyId: string) => `strategy:${strategyId}:result`
|
|
})
|
|
async runStrategy(strategyId: string): Promise<StrategyResult> {
|
|
const result = await this.executeStrategy(strategyId);
|
|
// Result always cached after execution
|
|
return result;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Trading-Specific Usage
|
|
|
|
### Market Data Caching
|
|
|
|
```typescript
|
|
import { createMarketDataCache, CacheKeyGenerator } from '@stock-bot/cache';
|
|
|
|
const marketCache = createMarketDataCache();
|
|
const keyGen = new CacheKeyGenerator();
|
|
|
|
// Cache price data
|
|
const priceKey = keyGen.priceKey('AAPL');
|
|
await marketCache.set(priceKey, { price: 150.25, volume: 1000000 }, 30);
|
|
|
|
// Cache technical indicators
|
|
const smaKey = keyGen.indicatorKey('AAPL', 'SMA', { period: 20 });
|
|
await marketCache.set(smaKey, 148.50, 300);
|
|
|
|
// Cache order book
|
|
const orderBookKey = keyGen.orderBookKey('AAPL');
|
|
await marketCache.set(orderBookKey, orderBookData, 5);
|
|
```
|
|
|
|
### Strategy Result Caching
|
|
|
|
```typescript
|
|
import { createStrategyCache, CacheKeyGenerator } from '@stock-bot/cache';
|
|
|
|
const strategyCache = createStrategyCache();
|
|
const keyGen = new CacheKeyGenerator();
|
|
|
|
// Cache backtest results
|
|
const backtestKey = keyGen.backtestKey('momentum-strategy', {
|
|
startDate: '2024-01-01',
|
|
endDate: '2024-12-31',
|
|
symbol: 'AAPL'
|
|
});
|
|
await strategyCache.set(backtestKey, backtestResults, 86400);
|
|
|
|
// Cache trading signals
|
|
const signalKey = keyGen.signalKey('AAPL', 'momentum-strategy');
|
|
await strategyCache.set(signalKey, { action: 'BUY', confidence: 0.85 }, 300);
|
|
```
|
|
|
|
### Portfolio Data Caching
|
|
|
|
```typescript
|
|
import { createTradingCache, CacheKeyGenerator } from '@stock-bot/cache';
|
|
|
|
const portfolioCache = createTradingCache();
|
|
const keyGen = new CacheKeyGenerator();
|
|
|
|
// Cache portfolio positions
|
|
const positionsKey = keyGen.portfolioKey('user123', 'positions');
|
|
await portfolioCache.set(positionsKey, positions, 300);
|
|
|
|
// Cache risk metrics
|
|
const riskKey = keyGen.riskKey('user123', 'VaR');
|
|
await portfolioCache.set(riskKey, { var95: 1250.50 }, 3600);
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Cache configuration is handled through the `@stock-bot/config` package. Key settings:
|
|
|
|
```typescript
|
|
// Dragonfly/Redis configuration
|
|
DRAGONFLY_HOST=localhost
|
|
DRAGONFLY_PORT=6379
|
|
DRAGONFLY_PASSWORD=your_password
|
|
DRAGONFLY_DATABASE=0
|
|
DRAGONFLY_MAX_RETRIES=3
|
|
DRAGONFLY_RETRY_DELAY=100
|
|
DRAGONFLY_CONNECT_TIMEOUT=10000
|
|
DRAGONFLY_COMMAND_TIMEOUT=5000
|
|
|
|
// TLS settings (optional)
|
|
DRAGONFLY_TLS=true
|
|
DRAGONFLY_TLS_CERT_FILE=/path/to/cert.pem
|
|
DRAGONFLY_TLS_KEY_FILE=/path/to/key.pem
|
|
DRAGONFLY_TLS_CA_FILE=/path/to/ca.pem
|
|
```
|
|
|
|
## Monitoring & Metrics
|
|
|
|
### Cache Statistics
|
|
|
|
```typescript
|
|
const cache = createTradingCache({ enableMetrics: true });
|
|
|
|
// Get cache statistics
|
|
const stats = await cache.getStats();
|
|
console.log(`Hit rate: ${stats.hitRate}%`);
|
|
console.log(`Total operations: ${stats.total}`);
|
|
console.log(`Uptime: ${stats.uptime} seconds`);
|
|
```
|
|
|
|
### Health Checks
|
|
|
|
```typescript
|
|
const cache = createCache('hybrid');
|
|
|
|
// Check cache health
|
|
const isHealthy = await cache.isHealthy();
|
|
if (!isHealthy) {
|
|
console.error('Cache is not healthy');
|
|
}
|
|
|
|
// Monitor connection status
|
|
cache.on('connect', () => console.log('Cache connected'));
|
|
cache.on('disconnect', () => console.error('Cache disconnected'));
|
|
cache.on('error', (error) => console.error('Cache error:', error));
|
|
```
|
|
|
|
### Metrics Integration
|
|
|
|
```typescript
|
|
// Export metrics to Prometheus/Grafana
|
|
const metrics = await cache.getStats();
|
|
|
|
// Custom metrics tracking
|
|
await cache.set('key', 'value', 300, {
|
|
tags: { service: 'trading-bot', operation: 'price-update' }
|
|
});
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
The cache library implements graceful error handling:
|
|
|
|
### Automatic Failover
|
|
|
|
```typescript
|
|
// Hybrid cache automatically falls back to memory if Redis fails
|
|
const hybridCache = createCache('hybrid');
|
|
|
|
// If Redis is down, data is served from memory cache
|
|
const data = await hybridCache.get('key'); // Never throws, returns null if not found
|
|
```
|
|
|
|
### Circuit Breaker Pattern
|
|
|
|
```typescript
|
|
const cache = createTradingCache({
|
|
maxConsecutiveFailures: 5, // Open circuit after 5 failures
|
|
circuitBreakerTimeout: 30000 // Try again after 30 seconds
|
|
});
|
|
|
|
try {
|
|
await cache.set('key', 'value');
|
|
} catch (error) {
|
|
// Handle cache unavailability
|
|
console.warn('Cache unavailable, falling back to direct data access');
|
|
}
|
|
```
|
|
|
|
### Error Events
|
|
|
|
```typescript
|
|
cache.on('error', (error) => {
|
|
if (error.code === 'CONNECTION_LOST') {
|
|
// Handle connection loss
|
|
await cache.reconnect();
|
|
}
|
|
});
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Choose the Right Cache Type
|
|
|
|
- **Memory Cache**: Fast access, limited by RAM, good for frequently accessed small data
|
|
- **Redis Cache**: Persistent, distributed, good for shared data across services
|
|
- **Hybrid Cache**: Best of both worlds, use for hot data with fallback
|
|
|
|
### 2. Set Appropriate TTLs
|
|
|
|
```typescript
|
|
// Trading data TTL guidelines
|
|
const TTL = {
|
|
PRICE_DATA: 30, // 30 seconds - very volatile
|
|
INDICATORS: 300, // 5 minutes - calculated values
|
|
NEWS: 1800, // 30 minutes - slower changing
|
|
BACKTEST_RESULTS: 86400, // 24 hours - expensive calculations
|
|
USER_PREFERENCES: 3600 // 1 hour - rarely change during session
|
|
};
|
|
```
|
|
|
|
### 3. Use Proper Key Naming
|
|
|
|
```typescript
|
|
// Good key naming convention
|
|
const keyGen = new CacheKeyGenerator();
|
|
const key = keyGen.priceKey('AAPL'); // trading:price:AAPL:2024-01-01
|
|
|
|
// Avoid generic keys
|
|
// Bad: "data", "result", "temp"
|
|
// Good: "trading:price:AAPL", "strategy:momentum:signals"
|
|
```
|
|
|
|
### 4. Implement Cache Warming
|
|
|
|
```typescript
|
|
// Pre-populate cache with frequently accessed data
|
|
async function warmupCache() {
|
|
const symbols = ['AAPL', 'GOOGL', 'MSFT'];
|
|
const cache = createMarketDataCache();
|
|
|
|
for (const symbol of symbols) {
|
|
const price = await fetchPrice(symbol);
|
|
await cache.set(keyGen.priceKey(symbol), price, 300);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5. Monitor Cache Performance
|
|
|
|
```typescript
|
|
// Regular performance monitoring
|
|
setInterval(async () => {
|
|
const stats = await cache.getStats();
|
|
if (stats.hitRate < 80) {
|
|
console.warn('Low cache hit rate:', stats.hitRate);
|
|
}
|
|
}, 60000); // Check every minute
|
|
```
|
|
|
|
### 6. Handle Cache Invalidation
|
|
|
|
```typescript
|
|
// Invalidate related cache entries when data changes
|
|
class PositionService {
|
|
async updatePosition(symbol: string, quantity: number) {
|
|
await this.saveToDatabase(symbol, quantity);
|
|
|
|
// Invalidate related cache entries
|
|
await cache.delete(`portfolio:positions`);
|
|
await cache.delete(`portfolio:risk:*`);
|
|
await cache.delete(`strategy:signals:${symbol}`);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Advanced Examples
|
|
|
|
### Custom Cache Provider
|
|
|
|
```typescript
|
|
class DatabaseCache implements CacheProvider {
|
|
async get<T>(key: string): Promise<T | null> {
|
|
// Implement database-backed cache
|
|
}
|
|
|
|
async set<T>(key: string, value: T, ttl?: number): Promise<boolean> {
|
|
// Store in database with expiration
|
|
}
|
|
|
|
// ... implement other methods
|
|
}
|
|
|
|
// Use with factory
|
|
const dbCache = new DatabaseCache();
|
|
```
|
|
|
|
### Batch Operations
|
|
|
|
```typescript
|
|
// Efficient batch operations
|
|
const keys = ['price:AAPL', 'price:GOOGL', 'price:MSFT'];
|
|
const values = await cache.mget<number>(keys);
|
|
|
|
const updates = new Map([
|
|
['price:AAPL', 150.25],
|
|
['price:GOOGL', 2800.50],
|
|
['price:MSFT', 350.75]
|
|
]);
|
|
await cache.mset(updates, 300);
|
|
```
|
|
|
|
### Conditional Caching
|
|
|
|
```typescript
|
|
class SmartCache {
|
|
async getOrCompute<T>(
|
|
key: string,
|
|
computeFn: () => Promise<T>,
|
|
shouldCache: (value: T) => boolean = () => true
|
|
): Promise<T> {
|
|
let value = await this.cache.get<T>(key);
|
|
|
|
if (value === null) {
|
|
value = await computeFn();
|
|
if (shouldCache(value)) {
|
|
await this.cache.set(key, value, this.defaultTTL);
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
}
|
|
```
|
|
|
|
This cache library provides enterprise-grade caching capabilities specifically designed for trading bot applications, with built-in monitoring, error handling, and performance optimization.
|