From 8d76d820fe43282a5d6a29997119a84bdb733f68 Mon Sep 17 00:00:00 2001 From: "Bobby (aider)" Date: Thu, 13 Feb 2025 08:39:51 -0800 Subject: [PATCH] feat: Enhance trade history display with position-based grouping and comprehensive trade details --- src/pages/journal/trading_journal_page.py | 70 +++++++++++++---------- src/trading/journal.py | 12 ++-- 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/pages/journal/trading_journal_page.py b/src/pages/journal/trading_journal_page.py index c1a43e4..74e98e8 100644 --- a/src/pages/journal/trading_journal_page.py +++ b/src/pages/journal/trading_journal_page.py @@ -280,40 +280,52 @@ def trading_journal_page(): history = get_trade_history() if history: + # Group trades by position_id + positions = {} + for trade in history: + if trade['position_id'] not in positions: + positions[trade['position_id']] = [] + positions[trade['position_id']].append(trade) + # Add P/L chart fig = plot_trade_history(history) if fig: st.plotly_chart(fig, use_container_width=True) - for trade in history: - # Determine if this is a sell order or a closed trade - is_sell = trade.get('direction') == 'sell' + # Display trades grouped by position + for position_id, trades in positions.items(): + # Sort trades by entry_date + trades.sort(key=lambda x: x['entry_date']) + first_trade = trades[0] - with st.expander(f"{trade['ticker']} - {format_datetime(trade['entry_date'])}"): - if is_sell: - profit_loss = (trade['entry_price'] - trade.get('exit_price', 0)) * trade['shares'] - else: - profit_loss = (trade.get('exit_price', 0) - trade['entry_price']) * trade['shares'] if trade.get('exit_price') else None - - col1, col2 = st.columns(2) - with col1: - if is_sell: - st.metric("Sell Price", f"${trade['entry_price']:.2f}") - else: - st.metric("Entry Price", f"${trade['entry_price']:.2f}") - st.metric("Shares", trade['shares']) - if profit_loss is not None: - st.metric("P/L", f"${profit_loss:.2f}") - - with col2: - if not is_sell and trade.get('exit_price'): - st.metric("Exit Price", f"${trade['exit_price']:.2f}") - st.metric("Exit Date", format_datetime(trade['exit_date'])) - - if trade.get('strategy'): - st.text(f"Strategy: {trade['strategy']}") - if trade.get('notes'): - st.text(f"Notes: {trade['notes']}") - st.text(f"Type: {'Sell Order' if is_sell else 'Buy'}") + with st.expander(f"{first_trade['ticker']} - Position {position_id}"): + for trade in trades: + st.markdown(f"**{format_datetime(trade['entry_date'])}**") + + col1, col2 = st.columns(2) + with col1: + if trade['direction'] == 'sell': + st.metric("Sell Price", f"${trade['entry_price']:.2f}") + else: + st.metric("Entry Price", f"${trade['entry_price']:.2f}") + st.metric("Shares", trade['shares']) + st.metric("Type", trade['direction'].capitalize()) + + with col2: + if trade['direction'] == 'buy': + if trade.get('target_price'): + st.metric("Target", f"${trade['target_price']:.2f}") + if trade.get('stop_loss'): + st.metric("Stop Loss", f"${trade['stop_loss']:.2f}") + if trade.get('exit_price'): + st.metric("Exit Price", f"${trade['exit_price']:.2f}") + st.metric("Exit Date", format_datetime(trade['exit_date'])) + + if trade.get('strategy'): + st.text(f"Strategy: {trade['strategy']}") + if trade.get('notes'): + st.text(f"Notes: {trade['notes']}") + + st.markdown("---") else: st.info("No trade history found") diff --git a/src/trading/journal.py b/src/trading/journal.py index 746a127..d863bc0 100644 --- a/src/trading/journal.py +++ b/src/trading/journal.py @@ -524,16 +524,18 @@ def delete_trade(trade_id: int) -> bool: def get_trade_history(limit: int = 50): with create_client() as client: query = f""" - SELECT * FROM stock_db.trades - WHERE exit_price IS NOT NULL - OR direction = 'sell' - ORDER BY COALESCE(exit_date, entry_date) DESC + SELECT + *, + groupArray(ticker) OVER (PARTITION BY position_id) as related_tickers, + groupArray(id) OVER (PARTITION BY position_id) as related_ids + FROM stock_db.trades + ORDER BY entry_date DESC LIMIT {limit} """ result = client.query(query).result_rows columns = ['id', 'position_id', 'ticker', 'entry_date', 'shares', 'entry_price', 'target_price', 'stop_loss', 'strategy', 'order_type', 'followed_rules', 'entry_reason', 'exit_price', - 'exit_date', 'exit_reason', 'notes', 'created_at', 'direction'] + 'exit_date', 'exit_reason', 'notes', 'created_at', 'direction', 'related_tickers', 'related_ids'] return [dict(zip(columns, row)) for row in result] def journal_menu():