Задать вопрос
@Yuseko

Авто торговля на байбите?

У меня есть бот в телеграме, в нем есть функция авто торговли на байбите. Тесты показали, что позиции открываются, тейк 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


Часть кода отвечающая за ордера
  • Вопрос задан
  • 309 просмотров
Подписаться 1 Простой 9 комментариев
Помогут разобраться в теме Все курсы
  • Нетология
    Python-разработчик: расширенный курс + нейросети
    12 месяцев
    Далее
  • Академия Эдюсон
    Python-разработчик + ИИ
    9 месяцев
    Далее
  • ProductStar × РБК
    Профессия: Python-разработчик + ИИ
    8 месяцев
    Далее
Пригласить эксперта
Ответы на вопрос 1
opium
@opium
Просто люблю качественно работать
похоже у тебя tpslMode=Full (дефолт) — можно только один TP. Переключи в Partial: в pybit это
set_tp_sl_mode(category='linear', symbol='...', tpSlMode='Partial')
, потом для каждого тейка
set_trading_stop(..., takeProfit=str(tp1), tpSize=str(qty))
. Либо просто ставь reduce_only лимитки на tp1/tp2/tp3.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы