Initial commit: Mantle AI Trading Bot
Features: - AI-powered signal generation with multi-factor analysis - Fundamental news aggregation from multiple sources - Technical analysis with 6+ indicators - VectorDB integration for semantic search - Backtesting engine with performance metrics - Demo/paper trading mode - Real-time WebSocket updates - Comprehensive dashboard UI Built for Mantle Turing Test Hackathon - AI Trading track - AI Alpha & Data track
This commit is contained in:
141
src/app/api/trading/signals/route.ts
Normal file
141
src/app/api/trading/signals/route.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Trading Signals API Routes for Mantle AI Trading Bot
|
||||
*/
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { signalEngine } from '@/lib/trading/signals/signal-engine';
|
||||
import { newsAggregator } from '@/lib/trading/news/news-aggregator';
|
||||
import { TimeFrame } from '@/lib/trading/core/types';
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
// GET /api/trading/signals - Get signals
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const symbol = searchParams.get('symbol');
|
||||
const status = searchParams.get('status');
|
||||
const limit = parseInt(searchParams.get('limit') || '50');
|
||||
|
||||
const where: Record<string, unknown> = {};
|
||||
if (symbol) where.symbol = symbol;
|
||||
if (status) where.status = status;
|
||||
|
||||
const signals = await db.signal.findMany({
|
||||
where,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: limit
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, data: signals });
|
||||
} catch (error) {
|
||||
console.error('Error fetching signals:', error);
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Failed to fetch signals' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/trading/signals - Generate new signal
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { symbol, timeframe = '1h', demo = true } = body;
|
||||
|
||||
if (!symbol) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Symbol is required' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Generate simulated market data (in production, fetch from Bybit)
|
||||
const marketData = generateDemoMarketData(symbol, 200);
|
||||
|
||||
// Fetch news for the symbol
|
||||
const news = await newsAggregator.getNewsForSymbol(symbol, 10);
|
||||
|
||||
// Generate signal
|
||||
const signalOutput = await signalEngine.generateSignal({
|
||||
symbol,
|
||||
timeframe: timeframe as TimeFrame,
|
||||
marketData,
|
||||
newsArticles: news
|
||||
});
|
||||
|
||||
// Save signal to database
|
||||
const savedSignal = await db.signal.create({
|
||||
data: {
|
||||
symbol: signalOutput.signal.symbol,
|
||||
action: signalOutput.signal.action,
|
||||
confidence: signalOutput.signal.confidence,
|
||||
rating: 0,
|
||||
priceTarget: signalOutput.signal.priceTarget,
|
||||
stopLoss: signalOutput.signal.stopLoss,
|
||||
takeProfit: signalOutput.signal.takeProfit,
|
||||
reasoning: signalOutput.signal.reasoning,
|
||||
newsSources: signalOutput.signal.newsSources || [],
|
||||
sentimentScore: signalOutput.signal.sentimentScore,
|
||||
technicalScore: signalOutput.signal.technicalScore,
|
||||
fundamentalScore: signalOutput.signal.fundamentalScore,
|
||||
status: 'PENDING',
|
||||
demo
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
signal: savedSignal,
|
||||
analysis: signalOutput.analysis,
|
||||
riskAssessment: signalOutput.riskAssessment
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error generating signal:', error);
|
||||
return NextResponse.json(
|
||||
{ success: false, error: 'Failed to generate signal' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to generate demo market data
|
||||
function generateDemoMarketData(symbol: string, count: number) {
|
||||
const prices: Record<string, number> = {
|
||||
BTCUSDT: 45000,
|
||||
ETHUSDT: 2500,
|
||||
SOLUSDT: 100,
|
||||
BNBUSDT: 300,
|
||||
XRPUSDT: 0.5
|
||||
};
|
||||
|
||||
const data = [];
|
||||
let price = prices[symbol] || 100;
|
||||
const now = Date.now();
|
||||
const hourMs = 60 * 60 * 1000;
|
||||
|
||||
for (let i = count; i >= 0; i--) {
|
||||
const change = (Math.random() - 0.5) * price * 0.02;
|
||||
const open = price;
|
||||
const close = price + change;
|
||||
const high = Math.max(open, close) + Math.random() * Math.abs(change) * 0.5;
|
||||
const low = Math.min(open, close) - Math.random() * Math.abs(change) * 0.5;
|
||||
const volume = 1000 + Math.random() * 5000;
|
||||
|
||||
data.push({
|
||||
symbol,
|
||||
timeframe: TimeFrame.ONE_HOUR,
|
||||
timestamp: new Date(now - i * hourMs),
|
||||
open,
|
||||
high,
|
||||
low,
|
||||
close,
|
||||
volume
|
||||
});
|
||||
|
||||
price = close;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
Reference in New Issue
Block a user