- Added comprehensive PositionCalculator component with real-time PnL calculations - Implemented dynamic leverage adjustment with slider (1x to 100x) - Added investment amount input for position sizing - Integrated liquidation price calculations based on leverage and maintenance margin - Added real-time price fetching from multiple sources (CoinGecko, CoinCap, Binance) - Implemented automatic stop loss and take profit extraction from AI analysis - Added risk/reward ratio calculations and position metrics - Included trading fee calculations and net investment display - Added position type selection (Long/Short) with dynamic PnL calculation - Integrated high leverage warning system for risk management - Added advanced settings for customizable trading fees and maintenance margins - Automatically updates calculations when analysis parameters change - Supports both manual price input and real-time market data - Fully responsive design with gradient styling matching app theme
153 lines
4.1 KiB
TypeScript
153 lines
4.1 KiB
TypeScript
// Price fetcher utility for getting current market prices
|
|
export class PriceFetcher {
|
|
private static cache = new Map<string, { price: number; timestamp: number }>()
|
|
private static readonly CACHE_DURATION = 30000 // 30 seconds
|
|
|
|
static async getCurrentPrice(symbol: string): Promise<number> {
|
|
const cacheKey = symbol.toUpperCase()
|
|
const cached = this.cache.get(cacheKey)
|
|
|
|
// Return cached price if recent
|
|
if (cached && Date.now() - cached.timestamp < this.CACHE_DURATION) {
|
|
return cached.price
|
|
}
|
|
|
|
try {
|
|
// Try multiple price sources
|
|
let price = await this.fetchFromCoinGecko(symbol)
|
|
|
|
if (!price) {
|
|
price = await this.fetchFromCoinCap(symbol)
|
|
}
|
|
|
|
if (!price) {
|
|
price = await this.fetchFromBinance(symbol)
|
|
}
|
|
|
|
if (price) {
|
|
this.cache.set(cacheKey, { price, timestamp: Date.now() })
|
|
return price
|
|
}
|
|
|
|
return 0
|
|
} catch (error) {
|
|
console.error('Error fetching price:', error)
|
|
return cached?.price || 0
|
|
}
|
|
}
|
|
|
|
private static async fetchFromCoinGecko(symbol: string): Promise<number | null> {
|
|
try {
|
|
const coinId = this.getCoinGeckoId(symbol)
|
|
if (!coinId) return null
|
|
|
|
const response = await fetch(
|
|
`https://api.coingecko.com/api/v3/simple/price?ids=${coinId}&vs_currencies=usd`,
|
|
{ cache: 'no-cache' }
|
|
)
|
|
|
|
if (!response.ok) return null
|
|
|
|
const data = await response.json()
|
|
return data[coinId]?.usd || null
|
|
} catch (error) {
|
|
console.error('CoinGecko fetch error:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
private static async fetchFromCoinCap(symbol: string): Promise<number | null> {
|
|
try {
|
|
const asset = this.getCoinCapAsset(symbol)
|
|
if (!asset) return null
|
|
|
|
const response = await fetch(
|
|
`https://api.coincap.io/v2/assets/${asset}`,
|
|
{ cache: 'no-cache' }
|
|
)
|
|
|
|
if (!response.ok) return null
|
|
|
|
const data = await response.json()
|
|
return parseFloat(data.data?.priceUsd) || null
|
|
} catch (error) {
|
|
console.error('CoinCap fetch error:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
private static async fetchFromBinance(symbol: string): Promise<number | null> {
|
|
try {
|
|
const binanceSymbol = this.getBinanceSymbol(symbol)
|
|
if (!binanceSymbol) return null
|
|
|
|
const response = await fetch(
|
|
`https://api.binance.com/api/v3/ticker/price?symbol=${binanceSymbol}`,
|
|
{ cache: 'no-cache' }
|
|
)
|
|
|
|
if (!response.ok) return null
|
|
|
|
const data = await response.json()
|
|
return parseFloat(data.price) || null
|
|
} catch (error) {
|
|
console.error('Binance fetch error:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
private static getCoinGeckoId(symbol: string): string | null {
|
|
const mapping: Record<string, string> = {
|
|
'BTCUSD': 'bitcoin',
|
|
'ETHUSD': 'ethereum',
|
|
'SOLUSD': 'solana',
|
|
'SUIUSD': 'sui',
|
|
'ADAUSD': 'cardano',
|
|
'DOTUSD': 'polkadot',
|
|
'AVAXUSD': 'avalanche-2',
|
|
'LINKUSD': 'chainlink',
|
|
'MATICUSD': 'matic-network',
|
|
'UNIUSD': 'uniswap'
|
|
}
|
|
return mapping[symbol.toUpperCase()] || null
|
|
}
|
|
|
|
private static getCoinCapAsset(symbol: string): string | null {
|
|
const mapping: Record<string, string> = {
|
|
'BTCUSD': 'bitcoin',
|
|
'ETHUSD': 'ethereum',
|
|
'SOLUSD': 'solana',
|
|
'SUIUSD': 'sui',
|
|
'ADAUSD': 'cardano',
|
|
'DOTUSD': 'polkadot',
|
|
'AVAXUSD': 'avalanche',
|
|
'LINKUSD': 'chainlink',
|
|
'MATICUSD': 'polygon',
|
|
'UNIUSD': 'uniswap'
|
|
}
|
|
return mapping[symbol.toUpperCase()] || null
|
|
}
|
|
|
|
private static getBinanceSymbol(symbol: string): string | null {
|
|
const mapping: Record<string, string> = {
|
|
'BTCUSD': 'BTCUSDT',
|
|
'ETHUSD': 'ETHUSDT',
|
|
'SOLUSD': 'SOLUSDT',
|
|
'SUIUSD': 'SUIUSDT',
|
|
'ADAUSD': 'ADAUSDT',
|
|
'DOTUSD': 'DOTUSDT',
|
|
'AVAXUSD': 'AVAXUSDT',
|
|
'LINKUSD': 'LINKUSDT',
|
|
'MATICUSD': 'MATICUSDT',
|
|
'UNIUSD': 'UNIUSDT'
|
|
}
|
|
return mapping[symbol.toUpperCase()] || null
|
|
}
|
|
|
|
static clearCache(): void {
|
|
this.cache.clear()
|
|
}
|
|
}
|
|
|
|
export default PriceFetcher
|