From 9be14a1602ef5c764927e3bafe5d8faaa2eeff3b Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 3 Nov 2025 21:27:04 -0500 Subject: [PATCH] fix: correct profit calculation to compare against start-of-day value Previously, profit calculations compared portfolio value to the previous day's final value. This caused trades to appear as losses since buying stocks decreases cash and increases stock value equally (net zero change). Now profit calculations compare to the start-of-day portfolio value (action_id=0 for current date), which accurately reflects gains/losses from price movements and trading decisions. Changes: - agent_tools/tool_trade.py: Fixed profit calc in _buy_impl() and _sell_impl() - tools/price_tools.py: Fixed profit calc in add_no_trade_record_to_db() Test: test_profit_calculation_accuracy now passes --- agent_tools/tool_trade.py | 34 ++++++++++++++++++++++------------ tools/price_tools.py | 17 +++++++++++------ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/agent_tools/tool_trade.py b/agent_tools/tool_trade.py index 981b7ba..2b52b8e 100644 --- a/agent_tools/tool_trade.py +++ b/agent_tools/tool_trade.py @@ -141,20 +141,25 @@ def _buy_impl(symbol: str, amount: int, signature: str = None, today_date: str = except KeyError: pass # Symbol price not available, skip - # Get previous portfolio value for P&L calculation + # Get start-of-day portfolio value (action_id=0 for today) for P&L calculation cursor.execute(""" SELECT portfolio_value FROM positions - WHERE job_id = ? AND model = ? AND date < ? - ORDER BY date DESC, action_id DESC + WHERE job_id = ? AND model = ? AND date = ? AND action_id = 0 LIMIT 1 """, (job_id, signature, today_date)) row = cursor.fetchone() - previous_value = row[0] if row else 10000.0 # Default initial value - daily_profit = portfolio_value - previous_value - daily_return_pct = (daily_profit / previous_value * 100) if previous_value > 0 else 0 + if row: + # Compare to start of day (action_id=0) + start_of_day_value = row[0] + daily_profit = portfolio_value - start_of_day_value + daily_return_pct = (daily_profit / start_of_day_value * 100) if start_of_day_value > 0 else 0 + else: + # First action of first day - no baseline yet + daily_profit = 0.0 + daily_return_pct = 0.0 # Step 6: Write to positions table created_at = datetime.utcnow().isoformat() + "Z" @@ -284,20 +289,25 @@ def _sell_impl(symbol: str, amount: int, signature: str = None, today_date: str except KeyError: pass - # Get previous portfolio value + # Get start-of-day portfolio value (action_id=0 for today) for P&L calculation cursor.execute(""" SELECT portfolio_value FROM positions - WHERE job_id = ? AND model = ? AND date < ? - ORDER BY date DESC, action_id DESC + WHERE job_id = ? AND model = ? AND date = ? AND action_id = 0 LIMIT 1 """, (job_id, signature, today_date)) row = cursor.fetchone() - previous_value = row[0] if row else 10000.0 - daily_profit = portfolio_value - previous_value - daily_return_pct = (daily_profit / previous_value * 100) if previous_value > 0 else 0 + if row: + # Compare to start of day (action_id=0) + start_of_day_value = row[0] + daily_profit = portfolio_value - start_of_day_value + daily_return_pct = (daily_profit / start_of_day_value * 100) if start_of_day_value > 0 else 0 + else: + # First action of first day - no baseline yet + daily_profit = 0.0 + daily_return_pct = 0.0 # Step 6: Write to positions table created_at = datetime.utcnow().isoformat() + "Z" diff --git a/tools/price_tools.py b/tools/price_tools.py index f25b1b0..c5e8650 100644 --- a/tools/price_tools.py +++ b/tools/price_tools.py @@ -414,20 +414,25 @@ def add_no_trade_record_to_db( logger.warning(f"Price not found for {symbol} on {today_date}") pass - # Get previous value for P&L + # Get start-of-day portfolio value (action_id=0 for today) for P&L calculation cursor.execute(""" SELECT portfolio_value FROM positions - WHERE job_id = ? AND model = ? AND date < ? - ORDER BY date DESC, action_id DESC + WHERE job_id = ? AND model = ? AND date = ? AND action_id = 0 LIMIT 1 """, (job_id, modelname, today_date)) row = cursor.fetchone() - previous_value = row[0] if row else 10000.0 - daily_profit = portfolio_value - previous_value - daily_return_pct = (daily_profit / previous_value * 100) if previous_value > 0 else 0 + if row: + # Compare to start of day (action_id=0) + start_of_day_value = row[0] + daily_profit = portfolio_value - start_of_day_value + daily_return_pct = (daily_profit / start_of_day_value * 100) if start_of_day_value > 0 else 0 + else: + # First action of first day - no baseline yet + daily_profit = 0.0 + daily_return_pct = 0.0 # Insert position record created_at = datetime.utcnow().isoformat() + "Z"