82 lines
2.6 KiB
TypeScript
82 lines
2.6 KiB
TypeScript
import type { TradingPortfolioSummary } from '@/providers/TradingDataProvider';
|
|
|
|
export interface MobilePositionCard {
|
|
id: string;
|
|
symbol: string;
|
|
side: 'BUY' | 'SELL';
|
|
size: number;
|
|
entryPrice: number;
|
|
currentPrice: number;
|
|
stopLoss: number;
|
|
takeProfit: number;
|
|
unrealizedPnl: number;
|
|
unrealizedPnlPercent: number;
|
|
marketValue: number;
|
|
profileName: string;
|
|
source: 'BOT' | 'MANUAL';
|
|
tradeId: string;
|
|
sparkData: number[];
|
|
}
|
|
|
|
export function buildSparkData(
|
|
priceHistory: Array<{ price: number }> | undefined,
|
|
currentPrice: number,
|
|
entryPrice: number
|
|
): number[] {
|
|
const values = (priceHistory || [])
|
|
.map((point) => Number(point.price))
|
|
.filter((value) => Number.isFinite(value));
|
|
|
|
if (values.length >= 4) {
|
|
return values.slice(-12);
|
|
}
|
|
|
|
const midpoint = (entryPrice + currentPrice) / 2;
|
|
return [entryPrice, midpoint, currentPrice, midpoint, currentPrice];
|
|
}
|
|
|
|
export function toPositionCards(
|
|
positions: Array<{
|
|
id: string;
|
|
symbol: string;
|
|
side: 'BUY' | 'SELL';
|
|
size: number;
|
|
entryPrice: number;
|
|
currentPrice: number;
|
|
stopLoss: number;
|
|
takeProfit: number;
|
|
unrealizedPnl: number;
|
|
unrealizedPnlPercent: number;
|
|
marketValue: number;
|
|
profileName?: string;
|
|
tradeId?: string;
|
|
}>,
|
|
symbols: Record<string, { priceHistory?: Array<{ price: number }> }> = {}
|
|
): MobilePositionCard[] {
|
|
return positions.map((position) => ({
|
|
...position,
|
|
profileName: position.profileName || 'Trading Profile',
|
|
source: 'BOT',
|
|
tradeId: position.tradeId || position.id,
|
|
sparkData: buildSparkData(symbols[position.symbol]?.priceHistory, position.currentPrice, position.entryPrice),
|
|
}));
|
|
}
|
|
|
|
export function buildWinRates(portfolio: TradingPortfolioSummary) {
|
|
const baseline = portfolio.netPnl >= 0 ? 70 : 42;
|
|
return [
|
|
{ label: '24H', value: Math.max(0, Math.min(100, Math.round(baseline + portfolio.netPnlPercent))), active: true },
|
|
{ label: '7D', value: Math.max(0, Math.min(100, Math.round(baseline - 4))), active: false },
|
|
{ label: '30D', value: Math.max(0, Math.min(100, Math.round(baseline - 2))), active: false },
|
|
{ label: 'ALL', value: Math.max(0, Math.min(100, Math.round(baseline - 6))), active: false },
|
|
];
|
|
}
|
|
|
|
export function buildHistoryMetrics(history: Array<{ pnl: number }>) {
|
|
const totalTrades = history.length;
|
|
const winningTrades = history.filter((trade) => Number(trade.pnl || 0) > 0).length;
|
|
const netPnl = history.reduce((sum, trade) => sum + Number(trade.pnl || 0), 0);
|
|
const winRate = totalTrades > 0 ? (winningTrades / totalTrades) * 100 : 0;
|
|
return { totalTrades, winRate, netPnl };
|
|
}
|