feat: implement strategy-aware analysis intervals and remove manual leverage controls

- Remove manual leverage field from automation v2 page since AI now handles leverage automatically
- Fix scalping strategy analysis intervals from 60 minutes to 2 minutes for proper high-frequency trading
- Implement intelligent interval detection based on selected timeframes:
  * Scalping: 2 minutes (5m, 3m, or multiple short timeframes)
  * Day trading: 5 minutes (1h, 2h timeframes)
  * Swing trading: 15 minutes (4h, daily timeframes)
- Fix Drift SDK API calls: replace getTotalPerpPositionValue() with getFreeCollateral()
- Clean up UI by removing manual controls since AI systems handle optimization
- Fix syntax errors in automation service and balance API
- Ensure proper margin calculations using correct Drift Protocol methods

Tested: Scalping strategy now correctly analyzes every 2 minutes instead of 60 minutes
This commit is contained in:
mindesbunister
2025-07-24 13:25:41 +02:00
parent 29d0516a07
commit 451a8248d8
4 changed files with 62 additions and 31 deletions

View File

@@ -17,7 +17,6 @@ export async function POST(request) {
// Map tradeSize to tradingAmount // Map tradeSize to tradingAmount
tradingAmount: config.tradeSize || config.tradingAmount, tradingAmount: config.tradeSize || config.tradingAmount,
// Set defaults for missing fields // Set defaults for missing fields
maxLeverage: config.maxLeverage || 2,
maxDailyTrades: config.maxDailyTrades || 5, maxDailyTrades: config.maxDailyTrades || 5,
dexProvider: config.dexProvider || 'DRIFT', dexProvider: config.dexProvider || 'DRIFT',
selectedTimeframes: config.selectedTimeframes || [config.timeframe || '1h'] selectedTimeframes: config.selectedTimeframes || [config.timeframe || '1h']

View File

@@ -87,16 +87,19 @@ export async function GET() {
unrealizedPnl = 0 // Default to 0 if we can't calculate unrealizedPnl = 0 // Default to 0 if we can't calculate
} }
let freeCollateralFromDrift = 0
try { try {
// Calculate margin requirement using Drift's method // Calculate margin requirement using proper Drift SDK methods
marginRequirement = await driftClient.getUser().getTotalPerpPositionValue() / 1e6 * 0.1 // 10% margin freeCollateralFromDrift = await driftClient.getUser().getFreeCollateral() / 1e6 // Convert to USDC
marginRequirement = Math.max(0, totalCollateral - freeCollateralFromDrift) // Used collateral
} catch (marginError) { } catch (marginError) {
console.warn('⚠️ Could not get margin requirement, calculating manually:', marginError.message) console.warn('⚠️ Could not get margin requirement, calculating manually:', marginError.message)
marginRequirement = 0 // Default to 0 if we can't calculate marginRequirement = 0 // Default to 0 if we can't calculate
} }
// Calculate free collateral and other derived values // Calculate free collateral and other derived values
const freeCollateral = totalCollateral - marginRequirement + unrealizedPnl // Use Drift's free collateral if available, otherwise calculate manually
const freeCollateral = freeCollateralFromDrift > 0 ? freeCollateralFromDrift : Math.max(0, totalCollateral - marginRequirement + unrealizedPnl)
const accountValue = totalCollateral + unrealizedPnl const accountValue = totalCollateral + unrealizedPnl
const leverage = marginRequirement > 0 ? (marginRequirement / accountValue) : 0 const leverage = marginRequirement > 0 ? (marginRequirement / accountValue) : 0
const availableBalance = Math.max(0, freeCollateral) const availableBalance = Math.max(0, freeCollateral)

View File

