Conversation
📝 WalkthroughWalkthroughThis pull request introduces defensive programming enhancements across three modules: reorganizes the startup sequence in Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
main.py (2)
255-266: Startup correctness:_running = Truecan be set even if Polymarket connect fails.If
await self.client.connect()fails, the instance may remain “running” (andshutdown()doesn’t clear_running), which can confuse background loops/state checks and future restarts.Safer sequencing (set running after all required connects succeed)
# Connect MQTT if enabled if self.mqtt_publisher: logger.info("connecting_to_mqtt_broker") await self.mqtt_publisher.connect() - # Set running flag immediately after connections succeed - # This ensures the flag is consistent before any background tasks start - self._running = True - # Connect to Polymarket logger.info("connecting_to_polymarket") await self.client.connect() + + # Mark running only after all startup connects succeed + self._running = True
202-225: Multiple MQTT payload fields changed without backward compatibility—breaking downstream consumers.The renaming of
"position_value"to"invested_amount"is confirmed, but this change is part of a larger breaking update:locked_in_positionsandunrealized_pnlwere removed, andupdate_reasonchanged from a string to a list. The outdated test file (test_mqtt.py) still reflects the old payload structure, confirming the risk.Without versioning or a compatibility period, any external consumer (e.g., the Discord bot mentioned in README) will break. Consider publishing both old and new field names for one release while external integrations migrate.
Proposed compatibility approach
await self.mqtt_publisher.publish_balance_update({ "balance": current_balance, "equity": total_equity, "available_balance": available, "total_pnl": self.paper_engine.total_pnl, "position_count": len(self.paper_engine.positions), "invested_amount": invested_amount, + "position_value": invested_amount, # Backward compat (deprecated, remove after migration) "update_reason": update_reason })Also update test_mqtt.py to reflect current payload structure.
src/core/paper_trading.py (1)
360-389: Inconsistent state risk: invalid price returns early, but the order is still “FILLED”.With the new guard, a BUY can produce a
PaperOrder(status=FILLED)that never opens a position (andcreate_order()still logs"paper_order_filled"), which can silently desync stats/UX. Prefer validatingcurrent_pricebefore constructing a FILLED order (or downgrade the order to REJECTED and avoid “filled” logging/return).src/utils/mqtt_publisher.py (1)
250-279:_do_publish()returnsboolbut result is ignored;disconnect()can race withpublish()since it doesn't hold_publish_lock.The return value (line 278) is never used, so callers have no way to detect failure. More critically,
disconnect()does not acquire_publish_lock, allowing it to callloop_stop()anddisconnect()while a publish is in-flight on another thread. The atomic client capture preventsNonedereference but not concurrent use of a disconnecting client. Also,info.wait_for_publish()timeout is ignored—if it returnsFalse, the code logs success anyway.Fix: (1) capture and check the boolean return from
_do_publish(), (2) havedisconnect()acquire_publish_lockto serialize against in-flight publishes, (3) checkwait_for_publish()return value and log/return on timeout.
🧹 Nitpick comments (1)
src/core/paper_trading.py (1)
631-686: Atomic load looks good; consider clarifying return semantics for “empty but valid” files.The temp-parse + atomic assignment pattern is solid, but
return len(loaded_position_ids) > 0 or failed_positions == 0makes an empty positions file returnTrue, which may cause misleading “positions_restored” logs inmain.py. Consider returningTrueonly when the file is successfully parsed/applied, and let callers decide whether “restored” means> 0positions.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
main.pysrc/core/paper_trading.pysrc/utils/mqtt_publisher.py
🧰 Additional context used
🧬 Code graph analysis (1)
src/utils/mqtt_publisher.py (1)
src/core/client.py (1)
client(142-148)
Summary by CodeRabbit
Bug Fixes
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.