diff --git a/docs/exchanges.md b/docs/exchanges.md index 1ef9aa526..ec7f1baac 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -227,8 +227,11 @@ Kraken Futures uses the exchange id `krakenfutures` and supports isolated future "key": "your_exchange_key", "secret": "your_exchange_secret", "ccxt_config": {"enableRateLimit": true}, - "ccxt_async_config": {"enableRateLimit": true}, - "triggerSignal": "mark" // "mark" (default), "last", or "index" + "ccxt_async_config": {"enableRateLimit": true} +}, +"order_types": { + "stoploss": "market", + "stoploss_price_type": "mark" // "mark" (default), "last", or "index" }, "trading_mode": "futures", "margin_mode": "isolated", @@ -237,7 +240,7 @@ Kraken Futures uses the exchange id `krakenfutures` and supports isolated future !!! Tip "Stoploss on Exchange" Kraken Futures supports `stoploss_on_exchange` with both `limit` and `market` stop orders. - Use `exchange.triggerSignal` to select the trigger price source (`mark`, `last`, or `index`). + Use `order_types.stoploss_price_type` to select the trigger price source (`mark`, `last`, or `index`). !!! Note "Collateral" Kraken Futures is USD-settled. Kraken allows EUR collateral, but USD is the recommended stake currency. @@ -245,16 +248,6 @@ Kraken Futures uses the exchange id `krakenfutures` and supports isolated future !!! Note "Pair format" Futures pairs use CCXT symbols, for example `BTC/USD:USD`. -### Data download - -Kraken Futures uses normal OHLCV downloads. - -```bash -freqtrade download-data --exchange krakenfutures --trading-mode futures --pairs BTC/USD:USD --timeframes 1m 5m -``` - -Note: OHLCV requests are capped at 2000 candles per call, so large downloads may take longer. - ## Kucoin 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: diff --git a/freqtrade/exchange/krakenfutures.py b/freqtrade/exchange/krakenfutures.py index aa1634609..9f6167188 100644 --- a/freqtrade/exchange/krakenfutures.py +++ b/freqtrade/exchange/krakenfutures.py @@ -8,7 +8,6 @@ from typing import Any from ccxt.base.errors import NotSupported, OrderNotFound -from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, PriceType, TradingMode from freqtrade.exceptions import ExchangeError, InvalidOrderException from freqtrade.exchange.common import retrier @@ -537,28 +536,3 @@ class Krakenfutures(Exchange): ) -> list[dict[str, Any]]: params = self._filter_params_for_open_closed(params or {}) return self._api.fetch_closed_orders(pair, since, limit, params) - - def _get_stop_params(self, side: BuySell, ordertype: str, stop_price: float) -> dict[str, Any]: - params: dict[str, Any] = super()._get_stop_params( - side=side, ordertype=ordertype, stop_price=stop_price - ) - - # Force Kraken Futures naming - params.setdefault("triggerPrice", stop_price) - - trigger_signal = self._get_trigger_signal() - if trigger_signal is not None: - params.setdefault("triggerSignal", trigger_signal) - - if getattr(self, "trading_mode", None) == TradingMode.FUTURES: - params.setdefault("reduceOnly", True) - - return params - - def _get_trigger_signal(self) -> str | None: - ex_conf = self._config.get("exchange") - if isinstance(ex_conf, dict): - v = ex_conf.get("triggerSignal") or ex_conf.get("trigger_signal") - if isinstance(v, str) and v.strip(): - return v.strip() - return "mark" diff --git a/tests/exchange/test_krakenfutures.py b/tests/exchange/test_krakenfutures.py index ee175aaeb..1ea765197 100644 --- a/tests/exchange/test_krakenfutures.py +++ b/tests/exchange/test_krakenfutures.py @@ -3,6 +3,7 @@ from __future__ import annotations from copy import deepcopy +from unittest.mock import MagicMock import pytest from ccxt.base.errors import NotSupported @@ -11,7 +12,7 @@ from freqtrade.enums import CandleType, MarginMode, TradingMode from freqtrade.exceptions import InvalidOrderException from freqtrade.exchange.exchange import Exchange from freqtrade.exchange.krakenfutures import Krakenfutures -from tests.conftest import get_patched_exchange +from tests.conftest import EXMS, get_patched_exchange def test_krakenfutures_ft_has_overrides(): @@ -169,20 +170,32 @@ def test_krakenfutures_fetch_order_falls_back_to_history_orders(mocker, default_ assert res["filled"] == 0.0 -def test_krakenfutures_get_stop_params_adds_triggerprice_signal_and_reduceonly( - mocker, default_conf -): - """Test _get_stop_params adds triggerPrice, triggerSignal, and reduceOnly.""" +def test_krakenfutures_create_stoploss_uses_trigger_price_type(mocker, default_conf): + """Test create_stoploss uses triggerPrice, triggerSignal, and reduceOnly.""" + api_mock = MagicMock() + api_mock.create_order = MagicMock(return_value={"id": "order-id", "info": {"foo": "bar"}}) + conf = deepcopy(default_conf) + conf["dry_run"] = False conf["trading_mode"] = TradingMode.FUTURES conf["margin_mode"] = MarginMode.ISOLATED - if isinstance(conf.get("exchange"), dict): - conf["exchange"]["triggerSignal"] = "mark" + mocker.patch(f"{EXMS}.amount_to_precision", lambda s, x, y: y) + mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y, **kwargs: y) - ex = get_patched_exchange(mocker, conf, exchange="krakenfutures") + ex = get_patched_exchange(mocker, conf, api_mock, exchange="krakenfutures") + + ex.create_stoploss( + pair="ETH/BTC", + amount=1, + stop_price=90000.0, + side="sell", + order_types={"stoploss": "market", "stoploss_price_type": "mark"}, + leverage=1.0, + ) - params = ex._get_stop_params(side="sell", ordertype="market", stop_price=90000.0) + call_args = api_mock.create_order.call_args + params = call_args[1].get("params") if call_args[1] else call_args[0][5] assert params["triggerPrice"] == 90000.0 assert params["triggerSignal"] == "mark"