@@ -38,6 +38,7 @@ const PerformanceChart = React.memo(({ selectedStock, onClearSelection }: Perfor
3838 const navigate = useNavigate ( ) ;
3939 const [ selectedPeriod , setSelectedPeriod ] = useState < TimePeriod > ( "1D" ) ;
4040 const [ loading , setLoading ] = useState ( false ) ;
41+ const [ positionsLoading , setPositionsLoading ] = useState ( true ) ; // Track positions loading separately
4142 const [ error , setError ] = useState < string | null > ( null ) ;
4243 const [ metrics , setMetrics ] = useState < any > ( null ) ;
4344 const [ portfolioData , setPortfolioData ] = useState < PortfolioData | null > ( null ) ;
@@ -111,6 +112,7 @@ const PerformanceChart = React.memo(({ selectedStock, onClearSelection }: Perfor
111112
112113 setMetrics ( metricsData ) ;
113114 setPositions ( positionsData || [ ] ) ;
115+ setPositionsLoading ( false ) ; // Mark positions as loaded
114116
115117 // If a stock is selected, fetch its data (uses Alpaca API)
116118 if ( selectedStock ) {
@@ -228,15 +230,19 @@ const PerformanceChart = React.memo(({ selectedStock, onClearSelection }: Perfor
228230 } ;
229231 }
230232
231- const shares = parseFloat ( position . qty ) ;
232- const avgCost = parseFloat ( position . avg_entry_price ) ;
233- const currentPrice = parseFloat ( position . current_price || 'Loading...' ) ;
234- const lastdayPrice = parseFloat ( position . lastday_price || 'Loading...' ) ;
235- const marketValue = parseFloat ( position . market_value ) ;
236- const unrealizedPL = parseFloat ( position . unrealized_pl ) ;
237- const unrealizedPLPercent = parseFloat ( position . unrealized_plpc ) * 100 ;
238- const todayPL = parseFloat ( position . unrealized_intraday_pl || 'Loading...' ) ;
239- const todayPLPercent = parseFloat ( position . unrealized_intraday_plpc || 'Loading...' ) * 100 ;
233+ // Handle both raw Alpaca format and transformed metrics format
234+ const shares = position . shares !== undefined ? position . shares : ( parseFloat ( position . qty || '0' ) || 0 ) ;
235+ const avgCost = position . avgCost !== undefined ? position . avgCost : ( parseFloat ( position . avg_entry_price || '0' ) || 0 ) ;
236+ const currentPrice = position . currentPrice !== undefined ? position . currentPrice : ( parseFloat ( position . current_price || '0' ) || 0 ) ;
237+ const lastdayPrice = position . lastdayPrice !== undefined ? position . lastdayPrice : ( parseFloat ( position . lastday_price || '0' ) || 0 ) ;
238+ const marketValue = position . marketValue !== undefined ? position . marketValue : ( parseFloat ( position . market_value || '0' ) || 0 ) ;
239+ const unrealizedPL = position . unrealizedPL !== undefined ? position . unrealizedPL : ( parseFloat ( position . unrealized_pl || '0' ) || 0 ) ;
240+ const unrealizedPLPercent = position . unrealizedPLPct !== undefined ? position . unrealizedPLPct : ( ( parseFloat ( position . unrealized_plpc || '0' ) || 0 ) * 100 ) ;
241+
242+ // For intraday P/L, calculate from day change if not directly available
243+ const dayChange = position . dayChange !== undefined ? position . dayChange : 0 ;
244+ const todayPL = position . unrealized_intraday_pl !== undefined ? parseFloat ( position . unrealized_intraday_pl || '0' ) : ( dayChange * shares * currentPrice / 100 ) ;
245+ const todayPLPercent = position . unrealized_intraday_plpc !== undefined ? ( parseFloat ( position . unrealized_intraday_plpc || '0' ) * 100 ) : dayChange ;
240246
241247 // Calculate stock's daily price change (not position P&L)
242248 const stockDailyChange = currentPrice - lastdayPrice ;
@@ -420,7 +426,7 @@ const PerformanceChart = React.memo(({ selectedStock, onClearSelection }: Perfor
420426 { periods . map ( ( period ) => (
421427 < TabsContent key = { period . value } value = { period . value } className = "space-y-4" >
422428 < div className = "h-48" >
423- { loading && ! portfolioData ? (
429+ { loading ? (
424430 < div className = "h-full flex items-center justify-center" >
425431 < Loader2 className = "h-8 w-8 animate-spin text-muted-foreground" />
426432 </ div >
@@ -499,7 +505,7 @@ const PerformanceChart = React.memo(({ selectedStock, onClearSelection }: Perfor
499505 </ ResponsiveContainer >
500506 ) : (
501507 < div className = "h-full flex items-center justify-center text-muted-foreground" >
502- { error ? error : ( hasAlpacaConfig ? "No data available for this period " : "Configure Alpaca API to view performance data" ) }
508+ { error ? error : ( hasAlpacaConfig ? "Loading chart data... " : "Configure Alpaca API to view performance data" ) }
503509 </ div >
504510 ) }
505511 </ div >
@@ -608,41 +614,57 @@ const PerformanceChart = React.memo(({ selectedStock, onClearSelection }: Perfor
608614 < div className = "grid grid-cols-3 gap-4 pt-4 border-t" >
609615 < div >
610616 < p className = "text-xs text-muted-foreground" > Position P& L Today </ p >
611- < p className = { `text-sm font-medium ${ getStockMetrics ( selectedStock ) . dailyReturn >= 0 ? 'text-success' : 'text-danger'
617+ < p className = { `text-sm font-medium ${ positionsLoading ? '' : getStockMetrics ( selectedStock ) . dailyReturn >= 0 ? 'text-success' : 'text-danger'
612618 } `} >
613- { getStockMetrics ( selectedStock ) . dailyReturn >= 0 ? '+' : '' }
614- ${ getStockMetrics ( selectedStock ) . dailyReturn . toFixed ( 2 ) }
615- ({ getStockMetrics ( selectedStock ) . dailyReturnPercent >= 0 ? '+' : '' }
616- { getStockMetrics ( selectedStock ) . dailyReturnPercent . toFixed ( 2 ) } %)
619+ { positionsLoading ? 'Loading...' : (
620+ < >
621+ { getStockMetrics ( selectedStock ) . dailyReturn >= 0 ? '+' : '' }
622+ ${ getStockMetrics ( selectedStock ) . dailyReturn . toFixed ( 2 ) }
623+ ({ getStockMetrics ( selectedStock ) . dailyReturnPercent >= 0 ? '+' : '' }
624+ { getStockMetrics ( selectedStock ) . dailyReturnPercent . toFixed ( 2 ) } %)
625+ </ >
626+ ) }
617627 </ p >
618628 </ div >
619629 < div >
620630 < p className = "text-xs text-muted-foreground" > Total Position P& L </ p >
621- < p className = { `text-sm font-medium ${ getStockMetrics ( selectedStock ) . totalReturn >= 0 ? 'text-success' : 'text-danger'
631+ < p className = { `text-sm font-medium ${ positionsLoading ? '' : getStockMetrics ( selectedStock ) . totalReturn >= 0 ? 'text-success' : 'text-danger'
622632 } `} >
623- { getStockMetrics ( selectedStock ) . totalReturn >= 0 ? '+' : '' }
624- ${ getStockMetrics ( selectedStock ) . totalReturn . toFixed ( 2 ) }
625- ({ getStockMetrics ( selectedStock ) . totalReturnPercent >= 0 ? '+' : '' }
626- { getStockMetrics ( selectedStock ) . totalReturnPercent . toFixed ( 2 ) } %)
633+ { positionsLoading ? 'Loading...' : (
634+ < >
635+ { getStockMetrics ( selectedStock ) . totalReturn >= 0 ? '+' : '' }
636+ ${ getStockMetrics ( selectedStock ) . totalReturn . toFixed ( 2 ) }
637+ ({ getStockMetrics ( selectedStock ) . totalReturnPercent >= 0 ? '+' : '' }
638+ { getStockMetrics ( selectedStock ) . totalReturnPercent . toFixed ( 2 ) } %)
639+ </ >
640+ ) }
627641 </ p >
628642 </ div >
629643 < div >
630644 < p className = "text-xs text-muted-foreground" > Shares Owned</ p >
631- < p className = "text-sm font-medium" > { getStockMetrics ( selectedStock ) . shares } </ p >
645+ < p className = "text-sm font-medium" >
646+ { positionsLoading ? 'Loading...' : getStockMetrics ( selectedStock ) . shares }
647+ </ p >
632648 </ div >
633649 </ div >
634650 < div className = "grid grid-cols-3 gap-4 pt-4 border-t" >
635651 < div >
636652 < p className = "text-xs text-muted-foreground" > Avg Cost</ p >
637- < p className = "text-sm font-medium" > ${ getStockMetrics ( selectedStock ) . avgCost . toFixed ( 2 ) } </ p >
653+ < p className = "text-sm font-medium" >
654+ { positionsLoading ? 'Loading...' : `$${ getStockMetrics ( selectedStock ) . avgCost . toFixed ( 2 ) } ` }
655+ </ p >
638656 </ div >
639657 < div >
640658 < p className = "text-xs text-muted-foreground" > Total Position</ p >
641- < p className = "text-sm font-medium" > ${ getStockMetrics ( selectedStock ) . positionValue . toLocaleString ( ) } </ p >
659+ < p className = "text-sm font-medium" >
660+ { positionsLoading ? 'Loading...' : `$${ getStockMetrics ( selectedStock ) . positionValue . toLocaleString ( ) } ` }
661+ </ p >
642662 </ div >
643663 < div >
644664 < p className = "text-xs text-muted-foreground" > % of Portfolio</ p >
645- < p className = "text-sm font-medium" > { getStockMetrics ( selectedStock ) . portfolioPercent . toFixed ( 1 ) } %</ p >
665+ < p className = "text-sm font-medium" >
666+ { positionsLoading ? 'Loading...' : `${ getStockMetrics ( selectedStock ) . portfolioPercent . toFixed ( 1 ) } %` }
667+ </ p >
646668 </ div >
647669 </ div >
648670 </ div >
0 commit comments