Fix complete trading system: SL/TP working, live trading operational

- Fixed network connectivity and live trading mode
- Updated Drift SDK integration with proper API methods
- Fixed BN type conversions and minimum order size
- Fixed stop loss & take profit conditional orders
- Complete risk management system now functional
This commit is contained in:
mindesbunister
2025-07-25 09:38:41 +02:00
parent 0e3baa139f
commit 9175bb3add
7 changed files with 342 additions and 103 deletions

View File

@@ -210,7 +210,9 @@ export async function POST(request) {
// Store analysis for learning
await storeAnalysisForLearning(symbol, analysis)
} else {
throw new Error('AI analysis returned null')
console.log('AI analysis returned null (possibly rate limited) - continuing without analysis')
progressTracker.updateStep(sessionId, 'analysis', 'skipped', 'AI analysis skipped due to rate limits or other issues')
analysis = null
}
} catch (analysisError) {

View File

@@ -105,16 +105,48 @@ export async function POST(request) {
// Real Drift trading implementation
console.log('💰 Executing REAL Drift perpetual trade')
// Import Drift SDK components
const { DriftClient, initialize, MarketType, PositionDirection, OrderType } = await import('@drift-labs/sdk')
// Import Drift SDK components including Wallet and BN
const { DriftClient, initialize, MarketType, PositionDirection, OrderType, OrderTriggerCondition, Wallet, BN } = await import('@drift-labs/sdk')
const { Connection, Keypair } = await import('@solana/web3.js')
const { Wallet } = await import('@coral-xyz/anchor')
// Initialize connection and wallet
const connection = new Connection(
process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com',
'confirmed'
)
// Initialize connection and wallet with configured RPC endpoints in priority order
const rpcEndpoints = [
process.env.SOLANA_RPC_URL_PRIMARY, // Helius (best for trading)
process.env.SOLANA_RPC_URL_SECONDARY, // Solana official
process.env.SOLANA_RPC_URL_TERTIARY, // Alchemy
process.env.SOLANA_RPC_URL_BACKUP, // Ankr
process.env.SOLANA_RPC_URL, // Fallback env var
'https://mainnet.helius-rpc.com/?api-key=5e236449-f936-4af7-ae38-f15e2f1a3757'
].filter(Boolean)
let connection = null
let connectionError = null
// Try each RPC endpoint until one works
for (const endpoint of rpcEndpoints) {
try {
console.log(`🌐 Attempting to connect to RPC: ${endpoint}`)
connection = new Connection(endpoint, 'confirmed')
// Test the connection
await connection.getLatestBlockhash()
console.log(`✅ Successfully connected to RPC: ${endpoint}`)
break
} catch (error) {
console.log(`❌ RPC ${endpoint} failed: ${error.message}`)
connectionError = error
connection = null
}
}
if (!connection) {
console.error('❌ All RPC endpoints failed:', connectionError)
return NextResponse.json({
success: false,
error: 'Unable to connect to Solana network',
details: connectionError?.message
}, { status: 503 })
}
if (!process.env.SOLANA_PRIVATE_KEY) {
return NextResponse.json({
@@ -155,13 +187,19 @@ export async function POST(request) {
// Calculate position size in base asset units
const currentPrice = 166.75 // Get from oracle in production
const baseAssetAmount = (amount * leverage) / currentPrice * 1e9 // Convert to lamports for SOL
const calculatedAmount = (amount * leverage) / currentPrice * 1e9 // Convert to lamports for SOL
// Ensure minimum order size (Drift requires at least 10,000,000 units)
const minOrderSize = 10000000 // 0.01 SOL in protocol units
const baseAssetAmount = Math.max(calculatedAmount, minOrderSize)
console.log('📊 Trade parameters:', {
marketIndex,
direction: direction === PositionDirection.LONG ? 'LONG' : 'SHORT',
requestedAmount: calculatedAmount.toString(),
baseAssetAmount: baseAssetAmount.toString(),
leverage
leverage,
minOrderSize: minOrderSize.toString()
})
// Place market order
@@ -169,12 +207,12 @@ export async function POST(request) {
orderType: OrderType.MARKET,
marketType: MarketType.PERP,
direction,
baseAssetAmount: Math.floor(baseAssetAmount),
baseAssetAmount: new BN(Math.floor(baseAssetAmount)),
marketIndex,
}
console.log('🎯 Placing Drift market order...')
const txSig = await driftClient.placeOrder(orderParams)
console.log('🎯 Placing Drift perpetual market order...')
const txSig = await driftClient.placeAndTakePerpOrder(orderParams)
console.log('✅ Drift order placed:', txSig)
@@ -185,17 +223,18 @@ export async function POST(request) {
if (stopLoss) {
try {
const stopLossParams = {
orderType: OrderType.LIMIT,
orderType: OrderType.TRIGGER_LIMIT,
marketType: MarketType.PERP,
direction: direction === PositionDirection.LONG ? PositionDirection.SHORT : PositionDirection.LONG,
baseAssetAmount: Math.floor(baseAssetAmount),
price: stopLoss * 1e6, // Price in 6 decimal format
baseAssetAmount: new BN(Math.floor(baseAssetAmount)),
price: new BN(Math.floor(stopLoss * 1e6)), // Price in 6 decimal format
marketIndex,
triggerPrice: stopLoss * 1e6,
triggerCondition: direction === PositionDirection.LONG ? 'below' : 'above',
triggerPrice: new BN(Math.floor(stopLoss * 1e6)),
triggerCondition: direction === PositionDirection.LONG ? OrderTriggerCondition.BELOW : OrderTriggerCondition.ABOVE,
reduceOnly: true,
}
const slTxSig = await driftClient.placeOrder(stopLossParams)
const slTxSig = await driftClient.placePerpOrder(stopLossParams)
stopLossOrderId = slTxSig
console.log('🛑 Stop loss order placed:', slTxSig)
} catch (slError) {
@@ -206,17 +245,18 @@ export async function POST(request) {
if (takeProfit) {
try {
const takeProfitParams = {
orderType: OrderType.LIMIT,
orderType: OrderType.TRIGGER_LIMIT,
marketType: MarketType.PERP,
direction: direction === PositionDirection.LONG ? PositionDirection.SHORT : PositionDirection.LONG,
baseAssetAmount: Math.floor(baseAssetAmount),
price: takeProfit * 1e6, // Price in 6 decimal format
baseAssetAmount: new BN(Math.floor(baseAssetAmount)),
price: new BN(Math.floor(takeProfit * 1e6)), // Price in 6 decimal format
marketIndex,
triggerPrice: takeProfit * 1e6,
triggerCondition: direction === PositionDirection.LONG ? 'above' : 'below',
triggerPrice: new BN(Math.floor(takeProfit * 1e6)),
triggerCondition: direction === PositionDirection.LONG ? OrderTriggerCondition.ABOVE : OrderTriggerCondition.BELOW,
reduceOnly: true,
}
const tpTxSig = await driftClient.placeOrder(takeProfitParams)
const tpTxSig = await driftClient.placePerpOrder(takeProfitParams)
takeProfitOrderId = tpTxSig
console.log('🎯 Take profit order placed:', tpTxSig)
} catch (tpError) {

View File

@@ -156,67 +156,66 @@ export default function AutomationPageV2() {
return (
<div className="space-y-6">
{/* Header with Start/Stop */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold text-white">Automated Trading</h1>
<p className="text-gray-400 mt-1">Multi-Timeframe Analysis</p>
</div>
<div className="flex space-x-3">
{status?.isActive ? (
<button
onClick={handleStop}
disabled={loading}
className="px-6 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors disabled:opacity-50 font-semibold"
>
{loading ? 'Stopping...' : 'STOP'}
</button>
) : (
<button
onClick={handleStart}
disabled={loading}
className="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors disabled:opacity-50 font-semibold"
>
{loading ? 'Starting...' : 'START'}
</button>
)}
</div>
</div>
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6">
{/* Configuration Panel */}
<div className="xl:col-span-2 space-y-6">
<div className="bg-gray-800 p-6 rounded-lg border border-gray-700">
<h3 className="text-xl font-bold text-white mb-6">Configuration</h3>
{/* Header with Start/Stop Button */}
<div className="flex items-center justify-between mb-6">
<h3 className="text-xl font-bold text-white">Configuration</h3>
<div className="flex space-x-3">
{status?.isActive ? (
<button
onClick={handleStop}
disabled={loading}
className="px-6 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors disabled:opacity-50 font-semibold"
>
{loading ? 'Stopping...' : 'STOP'}
</button>
) : (
<button
onClick={handleStart}
disabled={loading}
className="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors disabled:opacity-50 font-semibold"
>
{loading ? 'Starting...' : status?.rateLimitHit ? 'RESTART' : 'START'}
</button>
)}
</div>
</div>
{/* Trading Mode */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
<div className="space-y-3">
<label className="block text-sm font-bold text-blue-400">Trading Mode</label>
<div className="space-y-2">
<label className="flex items-center space-x-3 cursor-pointer p-3 rounded-lg border border-gray-600 hover:border-blue-500 transition-colors">
<input
type="radio"
className="w-4 h-4 text-blue-600"
name="mode"
checked={config.mode === 'SIMULATION'}
onChange={() => setConfig({...config, mode: 'SIMULATION'})}
disabled={status?.isActive}
/>
<span className="text-white">Paper Trading</span>
</label>
<label className="flex items-center space-x-3 cursor-pointer p-3 rounded-lg border border-gray-600 hover:border-green-500 transition-colors">
<input
type="radio"
className="w-4 h-4 text-green-600"
name="mode"
checked={config.mode === 'LIVE'}
onChange={() => setConfig({...config, mode: 'LIVE'})}
disabled={status?.isActive}
/>
{/* Trading Mode - Side by Side Radio Buttons with Logos */}
<div className="mb-6">
<label className="block text-sm font-bold text-blue-400 mb-3">Trading Mode</label>
<div className="grid grid-cols-2 gap-4">
<label className="flex items-center space-x-3 cursor-pointer p-4 rounded-lg border border-gray-600 hover:border-blue-500 transition-colors">
<input
type="radio"
className="w-5 h-5 text-blue-600"
name="mode"
checked={config.mode === 'SIMULATION'}
onChange={() => setConfig({...config, mode: 'SIMULATION'})}
disabled={status?.isActive}
/>
<div className="flex items-center space-x-2">
<span className="text-2xl">📊</span>
<span className="text-white font-medium">Paper Trading</span>
</div>
</label>
<label className="flex items-center space-x-3 cursor-pointer p-4 rounded-lg border border-gray-600 hover:border-green-500 transition-colors">
<input
type="radio"
className="w-5 h-5 text-green-600"
name="mode"
checked={config.mode === 'LIVE'}
onChange={() => setConfig({...config, mode: 'LIVE'})}
disabled={status?.isActive}
/>
<div className="flex items-center space-x-2">
<span className="text-2xl">💰</span>
<span className="text-white font-semibold">Live Trading</span>
</label>
</div>
</div>
</label>
</div>
</div>
@@ -324,31 +323,37 @@ export default function AutomationPageV2() {
</div>
)}
{/* Quick Selection Buttons */}
<div className="flex gap-2">
{/* Quick Selection Buttons - Made Bigger */}
<div className="grid grid-cols-3 gap-3">
<button
type="button"
onClick={() => setConfig({...config, selectedTimeframes: ['5', '15', '30']})}
disabled={status?.isActive}
className="py-1 px-2 rounded text-xs font-medium bg-green-600/20 text-green-300 hover:bg-green-600/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
className="py-3 px-4 rounded-lg text-sm font-medium bg-green-600/20 text-green-300 hover:bg-green-600/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed border border-green-600/30 hover:border-green-600/50"
>
📈 Scalping
<div className="text-lg mb-1">📈</div>
<div>Scalping</div>
<div className="text-xs opacity-75">5m, 15m, 30m</div>
</button>
<button
type="button"
onClick={() => setConfig({...config, selectedTimeframes: ['60', '120']})}
disabled={status?.isActive}
className="py-1 px-2 rounded text-xs font-medium bg-blue-600/20 text-blue-300 hover:bg-blue-600/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
className="py-3 px-4 rounded-lg text-sm font-medium bg-blue-600/20 text-blue-300 hover:bg-blue-600/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed border border-blue-600/30 hover:border-blue-600/50"
>
Day Trading
<div className="text-lg mb-1"></div>
<div>Day Trading</div>
<div className="text-xs opacity-75">1h, 2h</div>
</button>
<button
type="button"
onClick={() => setConfig({...config, selectedTimeframes: ['240', 'D']})}
disabled={status?.isActive}
className="py-1 px-2 rounded text-xs font-medium bg-purple-600/20 text-purple-300 hover:bg-purple-600/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
className="py-3 px-4 rounded-lg text-sm font-medium bg-purple-600/20 text-purple-300 hover:bg-purple-600/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed border border-purple-600/30 hover:border-purple-600/50"
>
🎯 Swing Trading
<div className="text-lg mb-1">🎯</div>
<div>Swing Trading</div>
<div className="text-xs opacity-75">4h, 1d</div>
</button>
</div>
</div>
@@ -395,6 +400,21 @@ export default function AutomationPageV2() {
</div>
</>
)}
{/* Rate Limit Notification */}
{status?.rateLimitHit && (
<div className="mt-4 p-3 bg-red-900 border border-red-600 rounded-lg">
<div className="flex items-center space-x-2">
<span className="text-red-400 font-semibold"> Rate Limit Reached</span>
</div>
{status.rateLimitMessage && (
<p className="text-red-300 text-sm mt-1">{status.rateLimitMessage}</p>
)}
<p className="text-red-200 text-xs mt-2">
Automation stopped automatically. Please recharge your OpenAI account to continue.
</p>
</div>
)}
</div>
</div>