Cryptocurrency Integration: Handling Digital Currency Exchange Rates
Navigate the complexities of cryptocurrency exchange rate integration, including volatility management and regulatory considerations.
Table of Contents
Table of Contents
Cryptocurrency Integration: Handling Digital Currency Exchange Rates
Cryptocurrency integration presents unique challenges including extreme volatility, regulatory uncertainty, and technical complexity. Building robust crypto exchange systems requires specialized approaches and risk management strategies.
Cryptocurrency Integration Overview
Business Impact
- User experience enhancement
- Operational efficiency gains
- Cost optimization opportunities
- Risk mitigation strategies
Practical Implementation Examples
Cryptocurrency Price Feed Engine
// Production-ready cryptocurrency price feed engine with real-time data aggregation
interface PriceData {
symbol: string
price: number
change24h: number
changePercent24h: number
volume24h: number
marketCap: number
timestamp: number
source: string
confidence: number
}
interface AggregatedPrice {
symbol: string
price: number
spread: number
volume: number
sources: string[]
lastUpdated: number
volatility: number
outlierCount: number
confidence: number
}
interface PriceAlert {
id: string
symbol: string
condition: 'above' | 'below' | 'change'
threshold: number
currentValue: number
triggered: boolean
createdAt: number
triggeredAt?: number
}
interface ExchangeRate {
from: string
to: string
rate: number
inverse: number
timestamp: number
source: string
}
class CryptocurrencyPriceFeedEngine {
private priceCache: Map<string, PriceData[]> = new Map()
private aggregatedPrices: Map<string, AggregatedPrice> = new Map()
private priceAlerts: Map<string, PriceAlert> = new Map()
private exchangeRates: Map<string, Map<string, ExchangeRate>> = new Map()
private dataSources: Map<string, any> = new Map()
private circuitBreakers: Map<string, { isOpen: boolean; lastFail: number }> = new Map()
constructor() {
this.initializeDataSources()
this.startPriceAggregation()
this.startVolatilityMonitoring()
}
// Get real-time cryptocurrency price
async getPrice(symbol: string, useCache = true): Promise<AggregatedPrice | null> {
const normalizedSymbol = symbol.toUpperCase()
// Check circuit breaker
if (this.isCircuitBreakerOpen(normalizedSymbol)) {
return this.aggregatedPrices.get(normalizedSymbol) || null
}
try {
// Get prices from multiple sources
const sourcePrices = await this.fetchPricesFromSources(normalizedSymbol)
if (sourcePrices.length === 0) {
throw new Error(`No price data available for ${normalizedSymbol}`)
}
// Aggregate and validate prices
const aggregatedPrice = this.aggregatePrices(normalizedSymbol, sourcePrices)
// Cache the result
this.aggregatedPrices.set(normalizedSymbol, aggregatedPrice)
// Update exchange rates
await this.updateExchangeRates(normalizedSymbol, aggregatedPrice.price)
return aggregatedPrice
} catch (error) {
console.error(`Price fetch failed for ${normalizedSymbol}:`, error)
// Open circuit breaker on repeated failures
this.handlePriceFetchFailure(normalizedSymbol)
// Return cached price if available and within acceptable age
const cachedPrice = this.aggregatedPrices.get(normalizedSymbol)
if (cachedPrice && useCache && this.isCacheValid(cachedPrice)) {
return cachedPrice
}
return null
}
}
private async fetchPricesFromSources(symbol: string): Promise<PriceData[]> {
const sources = ['binance', 'coinbase', 'kraken', 'bybit', 'kucoin']
const pricePromises = sources.map(source => this.fetchFromSource(source, symbol))
const results = await Promise.allSettled(pricePromises)
return results
.filter((result): result is PromiseFulfilledResult<PriceData> => result.status === 'fulfilled')
.map(result => result.value)
.filter(price => this.validatePriceData(price))
}
private async fetchFromSource(source: string, symbol: string): Promise<PriceData> {
// In production, implement actual API calls to exchanges
// For demo, simulate API responses
await this.delay(Math.random() * 1000) // Simulate network latency
// Simulate occasional API failures
if (Math.random() < 0.1) {
throw new Error(`API failure for ${source}`)
}
const basePrice = this.getBasePrice(symbol)
const variance = (Math.random() - 0.5) * 0.02 // ±1% variance
const price = basePrice * (1 + variance)
return {
symbol,
price,
change24h: (Math.random() - 0.5) * 0.1 * basePrice,
changePercent24h: (Math.random() - 0.5) * 10,
volume24h: Math.random() * 1000000000,
marketCap: basePrice * (Math.random() * 1000000000 + 100000000),
timestamp: Date.now(),
source,
confidence: 0.8 + Math.random() * 0.2
}
}
private getBasePrice(symbol: string): number {
const basePrices: Record<string, number> = {
'BTC': 45000,
'ETH': 2500,
'BNB': 300,
'ADA': 0.5,
'SOL': 100,
'DOT': 8,
'AVAX': 20,
'MATIC': 0.8,
'LINK': 15,
'UNI': 6
}
return basePrices[symbol] || 1
}
private validatePriceData(price: PriceData): boolean {
return (
price.price > 0 &&
price.volume24h >= 0 &&
price.confidence > 0.5 &&
price.timestamp > Date.now() - 300000 // Within last 5 minutes
)
}
private aggregatePrices(symbol: string, prices: PriceData[]): AggregatedPrice {
// Remove outliers using IQR method
const priceValues = prices.map(p => p.price).sort((a, b) => a - b)
const q1 = priceValues[Math.floor(priceValues.length * 0.25)]
const q3 = priceValues[Math.floor(priceValues.length * 0.75)]
const iqr = q3 - q1
const lowerBound = q1 - 1.5 * iqr
const upperBound = q3 + 1.5 * iqr
const validPrices = prices.filter(p => p.price >= lowerBound && p.price <= upperBound)
const outlierCount = prices.length - validPrices.length
// Calculate weighted average price
const totalWeight = validPrices.reduce((sum, p) => sum + p.confidence, 0)
const weightedPrice = validPrices.reduce((sum, p) => sum + p.price * p.confidence, 0) / totalWeight
// Calculate spread (difference between highest and lowest valid prices)
const minPrice = Math.min(...validPrices.map(p => p.price))
const maxPrice = Math.max(...validPrices.map(p => p.price))
const spread = maxPrice - minPrice
// Calculate total volume
const totalVolume = validPrices.reduce((sum, p) => sum + p.volume24h, 0)
// Calculate volatility (coefficient of variation)
const mean = validPrices.reduce((sum, p) => sum + p.price, 0) / validPrices.length
const variance = validPrices.reduce((sum, p) => sum + Math.pow(p.price - mean, 2), 0) / validPrices.length
const volatility = Math.sqrt(variance) / mean
return {
symbol,
price: weightedPrice,
spread,
volume: totalVolume,
sources: validPrices.map(p => p.source),
lastUpdated: Date.now(),
volatility,
outlierCount,
confidence: validPrices.reduce((sum, p) => sum + p.confidence, 0) / validPrices.length
}
}
private async updateExchangeRates(symbol: string, price: number): Promise<void> {
// Update USD exchange rates
if (!this.exchangeRates.has(symbol)) {
this.exchangeRates.set(symbol, new Map())
}
const symbolRates = this.exchangeRates.get(symbol)!
// Update USD rate
symbolRates.set('USD', {
from: symbol,
to: 'USD',
rate: price,
inverse: 1 / price,
timestamp: Date.now(),
source: 'aggregated'
})
// Update cross rates with other major cryptocurrencies
const majorCryptos = ['BTC', 'ETH', 'BNB']
for (const otherSymbol of majorCryptos) {
if (otherSymbol === symbol) continue
const otherPrice = this.aggregatedPrices.get(otherSymbol)?.price || 1
const crossRate = price / otherPrice
symbolRates.set(otherSymbol, {
from: symbol,
to: otherSymbol,
rate: crossRate,
inverse: 1 / crossRate,
timestamp: Date.now(),
source: 'cross-calculated'
})
}
}
private isCircuitBreakerOpen(symbol: string): boolean {
const breaker = this.circuitBreakers.get(symbol)
return breaker?.isOpen && (Date.now() - breaker.lastFail) < 300000 // 5 minutes
}
private handlePriceFetchFailure(symbol: string): void {
const breaker = this.circuitBreakers.get(symbol) || { isOpen: false, lastFail: 0 }
if (!breaker.isOpen) {
// Open circuit breaker after first failure
breaker.isOpen = true
breaker.lastFail = Date.now()
this.circuitBreakers.set(symbol, breaker)
}
}
private isCacheValid(aggregatedPrice: AggregatedPrice): boolean {
return (Date.now() - aggregatedPrice.lastUpdated) < 60000 // 1 minute cache
}
private initializeDataSources(): void {
const sources = [
{
name: 'binance',
baseUrl: 'https://api.binance.com/api/v3',
rateLimit: 1000, // requests per minute
lastRequest: 0,
weight: 0.9
},
{
name: 'coinbase',
baseUrl: 'https://api.coinbase.com/v2',
rateLimit: 200,
lastRequest: 0,
weight: 0.8
}
]
sources.forEach(source => {
this.dataSources.set(source.name, source)
})
}
private async startPriceAggregation(): Promise<void> {
const majorCryptos = ['BTC', 'ETH', 'BNB', 'ADA', 'SOL', 'DOT']
// Aggregate prices every 30 seconds
setInterval(async () => {
for (const symbol of majorCryptos) {
try {
await this.getPrice(symbol, false)
} catch (error) {
console.error(`Price aggregation failed for ${symbol}:`, error)
}
}
}, 30000)
}
private async startVolatilityMonitoring(): Promise<void> {
// Monitor price volatility every 5 minutes
setInterval(() => {
this.updateVolatilityMetrics()
}, 300000)
}
private updateVolatilityMetrics(): void {
for (const [symbol, price] of this.aggregatedPrices) {
const historicalPrices = this.priceCache.get(symbol) || []
if (historicalPrices.length >= 20) {
// Calculate realized volatility
const returns = []
for (let i = 1; i < historicalPrices.length; i++) {
const return_pct = (historicalPrices[i].price - historicalPrices[i-1].price) / historicalPrices[i-1].price
returns.push(return_pct)
}
const meanReturn = returns.reduce((sum, r) => sum + r, 0) / returns.length
const variance = returns.reduce((sum, r) => sum + Math.pow(r - meanReturn, 2), 0) / returns.length
const volatility = Math.sqrt(variance * 365) // Annualized volatility
// Update price object with new volatility
price.volatility = volatility
}
}
}
// Set price alert
setAlert(symbol: string, condition: PriceAlert['condition'], threshold: number): string {
const alertId = `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
const alert: PriceAlert = {
id: alertId,
symbol: symbol.toUpperCase(),
condition,
threshold,
currentValue: this.aggregatedPrices.get(symbol.toUpperCase())?.price || 0,
triggered: false,
createdAt: Date.now()
}
this.priceAlerts.set(alertId, alert)
// Start monitoring this alert
this.monitorAlert(alertId)
return alertId
}
private monitorAlert(alertId: string): void {
const alert = this.priceAlerts.get(alertId)
if (!alert) return
const checkInterval = setInterval(() => {
const currentPrice = this.aggregatedPrices.get(alert.symbol)?.price || 0
alert.currentValue = currentPrice
this.priceAlerts.set(alertId, alert)
if (this.shouldTriggerAlert(alert, currentPrice)) {
alert.triggered = true
alert.triggeredAt = Date.now()
this.priceAlerts.set(alertId, alert)
console.log(`Price alert triggered: ${alert.symbol} ${alert.condition} ${alert.threshold}`)
// In production, send notifications
this.sendAlertNotification(alert)
clearInterval(checkInterval)
}
}, 5000) // Check every 5 seconds
}
private shouldTriggerAlert(alert: PriceAlert, currentPrice: number): boolean {
switch (alert.condition) {
case 'above':
return currentPrice > alert.threshold
case 'below':
return currentPrice < alert.threshold
case 'change':
const changePercent = Math.abs((currentPrice - alert.threshold) / alert.threshold) * 100
return changePercent >= 1 // Trigger on 1% change
default:
return false
}
}
private sendAlertNotification(alert: PriceAlert): void {
// In production, integrate with notification systems (Slack, email, SMS, etc.)
console.log(`🚨 PRICE ALERT: ${alert.symbol} ${alert.condition} ${alert.threshold}. Current: ${alert.currentValue}`)
}
// Get exchange rate between two cryptocurrencies
getExchangeRate(from: string, to: string): ExchangeRate | null {
const fromSymbol = from.toUpperCase()
const toSymbol = to.toUpperCase()
if (fromSymbol === toSymbol) {
return {
from: fromSymbol,
to: toSymbol,
rate: 1,
inverse: 1,
timestamp: Date.now(),
source: 'identity'
}
}
// Try direct rate first
const fromRates = this.exchangeRates.get(fromSymbol)
if (fromRates) {
const directRate = fromRates.get(toSymbol)
if (directRate) return directRate
}
// Calculate cross rate via USD
const fromUsdRate = this.exchangeRates.get(fromSymbol)?.get('USD')
const toUsdRate = this.exchangeRates.get(toSymbol)?.get('USD')
if (fromUsdRate && toUsdRate) {
return {
from: fromSymbol,
to: toSymbol,
rate: fromUsdRate.inverse / toUsdRate.inverse,
inverse: toUsdRate.inverse / fromUsdRate.inverse,
timestamp: Math.max(fromUsdRate.timestamp, toUsdRate.timestamp),
source: 'cross-via-usd'
}
}
return null
}
// Batch price update for multiple symbols
async updateMultiplePrices(symbols: string[]): Promise<Map<string, AggregatedPrice>> {
const pricePromises = symbols.map(symbol => this.getPrice(symbol, false))
const results = await Promise.allSettled(pricePromises)
const priceMap = new Map<string, AggregatedPrice>()
results.forEach((result, index) => {
if (result.status === 'fulfilled' && result.value) {
priceMap.set(symbols[index], result.value)
}
})
return priceMap
}
// Get price history for analysis
getPriceHistory(symbol: string, hours: number = 24): PriceData[] {
const cachedPrices = this.priceCache.get(symbol) || []
const cutoffTime = Date.now() - (hours * 60 * 60 * 1000)
return cachedPrices.filter(price => price.timestamp >= cutoffTime)
}
// Cache price data
cachePriceData(price: PriceData): void {
const symbol = price.symbol
if (!this.priceCache.has(symbol)) {
this.priceCache.set(symbol, [])
}
const prices = this.priceCache.get(symbol)!
prices.push(price)
// Keep only last 1000 price points
if (prices.length > 1000) {
prices.shift()
}
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}
// Get aggregated price statistics
getPriceStatistics(symbol: string, period: '1h' | '24h' | '7d'): {
high: number
low: number
average: number
volatility: number
volume: number
} | null {
const history = this.getPriceHistory(symbol, period === '1h' ? 1 : period === '24h' ? 24 : 168)
if (history.length === 0) return null
const prices = history.map(h => h.price)
const volumes = history.map(h => h.volume24h)
return {
high: Math.max(...prices),
low: Math.min(...prices),
average: prices.reduce((sum, p) => sum + p, 0) / prices.length,
volatility: this.calculateVolatility(prices),
volume: volumes.reduce((sum, v) => sum + v, 0)
}
}
private calculateVolatility(prices: number[]): number {
if (prices.length < 2) return 0
const returns = []
for (let i = 1; i < prices.length; i++) {
returns.push((prices[i] - prices[i-1]) / prices[i-1])
}
const mean = returns.reduce((sum, r) => sum + r, 0) / returns.length
const variance = returns.reduce((sum, r) => sum + Math.pow(r - mean, 2), 0) / returns.length
return Math.sqrt(variance)
}
}
// Initialize cryptocurrency price feed engine
const cryptoPriceFeed = new CryptocurrencyPriceFeedEngine()
// Price feed API endpoints
app.get('/api/crypto/price/:symbol', async (req, res) => {
try {
const { symbol } = req.params
if (!symbol) {
return res.status(400).json({ error: 'Symbol required' })
}
const price = await cryptoPriceFeed.getPrice(symbol)
if (!price) {
return res.status(404).json({ error: 'Price not available' })
}
res.json({
price,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Price fetch error:', error)
res.status(500).json({ error: 'Failed to fetch price' })
}
})
// Batch price endpoint
app.post('/api/crypto/prices', async (req, res) => {
try {
const { symbols } = req.body
if (!Array.isArray(symbols) || symbols.length === 0) {
return res.status(400).json({ error: 'Symbols array required' })
}
const prices = await cryptoPriceFeed.updateMultiplePrices(symbols)
res.json({
prices: Array.from(prices.entries()).map(([symbol, price]) => ({ symbol, ...price })),
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Batch price fetch error:', error)
res.status(500).json({ error: 'Failed to fetch prices' })
}
})
// Price alert endpoint
app.post('/api/crypto/alert', (req, res) => {
try {
const { symbol, condition, threshold } = req.body
if (!symbol || !condition || threshold === undefined) {
return res.status(400).json({
error: 'symbol, condition, and threshold required'
})
}
if (!['above', 'below', 'change'].includes(condition)) {
return res.status(400).json({
error: 'Invalid condition. Must be above, below, or change'
})
}
const alertId = cryptoPriceFeed.setAlert(symbol, condition, threshold)
res.json({
success: true,
alertId,
message: 'Price alert set successfully',
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Set alert error:', error)
res.status(500).json({ error: 'Failed to set alert' })
}
})
// Exchange rate endpoint
app.get('/api/crypto/exchange-rate/:from/:to', (req, res) => {
try {
const { from, to } = req.params
if (!from || !to) {
return res.status(400).json({ error: 'from and to symbols required' })
}
const rate = cryptoPriceFeed.getExchangeRate(from, to)
if (!rate) {
return res.status(404).json({ error: 'Exchange rate not available' })
}
res.json({
rate,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Exchange rate error:', error)
res.status(500).json({ error: 'Failed to get exchange rate' })
}
})
// Price statistics endpoint
app.get('/api/crypto/statistics/:symbol/:period', (req, res) => {
try {
const { symbol, period } = req.params
if (!symbol || !period) {
return res.status(400).json({ error: 'symbol and period required' })
}
if (!['1h', '24h', '7d'].includes(period)) {
return res.status(400).json({
error: 'Invalid period. Must be 1h, 24h, or 7d'
})
}
const statistics = cryptoPriceFeed.getPriceStatistics(symbol, period as any)
if (!statistics) {
return res.status(404).json({ error: 'Statistics not available' })
}
res.json({
statistics,
symbol,
period,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Statistics error:', error)
res.status(500).json({ error: 'Failed to get statistics' })
}
})
console.log('Cryptocurrency Price Feed Engine initialized')Volatility Management System
// Advanced volatility management system for cryptocurrency markets
interface VolatilityMetrics {
symbol: string
currentVolatility: number
historicalVolatility: number
impliedVolatility: number
volatilityRegime: 'low' | 'normal' | 'high' | 'extreme'
trend: 'increasing' | 'decreasing' | 'stable'
confidence: number
lastUpdated: number
}
interface VolatilityAlert {
id: string
symbol: string
type: 'threshold' | 'regime_change' | 'spike'
severity: 'low' | 'medium' | 'high' | 'critical'
message: string
triggered: boolean
createdAt: number
resolvedAt?: number
}
interface RiskAdjustment {
symbol: string
basePositionSize: number
adjustedPositionSize: number
volatilityMultiplier: number
confidenceAdjustment: number
recommendedHedgeRatio: number
maxDrawdown: number
timestamp: number
}
class CryptocurrencyVolatilityManager {
private volatilityMetrics: Map<string, VolatilityMetrics> = new Map()
private volatilityHistory: Map<string, number[]> = new Map()
private volatilityAlerts: Map<string, VolatilityAlert> = new Map()
private riskAdjustments: Map<string, RiskAdjustment> = new Map()
private volatilityModels: Map<string, any> = new Map()
constructor() {
this.initializeVolatilityModels()
this.startVolatilityMonitoring()
this.startRiskAdjustmentCalculation()
}
// Calculate comprehensive volatility metrics
async calculateVolatilityMetrics(symbol: string): Promise<VolatilityMetrics> {
const priceHistory = this.volatilityHistory.get(symbol) || []
if (priceHistory.length < 20) {
throw new Error(`Insufficient price history for ${symbol}`)
}
try {
// Calculate current (realized) volatility
const currentVolatility = this.calculateRealizedVolatility(priceHistory.slice(-20))
// Calculate historical volatility (longer timeframe)
const historicalVolatility = this.calculateHistoricalVolatility(priceHistory.slice(-100))
// Estimate implied volatility (using options data in production)
const impliedVolatility = this.estimateImpliedVolatility(symbol, currentVolatility)
// Determine volatility regime
const volatilityRegime = this.determineVolatilityRegime(currentVolatility)
// Analyze volatility trend
const trend = this.analyzeVolatilityTrend(symbol, currentVolatility)
// Calculate confidence level
const confidence = this.calculateVolatilityConfidence(priceHistory, currentVolatility)
const metrics: VolatilityMetrics = {
symbol,
currentVolatility,
historicalVolatility,
impliedVolatility,
volatilityRegime,
trend,
confidence,
lastUpdated: Date.now()
}
this.volatilityMetrics.set(symbol, metrics)
return metrics
} catch (error) {
console.error(`Volatility calculation failed for ${symbol}:`, error)
// Return default metrics
return {
symbol,
currentVolatility: 0.5,
historicalVolatility: 0.5,
impliedVolatility: 0.5,
volatilityRegime: 'normal',
trend: 'stable',
confidence: 0.5,
lastUpdated: Date.now()
}
}
}
private calculateRealizedVolatility(prices: number[]): number {
if (prices.length < 2) return 0
const returns = []
for (let i = 1; i < prices.length; i++) {
const dailyReturn = Math.log(prices[i] / prices[i-1])
returns.push(dailyReturn)
}
const mean = returns.reduce((sum, r) => sum + r, 0) / returns.length
const variance = returns.reduce((sum, r) => sum + Math.pow(r - mean, 2), 0) / returns.length
// Annualize daily volatility
return Math.sqrt(variance * 365)
}
private calculateHistoricalVolatility(prices: number[]): number {
return this.calculateRealizedVolatility(prices)
}
private estimateImpliedVolatility(symbol: string, realizedVol: number): number {
// In production, use actual options data
// For demo, use a simple adjustment based on market conditions
const marketAdjustment = 0.8 + Math.random() * 0.4 // 0.8 to 1.2 multiplier
const baseImpliedVol = realizedVol * marketAdjustment
// Add market stress factor
const stressFactor = this.getMarketStressFactor()
return baseImpliedVol * (1 + stressFactor)
}
private getMarketStressFactor(): number {
// In production, analyze market indicators like VIX, funding rates, etc.
return Math.random() * 0.3 // 0 to 0.3 stress factor
}
private determineVolatilityRegime(volatility: number): VolatilityMetrics['volatilityRegime'] {
if (volatility < 0.3) return 'low'
if (volatility < 0.6) return 'normal'
if (volatility < 1.0) return 'high'
return 'extreme'
}
private analyzeVolatilityTrend(symbol: string, currentVol: number): VolatilityMetrics['trend'] {
const metrics = this.volatilityMetrics.get(symbol)
if (!metrics) return 'stable'
const volChange = (currentVol - metrics.currentVolatility) / metrics.currentVolatility
if (volChange > 0.1) return 'increasing'
if (volChange < -0.1) return 'decreasing'
return 'stable'
}
private calculateVolatilityConfidence(prices: number[], volatility: number): number {
// Higher confidence with more data points and stable regime
const dataPointFactor = Math.min(prices.length / 100, 1) // Max confidence at 100+ points
const stabilityFactor = Math.max(0, 1 - Math.abs(volatility - 0.5)) // Higher confidence at moderate volatility
return (dataPointFactor + stabilityFactor) / 2
}
private initializeVolatilityModels(): void {
// Initialize GARCH, EWMA, and other volatility models
const models = [
{
name: 'GARCH(1,1)',
parameters: { alpha: 0.1, beta: 0.8, omega: 0.0001 }
},
{
name: 'EWMA',
parameters: { lambda: 0.94 }
}
]
models.forEach(model => {
this.volatilityModels.set(model.name, model)
})
}
private startVolatilityMonitoring(): void {
// Monitor volatility every 5 minutes
setInterval(async () => {
const symbols = Array.from(this.volatilityHistory.keys())
for (const symbol of symbols) {
try {
await this.calculateVolatilityMetrics(symbol)
// Check for volatility alerts
this.checkVolatilityAlerts(symbol)
} catch (error) {
console.error(`Volatility monitoring failed for ${symbol}:`, error)
}
}
}, 300000)
}
private checkVolatilityAlerts(symbol: string): void {
const metrics = this.volatilityMetrics.get(symbol)
if (!metrics) return
// Threshold alerts
if (metrics.currentVolatility > 1.2 && metrics.volatilityRegime === 'extreme') {
this.createVolatilityAlert(symbol, 'threshold', 'critical',
`Extreme volatility detected: ${(metrics.currentVolatility * 100).toFixed(1)}%`)
}
// Regime change alerts
if (metrics.trend === 'increasing' && metrics.volatilityRegime === 'high') {
this.createVolatilityAlert(symbol, 'regime_change', 'high',
'Volatility increasing towards extreme levels')
}
}
private createVolatilityAlert(symbol: string, type: string, severity: string, message: string): void {
const alertId = `vol_alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
const alert: VolatilityAlert = {
id: alertId,
symbol,
type: type as any,
severity: severity as any,
message,
triggered: true,
createdAt: Date.now()
}
this.volatilityAlerts.set(alertId, alert)
console.log(`🚨 VOLATILITY ALERT [${severity.toUpperCase()}]: ${symbol} - ${message}`)
}
private startRiskAdjustmentCalculation(): void {
// Calculate risk adjustments every minute
setInterval(() => {
this.calculateAllRiskAdjustments()
}, 60000)
}
private calculateAllRiskAdjustments(): void {
const symbols = Array.from(this.volatilityMetrics.keys())
for (const symbol of symbols) {
try {
const adjustment = this.calculateRiskAdjustment(symbol)
this.riskAdjustments.set(symbol, adjustment)
} catch (error) {
console.error(`Risk adjustment calculation failed for ${symbol}:`, error)
}
}
}
private calculateRiskAdjustment(symbol: string): RiskAdjustment {
const metrics = this.volatilityMetrics.get(symbol)
if (!metrics) {
throw new Error(`No volatility metrics available for ${symbol}`)
}
// Base position size (in production, use portfolio allocation)
const basePositionSize = 1000000 // $1M base position
// Volatility multiplier (inverse relationship)
const volatilityMultiplier = Math.max(0.1, 1 / (1 + metrics.currentVolatility))
// Confidence adjustment
const confidenceAdjustment = metrics.confidence
// Adjusted position size
const adjustedPositionSize = basePositionSize * volatilityMultiplier * confidenceAdjustment
// Recommended hedge ratio based on volatility
const recommendedHedgeRatio = Math.min(0.8, metrics.currentVolatility * 0.6)
// Maximum drawdown estimate
const maxDrawdown = metrics.currentVolatility * 2 // Conservative estimate
return {
symbol,
basePositionSize,
adjustedPositionSize,
volatilityMultiplier,
confidenceAdjustment,
recommendedHedgeRatio,
maxDrawdown,
timestamp: Date.now()
}
}
// Get volatility metrics for a symbol
getVolatilityMetrics(symbol: string): VolatilityMetrics | null {
return this.volatilityMetrics.get(symbol) || null
}
// Get risk adjustment for a symbol
getRiskAdjustment(symbol: string): RiskAdjustment | null {
return this.riskAdjustments.get(symbol) || null
}
// Update price history for volatility calculation
updatePriceHistory(symbol: string, price: number): void {
if (!this.volatilityHistory.has(symbol)) {
this.volatilityHistory.set(symbol, [])
}
const history = this.volatilityHistory.get(symbol)!
history.push(price)
// Keep only last 1000 data points
if (history.length > 1000) {
history.shift()
}
}
// Get volatility alerts
getActiveVolatilityAlerts(): VolatilityAlert[] {
return Array.from(this.volatilityAlerts.values())
.filter(alert => alert.triggered && !alert.resolvedAt)
}
// Resolve volatility alert
resolveVolatilityAlert(alertId: string): boolean {
const alert = this.volatilityAlerts.get(alertId)
if (!alert) return false
alert.resolvedAt = Date.now()
this.volatilityAlerts.set(alertId, alert)
return true
}
// Generate volatility report
generateVolatilityReport(): {
totalSymbols: number
extremeVolatility: string[]
highVolatility: string[]
normalVolatility: string[]
lowVolatility: string[]
alerts: number
averageVolatility: number
riskAdjustments: number
} {
const symbols = Array.from(this.volatilityMetrics.keys())
const metrics = symbols.map(s => this.volatilityMetrics.get(s)!).filter(Boolean)
const extremeVolatility = metrics.filter(m => m.volatilityRegime === 'extreme').map(m => m.symbol)
const highVolatility = metrics.filter(m => m.volatilityRegime === 'high').map(m => m.symbol)
const normalVolatility = metrics.filter(m => m.volatilityRegime === 'normal').map(m => m.symbol)
const lowVolatility = metrics.filter(m => m.volatilityRegime === 'low').map(m => m.symbol)
const averageVolatility = metrics.reduce((sum, m) => sum + m.currentVolatility, 0) / metrics.length
const activeAlerts = this.getActiveVolatilityAlerts().length
return {
totalSymbols: symbols.length,
extremeVolatility,
highVolatility,
normalVolatility,
lowVolatility,
alerts: activeAlerts,
averageVolatility,
riskAdjustments: this.riskAdjustments.size
}
}
}
// Initialize volatility management system
const volatilityManager = new CryptocurrencyVolatilityManager()
// Volatility metrics endpoint
app.get('/api/crypto/volatility/:symbol', async (req, res) => {
try {
const { symbol } = req.params
if (!symbol) {
return res.status(400).json({ error: 'Symbol required' })
}
const metrics = await volatilityManager.calculateVolatilityMetrics(symbol)
res.json({
metrics,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Volatility metrics error:', error)
res.status(500).json({ error: 'Failed to calculate volatility metrics' })
}
})
// Risk adjustment endpoint
app.get('/api/crypto/risk-adjustment/:symbol', (req, res) => {
try {
const { symbol } = req.params
if (!symbol) {
return res.status(400).json({ error: 'Symbol required' })
}
const adjustment = volatilityManager.getRiskAdjustment(symbol)
if (!adjustment) {
return res.status(404).json({ error: 'Risk adjustment not available' })
}
res.json({
adjustment,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Risk adjustment error:', error)
res.status(500).json({ error: 'Failed to get risk adjustment' })
}
})
// Volatility alerts endpoint
app.get('/api/crypto/volatility-alerts', (req, res) => {
try {
const alerts = volatilityManager.getActiveVolatilityAlerts()
res.json({
alerts,
count: alerts.length,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Volatility alerts error:', error)
res.status(500).json({ error: 'Failed to get volatility alerts' })
}
})
// Volatility report endpoint
app.get('/api/crypto/volatility-report', (req, res) => {
try {
const report = volatilityManager.generateVolatilityReport()
res.json({
report,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('Volatility report error:', error)
res.status(500).json({ error: 'Failed to generate volatility report' })
}
})
console.log('Cryptocurrency Volatility Management System initialized')Settlement and Accounting
Choosing how you settle crypto amounts impacts user pricing and PnL.
Pricing Windows and Quotes
- Quote modes: firm quote (locked n seconds) vs indicative (refreshing)
- Price sources: mid, best bid/ask, VWAP over window
- Slippage controls: max deviation %, reject if exceeded
- Fees/spread: explicit vs embedded; disclose to users
Settlement Models
- Instant convert to fiat (no crypto custody; exchange execution risk)
- Deferred batch conversion (better fees; inventory risk during window)
- Natural hedging (match in/out flows; net exposure control)
- On-chain settle (monitor mempool, confirmations; reorg handling)
Accounting Considerations
- Lot tracking (FIFO/LIFO) for inventory valuation
- PnL recognition on conversion vs at delivery
- FX triangulation: CRYPTO→USD→LOCAL; record both legs
- Reconciliation: exchange fills vs internal quotes, daily
Risk and Compliance
- Volatility limits: circuit breakers on extreme spread/vol
- Exchange failover: multi-venue routing; health/latency scoring
- Wallet hygiene: allowlist addresses, chain risk screening
- AML/KYC: Travel Rule where applicable, sanctions screening
- Geo controls: restrict unsupported jurisdictions
Monitoring and SRE
- Golden signals: price latency, spread, error rate, quote success
- SLIs/SLOs: p95 quote latency, price staleness < 10s, fill success rate
- Alerting: datasource lag, diverging sources, spread spikes, circuit open
- Runbooks: datasource failover, stale pricing, extreme volatility days
Conclusion
Crypto integration succeeds with resilient pricing, clear settlement, and strict risk controls. Start with firm quotes + instant conversion, add venues for redundancy, and continuously monitor spreads and latency.
Build robust crypto pricing with our aggregation and risk tooling: multi-venue feeds, volatility controls, and audit-ready accounting hooks.