workspace/projects/trading-platform/apps/frontend/src/services/trading.service.ts
rckrdmrd 789d1ab46b
Some checks failed
CI Pipeline / changes (push) Has been cancelled
CI Pipeline / core (push) Has been cancelled
CI Pipeline / trading-backend (push) Has been cancelled
CI Pipeline / trading-data-service (push) Has been cancelled
CI Pipeline / trading-frontend (push) Has been cancelled
CI Pipeline / erp-core (push) Has been cancelled
CI Pipeline / erp-mecanicas (push) Has been cancelled
CI Pipeline / gamilit-backend (push) Has been cancelled
CI Pipeline / gamilit-frontend (push) Has been cancelled
changes on workspace
2025-12-09 14:46:20 -06:00

848 lines
22 KiB
TypeScript

/**
* Trading Service
* API client for trading and market data endpoints
*/
import axios from 'axios';
import type {
Candle,
Ticker,
OrderBook,
TradingSymbol,
Interval,
SMAData,
EMAData,
RSIData,
MACDData,
BollingerBandsData,
Watchlist,
WatchlistSymbolData,
PaperAccount,
PaperBalance,
PaperPosition,
PaperOrder,
PaperTrade,
CreateOrderInput,
AccountSummary,
} from '../types/trading.types';
// ============================================================================
// API Configuration
// ============================================================================
const API_BASE_URL = import.meta.env?.VITE_API_URL || '/api/v1';
const api = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json',
},
});
// Add request interceptor for auth token
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Add response interceptor for error handling
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Token expired or invalid
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
// ============================================================================
// Market Data API
// ============================================================================
/**
* Get candlestick data (OHLCV)
*/
export async function getKlines(
symbol: string,
interval: Interval = '1h',
limit: number = 500
): Promise<Candle[]> {
try {
const response = await api.get(`/trading/market/klines/${symbol}`, {
params: { interval, limit },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch klines:', error);
throw new Error('Failed to fetch chart data');
}
}
/**
* Get current price for a symbol
*/
export async function getPrice(symbol: string): Promise<number> {
try {
const response = await api.get(`/trading/market/price/${symbol}`);
return response.data.data.price || response.data.price;
} catch (error) {
console.error('Failed to fetch price:', error);
throw new Error('Failed to fetch price');
}
}
/**
* Get 24h ticker data
*/
export async function getTicker(symbol: string): Promise<Ticker> {
try {
const response = await api.get(`/trading/market/ticker/${symbol}`);
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch ticker:', error);
throw new Error('Failed to fetch ticker data');
}
}
/**
* Get all tickers
*/
export async function getAllTickers(): Promise<Ticker[]> {
try {
const response = await api.get('/trading/market/tickers');
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch tickers:', error);
throw new Error('Failed to fetch tickers');
}
}
/**
* Get order book
*/
export async function getOrderBook(symbol: string, limit: number = 20): Promise<OrderBook> {
try {
const response = await api.get(`/trading/market/orderbook/${symbol}`, {
params: { limit },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch order book:', error);
throw new Error('Failed to fetch order book');
}
}
/**
* Search for symbols
*/
export async function searchSymbols(query: string): Promise<TradingSymbol[]> {
try {
const response = await api.get('/trading/market/search', {
params: { query },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to search symbols:', error);
throw new Error('Failed to search symbols');
}
}
/**
* Get popular symbols
*/
export async function getPopularSymbols(): Promise<TradingSymbol[]> {
try {
const response = await api.get('/trading/market/popular');
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch popular symbols:', error);
throw new Error('Failed to fetch popular symbols');
}
}
// ============================================================================
// Technical Indicators API
// ============================================================================
/**
* Get Simple Moving Average (SMA)
*/
export async function getSMA(
symbol: string,
interval: Interval = '1h',
period: number = 20
): Promise<SMAData[]> {
try {
const response = await api.get(`/trading/indicators/${symbol}/sma`, {
params: { interval, period },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch SMA:', error);
throw new Error('Failed to fetch SMA');
}
}
/**
* Get Exponential Moving Average (EMA)
*/
export async function getEMA(
symbol: string,
interval: Interval = '1h',
period: number = 20
): Promise<EMAData[]> {
try {
const response = await api.get(`/trading/indicators/${symbol}/ema`, {
params: { interval, period },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch EMA:', error);
throw new Error('Failed to fetch EMA');
}
}
/**
* Get Relative Strength Index (RSI)
*/
export async function getRSI(
symbol: string,
interval: Interval = '1h',
period: number = 14
): Promise<RSIData[]> {
try {
const response = await api.get(`/trading/indicators/${symbol}/rsi`, {
params: { interval, period },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch RSI:', error);
throw new Error('Failed to fetch RSI');
}
}
/**
* Get MACD
*/
export async function getMACD(
symbol: string,
interval: Interval = '1h',
fastPeriod: number = 12,
slowPeriod: number = 26,
signalPeriod: number = 9
): Promise<MACDData[]> {
try {
const response = await api.get(`/trading/indicators/${symbol}/macd`, {
params: { interval, fastPeriod, slowPeriod, signalPeriod },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch MACD:', error);
throw new Error('Failed to fetch MACD');
}
}
/**
* Get Bollinger Bands
*/
export async function getBollingerBands(
symbol: string,
interval: Interval = '1h',
period: number = 20,
stdDev: number = 2
): Promise<BollingerBandsData[]> {
try {
const response = await api.get(`/trading/indicators/${symbol}/bollinger`, {
params: { interval, period, stdDev },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch Bollinger Bands:', error);
throw new Error('Failed to fetch Bollinger Bands');
}
}
// ============================================================================
// Watchlist API
// ============================================================================
/**
* Get all user watchlists
*/
export async function getWatchlists(): Promise<Watchlist[]> {
try {
const response = await api.get('/trading/watchlists');
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch watchlists:', error);
throw new Error('Failed to fetch watchlists');
}
}
/**
* Get default watchlist
*/
export async function getDefaultWatchlist(): Promise<Watchlist> {
try {
const response = await api.get('/trading/watchlists/default');
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch default watchlist:', error);
throw new Error('Failed to fetch default watchlist');
}
}
/**
* Get watchlist by ID
*/
export async function getWatchlist(id: string): Promise<Watchlist> {
try {
const response = await api.get(`/trading/watchlists/${id}`);
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch watchlist:', error);
throw new Error('Failed to fetch watchlist');
}
}
/**
* Create new watchlist
*/
export async function createWatchlist(name: string): Promise<Watchlist> {
try {
const response = await api.post('/trading/watchlists', { name });
return response.data.data || response.data;
} catch (error) {
console.error('Failed to create watchlist:', error);
throw new Error('Failed to create watchlist');
}
}
/**
* Update watchlist
*/
export async function updateWatchlist(id: string, name: string): Promise<Watchlist> {
try {
const response = await api.patch(`/trading/watchlists/${id}`, { name });
return response.data.data || response.data;
} catch (error) {
console.error('Failed to update watchlist:', error);
throw new Error('Failed to update watchlist');
}
}
/**
* Delete watchlist
*/
export async function deleteWatchlist(id: string): Promise<void> {
try {
await api.delete(`/trading/watchlists/${id}`);
} catch (error) {
console.error('Failed to delete watchlist:', error);
throw new Error('Failed to delete watchlist');
}
}
/**
* Add symbol to watchlist
*/
export async function addSymbolToWatchlist(watchlistId: string, symbol: string): Promise<void> {
try {
await api.post(`/trading/watchlists/${watchlistId}/symbols`, { symbol });
} catch (error) {
console.error('Failed to add symbol to watchlist:', error);
throw new Error('Failed to add symbol to watchlist');
}
}
/**
* Remove symbol from watchlist
*/
export async function removeSymbolFromWatchlist(watchlistId: string, symbol: string): Promise<void> {
try {
await api.delete(`/trading/watchlists/${watchlistId}/symbols/${symbol}`);
} catch (error) {
console.error('Failed to remove symbol from watchlist:', error);
throw new Error('Failed to remove symbol from watchlist');
}
}
/**
* Get watchlist data with prices
*/
export async function getWatchlistData(symbols: string[]): Promise<WatchlistSymbolData[]> {
try {
const symbolsParam = symbols.join(',');
const response = await api.get('/trading/market/watchlist', {
params: { symbols: symbolsParam },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch watchlist data:', error);
throw new Error('Failed to fetch watchlist data');
}
}
// ============================================================================
// Paper Trading API
// ============================================================================
/**
* Initialize paper trading account
*/
export async function initializePaperAccount(
initialBalance: number = 100000,
name: string = 'Default Paper Account'
): Promise<PaperAccount> {
try {
const response = await api.post('/trading/paper/initialize', {
initialBalance,
name,
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to initialize paper account:', error);
throw new Error('Failed to initialize paper account');
}
}
/**
* Get paper trading balances
*/
export async function getPaperBalances(): Promise<PaperBalance> {
try {
const response = await api.get('/trading/paper/balances');
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch paper balances:', error);
throw new Error('Failed to fetch paper balances');
}
}
/**
* Create paper trading order
*/
export async function createPaperOrder(orderData: CreateOrderInput): Promise<PaperOrder> {
try {
const response = await api.post('/trading/paper/orders', orderData);
return response.data.data || response.data;
} catch (error) {
console.error('Failed to create paper order:', error);
throw new Error('Failed to create paper order');
}
}
/**
* Cancel paper trading order
*/
export async function cancelPaperOrder(orderId: string): Promise<void> {
try {
await api.delete(`/trading/paper/orders/${orderId}`);
} catch (error) {
console.error('Failed to cancel paper order:', error);
throw new Error('Failed to cancel paper order');
}
}
/**
* Get paper trading orders
*/
export async function getPaperOrders(status?: string): Promise<PaperOrder[]> {
try {
const response = await api.get('/trading/paper/orders', {
params: status ? { status } : undefined,
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch paper orders:', error);
throw new Error('Failed to fetch paper orders');
}
}
/**
* Get paper trading positions
*/
export async function getPaperPositions(status: string = 'open'): Promise<PaperPosition[]> {
try {
const response = await api.get('/trading/paper/positions', {
params: { status },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch paper positions:', error);
throw new Error('Failed to fetch paper positions');
}
}
/**
* Close paper trading position
*/
export async function closePaperPosition(positionId: string): Promise<PaperPosition> {
try {
const response = await api.post(`/trading/paper/positions/${positionId}/close`);
return response.data.data || response.data;
} catch (error) {
console.error('Failed to close paper position:', error);
throw new Error('Failed to close paper position');
}
}
/**
* Get paper trading trades history
*/
export async function getPaperTrades(limit: number = 50): Promise<PaperTrade[]> {
try {
const response = await api.get('/trading/paper/trades', {
params: { limit },
});
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch paper trades:', error);
throw new Error('Failed to fetch paper trades');
}
}
/**
* Get paper trading portfolio summary
*/
export async function getPaperPortfolio(): Promise<AccountSummary> {
try {
const response = await api.get('/trading/paper/portfolio');
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch paper portfolio:', error);
throw new Error('Failed to fetch paper portfolio');
}
}
/**
* Reset paper trading account
*/
export async function resetPaperAccount(): Promise<PaperAccount> {
try {
const response = await api.post('/trading/paper/reset');
return response.data.data || response.data;
} catch (error) {
console.error('Failed to reset paper account:', error);
throw new Error('Failed to reset paper account');
}
}
/**
* Get paper trading statistics
*/
export async function getPaperStats(): Promise<AccountSummary> {
try {
const response = await api.get('/trading/paper/stats');
return response.data.data || response.data;
} catch (error) {
console.error('Failed to fetch paper stats:', error);
throw new Error('Failed to fetch paper stats');
}
}
// ============================================================================
// ML-Powered Trade Execution
// ============================================================================
export interface MLTradeRequest {
symbol: string;
direction: 'buy' | 'sell';
source: 'ict' | 'ensemble' | 'manual';
entry_price?: number;
stop_loss?: number;
take_profit?: number;
risk_percent?: number;
lot_size?: number;
analysis_data?: Record<string, unknown>;
}
export interface MLTradeResult {
success: boolean;
trade_id?: string;
order_id?: string;
executed_price?: number;
lot_size?: number;
message: string;
error?: string;
}
export interface MT4Account {
account_id: string;
broker: string;
balance: number;
equity: number;
margin: number;
free_margin: number;
leverage: number;
currency: string;
connected: boolean;
}
export interface MT4Position {
ticket: number;
symbol: string;
type: 'buy' | 'sell';
volume: number;
open_price: number;
current_price: number;
stop_loss: number;
take_profit: number;
profit: number;
open_time: string;
comment?: string;
}
const LLM_AGENT_URL = import.meta.env.VITE_LLM_AGENT_URL || 'http://localhost:8003';
/**
* Execute a trade based on ML signal via LLM Agent
*/
export async function executeMLTrade(request: MLTradeRequest): Promise<MLTradeResult> {
try {
const response = await fetch(`${LLM_AGENT_URL}/api/trade/execute`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`,
},
body: JSON.stringify(request),
});
if (!response.ok) {
const error = await response.json();
return {
success: false,
message: 'Trade execution failed',
error: error.detail || error.message || 'Unknown error',
};
}
return await response.json();
} catch (error) {
console.error('Failed to execute ML trade:', error);
return {
success: false,
message: 'Trade execution failed',
error: error instanceof Error ? error.message : 'Network error',
};
}
}
/**
* Get MT4 account information
*/
export async function getMT4Account(): Promise<MT4Account | null> {
try {
const response = await fetch(`${LLM_AGENT_URL}/api/mt4/account`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
},
});
if (!response.ok) return null;
return await response.json();
} catch (error) {
console.error('Failed to get MT4 account:', error);
return null;
}
}
/**
* Get MT4 open positions
*/
export async function getMT4Positions(): Promise<MT4Position[]> {
try {
const response = await fetch(`${LLM_AGENT_URL}/api/mt4/positions`, {
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
},
});
if (!response.ok) return [];
const data = await response.json();
return data.positions || [];
} catch (error) {
console.error('Failed to get MT4 positions:', error);
return [];
}
}
/**
* Close MT4 position
*/
export async function closeMT4Position(ticket: number): Promise<MLTradeResult> {
try {
const response = await fetch(`${LLM_AGENT_URL}/api/mt4/positions/${ticket}/close`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
},
});
if (!response.ok) {
const error = await response.json();
return {
success: false,
message: 'Failed to close position',
error: error.detail || error.message,
};
}
return await response.json();
} catch (error) {
console.error('Failed to close MT4 position:', error);
return {
success: false,
message: 'Failed to close position',
error: error instanceof Error ? error.message : 'Network error',
};
}
}
/**
* Modify MT4 position (SL/TP)
*/
export async function modifyMT4Position(
ticket: number,
stopLoss?: number,
takeProfit?: number
): Promise<MLTradeResult> {
try {
const response = await fetch(`${LLM_AGENT_URL}/api/mt4/positions/${ticket}/modify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`,
},
body: JSON.stringify({ stop_loss: stopLoss, take_profit: takeProfit }),
});
if (!response.ok) {
const error = await response.json();
return {
success: false,
message: 'Failed to modify position',
error: error.detail || error.message,
};
}
return await response.json();
} catch (error) {
console.error('Failed to modify MT4 position:', error);
return {
success: false,
message: 'Failed to modify position',
error: error instanceof Error ? error.message : 'Network error',
};
}
}
/**
* Calculate position size based on risk
*/
export async function calculatePositionSize(
symbol: string,
stopLossPips: number,
riskPercent: number = 1
): Promise<{ lot_size: number; risk_amount: number } | null> {
try {
const response = await fetch(`${LLM_AGENT_URL}/api/mt4/calculate-size`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`,
},
body: JSON.stringify({
symbol,
stop_loss_pips: stopLossPips,
risk_percent: riskPercent,
}),
});
if (!response.ok) return null;
return await response.json();
} catch (error) {
console.error('Failed to calculate position size:', error);
return null;
}
}
/**
* Get LLM Agent health status
*/
export async function getLLMAgentHealth(): Promise<boolean> {
try {
const response = await fetch(`${LLM_AGENT_URL}/health`);
return response.ok;
} catch {
return false;
}
}
// ============================================================================
// Export
// ============================================================================
export const tradingService = {
// Market data
getKlines,
getPrice,
getTicker,
getAllTickers,
getOrderBook,
searchSymbols,
getPopularSymbols,
// Indicators
getSMA,
getEMA,
getRSI,
getMACD,
getBollingerBands,
// Watchlist
getWatchlists,
getDefaultWatchlist,
getWatchlist,
createWatchlist,
updateWatchlist,
deleteWatchlist,
addSymbolToWatchlist,
removeSymbolFromWatchlist,
getWatchlistData,
// Paper Trading
initializePaperAccount,
getPaperBalances,
createPaperOrder,
cancelPaperOrder,
getPaperOrders,
getPaperPositions,
closePaperPosition,
getPaperTrades,
getPaperPortfolio,
resetPaperAccount,
getPaperStats,
// ML-Powered Trading & MT4
executeMLTrade,
getMT4Account,
getMT4Positions,
closeMT4Position,
modifyMT4Position,
calculatePositionSize,
getLLMAgentHealth,
};
export default tradingService;