Fix exchange API errors: stop cascade BUY failures and stop-loss race condition
- Set available_usdt=0 after BUY fails with "not enough balance" to prevent subsequent BUY signals from hitting the exchange in the same cycle - Add 0.3s delay after canceling stop orders before placing new ones to let Bitfinex release locked balance Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c473a581b0
commit
fa148da196
9
main.py
9
main.py
@ -149,6 +149,7 @@ def run_cycle():
|
|||||||
logger.info("Cancelled outdated stop %s for %s (amt=%.6f, px=%.6g)",
|
logger.info("Cancelled outdated stop %s for %s (amt=%.6f, px=%.6g)",
|
||||||
s["id"], sym, abs(s["amount"]), s["price"])
|
s["id"], sym, abs(s["amount"]), s["price"])
|
||||||
tracked_stops.pop(sym, None)
|
tracked_stops.pop(sym, None)
|
||||||
|
time.sleep(0.3) # Wait for Bitfinex to release locked balance
|
||||||
|
|
||||||
logger.warning("Position %s missing/outdated stop-loss, placing now", sym)
|
logger.warning("Position %s missing/outdated stop-loss, placing now", sym)
|
||||||
sl = trader.place_stop_loss_order(sym, amount, entry)
|
sl = trader.place_stop_loss_order(sym, amount, entry)
|
||||||
@ -345,6 +346,10 @@ def run_cycle():
|
|||||||
if result and result.get("status") == "failed":
|
if result and result.get("status") == "failed":
|
||||||
logger.warning("Order failed at exchange: %s %s — %s", action, validated["symbol"], result.get("error", ""))
|
logger.warning("Order failed at exchange: %s %s — %s", action, validated["symbol"], result.get("error", ""))
|
||||||
rejected.append({**validated, "reject_reason": f"交易所錯誤: {result.get('error', 'unknown')}"})
|
rejected.append({**validated, "reject_reason": f"交易所錯誤: {result.get('error', 'unknown')}"})
|
||||||
|
# BUY failed at exchange — mark balance as unreliable to skip remaining BUYs
|
||||||
|
if action == "BUY" and "not enough" in result.get("error", "").lower():
|
||||||
|
port["available_usdt"] = 0
|
||||||
|
logger.info("Marked available_usdt=0 to prevent further BUY attempts this cycle")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if result and result.get("status") in ("filled", "submitted"):
|
if result and result.get("status") in ("filled", "submitted"):
|
||||||
@ -369,9 +374,13 @@ def run_cycle():
|
|||||||
if action == "BUY":
|
if action == "BUY":
|
||||||
# Cancel existing exchange stop orders before placing new one
|
# Cancel existing exchange stop orders before placing new one
|
||||||
pos = port.get("positions", {}).get(sym, {})
|
pos = port.get("positions", {}).get(sym, {})
|
||||||
|
cancelled_any = False
|
||||||
for s in stop_orders_by_sym.get(sym, []):
|
for s in stop_orders_by_sym.get(sym, []):
|
||||||
trader.cancel_order(s["id"])
|
trader.cancel_order(s["id"])
|
||||||
|
cancelled_any = True
|
||||||
logger.info("Cancelled old stop %s for %s (position size changed)", s["id"], sym)
|
logger.info("Cancelled old stop %s for %s (position size changed)", s["id"], sym)
|
||||||
|
if cancelled_any:
|
||||||
|
time.sleep(0.3) # Wait for Bitfinex to release locked balance
|
||||||
|
|
||||||
# Place new stop-loss for TOTAL position amount at new avg entry
|
# Place new stop-loss for TOTAL position amount at new avg entry
|
||||||
total_amount = pos.get("amount", amount)
|
total_amount = pos.get("amount", amount)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user