"use strict"; /** * AI-Driven DCA (Dollar Cost Averaging) Manager * * Intelligently adds to positions when market shows reversal potential * Manages risk by respecting leverage limits and adjusting stop loss/take profit */ Object.defineProperty(exports, "__esModule", { value: true }); exports.AIDCAManager = void 0; const ai_leverage_calculator_1 = require("./ai-leverage-calculator"); class AIDCAManager { /** * Analyze if DCA opportunity exists and calculate optimal DCA parameters */ static analyzeDCAOpportunity(params) { const { currentPosition, accountStatus, marketData, maxLeverageAllowed } = params; console.log('🔄 AI DCA Analysis:', { position: `${currentPosition.side} ${currentPosition.size} @ $${currentPosition.entryPrice}`, currentPrice: `$${marketData.price}`, pnl: `$${currentPosition.unrealizedPnl.toFixed(2)}`, availableBalance: `$${accountStatus.availableBalance.toFixed(2)}` }); // Step 1: Analyze reversal potential const reversalAnalysis = this.analyzeReversalPotential(currentPosition, marketData); if (!reversalAnalysis.hasReversalPotential) { return { shouldDCA: false, dcaAmount: 0, newAveragePrice: currentPosition.entryPrice, newStopLoss: currentPosition.stopLoss, newTakeProfit: currentPosition.takeProfit, newLeverage: accountStatus.leverage, newLiquidationPrice: accountStatus.liquidationPrice, riskAssessment: 'HIGH', reasoning: reversalAnalysis.reasoning, confidence: 0 }; } // Step 2: Calculate safe DCA amount const dcaCalculation = this.calculateSafeDCAAmount(currentPosition, accountStatus, marketData, maxLeverageAllowed); if (dcaCalculation.dcaAmount === 0) { return { shouldDCA: false, dcaAmount: 0, newAveragePrice: currentPosition.entryPrice, newStopLoss: currentPosition.stopLoss, newTakeProfit: currentPosition.takeProfit, newLeverage: accountStatus.leverage, newLiquidationPrice: accountStatus.liquidationPrice, riskAssessment: 'HIGH', reasoning: dcaCalculation.reasoning, confidence: 0 }; } // Step 3: Calculate new position parameters const newPositionSize = currentPosition.size + dcaCalculation.dcaAmount; const newAveragePrice = this.calculateNewAveragePrice(currentPosition.size, currentPosition.entryPrice, dcaCalculation.dcaAmount, marketData.price); // Step 4: Calculate new stop loss and take profit const newSLTP = this.calculateNewStopLossAndTakeProfit(currentPosition.side, newAveragePrice, newPositionSize, marketData, reversalAnalysis.confidence); // Step 5: Calculate new leverage and liquidation price const newLeverage = this.calculateNewLeverage(newPositionSize, newAveragePrice, accountStatus.accountValue, dcaCalculation.dcaAmount); const newLiquidationPrice = this.calculateNewLiquidationPrice(newAveragePrice, newLeverage, currentPosition.side); // Step 6: Final risk assessment const riskAssessment = this.assessDCARisk(newLeverage, newLiquidationPrice, newSLTP.stopLoss, accountStatus.availableBalance, dcaCalculation.dcaAmount); const result = { shouldDCA: true, dcaAmount: dcaCalculation.dcaAmount, newAveragePrice, newStopLoss: newSLTP.stopLoss, newTakeProfit: newSLTP.takeProfit, newLeverage, newLiquidationPrice, riskAssessment, reasoning: this.generateDCAReasoning(reversalAnalysis, dcaCalculation, newAveragePrice, newLeverage), confidence: reversalAnalysis.confidence }; console.log('🚀 DCA Recommendation:', { shouldDCA: result.shouldDCA, dcaAmount: `$${result.dcaAmount.toFixed(2)}`, newAverage: `$${result.newAveragePrice.toFixed(4)}`, newSL: `$${result.newStopLoss.toFixed(4)}`, newTP: `$${result.newTakeProfit.toFixed(4)}`, newLeverage: `${result.newLeverage.toFixed(1)}x`, riskLevel: result.riskAssessment, confidence: `${result.confidence}%` }); return result; } /** * Analyze market conditions for reversal potential */ static analyzeReversalPotential(position, marketData) { const priceMovement = ((marketData.price - position.entryPrice) / position.entryPrice) * 100; const isMovingAgainstPosition = (position.side === 'long' && priceMovement < 0) || (position.side === 'short' && priceMovement > 0); // Only consider DCA if price moved against us (creating discount opportunity) if (!isMovingAgainstPosition) { return { hasReversalPotential: false, reasoning: "Price moving in our favor - no DCA needed", confidence: 0 }; } let confidence = 0; const reasons = []; // Factor 1: Price drop magnitude (for longs) or rise magnitude (for shorts) const movementMagnitude = Math.abs(priceMovement); if (movementMagnitude >= 1 && movementMagnitude <= 5) { confidence += 30; reasons.push(`${movementMagnitude.toFixed(1)}% movement creates DCA opportunity`); } else if (movementMagnitude > 5 && movementMagnitude <= 10) { confidence += 40; reasons.push(`${movementMagnitude.toFixed(1)}% movement shows strong discount`); } else if (movementMagnitude > 10) { confidence += 20; reasons.push(`${movementMagnitude.toFixed(1)}% movement may indicate trend change`); } // Factor 2: 24h price change context if (marketData.priceChange24h !== undefined) { if (position.side === 'long' && marketData.priceChange24h < -3) { confidence += 25; reasons.push("24h downtrend creates long DCA opportunity"); } else if (position.side === 'short' && marketData.priceChange24h > 3) { confidence += 25; reasons.push("24h uptrend creates short DCA opportunity"); } } // Factor 3: Support/Resistance levels if (marketData.support && position.side === 'long' && marketData.price <= marketData.support * 1.02) { confidence += 20; reasons.push("Price near support level"); } if (marketData.resistance && position.side === 'short' && marketData.price >= marketData.resistance * 0.98) { confidence += 20; reasons.push("Price near resistance level"); } // Factor 4: RSI oversold/overbought if (marketData.rsi !== undefined) { if (position.side === 'long' && marketData.rsi < 35) { confidence += 15; reasons.push("RSI oversold - reversal likely"); } else if (position.side === 'short' && marketData.rsi > 65) { confidence += 15; reasons.push("RSI overbought - reversal likely"); } } // Minimum confidence threshold for DCA const hasReversalPotential = confidence >= 50; return { hasReversalPotential, reasoning: hasReversalPotential ? reasons.join(", ") : `Insufficient reversal signals (${confidence}% confidence)`, confidence }; } /** * Calculate safe DCA amount respecting leverage and liquidation limits */ static calculateSafeDCAAmount(position, accountStatus, marketData, maxLeverageAllowed) { // Use AI Leverage Calculator to determine safe additional position size const currentStopLossPrice = position.side === 'long' ? position.entryPrice * (1 - position.stopLoss / 100) : position.entryPrice * (1 + position.stopLoss / 100); const leverageResult = ai_leverage_calculator_1.default.calculateOptimalLeverage({ accountValue: accountStatus.accountValue, availableBalance: accountStatus.availableBalance, entryPrice: marketData.price, // Current price for DCA entry stopLossPrice: currentStopLossPrice, // Keep same SL initially side: position.side, maxLeverageAllowed, safetyBuffer: 0.15 // More conservative for DCA }); // Calculate maximum safe DCA amount const maxDCAUSD = accountStatus.availableBalance * 0.5; // Use up to 50% of available balance const leveragedDCAAmount = maxDCAUSD * leverageResult.recommendedLeverage; const dcaTokenAmount = leveragedDCAAmount / marketData.price; // Ensure DCA doesn't make position too large relative to account const currentPositionValue = position.size * position.entryPrice; const maxPositionValue = accountStatus.accountValue * 3; // Max 3x account value const remainingCapacity = maxPositionValue - currentPositionValue; const finalDCAAmount = Math.min(dcaTokenAmount, remainingCapacity / marketData.price, position.size * 0.5 // Max 50% of current position size ); if (finalDCAAmount < 0.01) { return { dcaAmount: 0, reasoning: "Insufficient available balance or position capacity for safe DCA" }; } return { dcaAmount: finalDCAAmount, reasoning: `Safe DCA: ${finalDCAAmount.toFixed(4)} tokens using ${leverageResult.recommendedLeverage.toFixed(1)}x leverage` }; } /** * Calculate new average price after DCA */ static calculateNewAveragePrice(currentSize, currentPrice, dcaSize, dcaPrice) { const totalValue = (currentSize * currentPrice) + (dcaSize * dcaPrice); const totalSize = currentSize + dcaSize; return totalValue / totalSize; } /** * Calculate new stop loss and take profit for the averaged position */ static calculateNewStopLossAndTakeProfit(side, newAveragePrice, newPositionSize, marketData, confidence) { // Adjust SL/TP based on confidence and position size const baseStopLossPercent = 3; // Base 3% stop loss const baseTakeProfitPercent = confidence > 70 ? 8 : 6; // Higher TP if very confident // Make SL tighter for larger positions const positionSizeMultiplier = Math.min(newPositionSize / 5, 1.5); // Cap at 1.5x const adjustedSLPercent = baseStopLossPercent / positionSizeMultiplier; let stopLoss; let takeProfit; if (side === 'long') { stopLoss = newAveragePrice * (1 - adjustedSLPercent / 100); takeProfit = newAveragePrice * (1 + baseTakeProfitPercent / 100); } else { stopLoss = newAveragePrice * (1 + adjustedSLPercent / 100); takeProfit = newAveragePrice * (1 - baseTakeProfitPercent / 100); } return { stopLoss, takeProfit }; } /** * Calculate new effective leverage after DCA */ static calculateNewLeverage(newPositionSize, newAveragePrice, accountValue, dcaAmount) { const totalPositionValue = newPositionSize * newAveragePrice; return totalPositionValue / accountValue; } /** * Calculate new liquidation price */ static calculateNewLiquidationPrice(averagePrice, leverage, side) { if (side === 'long') { return averagePrice * (1 - 1 / leverage); } else { return averagePrice * (1 + 1 / leverage); } } /** * Assess risk of DCA operation */ static assessDCARisk(newLeverage, liquidationPrice, stopLoss, availableBalance, dcaAmount) { const liquidationBuffer = Math.abs(liquidationPrice - stopLoss) / stopLoss * 100; const balanceUsagePercent = (dcaAmount * liquidationPrice) / availableBalance * 100; if (newLeverage <= 3 && liquidationBuffer >= 15 && balanceUsagePercent <= 30) return 'LOW'; if (newLeverage <= 6 && liquidationBuffer >= 10 && balanceUsagePercent <= 50) return 'MEDIUM'; return 'HIGH'; } /** * Generate reasoning for DCA decision */ static generateDCAReasoning(reversalAnalysis, dcaCalculation, newAveragePrice, newLeverage) { return `${reversalAnalysis.reasoning}. ${dcaCalculation.reasoning}. New average: $${newAveragePrice.toFixed(4)} with ${newLeverage.toFixed(1)}x leverage.`; } } exports.AIDCAManager = AIDCAManager; exports.default = AIDCAManager;