У меня есть бот в телеграме, в нем есть функция авто торговли на байбите. Тесты показали, что позиции открываются, тейк 1 и стоп 1 расставляются, но когда я хочу поставить больше чем 1 тейк автоматически, этого не получается сделать, как это можно сделать. Кто знает и может помочь отпишитесь плс
def execute_signal(self, signal: dict, signal_message_id: int = None):
if not self.can_auto_trade():
return False, "Автоторговля не включена, нет ключей или подписка неактивна"
if self.position_manager is None:
return False, "Менеджер позиций не инициализирован. Попробуйте переподключить API ключи."
symbol = signal['symbol']
trend = signal['trend']
entry = signal['entry']
sl = signal['sl']
tp1 = signal['tp1']
tp2 = signal['tp2']
tp3 = signal['tp3']
risk_pct = abs(entry - sl) / entry * 100
if risk_pct < 0.2:
return False, f"Стоп-лосс слишком узкий ({risk_pct:.2f}% < 0.2%)"
if risk_pct > 5.0:
return False, f"Стоп-лосс слишком широкий ({risk_pct:.2f}% > 5%)"
# --- ПРОВЕРКА ЛИМИТА ПО РЕАЛЬНЫМ ПОЗИЦИЯМ НА БИРЖЕ ---
try:
exchange_positions = self.api.get_open_positions()
current_positions_count = len(exchange_positions)
max_positions = self.get_setting('MAX_POSITIONS')
if current_positions_count >= max_positions:
return False, f"Достигнут лимит одновременных позиций ({max_positions}). Открыто {current_positions_count}."
if symbol in exchange_positions:
return False, f"Позиция по {symbol} уже открыта на бирже."
# Синхронизируем локальный менеджер с реальными позициями (удаляем призрачные)
self.position_manager.sync_with_exchange(exchange_positions)
except Exception as e:
logger.error(f"Ошибка получения позиций с биржи для проверки лимита: {e}")
return False, "Не удалось проверить лимит позиций. Попробуйте позже."
# --- ДАЛЬНЕЙШАЯ ЛОГИКА РАСЧЁТА РАЗМЕРА ПОЗИЦИИ ---
existing = self.position_manager.active_positions.get(symbol)
if existing:
if existing.side == trend:
if trend == "LONG":
if entry >= existing.entry_price * 0.985:
return False, f"Сигнал LONG по {symbol} не улучшает вход (тек. {existing.entry_price:.4f} -> новый {entry:.4f})"
else:
if entry <= existing.entry_price * 1.015:
return False, f"Сигнал SHORT по {symbol} не улучшает вход (тек. {existing.entry_price:.4f} -> новый {entry:.4f})"
success, msg = self.close_position(symbol, manual=False)
if not success:
return False, f"Не удалось закрыть позицию: {msg}"
else:
success, msg = self.close_position(symbol, manual=False)
if not success:
return False, f"Не удалось закрыть позицию для реверса: {msg}"
if not self.position_manager.can_open_position(symbol, trend):
return False, "Невозможно открыть позицию (лимит или уже есть)"
balance = self.api.get_balance()
if balance < CONFIG.get('MIN_BALANCE', 50):
return False, f"Баланс {balance} ниже минимального"
if self.risk_mode == 'fixed' and self.position_size_fixed and self.position_size_fixed > 0:
position_size_usdt = self.position_size_fixed
max_position_usdt = balance * self.get_setting('LEVERAGE', 30)
if position_size_usdt > max_position_usdt:
return False, f"Фиксированный объём {position_size_usdt:.2f} USDT превышает доступный с плечом {max_position_usdt:.2f} USDT"
else:
risk_amount = balance * self.get_setting('MAX_RISK', 0.01)
price_diff = abs(entry - sl)
if price_diff == 0:
return False, "Стоп-лосс равен входу"
position_size_usdt = risk_amount / (price_diff / entry)
max_position_usdt = balance * self.get_setting('LEVERAGE', 30)
if position_size_usdt > max_position_usdt:
return False, f"Размер позиции {position_size_usdt:.2f} USDT превышает доступный баланс с плечом ({max_position_usdt:.2f} USDT)"
contracts = position_size_usdt / entry
contracts = self.api.normalize_amount(symbol, contracts)
if contracts <= 0:
return False, f"Недопустимый размер позиции (0 контрактов). Возможно, слишком маленький объём."
self.api.set_leverage(symbol, self.get_setting('LEVERAGE', 30))
# --- ЛИМИТНЫЙ ОРДЕР (без встроенных TP/SL) ---
ticker = self.api.exchange.fetch_ticker(symbol)
current_price = ticker['last']
if trend == 'LONG':
limit_price = max(entry, current_price * 1.0001)
else:
limit_price = min(entry, current_price * 0.9999)
limit_price = float(self.api.exchange.price_to_precision(symbol, limit_price))
order = self.api.create_limit_order(
symbol=symbol,
side='buy' if trend == 'LONG' else 'sell',
amount=contracts,
price=limit_price
)
if not order or not order.get('id'):
return False, "Ошибка создания лимитного ордера"
filled_price = limit_price
# --- СОЗДАНИЕ ОБЪЕКТА TRADE И СОХРАНЕНИЕ ---
trade = Trade(
symbol=symbol, side=trend, entry_price=filled_price, size=contracts,
sl_price=sl, tp1_price=tp1, tp2_price=tp2, tp3_price=tp3,
opened_at=datetime.now(timezone.utc), position_id=order.get('id'),
signal_message_id=signal_message_id
)
self.position_manager.add_position(trade)
db.save_position(self.chat_id, trade)
# --- ФОНОВАЯ УСТАНОВКА ТРЁХ ТЕЙК-ОРДЕРОВ (25%, 50%, 25%) ---
def place_tp_orders():
# Ждём появления позиции на бирже (до 15 сек)
for attempt in range(15):
time.sleep(1)
try:
positions = self.api.get_open_positions()
if symbol in positions and positions[symbol]['size'] > 0:
logger.info(f"Позиция {symbol} подтверждена, размер {positions[symbol]['size']}")
break
except Exception as e:
logger.warning(f"Ожидание позиции {symbol}: {e}")
else:
logger.error(f"Не удалось подтвердить позицию {symbol} для установки TP")
return
time.sleep(1.5) # пауза для стабильности
# TP1 – 25%
tp1_size = self.api.normalize_amount(symbol, trade.size * 0.25)
if tp1_size > 0:
tp1_order = self.order_manager.create_stop_market_order(
symbol, trend, tp1_size, tp1, reduce_only=True
)
if tp1_order and tp1_order.get('id'):
trade.tp1_order_id = tp1_order['id']
db.save_position(self.chat_id, trade)
logger.info(f"TP1 ордер {symbol} создан, размер={tp1_size}, ID={tp1_order['id']}")
else:
logger.warning(f"Не удалось создать TP1 для {symbol}")
# TP2 – 50%
tp2_size = self.api.normalize_amount(symbol, trade.size * 0.5)
if tp2_size > 0:
tp2_order = self.order_manager.create_stop_market_order(
symbol, trend, tp2_size, tp2, reduce_only=True
)
if tp2_order and tp2_order.get('id'):
trade.tp2_order_id = tp2_order['id']
db.save_position(self.chat_id, trade)
logger.info(f"TP2 ордер {symbol} создан, размер={tp2_size}, ID={tp2_order['id']}")
else:
logger.warning(f"Не удалось создать TP2 для {symbol}")
# TP3 – оставшиеся 25%
tp3_size = self.api.normalize_amount(symbol, trade.size * 0.25)
if tp3_size > 0:
tp3_order = self.order_manager.create_stop_market_order(
symbol, trend, tp3_size, tp3, reduce_only=True
)
if tp3_order and tp3_order.get('id'):
trade.tp3_order_id = tp3_order['id']
db.save_position(self.chat_id, trade)
logger.info(f"TP3 ордер {symbol} создан, размер={tp3_size}, ID={tp3_order['id']}")
else:
logger.warning(f"Не удалось создать TP3 для {symbol}")
logger.info(f"✅ Все TP ордера для {symbol} выставлены")
threading.Thread(target=place_tp_orders, daemon=True).start()
audit_logger.info(
f"User {self.chat_id} opened {trend} {symbol} @ {filled_price:.8f} size_contracts={contracts:.8f}")
open_msg = f"✅ Позиция {symbol} открыта @ {format_price(filled_price)}"
send_telegram_message(self.chat_id, open_msg, parse_mode="HTML", reply_to_message_id=signal_message_id)
return True, open_msg
Часть кода отвечающая за ордера