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:
@@ -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']
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user