Merge pull request #13066 from ABSllk/fix-bitget-stoploss

Add pos_loss for Bitget futures stoploss cancellation
This commit is contained in:
Matthias
2026-04-20 20:55:31 +02:00
committed by GitHub
2 changed files with 50 additions and 1 deletions
+14
View File
@@ -7,6 +7,7 @@ from freqtrade.constants import BuySell
from freqtrade.enums import OPTIMIZE_MODES, CandleType, MarginMode, PriceType, TradingMode
from freqtrade.exceptions import (
DDosProtection,
InvalidOrderException,
OperationalException,
RetryableOrderError,
TemporaryError,
@@ -142,6 +143,19 @@ class Bitget(Exchange):
return self._fetch_stop_order_fallback(order_id, pair)
def cancel_stoploss_order(self, order_id: str, pair: str, params: dict | None = None) -> dict:
cancel_params = params.copy() if params else {}
cancel_params["stop"] = True
if self.trading_mode != TradingMode.FUTURES:
return self.cancel_order(order_id, pair, cancel_params)
try:
return self.cancel_order(order_id, pair, {**cancel_params, "planType": "pos_loss"})
except (InvalidOrderException, IndexError):
# Keep compatibility with stoploss orders created by older versions.
return self.cancel_order(order_id, pair, cancel_params)
@retrier
def additional_exchange_init(self) -> None:
"""
+36 -1
View File
@@ -5,7 +5,7 @@ from unittest.mock import MagicMock, PropertyMock
import pytest
from freqtrade.enums import CandleType, MarginMode, RunMode, TradingMode
from freqtrade.exceptions import OperationalException, RetryableOrderError
from freqtrade.exceptions import InvalidOrderException, OperationalException, RetryableOrderError
from freqtrade.exchange.common import API_RETRY_COUNT
from freqtrade.util import dt_now, dt_ts, dt_utc
from tests.conftest import EXMS, get_patched_exchange
@@ -77,6 +77,41 @@ def test_fetch_stoploss_order_bitget_exceptions(default_conf_usdt, mocker):
)
@pytest.mark.usefixtures("init_persistence")
def test_cancel_stoploss_order_bitget(default_conf_usdt, mocker):
default_conf_usdt["dry_run"] = False
api_mock = MagicMock()
exchange = get_patched_exchange(mocker, default_conf_usdt, api_mock, exchange="bitget")
# Spot scenario
exchange.cancel_order = MagicMock(return_value={"id": "1234"})
assert exchange.cancel_stoploss_order("1234", "ETH/USDT", {}) == {"id": "1234"}
assert exchange.cancel_order.call_count == 1
exchange.cancel_order.assert_called_once_with("1234", "ETH/USDT", {"stop": True})
# Futures scenario
default_conf_usdt["trading_mode"] = TradingMode.FUTURES
default_conf_usdt["margin_mode"] = MarginMode.ISOLATED
exchange = get_patched_exchange(mocker, default_conf_usdt, api_mock, exchange="bitget")
exchange.cancel_order = MagicMock(return_value={"id": "1234"})
assert exchange.cancel_stoploss_order("1234", "ETH/USDT:USDT", {}) == {"id": "1234"}
assert exchange.cancel_order.call_count == 1
exchange.cancel_order.assert_called_once_with(
"1234", "ETH/USDT:USDT", {"stop": True, "planType": "pos_loss"}
)
exchange.cancel_order = MagicMock(
side_effect=[InvalidOrderException("API error"), {"id": "1234"}]
)
assert exchange.cancel_stoploss_order("1234", "ETH/USDT:USDT", {}) == {"id": "1234"}
assert exchange.cancel_order.call_count == 2
exchange.cancel_order.assert_any_call(
"1234", "ETH/USDT:USDT", {"stop": True, "planType": "pos_loss"}
)
exchange.cancel_order.assert_any_call("1234", "ETH/USDT:USDT", {"stop": True})
def test_bitget_ohlcv_candle_limit(mocker, default_conf_usdt):
# This test is also a live test - so we're sure our limits are correct.
api_mock = MagicMock()