-
-
🔄
+ {/* Service Status */}
+
+
+
Service Status
+
+
+
+
Trading Bot
+
+ {statusIcon[status.systemStatus]}
+
+ {status.systemStatus.toUpperCase()}
+
+
+
+
+
Bitquery API
+
+ {statusIcon[status.bitqueryStatus]}
+
+ {status.bitqueryStatus.toUpperCase()}
+
+
+
-
- {status.activeTrades}
-
-
Active Trades
-
-
-
📈
+ {/* Market Prices */}
+ {status.marketPrices.length > 0 && (
+
+
+
Live Market Prices
+ Via Bitquery
+
+
+ {status.marketPrices.map((price, index) => (
+
+
+ {price.symbol}
+ ${price.price?.toFixed(4)}
+
+
+ 24h Change
+ = 0 ? 'text-green-400' : 'text-red-400'
+ }`}>
+ {price.change24h >= 0 ? '+' : ''}{price.change24h?.toFixed(2)}%
+
+
+
+ ))}
+
-
= 0 ? 'text-green-400' : 'text-red-400'}`}>
- {status.dailyPnL >= 0 ? '+' : ''}${status.dailyPnL.toFixed(2)}
-
-
Daily P&L
-
+ )}
)}
diff --git a/components/TradeExecutionPanel.js b/components/TradeExecutionPanel.js
new file mode 100644
index 0000000..926f149
--- /dev/null
+++ b/components/TradeExecutionPanel.js
@@ -0,0 +1,296 @@
+'use client'
+import React, { useState, useEffect } from 'react'
+
+export default function TradeExecutionPanel({ analysis, symbol = 'SOL' }) {
+ const [tradeType, setTradeType] = useState('BUY')
+ const [amount, setAmount] = useState('')
+ const [customPrice, setCustomPrice] = useState('')
+ const [useRecommendedPrice, setUseRecommendedPrice] = useState(true)
+ const [isExecuting, setIsExecuting] = useState(false)
+ const [executionResult, setExecutionResult] = useState(null)
+ const [balance, setBalance] = useState(null)
+
+ // Get recommended price from analysis
+ const getRecommendedPrice = () => {
+ if (!analysis) return null
+
+ if (analysis.recommendation === 'BUY' && analysis.entry?.price) {
+ return analysis.entry.price
+ } else if (analysis.recommendation === 'SELL' && analysis.entry?.price) {
+ return analysis.entry.price
+ }
+
+ return null
+ }
+
+ const recommendedPrice = getRecommendedPrice()
+
+ // Fetch balance on component mount
+ useEffect(() => {
+ fetchBalance()
+ }, [])
+
+ const fetchBalance = async () => {
+ try {
+ const response = await fetch('/api/trading/balance')
+ const data = await response.json()
+
+ if (data.success) {
+ setBalance(data.balance)
+ }
+ } catch (error) {
+ console.error('Failed to fetch balance:', error)
+ }
+ }
+
+ const executeTrade = async () => {
+ if (!amount || parseFloat(amount) <= 0) {
+ alert('Please enter a valid amount')
+ return
+ }
+
+ setIsExecuting(true)
+ setExecutionResult(null)
+
+ try {
+ const tradePrice = useRecommendedPrice && recommendedPrice
+ ? recommendedPrice
+ : customPrice ? parseFloat(customPrice) : undefined
+
+ const response = await fetch('/api/trading/execute', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ symbol,
+ side: tradeType,
+ amount: parseFloat(amount),
+ price: tradePrice,
+ orderType: tradePrice ? 'limit' : 'market'
+ })
+ })
+
+ const result = await response.json()
+
+ if (result.success) {
+ setExecutionResult({
+ success: true,
+ trade: result.trade,
+ message: result.message
+ })
+ // Refresh balance after successful trade
+ await fetchBalance()
+ } else {
+ setExecutionResult({
+ success: false,
+ error: result.error,
+ message: result.message
+ })
+ }
+ } catch (error) {
+ setExecutionResult({
+ success: false,
+ error: 'Network error',
+ message: 'Failed to execute trade. Please try again.'
+ })
+ } finally {
+ setIsExecuting(false)
+ }
+ }
+
+ const getTradeButtonColor = () => {
+ if (tradeType === 'BUY') return 'bg-green-600 hover:bg-green-700'
+ return 'bg-red-600 hover:bg-red-700'
+ }
+
+ const getRecommendationColor = () => {
+ if (!analysis) return 'text-gray-400'
+
+ switch (analysis.recommendation) {
+ case 'BUY': return 'text-green-400'
+ case 'SELL': return 'text-red-400'
+ default: return 'text-yellow-400'
+ }
+ }
+
+ return (
+
+
+
Execute Trade
+
+ {symbol} Trading
+
+
+
+ {/* Balance Display */}
+ {balance && (
+
+
Portfolio Balance
+
+
+ ${balance.totalValue?.toFixed(2)}
+
+
+ Available: ${balance.availableBalance?.toFixed(2)}
+
+
+
+ )}
+
+ {/* AI Recommendation Display */}
+ {analysis && (
+
+
AI Recommendation
+
+
+ {analysis.recommendation}
+
+
+ {analysis.confidence}% confidence
+
+
+ {recommendedPrice && (
+
+ Entry: ${recommendedPrice.toFixed(4)}
+ {analysis.entry?.buffer && (
+ ({analysis.entry.buffer})
+ )}
+
+ )}
+ {analysis.stopLoss && (
+
+ Stop Loss: ${analysis.stopLoss.price.toFixed(4)}
+
+ )}
+ {analysis.takeProfits?.tp1 && (
+
+ TP1: ${analysis.takeProfits.tp1.price.toFixed(4)}
+
+ )}
+
+ {analysis.reasoning}
+
+
+ )}
+
+ {/* Trade Type Selection */}
+
+
+
+
+
+ {/* Amount Input */}
+
+
+ setAmount(e.target.value)}
+ placeholder="0.00"
+ step="0.001"
+ min="0"
+ className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
+ />
+
+
+ {/* Price Selection */}
+
+
+
+ {recommendedPrice && (
+
+ )}
+
+
+
+ {!useRecommendedPrice && (
+ setCustomPrice(e.target.value)}
+ placeholder="Enter price (leave empty for market)"
+ step="0.0001"
+ min="0"
+ className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
+ />
+ )}
+
+
+ {/* Execute Button */}
+
+
+ {/* Execution Result */}
+ {executionResult && (
+
+
+ {executionResult.success ? '✅ Trade Executed' : '❌ Trade Failed'}
+
+
+ {executionResult.message}
+
+ {executionResult.trade && (
+
+ TX ID: {executionResult.trade.txId}
+
+ )}
+
+ )}
+
+ {/* Risk Warning */}
+
+ ⚠️ Trading involves significant risk. This is a simulated trading environment using Bitquery data.
+
+
+ )
+}
diff --git a/components/WalletConnection.js b/components/WalletConnection.js
new file mode 100644
index 0000000..a9bd418
--- /dev/null
+++ b/components/WalletConnection.js
@@ -0,0 +1,148 @@
+'use client'
+import React, { useState } from 'react'
+
+export default function WalletConnection({ onWalletConnected }) {
+ const [walletAddress, setWalletAddress] = useState('')
+ const [isConnecting, setIsConnecting] = useState(false)
+ const [connectionStatus, setConnectionStatus] = useState(null)
+
+ const connectPhantomWallet = async () => {
+ setIsConnecting(true)
+ try {
+ // Check if Phantom wallet is available
+ if (typeof window !== 'undefined' && window.solana && window.solana.isPhantom) {
+ const response = await window.solana.connect()
+ const address = response.publicKey.toString()
+ setWalletAddress(address)
+ setConnectionStatus({ success: true, message: 'Wallet connected successfully!' })
+
+ if (onWalletConnected) {
+ onWalletConnected(address)
+ }
+ } else {
+ setConnectionStatus({
+ success: false,
+ message: 'Phantom wallet not found. Please install Phantom wallet extension.'
+ })
+ }
+ } catch (error) {
+ setConnectionStatus({
+ success: false,
+ message: `Failed to connect wallet: ${error.message}`
+ })
+ } finally {
+ setIsConnecting(false)
+ }
+ }
+
+ const connectManualAddress = () => {
+ if (walletAddress.length >= 32) {
+ setConnectionStatus({ success: true, message: 'Manual address set!' })
+ if (onWalletConnected) {
+ onWalletConnected(walletAddress)
+ }
+ } else {
+ setConnectionStatus({
+ success: false,
+ message: 'Please enter a valid Solana wallet address'
+ })
+ }
+ }
+
+ const disconnectWallet = () => {
+ setWalletAddress('')
+ setConnectionStatus(null)
+ if (onWalletConnected) {
+ onWalletConnected(null)
+ }
+ }
+
+ return (
+
+
Wallet Connection
+
+ {!walletAddress ? (
+
+ {/* Phantom Wallet Connection */}
+
+
+
+
+ {/* Manual Address Input */}
+
+
+
+ setWalletAddress(e.target.value)}
+ placeholder="Enter Solana wallet address..."
+ className="flex-1 px-3 py-2 bg-gray-700 border border-gray-600 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
+ />
+
+
+
+
+ ) : (
+
+
+
+
+
✅ Wallet Connected
+
+ {walletAddress.substring(0, 8)}...{walletAddress.substring(walletAddress.length - 8)}
+
+
+
+
+
+
+ )}
+
+ {/* Connection Status */}
+ {connectionStatus && (
+
+ {connectionStatus.message}
+
+ )}
+
+ {/* Instructions */}
+
+
💡 Connect your Solana wallet to see real portfolio balance and execute trades.
+
🔒 Your wallet address is only used to fetch balance - no private keys are stored.
+
+
+ )
+}
diff --git a/lib/bitquery-service.ts b/lib/bitquery-service.ts
index aba7a19..0a5e3e3 100644
--- a/lib/bitquery-service.ts
+++ b/lib/bitquery-service.ts
@@ -58,98 +58,69 @@ class BitqueryService {
async getTokenPrices(symbols: string[] = ['SOL', 'ETH', 'BTC']): Promise
{
try {
- // Real Bitquery query for Solana DEX trades
- const query = `
- query GetSolanaTokenPrices {
- Solana {
- DEXTrades(
- limit: {count: 10}
- orderBy: {descendingByField: "Block_Time"}
- where: {
- Trade: {Buy: {Currency: {MintAddress: {in: ["So11111111111111111111111111111111111111112", "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"]}}}}
- }
- ) {
- Block {
- Time
- }
- Trade {
- Buy {
- Currency {
- Symbol
- MintAddress
- }
- Amount
- }
- Sell {
- Currency {
- Symbol
- MintAddress
- }
- Amount
- }
- }
- }
- }
- }
- `;
-
- console.log('🔍 Querying Bitquery for real Solana token prices...');
- const response = await this.makeRequest(query);
+ console.log('🔍 Fetching real market prices from CoinGecko...');
- if (response.errors) {
- console.error('Bitquery GraphQL errors:', response.errors);
- }
-
- // Parse the response to extract prices
- const trades = response.data?.Solana?.DEXTrades || [];
- const prices: TokenPrice[] = [];
-
- // Process SOL price from trades
- const solTrades = trades.filter((trade: any) =>
- trade.Trade.Buy.Currency.Symbol === 'SOL' || trade.Trade.Sell.Currency.Symbol === 'SOL'
- );
-
- if (solTrades.length > 0) {
- const latestTrade = solTrades[0];
- const solPrice = this.calculatePrice(latestTrade);
- prices.push({
- symbol: 'SOL',
- price: solPrice,
- change24h: Math.random() * 10 - 5, // Mock 24h change for now
- volume24h: Math.random() * 1000000,
- marketCap: solPrice * 464000000, // Approximate SOL supply
- });
- }
-
- // Add other tokens with fallback prices
- const symbolPriceMap: { [key: string]: number } = {
- ETH: 2400,
- BTC: 67000,
- SOL: 144,
+ // Use CoinGecko API for real prices
+ const coinGeckoIds: { [key: string]: string } = {
+ 'SOL': 'solana',
+ 'BTC': 'bitcoin',
+ 'ETH': 'ethereum',
+ 'AVAX': 'avalanche-2',
+ 'ADA': 'cardano'
};
- symbols.forEach(symbol => {
- if (!prices.find(p => p.symbol === symbol)) {
- prices.push({
+ const ids = symbols.map(symbol => coinGeckoIds[symbol]).filter(Boolean).join(',');
+
+ const response = await fetch(
+ `https://api.coingecko.com/api/v3/simple/price?ids=${ids}&vs_currencies=usd&include_24hr_change=true`,
+ {
+ headers: {
+ 'Accept': 'application/json',
+ }
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`CoinGecko API failed: ${response.status}`);
+ }
+
+ const data = await response.json();
+ console.log('📊 Real price data received:', data);
+
+ const prices: TokenPrice[] = symbols.map(symbol => {
+ const coinId = coinGeckoIds[symbol];
+ const priceData = data[coinId];
+
+ if (priceData) {
+ return {
symbol,
- price: symbolPriceMap[symbol] || 100,
- change24h: Math.random() * 10 - 5,
- volume24h: Math.random() * 1000000,
- marketCap: Math.random() * 10000000000,
- });
+ price: priceData.usd,
+ change24h: priceData.usd_24h_change || 0,
+ volume24h: Math.random() * 1000000, // Volume not provided by this endpoint
+ marketCap: priceData.usd * 1000000000, // Mock market cap calculation
+ };
+ } else {
+ // Fallback for unknown symbols
+ return {
+ symbol,
+ price: 100,
+ change24h: 0,
+ volume24h: 0,
+ marketCap: 0,
+ };
}
});
return prices;
} catch (error) {
- console.error('❌ Failed to get token prices from Bitquery:', error);
- // Return realistic fallback data
+ console.error('❌ Failed to get real token prices:', error);
+ // Return demo data when API fails
return symbols.map(symbol => ({
symbol,
- price: symbol === 'SOL' ? 144 : symbol === 'ETH' ? 2400 : 67000,
- change24h: Math.random() * 10 - 5,
- volume24h: Math.random() * 1000000,
- marketCap: Math.random() * 10000000000,
+ price: 0, // Will be updated when API works
+ change24h: 0,
+ volume24h: 0,
+ marketCap: 0,
}));
}
}
@@ -172,18 +143,21 @@ class BitqueryService {
async getTradingBalance(): Promise {
try {
- const positions = await this.getTokenPrices(['SOL', 'ETH', 'BTC']);
- const totalValue = positions.reduce((sum, pos) => sum + (pos.price * 1), 0); // Assuming 1 token each
-
+ console.log('💰 Getting portfolio balance...');
+
+ // TODO: Replace with actual wallet integration
+ // For now, return demo portfolio - user needs to configure their actual wallet
+ const demoBalance = 0; // Set to 0 until real wallet is connected
+
return {
- totalValue,
- availableBalance: totalValue * 0.8, // 80% available
- positions,
+ totalValue: demoBalance,
+ availableBalance: demoBalance,
+ positions: [], // Empty until real wallet connected
};
} catch (error) {
console.error('❌ Failed to get trading balance:', error);
return {
- totalValue: 0,
+ totalValue: 0, // No balance until wallet connected
availableBalance: 0,
positions: [],
};
diff --git a/lib/solana-wallet-service.ts b/lib/solana-wallet-service.ts
new file mode 100644
index 0000000..9053bb8
--- /dev/null
+++ b/lib/solana-wallet-service.ts
@@ -0,0 +1,77 @@
+import { Connection, PublicKey, Keypair } from '@solana/web3.js'
+
+class SolanaWalletService {
+ private connection: Connection
+ private keypair: Keypair | null = null
+
+ constructor() {
+ const rpcUrl = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com'
+ this.connection = new Connection(rpcUrl, 'confirmed')
+
+ // Initialize keypair from environment
+ this.initializeWallet()
+ }
+
+ private initializeWallet() {
+ try {
+ if (process.env.SOLANA_PRIVATE_KEY) {
+ const privateKeyArray = JSON.parse(process.env.SOLANA_PRIVATE_KEY)
+ this.keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyArray))
+ console.log('✅ Solana wallet initialized:', this.keypair.publicKey.toString())
+ } else {
+ console.warn('⚠️ No SOLANA_PRIVATE_KEY found in environment')
+ }
+ } catch (error) {
+ console.error('❌ Failed to initialize Solana wallet:', error)
+ }
+ }
+
+ async getWalletBalance(): Promise<{
+ solBalance: number
+ usdValue: number
+ publicKey: string
+ }> {
+ if (!this.keypair) {
+ throw new Error('Wallet not initialized')
+ }
+
+ try {
+ console.log('💰 Fetching real wallet balance...')
+
+ // Get SOL balance
+ const balance = await this.connection.getBalance(this.keypair.publicKey)
+ const solBalance = balance / 1000000000 // Convert lamports to SOL
+
+ // Get current SOL price
+ const priceResponse = await fetch(
+ 'https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd'
+ )
+ const priceData = await priceResponse.json()
+ const solPrice = priceData.solana?.usd || 0
+
+ const usdValue = solBalance * solPrice
+
+ console.log(`💎 Real wallet balance: ${solBalance.toFixed(4)} SOL ($${usdValue.toFixed(2)})`)
+
+ return {
+ solBalance,
+ usdValue,
+ publicKey: this.keypair.publicKey.toString()
+ }
+ } catch (error) {
+ console.error('❌ Failed to fetch wallet balance:', error)
+ throw error
+ }
+ }
+
+ getPublicKey(): string | null {
+ return this.keypair?.publicKey.toString() || null
+ }
+
+ isWalletConnected(): boolean {
+ return this.keypair !== null
+ }
+}
+
+export const solanaWalletService = new SolanaWalletService()
+export default SolanaWalletService