From 0e5235e6dc8706394be77aeb52c338292a82163f Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jul 2025 21:18:31 +0200 Subject: [PATCH 1/9] chore: add basic bitget exchange --- freqtrade/exchange/__init__.py | 1 + freqtrade/exchange/bitget.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 freqtrade/exchange/bitget.py diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 36aadcad1..3ba603f33 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -6,6 +6,7 @@ from freqtrade.exchange.exchange import Exchange # isort: on from freqtrade.exchange.binance import Binance from freqtrade.exchange.bingx import Bingx +from freqtrade.exchange.bitget import Bitget from freqtrade.exchange.bitmart import Bitmart from freqtrade.exchange.bitpanda import Bitpanda from freqtrade.exchange.bitvavo import Bitvavo diff --git a/freqtrade/exchange/bitget.py b/freqtrade/exchange/bitget.py new file mode 100644 index 000000000..8ab01461d --- /dev/null +++ b/freqtrade/exchange/bitget.py @@ -0,0 +1,22 @@ +import logging + +from freqtrade.exchange import Exchange +from freqtrade.exchange.exchange_types import FtHas + + +logger = logging.getLogger(__name__) + + +class Bitget(Exchange): + """ + Bitget exchange class. Contains adjustments needed for Freqtrade to work + with this exchange. + + Please note that this exchange is not included in the list of exchanges + officially supported by the Freqtrade development team. So some features + may still not work as expected. + """ + + _ft_has: FtHas = { + "ohlcv_candle_limit": 200, # 200 for historical candles, 1000 for recent ones. + } From a6b643a33fd1f23161d287a0caf4f1b0c4105720 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jul 2025 21:36:50 +0200 Subject: [PATCH 2/9] feat: add ohlcv candle limit specific for bitget --- freqtrade/exchange/bitget.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/freqtrade/exchange/bitget.py b/freqtrade/exchange/bitget.py index 8ab01461d..3b35beca3 100644 --- a/freqtrade/exchange/bitget.py +++ b/freqtrade/exchange/bitget.py @@ -1,7 +1,10 @@ import logging +from datetime import timedelta +from freqtrade.enums import CandleType from freqtrade.exchange import Exchange from freqtrade.exchange.exchange_types import FtHas +from freqtrade.util.datetime_helpers import dt_now, dt_ts logger = logging.getLogger(__name__) @@ -20,3 +23,26 @@ class Bitget(Exchange): _ft_has: FtHas = { "ohlcv_candle_limit": 200, # 200 for historical candles, 1000 for recent ones. } + + def ohlcv_candle_limit( + self, timeframe: str, candle_type: CandleType, since_ms: int | None = None + ) -> int: + """ + Exchange ohlcv candle limit + bitget has the following behaviour: + * 1000 candles for up-to-date data + * 200 candles for historic data (prior to a certain date) + :param timeframe: Timeframe to check + :param candle_type: Candle-type + :param since_ms: Starting timestamp + :return: Candle limit as integer + """ + timeframe_map = self._api.options["fetchOHLCV"]["maxRecentDaysPerTimeframe"] + days = timeframe_map.get(timeframe, 30) + + if candle_type in (CandleType.FUTURES, CandleType.SPOT) and ( + not since_ms or dt_ts(dt_now() - timedelta(days=days)) < since_ms + ): + return 1000 + + return super().ohlcv_candle_limit(timeframe, candle_type, since_ms) From 786c858452300755906756123ee007c2e973e6cf Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jul 2025 21:37:17 +0200 Subject: [PATCH 3/9] test: enable testing bitget spot markets --- tests/exchange_online/conftest.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/exchange_online/conftest.py b/tests/exchange_online/conftest.py index ffc25b0dc..185acda6f 100644 --- a/tests/exchange_online/conftest.py +++ b/tests/exchange_online/conftest.py @@ -408,6 +408,19 @@ EXCHANGES = { "candle_count": 200, "orderbook_max_entries": 50, }, + "bitget": { + "pair": "BTC/USDT", + "stake_currency": "USDT", + "hasQuoteVolume": True, + "timeframe": "1h", + "candle_count": 1000, + # "futures": False, + # "futures_pair": "BTC/USDT:USDT", + # "hasQuoteVolumeFutures": False, + # "leverage_tiers_public": True, + # "leverage_in_spot_market": True, + # "private_methods": ["fetch_accounts"], + }, "htx": { "pair": "ETH/BTC", "stake_currency": "BTC", From ea2350f1ed5f7611038281ac19c43d185470f153 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jul 2025 21:37:28 +0200 Subject: [PATCH 4/9] test: add test for bitget ohlcv specifics --- tests/exchange_online/test_ccxt_compat.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/exchange_online/test_ccxt_compat.py b/tests/exchange_online/test_ccxt_compat.py index baab85bae..578549a26 100644 --- a/tests/exchange_online/test_ccxt_compat.py +++ b/tests/exchange_online/test_ccxt_compat.py @@ -521,3 +521,35 @@ class TestCCXTExchange: exch, exchangename = exchange for method in EXCHANGES[exchangename].get("private_methods", []): assert hasattr(exch._api, method) + + def test_ccxt_bitget_ohlcv_candle_limit(self, exchange: EXCHANGE_FIXTURE_TYPE): + exch, exchangename = exchange + if exchangename != "bitget": + pytest.skip("This test is only for the Bitget exchange") + + timeframes = ("1m", "5m", "1h") + + for timeframe in timeframes: + assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT) == 1000 + assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES) == 1000 + assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK) == 200 + assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE) == 200 + + start_time = dt_ts(dt_now() - timedelta(days=17)) + assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == 1000 + assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == 1000 + assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 200 + assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200 + start_time = dt_ts(dt_now() - timedelta(days=48)) + length = 200 if timeframe in ("1m", "5m") else 1000 + assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == length + assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == length + assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 200 + assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200 + + start_time = dt_ts(dt_now() - timedelta(days=61)) + length = 200 + assert exch.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == length + assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == length + assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 200 + assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200 From b887e2ad2189f8a371051aef3d04f8218125ad6e Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jul 2025 21:40:36 +0200 Subject: [PATCH 5/9] test: cleanup conftest file --- tests/exchange_online/conftest.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/exchange_online/conftest.py b/tests/exchange_online/conftest.py index 185acda6f..2f181d610 100644 --- a/tests/exchange_online/conftest.py +++ b/tests/exchange_online/conftest.py @@ -414,12 +414,6 @@ EXCHANGES = { "hasQuoteVolume": True, "timeframe": "1h", "candle_count": 1000, - # "futures": False, - # "futures_pair": "BTC/USDT:USDT", - # "hasQuoteVolumeFutures": False, - # "leverage_tiers_public": True, - # "leverage_in_spot_market": True, - # "private_methods": ["fetch_accounts"], }, "htx": { "pair": "ETH/BTC", From 7afd3cb730a230bd46fa1a2176a2dbf58aefdcf1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Jul 2025 22:02:38 +0200 Subject: [PATCH 6/9] feat(bitget): configure mark timeframe --- freqtrade/exchange/bitget.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/exchange/bitget.py b/freqtrade/exchange/bitget.py index 3b35beca3..8389c25ee 100644 --- a/freqtrade/exchange/bitget.py +++ b/freqtrade/exchange/bitget.py @@ -23,6 +23,9 @@ class Bitget(Exchange): _ft_has: FtHas = { "ohlcv_candle_limit": 200, # 200 for historical candles, 1000 for recent ones. } + _ft_has_futures: FtHas = { + "mark_ohlcv_timeframe": "4h", + } def ohlcv_candle_limit( self, timeframe: str, candle_type: CandleType, since_ms: int | None = None From 86de1dee2992b1aa1447084c866fa1c1781b67a1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 1 Aug 2025 07:09:17 +0200 Subject: [PATCH 7/9] feat(bitget): add support for order time in force --- freqtrade/exchange/bitget.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/exchange/bitget.py b/freqtrade/exchange/bitget.py index 8389c25ee..89a549ad1 100644 --- a/freqtrade/exchange/bitget.py +++ b/freqtrade/exchange/bitget.py @@ -22,6 +22,7 @@ class Bitget(Exchange): _ft_has: FtHas = { "ohlcv_candle_limit": 200, # 200 for historical candles, 1000 for recent ones. + "order_time_in_force": ["GTC", "FOK", "IOC", "PO"], } _ft_has_futures: FtHas = { "mark_ohlcv_timeframe": "4h", From 78c5b1893708374fc46bbcd79048eb8de59288b8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 1 Aug 2025 07:09:56 +0200 Subject: [PATCH 8/9] docs(bitget): add bitget documentation --- docs/exchanges.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/exchanges.md b/docs/exchanges.md index 647dfa868..121ac3f6e 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -328,6 +328,22 @@ It's therefore required to pass the UID as well. !!! Warning "Necessary Verification" Bitmart requires Verification Lvl2 to successfully trade on the spot market through the API - even though trading via UI works just fine with just Lvl1 verification. +## Bitget + +Kucoin requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows: + +```json +"exchange": { + "name": "bitget", + "key": "your_exchange_key", + "secret": "your_exchange_secret", + "password": "your_exchange_api_key_password", + // ... +} +``` + +Bitget supports [time_in_force](configuration.md#understand-order_time_in_force). + ## Hyperliquid !!! Tip "Stoploss on Exchange" From f2fb1b7919fbffe2c1718c86b4aeaf2ae3ceacb2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 3 Aug 2025 09:01:03 +0200 Subject: [PATCH 9/9] docs(bitget): fix typo --- docs/exchanges.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/exchanges.md b/docs/exchanges.md index 121ac3f6e..1f3b80fd1 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -330,7 +330,7 @@ It's therefore required to pass the UID as well. ## Bitget -Kucoin requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows: +Bitget requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows: ```json "exchange": {