/** * šŸ’° M2 Money Supply Crypto Indicator * * Analyzes M2 money supply data for crypto trading signals * Accounts for 3-6 month correlation delays */ const https = require('https'); class M2MoneySupplyIndicator { constructor() { this.apiKey = process.env.FRED_API_KEY || 'your_fred_api_key_here'; this.baseUrl = 'https://api.stlouisfed.org/fred/series/observations'; this.cache = new Map(); this.cacheExpiry = 24 * 60 * 60 * 1000; // 24 hours } async makeRequest(url) { return new Promise((resolve, reject) => { https.get(url, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { resolve(JSON.parse(data)); } catch (e) { resolve(null); } }); }).on('error', reject); }); } async getM2Data(months = 24) { const cacheKey = `m2_${months}`; const cached = this.cache.get(cacheKey); if (cached && Date.now() - cached.timestamp < this.cacheExpiry) { return cached.data; } try { // FRED M2 Money Supply series (M2SL) const endDate = new Date(); const startDate = new Date(); startDate.setMonth(endDate.getMonth() - months); const url = `${this.baseUrl}?series_id=M2SL&api_key=${this.apiKey}&file_type=json&start_date=${startDate.toISOString().split('T')[0]}&end_date=${endDate.toISOString().split('T')[0]}`; console.log('šŸ“Š Fetching M2 data from FRED...'); const response = await this.makeRequest(url); if (response?.observations) { const data = response.observations .filter(obs => obs.value !== '.') .map(obs => ({ date: obs.date, value: parseFloat(obs.value), timestamp: new Date(obs.date).getTime() })) .sort((a, b) => a.timestamp - b.timestamp); this.cache.set(cacheKey, { data, timestamp: Date.now() }); console.log(`āœ… Retrieved ${data.length} M2 data points`); return data; } } catch (error) { console.log('āŒ M2 API error, using estimation'); } // Fallback: Generate estimated M2 data based on typical growth patterns return this.generateEstimatedM2(months); } generateEstimatedM2(months) { const data = []; const baseValue = 21500; // Approximate current M2 in billions const currentDate = new Date(); for (let i = months; i >= 0; i--) { const date = new Date(currentDate); date.setMonth(date.getMonth() - i); // Estimate based on typical M2 growth patterns const monthsFromStart = months - i; const trend = 0.08; // 8% annual growth baseline const cyclical = Math.sin(monthsFromStart * 0.3) * 0.02; // Cyclical component const growthRate = trend + cyclical; const value = baseValue * Math.pow(1 + growthRate / 12, monthsFromStart); data.push({ date: date.toISOString().split('T')[0], value: Math.round(value), timestamp: date.getTime(), estimated: true }); } console.log(`šŸ“Š Generated ${data.length} estimated M2 data points`); return data; } analyzeM2Trends(data) { if (data.length < 12) return null; const latest = data[data.length - 1]; const threeMonthsAgo = data[data.length - 4]; const sixMonthsAgo = data[data.length - 7]; const twelveMonthsAgo = data[data.length - 13]; // Calculate growth rates const m3Growth = ((latest.value - threeMonthsAgo.value) / threeMonthsAgo.value) * 4; // Annualized const m6Growth = ((latest.value - sixMonthsAgo.value) / sixMonthsAgo.value) * 2; // Annualized const m12Growth = (latest.value - twelveMonthsAgo.value) / twelveMonthsAgo.value; // Annual // Calculate trend acceleration const recentTrend = m3Growth; const longerTrend = m12Growth; const acceleration = recentTrend - longerTrend; return { current: { value: latest.value, date: latest.date, estimated: latest.estimated || false }, growth: { threeMonth: m3Growth * 100, sixMonth: m6Growth * 100, twelveMonth: m12Growth * 100 }, trend: { acceleration: acceleration * 100, direction: acceleration > 0.01 ? 'ACCELERATING' : acceleration < -0.01 ? 'DECELERATING' : 'STABLE' } }; } getCryptoSignal(analysis) { if (!analysis) return null; const { growth, trend } = analysis; let signal = 'NEUTRAL'; let strength = 0; let reasoning = []; // M2 Growth Analysis if (growth.threeMonth > 12) { signal = 'BULLISH'; strength += 0.3; reasoning.push(`High M2 growth (${growth.threeMonth.toFixed(1)}%) increases liquidity`); } else if (growth.threeMonth < 3) { signal = 'BEARISH'; strength += 0.2; reasoning.push(`Low M2 growth (${growth.threeMonth.toFixed(1)}%) reduces liquidity`); } // Trend Analysis if (trend.direction === 'ACCELERATING' && trend.acceleration > 2) { if (signal === 'NEUTRAL') signal = 'BULLISH'; strength += 0.4; reasoning.push(`M2 growth accelerating (+${trend.acceleration.toFixed(1)}%) - bullish for risk assets`); } else if (trend.direction === 'DECELERATING' && trend.acceleration < -2) { if (signal === 'NEUTRAL') signal = 'BEARISH'; strength += 0.3; reasoning.push(`M2 growth decelerating (${trend.acceleration.toFixed(1)}%) - bearish for risk assets`); } // Historical Context if (growth.twelveMonth > 15) { reasoning.push(`High annual M2 expansion (${growth.twelveMonth.toFixed(1)}%) supports inflation hedge narrative`); strength += 0.2; } else if (growth.twelveMonth < 2) { reasoning.push(`Very low M2 growth (${growth.twelveMonth.toFixed(1)}%) reduces crypto demand`); strength += 0.2; } // Correlation delay adjustment const delayAdjustment = this.getDelayAdjustedSignal(growth, trend); return { signal, strength: Math.min(1.0, strength), confidence: Math.round(strength * 100), reasoning: reasoning.join('. '), delayAdjustment, timeframe: '3-6 month correlation peak', impact: this.getImpactLevel(strength) }; } getDelayAdjustedSignal(growth, trend) { // Account for 3-6 month delay in crypto correlation return { immediate: 'Low correlation expected (0-30 days)', shortTerm: 'Building correlation (1-3 months)', mediumTerm: 'Peak correlation expected (3-6 months)', recommendation: trend.direction === 'ACCELERATING' ? 'Position for delayed bullish impact' : trend.direction === 'DECELERATING' ? 'Prepare for delayed bearish impact' : 'Monitor for trend changes' }; } getImpactLevel(strength) { if (strength > 0.7) return 'HIGH'; if (strength > 0.4) return 'MODERATE'; if (strength > 0.2) return 'LOW'; return 'MINIMAL'; } async getFullAnalysis() { try { console.log('šŸ’° Starting M2 Money Supply analysis...'); const data = await this.getM2Data(24); const analysis = this.analyzeM2Trends(data); const signal = this.getCryptoSignal(analysis); return { success: true, timestamp: new Date().toISOString(), m2Analysis: analysis, cryptoSignal: signal, dataSource: data[0]?.estimated ? 'ESTIMATED' : 'FRED_API', summary: `M2 ${analysis?.trend.direction || 'STABLE'} - ${signal?.signal || 'NEUTRAL'} for crypto (${signal?.timeframe || 'delayed impact'})` }; } catch (error) { console.error('āŒ M2 analysis error:', error); return { success: false, error: error.message, fallback: this.getFallbackAnalysis() }; } } getFallbackAnalysis() { return { m2Analysis: { current: { value: 21500, estimated: true }, growth: { threeMonth: 6.5, sixMonth: 7.2, twelveMonth: 8.1 }, trend: { direction: 'STABLE', acceleration: 0.5 } }, cryptoSignal: { signal: 'NEUTRAL', strength: 0.3, reasoning: 'Moderate M2 growth supports baseline crypto demand', timeframe: '3-6 month correlation peak', impact: 'LOW' } }; } } // Example usage async function testM2Analysis() { const m2Indicator = new M2MoneySupplyIndicator(); const result = await m2Indicator.getFullAnalysis(); console.log('\nšŸ’° M2 Money Supply Analysis:'); console.log('====================================='); console.log(`šŸ“Š Current M2: $${result.m2Analysis?.current.value}B`); console.log(`šŸ“ˆ 12M Growth: ${result.m2Analysis?.growth.twelveMonth.toFixed(1)}%`); console.log(`šŸŽÆ Trend: ${result.m2Analysis?.trend.direction}`); console.log(`šŸš€ Crypto Signal: ${result.cryptoSignal?.signal} (${result.cryptoSignal?.confidence}%)`); console.log(`šŸ’” Reasoning: ${result.cryptoSignal?.reasoning}`); console.log(`ā° Timeline: ${result.cryptoSignal?.timeframe}`); console.log(`šŸŽšļø Impact Level: ${result.cryptoSignal?.impact}`); return result; } if (require.main === module) { testM2Analysis(); } module.exports = M2MoneySupplyIndicator;