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
848 lines
22 KiB
TypeScript
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;
|