Răsfoiți Sursa

Fix grid side reconciliation and sizing caps

Lukas Goldschmidt 1 lună în urmă
părinte
comite
25d984c9fb
2 a modificat fișierele cu 14 adăugiri și 4 ștergeri
  1. 5 2
      src/trader_mcp/strategy_context.py
  2. 9 2
      strategies/grid_trader.py

+ 5 - 2
src/trader_mcp/strategy_context.py

@@ -156,7 +156,9 @@ class StrategyContext:
                     quote_cap = spendable_quote
             if quote_cap <= 0:
                 return 0.0
-            per_order_quote = quote_cap / max(levels, 1)
+            # `max_notional_per_order` is already a per-order cap in quote
+            # currency, so do not dilute it by the number of grid levels.
+            per_order_quote = quote_cap
             min_quote_needed = min_notional * (1 + fee_rate)
             if per_order_quote < min_quote_needed:
                 return 0.0
@@ -177,7 +179,8 @@ class StrategyContext:
                     spendable_base = min(spendable_base, base_cap)
             if spendable_base <= 0:
                 return 0.0
-            amount = spendable_base / max(levels, 1)
+            # Same rule as above, the cap is per order, not per grid level.
+            amount = spendable_base
 
         if amount < min_amount:
             return 0.0

+ 9 - 2
strategies/grid_trader.py

@@ -870,11 +870,18 @@ class Strategy(Strategy):
 
         if desired_sides == {"buy", "sell"}:
             current_sides = {str(order.get("side") or "").lower() for order in live_orders if isinstance(order, dict)}
+            tracked_sides = {str(order.get("side") or "").lower() for order in previous_orders if isinstance(order, dict)}
             missing_sides = [side for side in ("buy", "sell") if side not in current_sides]
             reconciled_sides: list[str] = []
-            if missing_sides and self.state.get("center_price") and not self._grid_refresh_paused():
+            has_live_grid = bool(live_orders) or bool(live_ids) or bool(tracked_sides)
+
+            # If the grid is empty because both sides were skipped, do not keep
+            # trying to "restore" a missing side every tick. Let the normal
+            # reseed path decide when to try again.
+            if missing_sides and has_live_grid and self.state.get("center_price") and not self._grid_refresh_paused():
                 for side in missing_sides:
-                    self._log(f"adding missing {side} side after trade_sides change, live_sides={sorted(current_sides)} live_ids={live_ids}")
+                    if current_sides or tracked_sides:
+                        self._log(f"adding missing {side} side, live_sides={sorted(current_sides)} tracked_sides={sorted(tracked_sides)} live_ids={live_ids}")
                     self._place_side_grid(side, float(self.state.get("center_price") or price))
                     reconciled_sides.append(side)
                 live_orders = self._sync_open_orders_state()