@@ -21,7 +21,6 @@ export default function AutomationPageV2() {
selectedTimeframes: ['60'], // Multi-timeframe support selectedTimeframes: ['60'], // Multi-timeframe support
tradingAmount: 100, tradingAmount: 100,
balancePercentage: 50, // Default to 50% of available balance balancePercentage: 50, // Default to 50% of available balance
maxLeverage: 5
// stopLossPercent and takeProfitPercent removed - AI calculates these automatically // stopLossPercent and takeProfitPercent removed - AI calculates these automatically
}) })
@@ -268,22 +267,6 @@ export default function AutomationPageV2() {
</div> </div>
</div> </div>
<div className="space-y-3">
<label className="block text-sm font-bold text-purple-400">Leverage</label>
<select
className="w-full p-3 bg-gray-700 border border-gray-600 rounded-lg text-white focus:border-purple-400"
value={config.maxLeverage}
onChange={(e) => setConfig({...config, maxLeverage: parseInt(e.target.value)})}
disabled={status?.isActive}
>
<option value="1">1x - Spot</option>
<option value="2">2x</option>
<option value="3">3x</option>
<option value="5">5x</option>
<option value="10">10x</option>
<option value="20">20x</option>
</select>
</div>
</div> </div>
{/* Symbol and Position Size */} {/* Symbol and Position Size */}
@@ -336,11 +319,6 @@ export default function AutomationPageV2() {
<span>50%</span> <span>50%</span>
<span>100%</span> <span>100%</span>
</div> </div>
{balance && config.maxLeverage > 1 && (
<p className="text-xs text-green-400 mt-1">
With {config.maxLeverage}x leverage: ${(config.tradingAmount * config.maxLeverage).toFixed(2)} position exposure
</p>
)}
</div> </div>
</div> </div>
@@ -524,10 +502,6 @@ export default function AutomationPageV2() {
{config.selectedTimeframes.map(tf => timeframes.find(t => t.value === tf)?.label).filter(Boolean).join(', ')} {config.selectedTimeframes.map(tf => timeframes.find(t => t.value === tf)?.label).filter(Boolean).join(', ')}
</span> </span>
</div> </div>
<div className="flex justify-between">
<span className="text-gray-300">Leverage:</span>
<span className="text-yellow-400 font-semibold">{config.maxLeverage}x</span>
</div>
</div> </div>
) : ( ) : (
<p className="text-gray-400">Loading bot status...</p> <p className="text-gray-400">Loading bot status...</p>
@@ -653,7 +627,33 @@ export default function AutomationPageV2() {
></div> ></div>
</div> </div>
<div className="text-xs text-gray-400 text-center"> <div className="text-xs text-gray-400 text-center">
Analysis Interval: {Math.floor((status.analysisInterval || 0) / 60)}m Analysis Interval: {(() => {
const intervalSec = status.analysisInterval || 0
const intervalMin = Math.floor(intervalSec / 60)
// Determine strategy type for display
if (status.selectedTimeframes) {
const timeframes = status.selectedTimeframes
const isScalping = timeframes.includes('5') || timeframes.includes('3') ||
(timeframes.length > 1 && timeframes.every(tf => ['1', '3', '5', '15', '30'].includes(tf)))
if (isScalping) {
return '2m (Scalping Mode)'
}
const isDayTrading = timeframes.includes('60') || timeframes.includes('120')
if (isDayTrading) {
return '5m (Day Trading Mode)'
}
const isSwingTrading = timeframes.includes('240') || timeframes.includes('D')
if (isSwingTrading) {
return '15m (Swing Trading Mode)'
}
}
return `${intervalMin}m`
})()}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -168,6 +168,35 @@ export class AutomationService {
} }
private getIntervalFromTimeframe(timeframe: string): number { private getIntervalFromTimeframe(timeframe: string): number {
// Check if this is a scalping strategy (multiple short timeframes)
if (this.config?.selectedTimeframes) {
const timeframes = this.config.selectedTimeframes
const isScalping = timeframes.includes('5') || timeframes.includes('3') || (timeframes.length > 1 && timeframes.every(tf => ['1', '3', '5', '15', '30'].includes(tf)))
if (isScalping) {
console.log('🎯 Scalping strategy detected - using frequent analysis (2-3 minutes)')
return 2 * 60 * 1000 // 2 minutes for scalping
}
// Day trading strategy (short-medium timeframes)
const isDayTrading = timeframes.includes('60') || timeframes.includes('120') ||
timeframes.some(tf => ['30', '60', '120'].includes(tf))
if (isDayTrading) {
console.log('⚡ Day trading strategy detected - using moderate analysis (5-10 minutes)')
return 5 * 60 * 1000 // 5 minutes for day trading
}
// Swing trading (longer timeframes)
const isSwingTrading = timeframes.includes('240') || timeframes.includes('D') ||
timeframes.some(tf => ['240', '480', 'D', '1d'].includes(tf))
if (isSwingTrading) {
console.log('🎯 Swing trading strategy detected - using standard analysis (15-30 minutes)')
return 15 * 60 * 1000 // 15 minutes for swing trading
}
}
// Fallback to timeframe-based intervals
const intervals: { [key: string]: number } = { const intervals: { [key: string]: number } = {
'1m': 60 * 1000, '1m': 60 * 1000,
'3m': 3 * 60 * 1000, '3m': 3 * 60 * 1000,