diff --git a/bot.py b/bot.py index a31d558..1f0eea2 100644 --- a/bot.py +++ b/bot.py @@ -107,9 +107,27 @@ def run_cycle(config: Config) -> bool: if signal is None: continue + sell_qty = position.quantity + if not config.paper_trading: + # Kraken's fill may differ slightly from our stored quantity — sell + # whatever we actually hold to avoid "Insufficient funds" errors. + try: + balances = client.get_all_balances() + # Derive base asset from pair altname: "PENDLEUSD" -> "PENDLE" + base = position.pair.removesuffix("USD") + actual = balances.get(base, balances.get("X" + base)) + if actual is not None and actual < sell_qty: + log.info( + "%s: adjusting sell qty %.8f -> %.8f to match Kraken balance", + position.pair, sell_qty, actual, + ) + sell_qty = actual + except KrakenError as exc: + log.warning("Could not fetch balances before sell: %s", exc) + try: order_id = client.market_sell( - position.pair, position.quantity, paper=config.paper_trading + position.pair, sell_qty, paper=config.paper_trading ) except KrakenError as exc: log.error("Sell failed for %s: %s — will retry next run", position.pair, exc) diff --git a/kraken_client.py b/kraken_client.py index e1fd610..1d0d7c6 100644 --- a/kraken_client.py +++ b/kraken_client.py @@ -85,6 +85,11 @@ class KrakenClient: # ── Private account data ────────────────────────────────────────────────── + def get_all_balances(self) -> dict[str, float]: + """Return all asset balances with non-zero amounts.""" + raw = self._private("Balance") + return {k: float(v) for k, v in raw.items() if float(v) > 0} + def get_usd_balance(self) -> float: """Return available USD balance (ZUSD key in Kraken).""" balance = self._private("Balance")