CRITICAL FIX: LOT_SIZE Filter + Quantity Precision - nutze Decimal für exakte Rounding (ROUND_DOWN), validiere Qty vor BUY + SELL (2026-07-10 16:35)

This commit is contained in:
Marc Blatter 2026-07-10 16:36:24 +02:00
parent 70e58ac0a7
commit 8e0545cc6f
1 changed files with 41 additions and 10 deletions

View File

@ -8,6 +8,7 @@ import os
import time
import logging
from datetime import datetime
from decimal import Decimal, ROUND_DOWN
from dotenv import load_dotenv
from binance.client import Client
from binance.exceptions import BinanceAPIException
@ -92,7 +93,7 @@ class TradingBotV03:
return None
def calculate_valid_quantity(self, symbol, usdt_amount):
"""Calculate valid order quantity respecting LOT_SIZE"""
"""Berechne korrekte Qty mit Decimal precision für LOT_SIZE"""
try:
price = self.get_current_price(symbol)
if not price:
@ -102,21 +103,46 @@ class TradingBotV03:
if not info:
return 0
step_size = 0.00001 # default
# Hole LOT_SIZE filter
lot_size_info = None
for filt in info.get('filters', []):
if filt['filterType'] == 'LOT_SIZE':
step_size = float(filt['stepSize'])
lot_size_info = filt
break
qty = (usdt_amount / price)
qty = int(qty / step_size) * step_size # Round to step_size
notional = qty * price
if not lot_size_info:
return 0
step_size = Decimal(lot_size_info.get('stepSize', '0.00001'))
min_qty = Decimal(lot_size_info.get('minQty', '0'))
max_qty = Decimal(lot_size_info.get('maxQty', '10000'))
# Berechne Qty mit Decimal (kein floating-point Fehler!)
qty_decimal = Decimal(str(usdt_amount)) / Decimal(str(price))
# Runde auf step_size (immer abrunden, nie aufrunden)
qty_rounded = (qty_decimal / step_size).quantize(Decimal('1'), rounding=ROUND_DOWN) * step_size
# Prüfe Min/Max Grenzen
if qty_rounded < min_qty:
logger.debug(f"Qty zu klein: {symbol} {qty_rounded} < {min_qty}")
return 0
if qty_rounded > max_qty:
logger.debug(f"Qty zu groß: {symbol} {qty_rounded} > {max_qty}")
qty_rounded = max_qty
# Konvertiere zu float mit gerader Präzision
qty_float = float(qty_rounded)
notional = qty_float * price
if notional < MIN_USDT:
logger.debug(f"Order too small: {symbol} ${notional:.2f}")
return 0
return qty
logger.debug(f"Qty valid: {symbol} {qty_float} (step={step_size})")
return qty_float
except Exception as e:
logger.warning(f"Qty calc failed: {e}")
return 0
@ -187,7 +213,9 @@ class TradingBotV03:
if pnl_pct >= TAKE_PROFIT_PCT:
logger.info(f"TAKE PROFIT: {symbol} +{pnl_pct*100:.2f}% (${pnl_usdt:.2f})")
try:
self.client.order_market_sell(symbol=symbol, quantity=qty)
# Validiere Qty vor Verkauf (rund ab für LOT_SIZE)
qty_sell = float(Decimal(str(qty)).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN))
self.client.order_market_sell(symbol=symbol, quantity=qty_sell)
del self.active_trades[symbol]
except Exception as e:
logger.error(f"Sell failed: {e}")
@ -197,7 +225,9 @@ class TradingBotV03:
if pnl_pct <= STOP_LOSS_PCT:
logger.warning(f"STOP LOSS: {symbol} {pnl_pct*100:.2f}% (${pnl_usdt:.2f})")
try:
self.client.order_market_sell(symbol=symbol, quantity=qty)
# Validiere Qty vor Verkauf (rund ab für LOT_SIZE)
qty_sell = float(Decimal(str(qty)).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN))
self.client.order_market_sell(symbol=symbol, quantity=qty_sell)
del self.active_trades[symbol]
except Exception as e:
logger.error(f"Sell failed: {e}")
@ -286,3 +316,4 @@ if __name__ == '__main__':