diff --git a/app/automation-v2/page.js b/app/automation-v2/page.js
new file mode 100644
index 0000000..163f445
--- /dev/null
+++ b/app/automation-v2/page.js
@@ -0,0 +1,530 @@
+'use client'
+import React, { useState, useEffect } from 'react'
+
+// Available timeframes for automation (matching analysis page format)
+const timeframes = [
+ { label: '5m', value: '5' },
+ { label: '15m', value: '15' },
+ { label: '30m', value: '30' },
+ { label: '1h', value: '60' },
+ { label: '2h', value: '120' },
+ { label: '4h', value: '240' },
+ { label: '1d', value: 'D' },
+]
+
+export default function AutomationPageV2() {
+ const [config, setConfig] = useState({
+ mode: 'SIMULATION',
+ dexProvider: 'DRIFT',
+ symbol: 'SOLUSD',
+ timeframe: '1h', // Primary timeframe for backwards compatibility
+ selectedTimeframes: ['60'], // Multi-timeframe support
+ tradingAmount: 100,
+ maxLeverage: 5,
+ stopLossPercent: 2,
+ takeProfitPercent: 6,
+ riskPercentage: 2
+ })
+
+ const [status, setStatus] = useState(null)
+ const [balance, setBalance] = useState(null)
+ const [positions, setPositions] = useState([])
+ const [loading, setLoading] = useState(false)
+
+ useEffect(() => {
+ fetchStatus()
+ fetchBalance()
+ fetchPositions()
+
+ const interval = setInterval(() => {
+ fetchStatus()
+ fetchBalance()
+ fetchPositions()
+ }, 30000)
+ return () => clearInterval(interval)
+ }, [])
+
+ const toggleTimeframe = (timeframe) => {
+ setConfig(prev => ({
+ ...prev,
+ selectedTimeframes: prev.selectedTimeframes.includes(timeframe)
+ ? prev.selectedTimeframes.filter(tf => tf !== timeframe)
+ : [...prev.selectedTimeframes, timeframe]
+ }))
+ }
+
+ const fetchStatus = async () => {
+ try {
+ const response = await fetch('/api/automation/status')
+ const data = await response.json()
+ if (data.success) {
+ setStatus(data.status)
+ }
+ } catch (error) {
+ console.error('Failed to fetch status:', error)
+ }
+ }
+
+ const fetchBalance = async () => {
+ try {
+ const response = await fetch('/api/drift/balance')
+ const data = await response.json()
+ if (data.success) {
+ setBalance(data)
+ }
+ } catch (error) {
+ console.error('Failed to fetch balance:', error)
+ }
+ }
+
+ const fetchPositions = async () => {
+ try {
+ const response = await fetch('/api/drift/positions')
+ const data = await response.json()
+ if (data.success) {
+ setPositions(data.positions || [])
+ }
+ } catch (error) {
+ console.error('Failed to fetch positions:', error)
+ }
+ }
+
+ const handleStart = async () => {
+ setLoading(true)
+ try {
+ const response = await fetch('/api/automation/start', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(config)
+ })
+ const data = await response.json()
+ if (data.success) {
+ fetchStatus()
+ } else {
+ alert('Failed to start automation: ' + data.error)
+ }
+ } catch (error) {
+ console.error('Failed to start automation:', error)
+ alert('Failed to start automation')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ const handleStop = async () => {
+ setLoading(true)
+ try {
+ const response = await fetch('/api/automation/stop', {
+ method: 'POST'
+ })
+ const data = await response.json()
+ if (data.success) {
+ fetchStatus()
+ } else {
+ alert('Failed to stop automation: ' + data.error)
+ }
+ } catch (error) {
+ console.error('Failed to stop automation:', error)
+ alert('Failed to stop automation')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+
+
+ 🚀 NEW AUTOMATION V2 - MULTI-TIMEFRAME READY 🚀
+
+
+
+
+
Automated Trading V2
+
Drift Protocol - Multi-Timeframe Analysis
+
+
+ {status?.isActive ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {/* Configuration Panel */}
+
+
+
Configuration
+
+ {/* Trading Mode */}
+
+
+
+
+
+
+
+
+
+ {/* Symbol and Position Size */}
+
+
+
+
+
+
+
+
+
setConfig({...config, tradingAmount: parseFloat(e.target.value)})}
+ disabled={status?.isActive}
+ />
+ {balance && (
+
+ Available: ${parseFloat(balance.availableBalance).toFixed(2)} • Using {((config.tradingAmount / balance.availableBalance) * 100).toFixed(1)}% of balance
+
+ )}
+ {balance && config.maxLeverage > 1 && (
+
+ With {config.maxLeverage}x leverage: ${(config.tradingAmount * config.maxLeverage).toFixed(2)} position size
+
+ )}
+
+
+
+
+
+ {balance && (
+
+ Quick calculation based on ${parseFloat(balance.availableBalance).toFixed(2)} balance
+
+ )}
+
+
+
+ {/* MULTI-TIMEFRAME SELECTION */}
+
+
+
+ {/* Timeframe Checkboxes */}
+
+ {timeframes.map(tf => (
+
+ ))}
+
+
+ {/* Selected Timeframes Display */}
+ {config.selectedTimeframes.length > 0 && (
+
+
+ Selected:
+ {config.selectedTimeframes.map(tf => timeframes.find(t => t.value === tf)?.label).filter(Boolean).join(', ')}
+
+
+
+ 💡 Multiple timeframes provide more robust analysis
+
+
+ )}
+
+ {/* Quick Selection Buttons */}
+
+
+
+
+
+
+
+ {/* Risk Management */}
+
+
+
+
+ {/* Status Panels */}
+
+ {/* Account Status */}
+
+
+
Account Status
+
+
+ {balance ? (
+
+
+ Available Balance:
+ ${parseFloat(balance.availableBalance).toFixed(2)}
+
+
+ Account Value:
+ ${parseFloat(balance.accountValue || balance.availableBalance).toFixed(2)}
+
+
+ Unrealized P&L:
+ 0 ? 'text-green-400' : balance.unrealizedPnl < 0 ? 'text-red-400' : 'text-gray-400'}`}>
+ ${parseFloat(balance.unrealizedPnl || 0).toFixed(2)}
+
+
+
+ Open Positions:
+ {positions.length}
+
+
+ ) : (
+
+
Loading account data...
+
+ )}
+
+
+ {/* Bot Status */}
+
+
Bot Status
+ {status ? (
+
+
+ Status:
+
+ {status.isActive ? 'ACTIVE' : 'STOPPED'}
+
+
+
+ Mode:
+
+ {status.mode}
+
+
+
+ Protocol:
+ DRIFT
+
+
+ Symbol:
+ {status.symbol}
+
+
+ Leverage:
+ {config.maxLeverage}x
+
+
+ ) : (
+
Loading bot status...
+ )}
+
+
+ {/* Trading Metrics */}
+
+
Trading Metrics
+
+
+
+ ${balance ? parseFloat(balance.accountValue || balance.availableBalance).toFixed(2) : '0.00'}
+
+
Portfolio
+
+
+
+ {balance ? parseFloat(balance.leverage || 0).toFixed(1) : '0.0'}%
+
+
Leverage Used
+
+
+
+ ${balance ? parseFloat(balance.unrealizedPnl || 0).toFixed(2) : '0.00'}
+
+
Unrealized P&L
+
+
+
+ {positions.length}
+
+
Open Positions
+
+
+
+
+
+
+ )
+}
diff --git a/app/automation/page-v2.js b/app/automation/page-v2.js
new file mode 100644
index 0000000..163f445
--- /dev/null
+++ b/app/automation/page-v2.js
@@ -0,0 +1,530 @@
+'use client'
+import React, { useState, useEffect } from 'react'
+
+// Available timeframes for automation (matching analysis page format)
+const timeframes = [
+ { label: '5m', value: '5' },
+ { label: '15m', value: '15' },
+ { label: '30m', value: '30' },
+ { label: '1h', value: '60' },
+ { label: '2h', value: '120' },
+ { label: '4h', value: '240' },
+ { label: '1d', value: 'D' },
+]
+
+export default function AutomationPageV2() {
+ const [config, setConfig] = useState({
+ mode: 'SIMULATION',
+ dexProvider: 'DRIFT',
+ symbol: 'SOLUSD',
+ timeframe: '1h', // Primary timeframe for backwards compatibility
+ selectedTimeframes: ['60'], // Multi-timeframe support
+ tradingAmount: 100,
+ maxLeverage: 5,
+ stopLossPercent: 2,
+ takeProfitPercent: 6,
+ riskPercentage: 2
+ })
+
+ const [status, setStatus] = useState(null)
+ const [balance, setBalance] = useState(null)
+ const [positions, setPositions] = useState([])
+ const [loading, setLoading] = useState(false)
+
+ useEffect(() => {
+ fetchStatus()
+ fetchBalance()
+ fetchPositions()
+
+ const interval = setInterval(() => {
+ fetchStatus()
+ fetchBalance()
+ fetchPositions()
+ }, 30000)
+ return () => clearInterval(interval)
+ }, [])
+
+ const toggleTimeframe = (timeframe) => {
+ setConfig(prev => ({
+ ...prev,
+ selectedTimeframes: prev.selectedTimeframes.includes(timeframe)
+ ? prev.selectedTimeframes.filter(tf => tf !== timeframe)
+ : [...prev.selectedTimeframes, timeframe]
+ }))
+ }
+
+ const fetchStatus = async () => {
+ try {
+ const response = await fetch('/api/automation/status')
+ const data = await response.json()
+ if (data.success) {
+ setStatus(data.status)
+ }
+ } catch (error) {
+ console.error('Failed to fetch status:', error)
+ }
+ }
+
+ const fetchBalance = async () => {
+ try {
+ const response = await fetch('/api/drift/balance')
+ const data = await response.json()
+ if (data.success) {
+ setBalance(data)
+ }
+ } catch (error) {
+ console.error('Failed to fetch balance:', error)
+ }
+ }
+
+ const fetchPositions = async () => {
+ try {
+ const response = await fetch('/api/drift/positions')
+ const data = await response.json()
+ if (data.success) {
+ setPositions(data.positions || [])
+ }
+ } catch (error) {
+ console.error('Failed to fetch positions:', error)
+ }
+ }
+
+ const handleStart = async () => {
+ setLoading(true)
+ try {
+ const response = await fetch('/api/automation/start', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(config)
+ })
+ const data = await response.json()
+ if (data.success) {
+ fetchStatus()
+ } else {
+ alert('Failed to start automation: ' + data.error)
+ }
+ } catch (error) {
+ console.error('Failed to start automation:', error)
+ alert('Failed to start automation')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ const handleStop = async () => {
+ setLoading(true)
+ try {
+ const response = await fetch('/api/automation/stop', {
+ method: 'POST'
+ })
+ const data = await response.json()
+ if (data.success) {
+ fetchStatus()
+ } else {
+ alert('Failed to stop automation: ' + data.error)
+ }
+ } catch (error) {
+ console.error('Failed to stop automation:', error)
+ alert('Failed to stop automation')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+
+
+ 🚀 NEW AUTOMATION V2 - MULTI-TIMEFRAME READY 🚀
+
+
+
+
+
Automated Trading V2
+
Drift Protocol - Multi-Timeframe Analysis
+
+
+ {status?.isActive ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {/* Configuration Panel */}
+
+
+
Configuration
+
+ {/* Trading Mode */}
+
+
+
+
+
+
+
+
+
+ {/* Symbol and Position Size */}
+
+
+
+
+
+
+
+
+
setConfig({...config, tradingAmount: parseFloat(e.target.value)})}
+ disabled={status?.isActive}
+ />
+ {balance && (
+
+ Available: ${parseFloat(balance.availableBalance).toFixed(2)} • Using {((config.tradingAmount / balance.availableBalance) * 100).toFixed(1)}% of balance
+
+ )}
+ {balance && config.maxLeverage > 1 && (
+
+ With {config.maxLeverage}x leverage: ${(config.tradingAmount * config.maxLeverage).toFixed(2)} position size
+
+ )}
+
+
+
+
+
+ {balance && (
+
+ Quick calculation based on ${parseFloat(balance.availableBalance).toFixed(2)} balance
+
+ )}
+
+
+
+ {/* MULTI-TIMEFRAME SELECTION */}
+
+
+
+ {/* Timeframe Checkboxes */}
+
+ {timeframes.map(tf => (
+
+ ))}
+
+
+ {/* Selected Timeframes Display */}
+ {config.selectedTimeframes.length > 0 && (
+
+
+ Selected:
+ {config.selectedTimeframes.map(tf => timeframes.find(t => t.value === tf)?.label).filter(Boolean).join(', ')}
+
+
+
+ 💡 Multiple timeframes provide more robust analysis
+
+
+ )}
+
+ {/* Quick Selection Buttons */}
+
+
+
+
+
+
+
+ {/* Risk Management */}
+
+
+
+
+ {/* Status Panels */}
+
+ {/* Account Status */}
+
+
+
Account Status
+
+
+ {balance ? (
+
+
+ Available Balance:
+ ${parseFloat(balance.availableBalance).toFixed(2)}
+
+
+ Account Value:
+ ${parseFloat(balance.accountValue || balance.availableBalance).toFixed(2)}
+
+
+ Unrealized P&L:
+ 0 ? 'text-green-400' : balance.unrealizedPnl < 0 ? 'text-red-400' : 'text-gray-400'}`}>
+ ${parseFloat(balance.unrealizedPnl || 0).toFixed(2)}
+
+
+
+ Open Positions:
+ {positions.length}
+
+
+ ) : (
+
+
Loading account data...
+
+ )}
+
+
+ {/* Bot Status */}
+
+
Bot Status
+ {status ? (
+
+
+ Status:
+
+ {status.isActive ? 'ACTIVE' : 'STOPPED'}
+
+
+
+ Mode:
+
+ {status.mode}
+
+
+
+ Protocol:
+ DRIFT
+
+
+ Symbol:
+ {status.symbol}
+
+
+ Leverage:
+ {config.maxLeverage}x
+
+
+ ) : (
+
Loading bot status...
+ )}
+
+
+ {/* Trading Metrics */}
+
+
Trading Metrics
+
+
+
+ ${balance ? parseFloat(balance.accountValue || balance.availableBalance).toFixed(2) : '0.00'}
+
+
Portfolio
+
+
+
+ {balance ? parseFloat(balance.leverage || 0).toFixed(1) : '0.0'}%
+
+
Leverage Used
+
+
+
+ ${balance ? parseFloat(balance.unrealizedPnl || 0).toFixed(2) : '0.00'}
+
+
Unrealized P&L
+
+
+
+ {positions.length}
+
+
Open Positions
+
+
+
+
+
+
+ )
+}
diff --git a/app/automation/page.js b/app/automation/page.js
index 2d3d210..2a432ac 100644
--- a/app/automation/page.js
+++ b/app/automation/page.js
@@ -2,11 +2,23 @@
import React, { useState, useEffect } from 'react'
export default function AutomationPage() {
+// Available timeframes for automation
+const timeframes = [
+ { label: '5m', value: '5' },
+ { label: '15m', value: '15' },
+ { label: '30m', value: '30' },
+ { label: '1h', value: '60' },
+ { label: '2h', value: '120' },
+ { label: '4h', value: '240' },
+ { label: '1d', value: 'D' },
+]
+
const [config, setConfig] = useState({
mode: 'SIMULATION',
dexProvider: 'DRIFT',
symbol: 'SOLUSD',
timeframe: '1h',
+ selectedTimeframes: ['60'], // Multi-timeframe support
tradingAmount: 100,
maxLeverage: 5,
stopLossPercent: 2,
@@ -32,6 +44,15 @@ export default function AutomationPage() {
return () => clearInterval(interval)
}, [])
+ const toggleTimeframe = (timeframe) => {
+ setConfig(prev => ({
+ ...prev,
+ selectedTimeframes: prev.selectedTimeframes.includes(timeframe)
+ ? prev.selectedTimeframes.filter(tf => tf !== timeframe)
+ : [...prev.selectedTimeframes, timeframe]
+ }))
+ }
+
const fetchStatus = async () => {
try {
const response = await fetch('/api/automation/status')
@@ -294,20 +315,12 @@ export default function AutomationPage() {
-
-
+
+
+ Multi-timeframe selection will appear here
+
diff --git a/app/automation/page.js.working-backup b/app/automation/page.js.working-backup
new file mode 100644
index 0000000..0f9ef54
--- /dev/null
+++ b/app/automation/page.js.working-backup
@@ -0,0 +1,529 @@
+'use client'
+import React, { useState, useEffect } from 'react'
+
+export default function AutomationPage() {
+// Available timeframes for automation
+const timeframes = [
+ { label: '5m', value: '5' },
+ { label: '15m', value: '15' },
+ { label: '30m', value: '30' },
+ { label: '1h', value: '60' },
+ { label: '2h', value: '120' },
+ { label: '4h', value: '240' },
+ { label: '1d', value: 'D' },
+]
+
+ const [config, setConfig] = useState({
+ mode: 'SIMULATION',
+ dexProvider: 'DRIFT',
+ symbol: 'SOLUSD',
+ timeframe: '1h',
+ selectedTimeframes: ['60'], // Multi-timeframe support
+ tradingAmount: 100,
+ maxLeverage: 5,
+ stopLossPercent: 2,
+ takeProfitPercent: 6,
+ riskPercentage: 2
+ })
+
+ const [status, setStatus] = useState(null)
+ const [balance, setBalance] = useState(null)
+ const [positions, setPositions] = useState([])
+ const [isLoading, setIsLoading] = useState(false)
+ const [balanceLoading, setBalanceLoading] = useState(false)
+
+ useEffect(() => {
+ fetchStatus()
+ fetchBalance()
+ fetchPositions()
+ const interval = setInterval(() => {
+ fetchStatus()
+ fetchBalance()
+ fetchPositions()
+ }, 30000)
+ return () => clearInterval(interval)
+ }, [])
+
+ const toggleTimeframe = (timeframe) => {
+ setConfig(prev => ({
+ ...prev,
+ selectedTimeframes: prev.selectedTimeframes.includes(timeframe)
+ ? prev.selectedTimeframes.filter(tf => tf !== timeframe)
+ : [...prev.selectedTimeframes, timeframe]
+ }))
+ }
+
+ const fetchStatus = async () => {
+ try {
+ const response = await fetch('/api/automation/status')
+ const data = await response.json()
+ if (data.success) {
+ setStatus(data.status)
+ }
+ } catch (error) {
+ console.error('Failed to fetch status:', error)
+ }
+ }
+
+ const fetchBalance = async () => {
+ if (config.dexProvider !== 'DRIFT') return
+
+ setBalanceLoading(true)
+ try {
+ const response = await fetch('/api/drift/balance')
+ const data = await response.json()
+ if (data.success) {
+ setBalance(data)
+ // Auto-calculate position size based on available balance and leverage
+ const maxPositionSize = (data.availableBalance * config.maxLeverage) * 0.9 // Use 90% of max
+ const suggestedSize = Math.max(10, Math.min(maxPositionSize, config.tradingAmount))
+
+ setConfig(prev => ({
+ ...prev,
+ tradingAmount: Math.round(suggestedSize)
+ }))
+ }
+ } catch (error) {
+ console.error('Failed to fetch balance:', error)
+ } finally {
+ setBalanceLoading(false)
+ }
+ }
+
+ const fetchPositions = async () => {
+ if (config.dexProvider !== 'DRIFT') return
+
+ try {
+ const response = await fetch('/api/drift/positions')
+ const data = await response.json()
+ if (data.success) {
+ setPositions(data.positions || [])
+ }
+ } catch (error) {
+ console.error('Failed to fetch positions:', error)
+ }
+ }
+
+ const handleLeverageChange = (newLeverage) => {
+ const leverage = parseFloat(newLeverage)
+
+ // Auto-calculate position size when leverage changes
+ if (balance?.availableBalance) {
+ const maxPositionSize = (balance.availableBalance * leverage) * 0.9 // Use 90% of max
+ const suggestedSize = Math.max(10, maxPositionSize)
+
+ setConfig(prev => ({
+ ...prev,
+ maxLeverage: leverage,
+ tradingAmount: Math.round(suggestedSize)
+ }))
+ } else {
+ setConfig(prev => ({
+ ...prev,
+ maxLeverage: leverage
+ }))
+ }
+ }
+
+ const hasOpenPosition = positions.some(pos =>
+ pos.symbol.includes(config.symbol.replace('USD', '')) && pos.size > 0.001
+ )
+
+ const handleStart = async () => {
+ setIsLoading(true)
+ try {
+ const response = await fetch('/api/automation/start', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(config)
+ })
+ const data = await response.json()
+ if (data.success) {
+ fetchStatus()
+ } else {
+ alert('Failed to start automation: ' + data.error)
+ }
+ } catch (error) {
+ console.error('Failed to start automation:', error)
+ alert('Failed to start automation')
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ const handleStop = async () => {
+ setIsLoading(true)
+ try {
+ const response = await fetch('/api/automation/stop', { method: 'POST' })
+ const data = await response.json()
+ if (data.success) {
+ fetchStatus()
+ } else {
+ alert('Failed to stop automation: ' + data.error)
+ }
+ } catch (error) {
+ console.error('Failed to stop automation:', error)
+ alert('Failed to stop automation')
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ return (
+
+ {/* Header */}
+
+
+
Automated Trading
+
Drift Protocol
+
+
+ {status?.isActive ? (
+
+ ) : (
+
+ )}
+
+
+
+ {/* Main Grid */}
+
+
+ {/* Configuration */}
+
+
+
+
Configuration
+
+
+
+ {/* Trading Mode */}
+
+
+ {/* Leverage */}
+
+
+
+
+
+
+
+ {/* Parameters */}
+
+
+
+
+
+
+
+
+
+
setConfig({...config, tradingAmount: parseFloat(e.target.value)})}
+ className="w-full p-3 bg-gray-700 border border-gray-600 rounded-lg text-white focus:border-blue-500"
+ disabled={status?.isActive}
+ min="10"
+ step="10"
+ />
+ {balance && (
+
+ Available: ${balance.availableBalance?.toFixed(2)} •
+ Using {((config.tradingAmount / balance.availableBalance) * 100).toFixed(0)}% of balance
+
+ )}
+
+
+
+
+
+
+
+
+
+ {/* Risk Management */}
+
+
+
+
+ setConfig({...config, stopLossPercent: parseFloat(e.target.value)})}
+ className="w-full p-3 bg-gray-700 border border-gray-600 rounded-lg text-white focus:border-blue-500"
+ disabled={status?.isActive}
+ min="0.5"
+ max="20"
+ step="0.5"
+ />
+
+
+
+
+ setConfig({...config, takeProfitPercent: parseFloat(e.target.value)})}
+ className="w-full p-3 bg-gray-700 border border-gray-600 rounded-lg text-white focus:border-blue-500"
+ disabled={status?.isActive}
+ min="1"
+ max="50"
+ step="1"
+ />
+
+
+
+
+
+
+
AI-Driven Trading
+
+
+
+ {hasOpenPosition ? 'Monitoring Position' : 'Ready to Trade'}
+
+
+
+
+ Bot will enter trades based on AI analysis when no position is open
+
+
+
+
+
+
+
+
+
+ {/* Status */}
+
+
+
+
+
Account Status
+
+
+
+ {balance ? (
+
+
+ Available Balance:
+ ${balance.availableBalance?.toFixed(2)}
+
+
+ Account Value:
+ ${balance.accountValue?.toFixed(2)}
+
+
+ Unrealized P&L:
+ = 0 ? 'text-green-400' : 'text-red-400'}`}>
+ {balance.unrealizedPnl >= 0 ? '+' : ''}${balance.unrealizedPnl?.toFixed(2)}
+
+
+
+ Open Positions:
+ {positions.length}
+
+ {positions.length > 0 && (
+
+
Active Positions:
+ {positions.map((pos, idx) => (
+
+ {pos.symbol}
+
+ {pos.side.toUpperCase()} {pos.size?.toFixed(4)}
+
+
+ ))}
+
+ )}
+
+ ) : (
+
+ {balanceLoading ? (
+
Loading account data...
+ ) : (
+
No account data available
+ )}
+
+ )}
+
+
+
+
Bot Status
+ {status ? (
+
+
+ Status:
+
+ {status.isActive ? 'ACTIVE' : 'STOPPED'}
+
+
+
+ Mode:
+
+ {status.mode}
+
+
+
+ Protocol:
+ DRIFT
+
+
+ Symbol:
+ {config.symbol}
+
+
+ Leverage:
+ {config.maxLeverage}x
+
+
+ Position Size:
+ ${config.tradingAmount}
+
+
+ ) : (
+
Loading...
+ )}
+
+
+
+
Trading Metrics
+
+
+
+ {balance?.accountValue ? `$${balance.accountValue.toFixed(0)}` : '$0'}
+
+
Portfolio
+
+
+
+ {balance?.leverage ? `${(balance.leverage * 100).toFixed(1)}%` : '0%'}
+
+
Leverage Used
+
+
+
= 0 ? 'text-green-400' : 'text-red-400'}`}>
+ {balance?.unrealizedPnl ? `$${balance.unrealizedPnl.toFixed(2)}` : '$0.00'}
+
+
Unrealized P&L
+
+
+
{positions.length}
+
Open Positions
+
+
+
+
+
+
+
+ )
+}
diff --git a/app/test-volume-mount.txt b/app/test-volume-mount.txt
new file mode 100644
index 0000000..e69de29
diff --git a/lib/automation-service.ts b/lib/automation-service.ts
index 6a9ee2e..08e08c7 100644
--- a/lib/automation-service.ts
+++ b/lib/automation-service.ts
@@ -413,7 +413,7 @@ export class AutomationService {
console.log(`🚀 Executing ${config.mode} trade: ${analysis.recommendation} ${config.symbol}`)
const side = analysis.recommendation === 'BUY' ? 'BUY' : 'SELL'
- const amount = this.calculateTradeAmount(config, analysis)
+ const amount = await this.calculateTradeAmount(config, analysis)
const leverage = Math.min(config.maxLeverage, 3) // Cap at 3x for safety
let tradeResult: any = null
@@ -559,20 +559,58 @@ export class AutomationService {
}
}
- private calculateTradeAmount(config: AutomationConfig, analysis: AnalysisResult): number {
- // Base amount from config
- let amount = config.tradingAmount
+ private async calculateTradeAmount(config: AutomationConfig, analysis: AnalysisResult): Promise {
+ try {
+ // Fetch actual account balance from Drift
+ console.log('💰 Fetching account balance for position sizing...')
+ const balanceResponse = await fetch(`http://localhost:3000/api/drift/balance`)
+
+ if (!balanceResponse.ok) {
+ console.log('⚠️ Failed to fetch balance, using fallback calculation')
+ // Fallback to config amount
+ let amount = Math.min(config.tradingAmount, 35) // Cap at $35 max
+ const riskAdjustment = config.riskPercentage / 100
+ return Math.max(amount * riskAdjustment, 5)
+ }
- // Adjust based on confidence
- const confidenceMultiplier = Math.min(analysis.confidence / 100, 1)
- amount *= confidenceMultiplier
+ const balanceData = await balanceResponse.json()
+ const availableBalance = parseFloat(balanceData.availableBalance || '0')
+
+ console.log(`💰 Available balance: $${availableBalance}`)
- // Adjust based on risk percentage
- const riskAdjustment = config.riskPercentage / 100
- amount *= riskAdjustment
+ if (availableBalance <= 0) {
+ throw new Error('No available balance')
+ }
- // Ensure minimum trade amount
- return Math.max(amount, 10)
+ // Calculate position size based on risk percentage of available balance
+ const riskAmount = availableBalance * (config.riskPercentage / 100)
+
+ // Adjust based on confidence (reduce risk for low confidence signals)
+ const confidenceMultiplier = Math.min(analysis.confidence / 100, 1)
+ let amount = riskAmount * confidenceMultiplier
+
+ // Apply leverage to get position size
+ amount *= Math.min(config.maxLeverage, 10)
+
+ // Ensure minimum trade amount but cap at available balance
+ amount = Math.max(amount, 5) // Minimum $5 position
+ amount = Math.min(amount, availableBalance * 0.8) // Never use more than 80% of balance
+
+ console.log(`📊 Position sizing calculation:`)
+ console.log(` - Available balance: $${availableBalance}`)
+ console.log(` - Risk percentage: ${config.riskPercentage}%`)
+ console.log(` - Risk amount: $${riskAmount.toFixed(2)}`)
+ console.log(` - Confidence multiplier: ${confidenceMultiplier}`)
+ console.log(` - Leverage: ${Math.min(config.maxLeverage, 10)}x`)
+ console.log(` - Final position size: $${amount.toFixed(2)}`)
+
+ return Math.round(amount * 100) / 100 // Round to 2 decimal places
+
+ } catch (error) {
+ console.log(`⚠️ Error calculating trade amount: ${error instanceof Error ? error.message : String(error)}`)
+ // Safe fallback - use small fixed amount
+ return 5
+ }
}
private parseRiskReward(rrString: string): number {
diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db
index f5e1308..4c7b637 100644
Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