Fix: UI incorrectly marking break-even wins as losses

This commit is contained in:
2026-03-15 18:49:31 -07:00
parent 02651535e6
commit bd0811e113

View File

@@ -79,7 +79,6 @@ export default function PaperDashboard() {
return ( return (
<div className="min-h-screen bg-gray-50 text-gray-900 font-sans pb-20"> <div className="min-h-screen bg-gray-50 text-gray-900 font-sans pb-20">
{/* Header */}
<header className="sticky top-0 z-50 bg-white/95 backdrop-blur border-b border-gray-200 px-4 py-3 shadow-sm"> <header className="sticky top-0 z-50 bg-white/95 backdrop-blur border-b border-gray-200 px-4 py-3 shadow-sm">
<div className="flex items-center justify-between max-w-lg mx-auto"> <div className="flex items-center justify-between max-w-lg mx-auto">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -105,10 +104,8 @@ export default function PaperDashboard() {
</header> </header>
<main className="max-w-lg mx-auto px-4 pt-4 space-y-4"> <main className="max-w-lg mx-auto px-4 pt-4 space-y-4">
{/* Market Card */}
<MarketCardCompact market={market} /> <MarketCardCompact market={market} />
{/* Strategy Tabs */}
<div className="flex gap-1 bg-gray-100 rounded-lg p-1 overflow-x-auto"> <div className="flex gap-1 bg-gray-100 rounded-lg p-1 overflow-x-auto">
{strategies.map(s => ( {strategies.map(s => (
<button <button
@@ -128,7 +125,6 @@ export default function PaperDashboard() {
))} ))}
</div> </div>
{/* Active Strategy View */}
{activeStrat && activeStratData && ( {activeStrat && activeStratData && (
<StrategyDetailView <StrategyDetailView
strategy={activeStratData} strategy={activeStratData}
@@ -137,11 +133,9 @@ export default function PaperDashboard() {
/> />
)} )}
{/* All Strategies Overview */}
<AllStrategiesOverview paperByStrategy={paperByStrategy} strategies={strategies} /> <AllStrategiesOverview paperByStrategy={paperByStrategy} strategies={strategies} />
</main> </main>
{/* Worker Uptime */}
<div className="fixed bottom-0 left-0 right-0 bg-white/95 backdrop-blur border-t border-gray-200 py-2 px-4"> <div className="fixed bottom-0 left-0 right-0 bg-white/95 backdrop-blur border-t border-gray-200 py-2 px-4">
<div className="max-w-lg mx-auto flex justify-between text-xs text-gray-400"> <div className="max-w-lg mx-auto flex justify-between text-xs text-gray-400">
<span>Worker: {formatUptime(data?.workerUptime)}</span> <span>Worker: {formatUptime(data?.workerUptime)}</span>
@@ -211,7 +205,6 @@ function StrategyDetailView({ strategy, stats, trades }) {
return ( return (
<div className="space-y-3"> <div className="space-y-3">
{/* Strategy Stats */}
<div className="bg-white rounded-xl p-4 border border-gray-200 shadow-sm"> <div className="bg-white rounded-xl p-4 border border-gray-200 shadow-sm">
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -228,7 +221,6 @@ function StrategyDetailView({ strategy, stats, trades }) {
<StatBox label="Trades" value={s.totalTrades} /> <StatBox label="Trades" value={s.totalTrades} />
</div> </div>
{/* Strategy Config */}
<div className="space-y-1 text-xs text-gray-500 border-t border-gray-100 pt-3"> <div className="space-y-1 text-xs text-gray-500 border-t border-gray-100 pt-3">
{strategy.config && Object.entries(strategy.config).map(([k, v]) => ( {strategy.config && Object.entries(strategy.config).map(([k, v]) => (
<div key={k} className="flex justify-between"> <div key={k} className="flex justify-between">
@@ -276,7 +268,6 @@ function StrategyDetailView({ strategy, stats, trades }) {
</div> </div>
</div> </div>
{/* Open Positions */}
{s.openPositions.length > 0 && ( {s.openPositions.length > 0 && (
<div> <div>
<h4 className="text-[10px] text-gray-400 uppercase tracking-wider mb-2 font-bold">Open Positions ({s.openPositions.length})</h4> <h4 className="text-[10px] text-gray-400 uppercase tracking-wider mb-2 font-bold">Open Positions ({s.openPositions.length})</h4>
@@ -284,7 +275,6 @@ function StrategyDetailView({ strategy, stats, trades }) {
</div> </div>
)} )}
{/* Trade History — only settled trades from DB */}
<div> <div>
<h4 className="text-[10px] text-gray-400 uppercase tracking-wider mb-2 font-bold"> <h4 className="text-[10px] text-gray-400 uppercase tracking-wider mb-2 font-bold">
Trade History ({trades.length}) Trade History ({trades.length})
@@ -349,8 +339,11 @@ function StatBox({ label, value, color }) {
} }
function TradeRow({ trade, isOpen }) { function TradeRow({ trade, isOpen }) {
const won = trade.pnl > 0; // Fix: Check side vs result for actual win condition, not strictly PNL > 0
const pnlColor = trade.pnl == null ? 'text-gray-400' : won ? 'text-green-600' : 'text-red-600'; const won = trade.result && trade.side.toLowerCase() === trade.result.toLowerCase();
const isNeutral = trade.result === 'cancelled' || trade.result === 'expired';
const pnlColor = trade.pnl == null ? 'text-gray-400' : trade.pnl > 0 ? 'text-green-600' : trade.pnl < 0 ? 'text-red-600' : 'text-gray-600';
return ( return (
<div className="bg-white rounded-lg p-3 border border-gray-200 mb-2 shadow-sm"> <div className="bg-white rounded-lg p-3 border border-gray-200 mb-2 shadow-sm">
@@ -359,7 +352,7 @@ function TradeRow({ trade, isOpen }) {
{isOpen ? ( {isOpen ? (
<span className="w-2 h-2 rounded-full bg-amber-400 animate-pulse" /> <span className="w-2 h-2 rounded-full bg-amber-400 animate-pulse" />
) : ( ) : (
<span>{won ? '✅' : '❌'}</span> <span>{isNeutral ? '' : won ? '✅' : '❌'}</span>
)} )}
<span className="text-sm font-medium capitalize text-gray-900">{trade.side}</span> <span className="text-sm font-medium capitalize text-gray-900">{trade.side}</span>
<span className="text-xs text-gray-400">@ {trade.price}¢</span> <span className="text-xs text-gray-400">@ {trade.price}¢</span>