|
@@ -1244,12 +1244,17 @@ class TradingStats:
|
|
|
# =============================================================================
|
|
|
|
|
|
def create_trade_lifecycle(self, symbol: str, side: str, entry_order_id: Optional[str] = None,
|
|
|
- stop_loss_price: Optional[float] = None, take_profit_price: Optional[float] = None,
|
|
|
+ entry_bot_order_ref_id: Optional[str] = None, # New parameter
|
|
|
+ stop_loss_price: Optional[float] = None,
|
|
|
+ take_profit_price: Optional[float] = None,
|
|
|
trade_type: str = 'manual') -> Optional[str]:
|
|
|
- """Create a new trade lifecycle when an entry order is placed."""
|
|
|
+ """Create a new trade lifecycle.
|
|
|
+ If stop_loss_price is provided, also creates a conceptual 'pending_sl_activation' order.
|
|
|
+ """
|
|
|
try:
|
|
|
lifecycle_id = str(uuid.uuid4())
|
|
|
|
|
|
+ # Main lifecycle record in 'trades' table
|
|
|
query = """
|
|
|
INSERT INTO trades (
|
|
|
symbol, side, amount, price, value, trade_type, timestamp,
|
|
@@ -1262,8 +1267,32 @@ class TradingStats:
|
|
|
entry_order_id, stop_loss_price, take_profit_price, timestamp)
|
|
|
|
|
|
self._execute_query(query, params)
|
|
|
-
|
|
|
- logger.info(f"📊 Created trade lifecycle {lifecycle_id}: {side.upper()} {symbol} (pending)")
|
|
|
+ logger.info(f"📊 Created trade lifecycle {lifecycle_id}: {side.upper()} {symbol} (pending for exch_id: {entry_order_id or 'N/A'})")
|
|
|
+
|
|
|
+ # If SL price is provided, create a conceptual pending SL order in 'orders' table
|
|
|
+ if stop_loss_price is not None and entry_bot_order_ref_id is not None:
|
|
|
+ sl_order_side = 'sell' if side.lower() == 'buy' else 'buy'
|
|
|
+ # Using entry_bot_order_ref_id ensures this conceptual SL is linked to the specific entry attempt
|
|
|
+ conceptual_sl_bot_ref_id = f"pending_sl_activation_{entry_bot_order_ref_id}"
|
|
|
+
|
|
|
+ # Record this conceptual order. Amount is 0 for now.
|
|
|
+ # The actual amount will be determined when the SL is placed after entry fill.
|
|
|
+ sl_order_db_id = self.record_order_placed(
|
|
|
+ symbol=symbol,
|
|
|
+ side=sl_order_side,
|
|
|
+ order_type='pending_sl_activation', # New conceptual type
|
|
|
+ amount_requested=0, # Placeholder amount
|
|
|
+ price=stop_loss_price,
|
|
|
+ bot_order_ref_id=conceptual_sl_bot_ref_id,
|
|
|
+ status='pending_activation', # New conceptual status
|
|
|
+ parent_bot_order_ref_id=entry_bot_order_ref_id, # Link to the main entry order
|
|
|
+ exchange_order_id=None # Not on exchange yet
|
|
|
+ )
|
|
|
+ if sl_order_db_id:
|
|
|
+ logger.info(f"💡 Recorded conceptual 'pending_sl_activation' order (DB ID: {sl_order_db_id}, BotRef: {conceptual_sl_bot_ref_id}) for lifecycle {lifecycle_id} at SL price {stop_loss_price}.")
|
|
|
+ else:
|
|
|
+ logger.error(f"⚠️ Failed to record conceptual 'pending_sl_activation' order for lifecycle {lifecycle_id} (Entry BotRef: {entry_bot_order_ref_id}).")
|
|
|
+
|
|
|
return lifecycle_id
|
|
|
|
|
|
except Exception as e:
|
|
@@ -1420,7 +1449,8 @@ class TradingStats:
|
|
|
query = "SELECT * FROM trades WHERE trade_lifecycle_id = ?"
|
|
|
return self._fetchone_query(query, (lifecycle_id,))
|
|
|
|
|
|
- def get_trade_by_symbol_and_status(self, symbol: str, status: str = 'position_opened') -> Optional[Dict[str, Any]]:
|
|
|
+ # Re-instating the correct get_trade_by_symbol_and_status from earlier version in case it was overwritten by file read
|
|
|
+ def get_trade_by_symbol_and_status(self, symbol: str, status: str = 'position_opened') -> Optional[Dict[str, Any]]: # Copied from earlier state
|
|
|
"""Get trade by symbol and status."""
|
|
|
query = "SELECT * FROM trades WHERE symbol = ? AND status = ? ORDER BY updated_at DESC LIMIT 1"
|
|
|
return self._fetchone_query(query, (symbol, status))
|
|
@@ -1760,4 +1790,4 @@ class TradingStats:
|
|
|
except sqlite3.Error as e:
|
|
|
logger.error(f"Database error purging old daily_aggregated_stats: {e}", exc_info=True)
|
|
|
except Exception as e:
|
|
|
- logger.error(f"Unexpected error purging old daily_aggregated_stats: {e}", exc_info=True)
|
|
|
+ logger.error(f"Unexpected error purging old daily_aggregated_stats: {e}", exc_info=True)
|