From f99fc7fdc154c9b72771593d041f9c974ea14a66 Mon Sep 17 00:00:00 2001 From: Celes Renata Date: Wed, 13 May 2026 19:51:43 +0000 Subject: [PATCH] fix: add 24h sell cooldown to prevent immediate re-entry after profit-taking After selling a position (profit-taking, stop-loss, or recommendation), the engine would immediately buy it back on the next poll cycle if a buy recommendation existed. Now sets a 24h Redis cooldown key per ticker on any sell, and checks it before entering a new buy position. --- services/trading/engine.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/services/trading/engine.py b/services/trading/engine.py index 6f91f9a..fdcec74 100644 --- a/services/trading/engine.py +++ b/services/trading/engine.py @@ -32,6 +32,7 @@ except ImportError: from services.shared.config import TradingConfig from services.shared.redis_keys import ( QUEUE_BROKER, + TRADING_DEDUPE_PREFIX, queue_key, trading_dedupe_key, ) @@ -735,6 +736,9 @@ class TradingEngine: if self.redis is not None: broker_queue = queue_key(QUEUE_BROKER) await self.redis.rpush(broker_queue, json.dumps(order_job)) + # Set 24h cooldown to prevent immediate re-entry + cooldown_key = f"{TRADING_DEDUPE_PREFIX}:sell_cooldown:{ticker}" + await self.redis.set(cooldown_key, "1", ex=86400) logger.info( "Pushed sell order for %s (%d shares, ~$%.2f) to broker queue", ticker, sell_qty, estimated_proceeds, @@ -779,6 +783,16 @@ class TradingEngine: continue # --- Buy path --- + # Check sell cooldown — don't re-enter a position we just sold + if self.redis is not None: + cooldown_key = f"{TRADING_DEDUPE_PREFIX}:sell_cooldown:{ticker}" + if await self.redis.get(cooldown_key): + logger.info( + "Decision for %s: skip (reason=sell_cooldown)", + ticker, + ) + continue + # Check if we already hold this ticker — don't double up try: existing_pos = await self.pool.fetchrow( @@ -1852,6 +1866,9 @@ class TradingEngine: try: broker_queue = queue_key(QUEUE_BROKER) await self.redis.rpush(broker_queue, json.dumps(order_job)) + # Set 24h cooldown to prevent immediate re-entry + cooldown_key = f"{TRADING_DEDUPE_PREFIX}:sell_cooldown:{ticker}" + await self.redis.set(cooldown_key, "1", ex=86400) logger.info("Submitted sell order for %s (%d shares): %s", ticker, quantity, reason) except Exception: logger.exception("Failed to push sell order for %s", ticker)