Changed name Collateral -> MarginMode, collateral -> margin_mode, and _supported_trading_mode_margin_pairs -> _supported_trading_margin_pairs
This commit is contained in:
		| @@ -155,7 +155,7 @@ CONF_SCHEMA = { | |||||||
|         'ignore_roi_if_buy_signal': {'type': 'boolean'}, |         'ignore_roi_if_buy_signal': {'type': 'boolean'}, | ||||||
|         'ignore_buying_expired_candle_after': {'type': 'number'}, |         'ignore_buying_expired_candle_after': {'type': 'number'}, | ||||||
|         'trading_mode': {'type': 'string', 'enum': TRADING_MODES}, |         'trading_mode': {'type': 'string', 'enum': TRADING_MODES}, | ||||||
|         'collateral': {'type': 'string', 'enum': COLLATERAL_TYPES}, |         'margin_mode': {'type': 'string', 'enum': COLLATERAL_TYPES}, | ||||||
|         'backtest_breakdown': { |         'backtest_breakdown': { | ||||||
|             'type': 'array', |             'type': 'array', | ||||||
|             'items': {'type': 'string', 'enum': BACKTEST_BREAKDOWNS} |             'items': {'type': 'string', 'enum': BACKTEST_BREAKDOWNS} | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| # flake8: noqa: F401 | # flake8: noqa: F401 | ||||||
| from freqtrade.enums.backteststate import BacktestState | from freqtrade.enums.backteststate import BacktestState | ||||||
| from freqtrade.enums.candletype import CandleType | from freqtrade.enums.candletype import CandleType | ||||||
| from freqtrade.enums.collateral import Collateral | from freqtrade.enums.marginmode import MarginMode | ||||||
| from freqtrade.enums.ordertypevalue import OrderTypeValues | from freqtrade.enums.ordertypevalue import OrderTypeValues | ||||||
| from freqtrade.enums.rpcmessagetype import RPCMessageType | from freqtrade.enums.rpcmessagetype import RPCMessageType | ||||||
| from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode | from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode | ||||||
|   | |||||||
| @@ -1,11 +1,11 @@ | |||||||
| from enum import Enum | from enum import Enum | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Collateral(Enum): | class MarginMode(Enum): | ||||||
|     """ |     """ | ||||||
|     Enum to distinguish between |     Enum to distinguish between | ||||||
|     cross margin/futures collateral and |     cross margin/futures margin_mode and | ||||||
|     isolated margin/futures collateral |     isolated margin/futures margin_mode | ||||||
|     """ |     """ | ||||||
|     CROSS = "cross" |     CROSS = "cross" | ||||||
|     ISOLATED = "isolated" |     ISOLATED = "isolated" | ||||||
| @@ -8,7 +8,7 @@ from typing import Dict, List, Optional, Tuple | |||||||
| import arrow | import arrow | ||||||
| import ccxt | import ccxt | ||||||
|  |  | ||||||
| from freqtrade.enums import CandleType, Collateral, TradingMode | from freqtrade.enums import CandleType, MarginMode, TradingMode | ||||||
| from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, | from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, | ||||||
|                                   OperationalException, TemporaryError) |                                   OperationalException, TemporaryError) | ||||||
| from freqtrade.exchange import Exchange | from freqtrade.exchange import Exchange | ||||||
| @@ -31,11 +31,11 @@ class Binance(Exchange): | |||||||
|         "ccxt_futures_name": "future" |         "ccxt_futures_name": "future" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ |     _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ | ||||||
|         # TradingMode.SPOT always supported and not required in this list |         # TradingMode.SPOT always supported and not required in this list | ||||||
|         # (TradingMode.MARGIN, Collateral.CROSS), |         # (TradingMode.MARGIN, MarginMode.CROSS), | ||||||
|         # (TradingMode.FUTURES, Collateral.CROSS), |         # (TradingMode.FUTURES, MarginMode.CROSS), | ||||||
|         (TradingMode.FUTURES, Collateral.ISOLATED) |         (TradingMode.FUTURES, MarginMode.ISOLATED) | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|     def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool: |     def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool: | ||||||
| @@ -177,7 +177,7 @@ class Binance(Exchange): | |||||||
|         """ |         """ | ||||||
|         Returns the maximum leverage that a pair can be traded at |         Returns the maximum leverage that a pair can be traded at | ||||||
|         :param pair: The base/quote currency pair being traded |         :param pair: The base/quote currency pair being traded | ||||||
|         :stake_amount: The total value of the traders collateral in quote currency |         :stake_amount: The total value of the traders margin_mode in quote currency | ||||||
|         """ |         """ | ||||||
|         if stake_amount is None: |         if stake_amount is None: | ||||||
|             raise OperationalException('binance.get_max_leverage requires argument stake_amount') |             raise OperationalException('binance.get_max_leverage requires argument stake_amount') | ||||||
| @@ -324,7 +324,7 @@ class Binance(Exchange): | |||||||
|  |  | ||||||
|         side_1 = -1 if is_short else 1 |         side_1 = -1 if is_short else 1 | ||||||
|         position = abs(position) |         position = abs(position) | ||||||
|         cross_vars = upnl_ex_1 - mm_ex_1 if self.collateral == Collateral.CROSS else 0.0 |         cross_vars = upnl_ex_1 - mm_ex_1 if self.margin_mode == MarginMode.CROSS else 0.0 | ||||||
|  |  | ||||||
|         # mm_ratio: Binance's formula specifies maintenance margin rate which is mm_ratio * 100% |         # mm_ratio: Binance's formula specifies maintenance margin rate which is mm_ratio * 100% | ||||||
|         # maintenance_amt: (CUM) Maintenance Amount of position |         # maintenance_amt: (CUM) Maintenance Amount of position | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| import logging | import logging | ||||||
| from typing import Dict, List, Tuple | from typing import Dict, List, Tuple | ||||||
|  |  | ||||||
| from freqtrade.enums import Collateral, TradingMode | from freqtrade.enums import MarginMode, TradingMode | ||||||
| from freqtrade.exchange import Exchange | from freqtrade.exchange import Exchange | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -24,8 +24,8 @@ class Bybit(Exchange): | |||||||
|         "ccxt_futures_name": "linear" |         "ccxt_futures_name": "linear" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ |     _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ | ||||||
|         # TradingMode.SPOT always supported and not required in this list |         # TradingMode.SPOT always supported and not required in this list | ||||||
|         # (TradingMode.FUTURES, Collateral.CROSS), |         # (TradingMode.FUTURES, MarginMode.CROSS), | ||||||
|         # (TradingMode.FUTURES, Collateral.ISOLATED) |         # (TradingMode.FUTURES, MarginMode.ISOLATED) | ||||||
|     ] |     ] | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ from pandas import DataFrame | |||||||
| from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, | from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, | ||||||
|                                  ListPairsWithTimeframes, PairWithTimeframe) |                                  ListPairsWithTimeframes, PairWithTimeframe) | ||||||
| from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list | from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list | ||||||
| from freqtrade.enums import CandleType, Collateral, TradingMode | from freqtrade.enums import CandleType, MarginMode, TradingMode | ||||||
| from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFundsError, | from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFundsError, | ||||||
|                                   InvalidOrderException, OperationalException, PricingError, |                                   InvalidOrderException, OperationalException, PricingError, | ||||||
|                                   RetryableOrderError, TemporaryError) |                                   RetryableOrderError, TemporaryError) | ||||||
| @@ -77,7 +77,7 @@ class Exchange: | |||||||
|     } |     } | ||||||
|     _ft_has: Dict = {} |     _ft_has: Dict = {} | ||||||
|  |  | ||||||
|     _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ |     _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ | ||||||
|         # TradingMode.SPOT always supported and not required in this list |         # TradingMode.SPOT always supported and not required in this list | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
| @@ -137,9 +137,9 @@ class Exchange: | |||||||
|  |  | ||||||
|         self.trading_mode = TradingMode(config.get('trading_mode', 'spot')) |         self.trading_mode = TradingMode(config.get('trading_mode', 'spot')) | ||||||
|  |  | ||||||
|         self.collateral: Optional[Collateral] = ( |         self.margin_mode: Optional[MarginMode] = ( | ||||||
|             Collateral(config.get('collateral')) |             MarginMode(config.get('margin_mode')) | ||||||
|             if config.get('collateral') |             if config.get('margin_mode') | ||||||
|             else None |             else None | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
| @@ -175,7 +175,7 @@ class Exchange: | |||||||
|             self.validate_order_time_in_force(config.get('order_time_in_force', {})) |             self.validate_order_time_in_force(config.get('order_time_in_force', {})) | ||||||
|             self.required_candle_call_count = self.validate_required_startup_candles( |             self.required_candle_call_count = self.validate_required_startup_candles( | ||||||
|                 config.get('startup_candle_count', 0), config.get('timeframe', '')) |                 config.get('startup_candle_count', 0), config.get('timeframe', '')) | ||||||
|             self.validate_trading_mode_and_collateral(self.trading_mode, self.collateral) |             self.validate_trading_mode_and_margin_mode(self.trading_mode, self.margin_mode) | ||||||
|  |  | ||||||
|         # Converts the interval provided in minutes in config to seconds |         # Converts the interval provided in minutes in config to seconds | ||||||
|         self.markets_refresh_interval: int = exchange_config.get( |         self.markets_refresh_interval: int = exchange_config.get( | ||||||
| @@ -599,23 +599,23 @@ class Exchange: | |||||||
|                            f"if you really need {startup_candles} candles for your strategy") |                            f"if you really need {startup_candles} candles for your strategy") | ||||||
|         return required_candle_call_count |         return required_candle_call_count | ||||||
|  |  | ||||||
|     def validate_trading_mode_and_collateral( |     def validate_trading_mode_and_margin_mode( | ||||||
|         self, |         self, | ||||||
|         trading_mode: TradingMode, |         trading_mode: TradingMode, | ||||||
|         collateral: Optional[Collateral]  # Only None when trading_mode = TradingMode.SPOT |         margin_mode: Optional[MarginMode]  # Only None when trading_mode = TradingMode.SPOT | ||||||
|     ): |     ): | ||||||
|         """ |         """ | ||||||
|         Checks if freqtrade can perform trades using the configured |         Checks if freqtrade can perform trades using the configured | ||||||
|         trading mode(Margin, Futures) and Collateral(Cross, Isolated) |         trading mode(Margin, Futures) and MarginMode(Cross, Isolated) | ||||||
|         Throws OperationalException: |         Throws OperationalException: | ||||||
|             If the trading_mode/collateral type are not supported by freqtrade on this exchange |             If the trading_mode/margin_mode type are not supported by freqtrade on this exchange | ||||||
|         """ |         """ | ||||||
|         if trading_mode != TradingMode.SPOT and ( |         if trading_mode != TradingMode.SPOT and ( | ||||||
|             (trading_mode, collateral) not in self._supported_trading_mode_collateral_pairs |             (trading_mode, margin_mode) not in self._supported_trading_mode_margin_pairs | ||||||
|         ): |         ): | ||||||
|             collateral_value = collateral and collateral.value |             mm_value = margin_mode and margin_mode.value | ||||||
|             raise OperationalException( |             raise OperationalException( | ||||||
|                 f"Freqtrade does not support {collateral_value} {trading_mode.value} on {self.name}" |                 f"Freqtrade does not support {mm_value} {trading_mode.value} on {self.name}" | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|     def exchange_has(self, endpoint: str) -> bool: |     def exchange_has(self, endpoint: str) -> bool: | ||||||
| @@ -879,7 +879,7 @@ class Exchange: | |||||||
|  |  | ||||||
|     def _lev_prep(self, pair: str, leverage: float): |     def _lev_prep(self, pair: str, leverage: float): | ||||||
|         if self.trading_mode != TradingMode.SPOT: |         if self.trading_mode != TradingMode.SPOT: | ||||||
|             self.set_margin_mode(pair, self.collateral) |             self.set_margin_mode(pair, self.margin_mode) | ||||||
|             self._set_leverage(leverage, pair) |             self._set_leverage(leverage, pair) | ||||||
|  |  | ||||||
|     def _get_params(self, ordertype: str, leverage: float, time_in_force: str = 'gtc') -> Dict: |     def _get_params(self, ordertype: str, leverage: float, time_in_force: str = 'gtc') -> Dict: | ||||||
| @@ -1810,7 +1810,7 @@ class Exchange: | |||||||
|         """ |         """ | ||||||
|         Returns the maximum leverage that a pair can be traded at |         Returns the maximum leverage that a pair can be traded at | ||||||
|         :param pair: The base/quote currency pair being traded |         :param pair: The base/quote currency pair being traded | ||||||
|         :param nominal_value: The total value of the trade in quote currency (collateral + debt) |         :param nominal_value: The total value of the trade in quote currency (margin_mode + debt) | ||||||
|         """ |         """ | ||||||
|         market = self.markets[pair] |         market = self.markets[pair] | ||||||
|         if market['limits']['leverage']['max'] is not None: |         if market['limits']['leverage']['max'] is not None: | ||||||
| @@ -1830,7 +1830,7 @@ class Exchange: | |||||||
|         have the same leverage on every trade |         have the same leverage on every trade | ||||||
|         """ |         """ | ||||||
|         if self._config['dry_run'] or not self.exchange_has("setLeverage"): |         if self._config['dry_run'] or not self.exchange_has("setLeverage"): | ||||||
|             # Some exchanges only support one collateral type |             # Some exchanges only support one margin_mode type | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
| @@ -1851,17 +1851,17 @@ class Exchange: | |||||||
|         return open_date.minute > 0 or open_date.second > 0 |         return open_date.minute > 0 or open_date.second > 0 | ||||||
|  |  | ||||||
|     @retrier |     @retrier | ||||||
|     def set_margin_mode(self, pair: str, collateral: Collateral, params: dict = {}): |     def set_margin_mode(self, pair: str, margin_mode: MarginMode, params: dict = {}): | ||||||
|         """ |         """ | ||||||
|         Set's the margin mode on the exchange to cross or isolated for a specific pair |         Set's the margin mode on the exchange to cross or isolated for a specific pair | ||||||
|         :param pair: base/quote currency pair (e.g. "ADA/USDT") |         :param pair: base/quote currency pair (e.g. "ADA/USDT") | ||||||
|         """ |         """ | ||||||
|         if self._config['dry_run'] or not self.exchange_has("setMarginMode"): |         if self._config['dry_run'] or not self.exchange_has("setMarginMode"): | ||||||
|             # Some exchanges only support one collateral type |             # Some exchanges only support one margin_mode type | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             self._api.set_margin_mode(pair, collateral.value, params) |             self._api.set_margin_mode(pair, margin_mode.value, params) | ||||||
|         except ccxt.DDoSProtection as e: |         except ccxt.DDoSProtection as e: | ||||||
|             raise DDosProtection(e) from e |             raise DDosProtection(e) from e | ||||||
|         except (ccxt.NetworkError, ccxt.ExchangeError) as e: |         except (ccxt.NetworkError, ccxt.ExchangeError) as e: | ||||||
| @@ -2000,11 +2000,11 @@ class Exchange: | |||||||
|         """ |         """ | ||||||
|         if self.trading_mode == TradingMode.SPOT: |         if self.trading_mode == TradingMode.SPOT: | ||||||
|             return None |             return None | ||||||
|         elif (self.collateral is None): |         elif (self.margin_mode is None): | ||||||
|             raise OperationalException(f'{self.name}.collateral must be set for liquidation_price') |             raise OperationalException(f'{self.name}.margin_mode must be set for liquidation_price') | ||||||
|         elif (self.trading_mode != TradingMode.FUTURES and self.collateral != Collateral.ISOLATED): |         elif (self.trading_mode != TradingMode.FUTURES and self.margin_mode != MarginMode.ISOLATED): | ||||||
|             raise OperationalException( |             raise OperationalException( | ||||||
|                 f"{self.name} does not support {self.collateral.value} {self.trading_mode.value}") |                 f"{self.name} does not support {self.margin_mode.value} {self.trading_mode.value}") | ||||||
|  |  | ||||||
|         if self._config['dry_run'] or not self.exchange_has("fetchPositions"): |         if self._config['dry_run'] or not self.exchange_has("fetchPositions"): | ||||||
|  |  | ||||||
| @@ -2064,8 +2064,8 @@ class Exchange: | |||||||
|         :param is_short: True if the trade is a short, false otherwise |         :param is_short: True if the trade is a short, false otherwise | ||||||
|         :param position: Absolute value of position size incl. leverage (in base currency) |         :param position: Absolute value of position size incl. leverage (in base currency) | ||||||
|         :param trading_mode: SPOT, MARGIN, FUTURES, etc. |         :param trading_mode: SPOT, MARGIN, FUTURES, etc. | ||||||
|         :param collateral: Either ISOLATED or CROSS |         :param margin_mode: Either ISOLATED or CROSS | ||||||
|         :param wallet_balance: Amount of collateral in the wallet being used to trade |         :param wallet_balance: Amount of margin_mode in the wallet being used to trade | ||||||
|             Cross-Margin Mode: crossWalletBalance |             Cross-Margin Mode: crossWalletBalance | ||||||
|             Isolated-Margin Mode: isolatedWalletBalance |             Isolated-Margin Mode: isolatedWalletBalance | ||||||
|  |  | ||||||
| @@ -2078,7 +2078,7 @@ class Exchange: | |||||||
|         taker_fee_rate = market['taker'] |         taker_fee_rate = market['taker'] | ||||||
|         mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, position) |         mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, position) | ||||||
|  |  | ||||||
|         if self.trading_mode == TradingMode.FUTURES and self.collateral == Collateral.ISOLATED: |         if self.trading_mode == TradingMode.FUTURES and self.margin_mode == MarginMode.ISOLATED: | ||||||
|  |  | ||||||
|             if market['inverse']: |             if market['inverse']: | ||||||
|                 raise OperationalException( |                 raise OperationalException( | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ from typing import Any, Dict, List, Tuple | |||||||
|  |  | ||||||
| import ccxt | import ccxt | ||||||
|  |  | ||||||
| from freqtrade.enums import Collateral, TradingMode | from freqtrade.enums import MarginMode, TradingMode | ||||||
| from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, | from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, | ||||||
|                                   OperationalException, TemporaryError) |                                   OperationalException, TemporaryError) | ||||||
| from freqtrade.exchange import Exchange | from freqtrade.exchange import Exchange | ||||||
| @@ -25,10 +25,10 @@ class Ftx(Exchange): | |||||||
|         "mark_ohlcv_timeframe": "1h", |         "mark_ohlcv_timeframe": "1h", | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ |     _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ | ||||||
|         # TradingMode.SPOT always supported and not required in this list |         # TradingMode.SPOT always supported and not required in this list | ||||||
|         # (TradingMode.MARGIN, Collateral.CROSS), |         # (TradingMode.MARGIN, MarginMode.CROSS), | ||||||
|         # (TradingMode.FUTURES, Collateral.CROSS) |         # (TradingMode.FUTURES, MarginMode.CROSS) | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|     def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool: |     def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool: | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| import logging | import logging | ||||||
| from typing import Dict, List, Optional, Tuple | from typing import Dict, List, Optional, Tuple | ||||||
|  |  | ||||||
| from freqtrade.enums import Collateral, TradingMode | from freqtrade.enums import MarginMode, TradingMode | ||||||
| from freqtrade.exceptions import OperationalException | from freqtrade.exceptions import OperationalException | ||||||
| from freqtrade.exchange import Exchange | from freqtrade.exchange import Exchange | ||||||
|  |  | ||||||
| @@ -27,11 +27,11 @@ class Gateio(Exchange): | |||||||
|  |  | ||||||
|     _headers = {'X-Gate-Channel-Id': 'freqtrade'} |     _headers = {'X-Gate-Channel-Id': 'freqtrade'} | ||||||
|  |  | ||||||
|     _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ |     _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ | ||||||
|         # TradingMode.SPOT always supported and not required in this list |         # TradingMode.SPOT always supported and not required in this list | ||||||
|         # (TradingMode.MARGIN, Collateral.CROSS), |         # (TradingMode.MARGIN, MarginMode.CROSS), | ||||||
|         # (TradingMode.FUTURES, Collateral.CROSS), |         # (TradingMode.FUTURES, MarginMode.CROSS), | ||||||
|         (TradingMode.FUTURES, Collateral.ISOLATED) |         (TradingMode.FUTURES, MarginMode.ISOLATED) | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|     def validate_ordertypes(self, order_types: Dict) -> None: |     def validate_ordertypes(self, order_types: Dict) -> None: | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ from typing import Any, Dict, List, Optional, Tuple | |||||||
| import ccxt | import ccxt | ||||||
| from pandas import DataFrame | from pandas import DataFrame | ||||||
|  |  | ||||||
| from freqtrade.enums import Collateral, TradingMode | from freqtrade.enums import MarginMode, TradingMode | ||||||
| from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, | from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, | ||||||
|                                   OperationalException, TemporaryError) |                                   OperationalException, TemporaryError) | ||||||
| from freqtrade.exchange import Exchange | from freqtrade.exchange import Exchange | ||||||
| @@ -27,10 +27,10 @@ class Kraken(Exchange): | |||||||
|         "mark_ohlcv_timeframe": "4h", |         "mark_ohlcv_timeframe": "4h", | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ |     _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ | ||||||
|         # TradingMode.SPOT always supported and not required in this list |         # TradingMode.SPOT always supported and not required in this list | ||||||
|         # (TradingMode.MARGIN, Collateral.CROSS), |         # (TradingMode.MARGIN, MarginMode.CROSS), | ||||||
|         # (TradingMode.FUTURES, Collateral.CROSS) |         # (TradingMode.FUTURES, MarginMode.CROSS) | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|     def market_is_tradable(self, market: Dict[str, Any]) -> bool: |     def market_is_tradable(self, market: Dict[str, Any]) -> bool: | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| import logging | import logging | ||||||
| from typing import Dict, List, Tuple | from typing import Dict, List, Tuple | ||||||
|  |  | ||||||
| from freqtrade.enums import Collateral, TradingMode | from freqtrade.enums import MarginMode, TradingMode | ||||||
| from freqtrade.exchange import Exchange | from freqtrade.exchange import Exchange | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -20,9 +20,9 @@ class Okex(Exchange): | |||||||
|         "funding_fee_timeframe": "8h", |         "funding_fee_timeframe": "8h", | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ |     _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ | ||||||
|         # TradingMode.SPOT always supported and not required in this list |         # TradingMode.SPOT always supported and not required in this list | ||||||
|         # (TradingMode.MARGIN, Collateral.CROSS), |         # (TradingMode.MARGIN, MarginMode.CROSS), | ||||||
|         # (TradingMode.FUTURES, Collateral.CROSS), |         # (TradingMode.FUTURES, MarginMode.CROSS), | ||||||
|         # (TradingMode.FUTURES, Collateral.ISOLATED) |         # (TradingMode.FUTURES, MarginMode.ISOLATED) | ||||||
|     ] |     ] | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ from freqtrade.configuration import validate_config_consistency | |||||||
| from freqtrade.data.converter import order_book_to_dataframe | from freqtrade.data.converter import order_book_to_dataframe | ||||||
| from freqtrade.data.dataprovider import DataProvider | from freqtrade.data.dataprovider import DataProvider | ||||||
| from freqtrade.edge import Edge | from freqtrade.edge import Edge | ||||||
| from freqtrade.enums import (Collateral, RPCMessageType, RunMode, SellType, SignalDirection, State, | from freqtrade.enums import (MarginMode, RPCMessageType, RunMode, SellType, SignalDirection, State, | ||||||
|                              TradingMode) |                              TradingMode) | ||||||
| from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError, | from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError, | ||||||
|                                   InvalidOrderException, OperationalException, PricingError) |                                   InvalidOrderException, OperationalException, PricingError) | ||||||
| @@ -105,9 +105,9 @@ class FreqtradeBot(LoggingMixin): | |||||||
|  |  | ||||||
|         self.trading_mode = TradingMode(self.config.get('trading_mode', 'spot')) |         self.trading_mode = TradingMode(self.config.get('trading_mode', 'spot')) | ||||||
|  |  | ||||||
|         self.collateral_type: Optional[Collateral] = None |         self.margin_mode_type: Optional[MarginMode] = None | ||||||
|         if 'collateral' in self.config: |         if 'margin_mode' in self.config: | ||||||
|             self.collateral_type = Collateral(self.config['collateral']) |             self.margin_mode = MarginMode(self.config['margin_mode']) | ||||||
|  |  | ||||||
|         self._schedule = Scheduler() |         self._schedule = Scheduler() | ||||||
|  |  | ||||||
| @@ -615,7 +615,7 @@ class FreqtradeBot(LoggingMixin): | |||||||
|         if self.trading_mode == TradingMode.SPOT: |         if self.trading_mode == TradingMode.SPOT: | ||||||
|             return (0.0, None) |             return (0.0, None) | ||||||
|         elif ( |         elif ( | ||||||
|             self.collateral_type == Collateral.ISOLATED and |             self.margin_mode == MarginMode.ISOLATED and | ||||||
|             self.trading_mode == TradingMode.FUTURES |             self.trading_mode == TradingMode.FUTURES | ||||||
|         ): |         ): | ||||||
|             wallet_balance = (amount * open_rate)/leverage |             wallet_balance = (amount * open_rate)/leverage | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ from freqtrade import constants | |||||||
| from freqtrade.commands import Arguments | from freqtrade.commands import Arguments | ||||||
| from freqtrade.data.converter import ohlcv_to_dataframe | from freqtrade.data.converter import ohlcv_to_dataframe | ||||||
| from freqtrade.edge import PairInfo | from freqtrade.edge import PairInfo | ||||||
| from freqtrade.enums import CandleType, Collateral, RunMode, SignalDirection, TradingMode | from freqtrade.enums import CandleType, MarginMode, RunMode, SignalDirection, TradingMode | ||||||
| from freqtrade.exchange import Exchange | from freqtrade.exchange import Exchange | ||||||
| from freqtrade.freqtradebot import FreqtradeBot | from freqtrade.freqtradebot import FreqtradeBot | ||||||
| from freqtrade.persistence import LocalTrade, Trade, init_db | from freqtrade.persistence import LocalTrade, Trade, init_db | ||||||
| @@ -115,12 +115,12 @@ def patch_exchange( | |||||||
|  |  | ||||||
|     if mock_supported_modes: |     if mock_supported_modes: | ||||||
|         mocker.patch( |         mocker.patch( | ||||||
|             f'freqtrade.exchange.{id.capitalize()}._supported_trading_mode_collateral_pairs', |             f'freqtrade.exchange.{id.capitalize()}._supported_trading_mode_margin_pairs', | ||||||
|             PropertyMock(return_value=[ |             PropertyMock(return_value=[ | ||||||
|                 (TradingMode.MARGIN, Collateral.CROSS), |                 (TradingMode.MARGIN, MarginMode.CROSS), | ||||||
|                 (TradingMode.MARGIN, Collateral.ISOLATED), |                 (TradingMode.MARGIN, MarginMode.ISOLATED), | ||||||
|                 (TradingMode.FUTURES, Collateral.CROSS), |                 (TradingMode.FUTURES, MarginMode.CROSS), | ||||||
|                 (TradingMode.FUTURES, Collateral.ISOLATED) |                 (TradingMode.FUTURES, MarginMode.ISOLATED) | ||||||
|             ]) |             ]) | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ from unittest.mock import MagicMock, PropertyMock | |||||||
| import ccxt | import ccxt | ||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
| from freqtrade.enums import Collateral, TradingMode | from freqtrade.enums import MarginMode, TradingMode | ||||||
| from freqtrade.exceptions import DependencyException, InvalidOrderException, OperationalException | from freqtrade.exceptions import DependencyException, InvalidOrderException, OperationalException | ||||||
| from tests.conftest import get_mock_coro, get_patched_exchange, log_has_re | from tests.conftest import get_mock_coro, get_patched_exchange, log_has_re | ||||||
| from tests.exchange.test_exchange import ccxt_exceptionhandlers | from tests.exchange.test_exchange import ccxt_exceptionhandlers | ||||||
| @@ -236,7 +236,7 @@ def test_fill_leverage_brackets_binance(default_conf, mocker): | |||||||
|     }) |     }) | ||||||
|     default_conf['dry_run'] = False |     default_conf['dry_run'] = False | ||||||
|     default_conf['trading_mode'] = TradingMode.FUTURES |     default_conf['trading_mode'] = TradingMode.FUTURES | ||||||
|     default_conf['collateral'] = Collateral.ISOLATED |     default_conf['margin_mode'] = MarginMode.ISOLATED | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance") |     exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance") | ||||||
|     exchange.fill_leverage_brackets() |     exchange.fill_leverage_brackets() | ||||||
|  |  | ||||||
| @@ -282,7 +282,7 @@ def test_fill_leverage_brackets_binance(default_conf, mocker): | |||||||
| def test_fill_leverage_brackets_binance_dryrun(default_conf, mocker): | def test_fill_leverage_brackets_binance_dryrun(default_conf, mocker): | ||||||
|     api_mock = MagicMock() |     api_mock = MagicMock() | ||||||
|     default_conf['trading_mode'] = TradingMode.FUTURES |     default_conf['trading_mode'] = TradingMode.FUTURES | ||||||
|     default_conf['collateral'] = Collateral.ISOLATED |     default_conf['margin_mode'] = MarginMode.ISOLATED | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance") |     exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance") | ||||||
|     exchange.fill_leverage_brackets() |     exchange.fill_leverage_brackets() | ||||||
|  |  | ||||||
| @@ -385,14 +385,14 @@ async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog, c | |||||||
|     assert log_has_re(r"Candle-data for ETH/BTC available starting with .*", caplog) |     assert log_has_re(r"Candle-data for ETH/BTC available starting with .*", caplog) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("trading_mode,collateral,config", [ | @pytest.mark.parametrize("trading_mode,margin_mode,config", [ | ||||||
|     ("spot", "", {}), |     ("spot", "", {}), | ||||||
|     ("margin", "cross", {"options": {"defaultType": "margin"}}), |     ("margin", "cross", {"options": {"defaultType": "margin"}}), | ||||||
|     ("futures", "isolated", {"options": {"defaultType": "future"}}), |     ("futures", "isolated", {"options": {"defaultType": "future"}}), | ||||||
| ]) | ]) | ||||||
| def test__ccxt_config(default_conf, mocker, trading_mode, collateral, config): | def test__ccxt_config(default_conf, mocker, trading_mode, margin_mode, config): | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = collateral |     default_conf['margin_mode'] = margin_mode | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, id="binance") |     exchange = get_patched_exchange(mocker, default_conf, id="binance") | ||||||
|     assert exchange._ccxt_config == config |     assert exchange._ccxt_config == config | ||||||
|  |  | ||||||
|   | |||||||
| @@ -104,12 +104,12 @@ def exchange_futures(request, exchange_conf, class_mocker): | |||||||
|         exchange_conf = deepcopy(exchange_conf) |         exchange_conf = deepcopy(exchange_conf) | ||||||
|         exchange_conf['exchange']['name'] = request.param |         exchange_conf['exchange']['name'] = request.param | ||||||
|         exchange_conf['trading_mode'] = 'futures' |         exchange_conf['trading_mode'] = 'futures' | ||||||
|         exchange_conf['collateral'] = 'cross' |         exchange_conf['margin_mode'] = 'cross' | ||||||
|         exchange_conf['stake_currency'] = EXCHANGES[request.param]['stake_currency'] |         exchange_conf['stake_currency'] = EXCHANGES[request.param]['stake_currency'] | ||||||
|  |  | ||||||
|         # TODO-lev: This mock should no longer be necessary once futures are enabled. |         # TODO-lev: This mock should no longer be necessary once futures are enabled. | ||||||
|         class_mocker.patch( |         class_mocker.patch( | ||||||
|             'freqtrade.exchange.exchange.Exchange.validate_trading_mode_and_collateral') |             'freqtrade.exchange.exchange.Exchange.validate_trading_mode_and_margin_mode') | ||||||
|         class_mocker.patch( |         class_mocker.patch( | ||||||
|             'freqtrade.exchange.binance.Binance.fill_leverage_brackets') |             'freqtrade.exchange.binance.Binance.fill_leverage_brackets') | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ import ccxt | |||||||
| import pytest | import pytest | ||||||
| from pandas import DataFrame | from pandas import DataFrame | ||||||
|  |  | ||||||
| from freqtrade.enums import CandleType, Collateral, TradingMode | from freqtrade.enums import CandleType, MarginMode, TradingMode | ||||||
| from freqtrade.exceptions import (DDosProtection, DependencyException, InvalidOrderException, | from freqtrade.exceptions import (DDosProtection, DependencyException, InvalidOrderException, | ||||||
|                                   OperationalException, PricingError, TemporaryError) |                                   OperationalException, PricingError, TemporaryError) | ||||||
| from freqtrade.exchange import Binance, Bittrex, Exchange, Kraken | from freqtrade.exchange import Binance, Bittrex, Exchange, Kraken | ||||||
| @@ -263,7 +263,7 @@ def test_amount_to_precision( | |||||||
|     }) |     }) | ||||||
|  |  | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|  |  | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, id="binance") |     exchange = get_patched_exchange(mocker, default_conf, id="binance") | ||||||
|     # digits counting mode |     # digits counting mode | ||||||
| @@ -473,7 +473,7 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None: | |||||||
|  |  | ||||||
|     markets["ETH/BTC"]["contractSize"] = '0.01' |     markets["ETH/BTC"]["contractSize"] = '0.01' | ||||||
|     default_conf['trading_mode'] = 'futures' |     default_conf['trading_mode'] = 'futures' | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, id="binance") |     exchange = get_patched_exchange(mocker, default_conf, id="binance") | ||||||
|     mocker.patch( |     mocker.patch( | ||||||
|         'freqtrade.exchange.Exchange.markets', |         'freqtrade.exchange.Exchange.markets', | ||||||
| @@ -1165,7 +1165,7 @@ def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice, | |||||||
|         'amount': 1 |         'amount': 1 | ||||||
|     }) |     }) | ||||||
|     default_conf['dry_run'] = False |     default_conf['dry_run'] = False | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     mocker.patch('freqtrade.exchange.Exchange.amount_to_precision', lambda s, x, y: y) |     mocker.patch('freqtrade.exchange.Exchange.amount_to_precision', lambda s, x, y: y) | ||||||
|     mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y) |     mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y) | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) |     exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) | ||||||
| @@ -2334,7 +2334,7 @@ async def test__async_fetch_trades(default_conf, mocker, caplog, exchange_name, | |||||||
| async def test__async_fetch_trades_contract_size(default_conf, mocker, caplog, exchange_name, | async def test__async_fetch_trades_contract_size(default_conf, mocker, caplog, exchange_name, | ||||||
|                                                  fetch_trades_result): |                                                  fetch_trades_result): | ||||||
|     caplog.set_level(logging.DEBUG) |     caplog.set_level(logging.DEBUG) | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     default_conf['trading_mode'] = 'futures' |     default_conf['trading_mode'] = 'futures' | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) |     exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) | ||||||
|     # Monkey-patch async function |     # Monkey-patch async function | ||||||
| @@ -2796,7 +2796,7 @@ def test_get_trades_for_order(default_conf, mocker, exchange_name, trading_mode, | |||||||
|     since = datetime(2018, 5, 5, 0, 0, 0) |     since = datetime(2018, 5, 5, 0, 0, 0) | ||||||
|     default_conf["dry_run"] = False |     default_conf["dry_run"] = False | ||||||
|     default_conf["trading_mode"] = trading_mode |     default_conf["trading_mode"] = trading_mode | ||||||
|     default_conf["collateral"] = 'isolated' |     default_conf["margin_mode"] = 'isolated' | ||||||
|     mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True) |     mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True) | ||||||
|     api_mock = MagicMock() |     api_mock = MagicMock() | ||||||
|  |  | ||||||
| @@ -3170,7 +3170,7 @@ def test_market_is_tradable( | |||||||
|         quote, spot, margin, futures, trademode, add_dict, exchange, expected_result |         quote, spot, margin, futures, trademode, add_dict, exchange, expected_result | ||||||
| ) -> None: | ) -> None: | ||||||
|     default_conf['trading_mode'] = trademode |     default_conf['trading_mode'] = trademode | ||||||
|     mocker.patch('freqtrade.exchange.exchange.Exchange.validate_trading_mode_and_collateral') |     mocker.patch('freqtrade.exchange.exchange.Exchange.validate_trading_mode_and_margin_mode') | ||||||
|     ex = get_patched_exchange(mocker, default_conf, id=exchange) |     ex = get_patched_exchange(mocker, default_conf, id=exchange) | ||||||
|     market = { |     market = { | ||||||
|         'symbol': market_symbol, |         'symbol': market_symbol, | ||||||
| @@ -3400,11 +3400,11 @@ def test__set_leverage(mocker, default_conf, exchange_name, trading_mode): | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("collateral", [ | @pytest.mark.parametrize("margin_mode", [ | ||||||
|     (Collateral.CROSS), |     (MarginMode.CROSS), | ||||||
|     (Collateral.ISOLATED) |     (MarginMode.ISOLATED) | ||||||
| ]) | ]) | ||||||
| def test_set_margin_mode(mocker, default_conf, collateral): | def test_set_margin_mode(mocker, default_conf, margin_mode): | ||||||
|  |  | ||||||
|     api_mock = MagicMock() |     api_mock = MagicMock() | ||||||
|     api_mock.set_margin_mode = MagicMock() |     api_mock.set_margin_mode = MagicMock() | ||||||
| @@ -3419,70 +3419,70 @@ def test_set_margin_mode(mocker, default_conf, collateral): | |||||||
|         "set_margin_mode", |         "set_margin_mode", | ||||||
|         "set_margin_mode", |         "set_margin_mode", | ||||||
|         pair="XRP/USDT", |         pair="XRP/USDT", | ||||||
|         collateral=collateral |         margin_mode=margin_mode | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("exchange_name, trading_mode, collateral, exception_thrown", [ | @pytest.mark.parametrize("exchange_name, trading_mode, margin_mode, exception_thrown", [ | ||||||
|     ("binance", TradingMode.SPOT, None, False), |     ("binance", TradingMode.SPOT, None, False), | ||||||
|     ("binance", TradingMode.MARGIN, Collateral.ISOLATED, True), |     ("binance", TradingMode.MARGIN, MarginMode.ISOLATED, True), | ||||||
|     ("kraken", TradingMode.SPOT, None, False), |     ("kraken", TradingMode.SPOT, None, False), | ||||||
|     ("kraken", TradingMode.MARGIN, Collateral.ISOLATED, True), |     ("kraken", TradingMode.MARGIN, MarginMode.ISOLATED, True), | ||||||
|     ("kraken", TradingMode.FUTURES, Collateral.ISOLATED, True), |     ("kraken", TradingMode.FUTURES, MarginMode.ISOLATED, True), | ||||||
|     ("ftx", TradingMode.SPOT, None, False), |     ("ftx", TradingMode.SPOT, None, False), | ||||||
|     ("ftx", TradingMode.MARGIN, Collateral.ISOLATED, True), |     ("ftx", TradingMode.MARGIN, MarginMode.ISOLATED, True), | ||||||
|     ("ftx", TradingMode.FUTURES, Collateral.ISOLATED, True), |     ("ftx", TradingMode.FUTURES, MarginMode.ISOLATED, True), | ||||||
|     ("bittrex", TradingMode.SPOT, None, False), |     ("bittrex", TradingMode.SPOT, None, False), | ||||||
|     ("bittrex", TradingMode.MARGIN, Collateral.CROSS, True), |     ("bittrex", TradingMode.MARGIN, MarginMode.CROSS, True), | ||||||
|     ("bittrex", TradingMode.MARGIN, Collateral.ISOLATED, True), |     ("bittrex", TradingMode.MARGIN, MarginMode.ISOLATED, True), | ||||||
|     ("bittrex", TradingMode.FUTURES, Collateral.CROSS, True), |     ("bittrex", TradingMode.FUTURES, MarginMode.CROSS, True), | ||||||
|     ("bittrex", TradingMode.FUTURES, Collateral.ISOLATED, True), |     ("bittrex", TradingMode.FUTURES, MarginMode.ISOLATED, True), | ||||||
|     ("gateio", TradingMode.MARGIN, Collateral.ISOLATED, True), |     ("gateio", TradingMode.MARGIN, MarginMode.ISOLATED, True), | ||||||
|     ("okex", TradingMode.SPOT, None, False), |     ("okex", TradingMode.SPOT, None, False), | ||||||
|     ("okex", TradingMode.MARGIN, Collateral.CROSS, True), |     ("okex", TradingMode.MARGIN, MarginMode.CROSS, True), | ||||||
|     ("okex", TradingMode.MARGIN, Collateral.ISOLATED, True), |     ("okex", TradingMode.MARGIN, MarginMode.ISOLATED, True), | ||||||
|     ("okex", TradingMode.FUTURES, Collateral.CROSS, True), |     ("okex", TradingMode.FUTURES, MarginMode.CROSS, True), | ||||||
|  |  | ||||||
|     ("binance", TradingMode.FUTURES, Collateral.ISOLATED, False), |     ("binance", TradingMode.FUTURES, MarginMode.ISOLATED, False), | ||||||
|     ("gateio", TradingMode.FUTURES, Collateral.ISOLATED, False), |     ("gateio", TradingMode.FUTURES, MarginMode.ISOLATED, False), | ||||||
|  |  | ||||||
|     # * Remove once implemented |     # * Remove once implemented | ||||||
|     ("okex", TradingMode.FUTURES, Collateral.ISOLATED, True), |     ("okex", TradingMode.FUTURES, MarginMode.ISOLATED, True), | ||||||
|     ("binance", TradingMode.MARGIN, Collateral.CROSS, True), |     ("binance", TradingMode.MARGIN, MarginMode.CROSS, True), | ||||||
|     ("binance", TradingMode.FUTURES, Collateral.CROSS, True), |     ("binance", TradingMode.FUTURES, MarginMode.CROSS, True), | ||||||
|     ("kraken", TradingMode.MARGIN, Collateral.CROSS, True), |     ("kraken", TradingMode.MARGIN, MarginMode.CROSS, True), | ||||||
|     ("kraken", TradingMode.FUTURES, Collateral.CROSS, True), |     ("kraken", TradingMode.FUTURES, MarginMode.CROSS, True), | ||||||
|     ("ftx", TradingMode.MARGIN, Collateral.CROSS, True), |     ("ftx", TradingMode.MARGIN, MarginMode.CROSS, True), | ||||||
|     ("ftx", TradingMode.FUTURES, Collateral.CROSS, True), |     ("ftx", TradingMode.FUTURES, MarginMode.CROSS, True), | ||||||
|     ("gateio", TradingMode.MARGIN, Collateral.CROSS, True), |     ("gateio", TradingMode.MARGIN, MarginMode.CROSS, True), | ||||||
|     ("gateio", TradingMode.FUTURES, Collateral.CROSS, True), |     ("gateio", TradingMode.FUTURES, MarginMode.CROSS, True), | ||||||
|  |  | ||||||
|     # * Uncomment once implemented |     # * Uncomment once implemented | ||||||
|     # ("okex", TradingMode.FUTURES, Collateral.ISOLATED, False), |     # ("okex", TradingMode.FUTURES, MarginMode.ISOLATED, False), | ||||||
|     # ("binance", TradingMode.MARGIN, Collateral.CROSS, False), |     # ("binance", TradingMode.MARGIN, MarginMode.CROSS, False), | ||||||
|     # ("binance", TradingMode.FUTURES, Collateral.CROSS, False), |     # ("binance", TradingMode.FUTURES, MarginMode.CROSS, False), | ||||||
|     # ("kraken", TradingMode.MARGIN, Collateral.CROSS, False), |     # ("kraken", TradingMode.MARGIN, MarginMode.CROSS, False), | ||||||
|     # ("kraken", TradingMode.FUTURES, Collateral.CROSS, False), |     # ("kraken", TradingMode.FUTURES, MarginMode.CROSS, False), | ||||||
|     # ("ftx", TradingMode.MARGIN, Collateral.CROSS, False), |     # ("ftx", TradingMode.MARGIN, MarginMode.CROSS, False), | ||||||
|     # ("ftx", TradingMode.FUTURES, Collateral.CROSS, False), |     # ("ftx", TradingMode.FUTURES, MarginMode.CROSS, False), | ||||||
|     # ("gateio", TradingMode.MARGIN, Collateral.CROSS, False), |     # ("gateio", TradingMode.MARGIN, MarginMode.CROSS, False), | ||||||
|     # ("gateio", TradingMode.FUTURES, Collateral.CROSS, False), |     # ("gateio", TradingMode.FUTURES, MarginMode.CROSS, False), | ||||||
| ]) | ]) | ||||||
| def test_validate_trading_mode_and_collateral( | def test_validate_trading_mode_and_margin_mode( | ||||||
|     default_conf, |     default_conf, | ||||||
|     mocker, |     mocker, | ||||||
|     exchange_name, |     exchange_name, | ||||||
|     trading_mode, |     trading_mode, | ||||||
|     collateral, |     margin_mode, | ||||||
|     exception_thrown |     exception_thrown | ||||||
| ): | ): | ||||||
|     exchange = get_patched_exchange( |     exchange = get_patched_exchange( | ||||||
|         mocker, default_conf, id=exchange_name, mock_supported_modes=False) |         mocker, default_conf, id=exchange_name, mock_supported_modes=False) | ||||||
|     if (exception_thrown): |     if (exception_thrown): | ||||||
|         with pytest.raises(OperationalException): |         with pytest.raises(OperationalException): | ||||||
|             exchange.validate_trading_mode_and_collateral(trading_mode, collateral) |             exchange.validate_trading_mode_and_margin_mode(trading_mode, margin_mode) | ||||||
|     else: |     else: | ||||||
|         exchange.validate_trading_mode_and_collateral(trading_mode, collateral) |         exchange.validate_trading_mode_and_margin_mode(trading_mode, margin_mode) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("exchange_name,trading_mode,ccxt_config", [ | @pytest.mark.parametrize("exchange_name,trading_mode,ccxt_config", [ | ||||||
| @@ -3508,7 +3508,7 @@ def test__ccxt_config( | |||||||
|     ccxt_config |     ccxt_config | ||||||
| ): | ): | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) |     exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) | ||||||
|     assert exchange._ccxt_config == ccxt_config |     assert exchange._ccxt_config == ccxt_config | ||||||
|  |  | ||||||
| @@ -3609,7 +3609,7 @@ def test_get_liquidation_price(mocker, default_conf): | |||||||
|             'marginRatio': None, |             'marginRatio': None, | ||||||
|             'liquidationPrice': 17.47, |             'liquidationPrice': 17.47, | ||||||
|             'markPrice': 18.89, |             'markPrice': 18.89, | ||||||
|             'collateral': 1.52549075, |             'margin_mode': 1.52549075, | ||||||
|             'marginType': 'isolated', |             'marginType': 'isolated', | ||||||
|             'side': 'buy', |             'side': 'buy', | ||||||
|             'percentage': 0.003177292946409658 |             'percentage': 0.003177292946409658 | ||||||
| @@ -3622,7 +3622,7 @@ def test_get_liquidation_price(mocker, default_conf): | |||||||
|     ) |     ) | ||||||
|     default_conf['dry_run'] = False |     default_conf['dry_run'] = False | ||||||
|     default_conf['trading_mode'] = 'futures' |     default_conf['trading_mode'] = 'futures' | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|  |  | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, api_mock) |     exchange = get_patched_exchange(mocker, default_conf, api_mock) | ||||||
|     liq_price = exchange.get_liquidation_price( |     liq_price = exchange.get_liquidation_price( | ||||||
| @@ -3786,7 +3786,7 @@ def test__fetch_and_calculate_funding_fees_datetime_called( | |||||||
| def test__get_contract_size(mocker, default_conf, pair, expected_size, trading_mode): | def test__get_contract_size(mocker, default_conf, pair, expected_size, trading_mode): | ||||||
|     api_mock = MagicMock() |     api_mock = MagicMock() | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     mocker.patch('freqtrade.exchange.Exchange.markets', { |     mocker.patch('freqtrade.exchange.Exchange.markets', { | ||||||
|         'LTC/USD': { |         'LTC/USD': { | ||||||
|             'symbol': 'LTC/USD', |             'symbol': 'LTC/USD', | ||||||
| @@ -3826,7 +3826,7 @@ def test__order_contracts_to_amount( | |||||||
| ): | ): | ||||||
|     api_mock = MagicMock() |     api_mock = MagicMock() | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     mocker.patch('freqtrade.exchange.Exchange.markets', markets) |     mocker.patch('freqtrade.exchange.Exchange.markets', markets) | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, api_mock) |     exchange = get_patched_exchange(mocker, default_conf, api_mock) | ||||||
|  |  | ||||||
| @@ -3910,7 +3910,7 @@ def test__trades_contracts_to_amount( | |||||||
| ): | ): | ||||||
|     api_mock = MagicMock() |     api_mock = MagicMock() | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     mocker.patch('freqtrade.exchange.Exchange.markets', markets) |     mocker.patch('freqtrade.exchange.Exchange.markets', markets) | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, api_mock) |     exchange = get_patched_exchange(mocker, default_conf, api_mock) | ||||||
|  |  | ||||||
| @@ -3946,7 +3946,7 @@ def test__amount_to_contracts( | |||||||
| ): | ): | ||||||
|     api_mock = MagicMock() |     api_mock = MagicMock() | ||||||
|     default_conf['trading_mode'] = 'spot' |     default_conf['trading_mode'] = 'spot' | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     mocker.patch('freqtrade.exchange.Exchange.markets', { |     mocker.patch('freqtrade.exchange.Exchange.markets', { | ||||||
|         'LTC/USD': { |         'LTC/USD': { | ||||||
|             'symbol': 'LTC/USD', |             'symbol': 'LTC/USD', | ||||||
| @@ -3978,7 +3978,7 @@ def test__amount_to_contracts( | |||||||
|     assert result_amount == param_amount |     assert result_amount == param_amount | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize('exchange_name,open_rate,is_short,trading_mode,collateral', [ | @pytest.mark.parametrize('exchange_name,open_rate,is_short,trading_mode,margin_mode', [ | ||||||
|     # Bittrex |     # Bittrex | ||||||
|     ('bittrex', 2.0, False, 'spot', None), |     ('bittrex', 2.0, False, 'spot', None), | ||||||
|     ('bittrex', 2.0, False, 'spot', 'cross'), |     ('bittrex', 2.0, False, 'spot', 'cross'), | ||||||
| @@ -3995,10 +3995,10 @@ def test_liquidation_price_is_none( | |||||||
|     open_rate, |     open_rate, | ||||||
|     is_short, |     is_short, | ||||||
|     trading_mode, |     trading_mode, | ||||||
|     collateral |     margin_mode | ||||||
| ): | ): | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = collateral |     default_conf['margin_mode'] = margin_mode | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) |     exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) | ||||||
|     assert exchange.get_liquidation_price( |     assert exchange.get_liquidation_price( | ||||||
|         pair='DOGE/USDT', |         pair='DOGE/USDT', | ||||||
| @@ -4012,7 +4012,7 @@ def test_liquidation_price_is_none( | |||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize( | @pytest.mark.parametrize( | ||||||
|     'exchange_name, is_short, trading_mode, collateral, wallet_balance, ' |     'exchange_name, is_short, trading_mode, margin_mode, wallet_balance, ' | ||||||
|     'mm_ex_1, upnl_ex_1, maintenance_amt, position, open_rate, ' |     'mm_ex_1, upnl_ex_1, maintenance_amt, position, open_rate, ' | ||||||
|     'mm_ratio, expected', |     'mm_ratio, expected', | ||||||
|     [ |     [ | ||||||
| @@ -4027,10 +4027,10 @@ def test_liquidation_price_is_none( | |||||||
|     ]) |     ]) | ||||||
| def test_liquidation_price( | def test_liquidation_price( | ||||||
|     mocker, default_conf, exchange_name, open_rate, is_short, trading_mode, |     mocker, default_conf, exchange_name, open_rate, is_short, trading_mode, | ||||||
|     collateral, wallet_balance, mm_ex_1, upnl_ex_1, maintenance_amt, position, mm_ratio, expected |     margin_mode, wallet_balance, mm_ex_1, upnl_ex_1, maintenance_amt, position, mm_ratio, expected | ||||||
| ): | ): | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = collateral |     default_conf['margin_mode'] = margin_mode | ||||||
|     exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) |     exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) | ||||||
|     exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(mm_ratio, maintenance_amt)) |     exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(mm_ratio, maintenance_amt)) | ||||||
|     assert isclose(round(exchange.get_liquidation_price( |     assert isclose(round(exchange.get_liquidation_price( | ||||||
|   | |||||||
| @@ -1177,7 +1177,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, | |||||||
|     # Tests detail-data loading |     # Tests detail-data loading | ||||||
|     default_conf_usdt.update({ |     default_conf_usdt.update({ | ||||||
|         "trading_mode": "futures", |         "trading_mode": "futures", | ||||||
|         "collateral": "isolated", |         "margin_mode": "isolated", | ||||||
|         "use_sell_signal": True, |         "use_sell_signal": True, | ||||||
|         "sell_profit_only": False, |         "sell_profit_only": False, | ||||||
|         "sell_profit_offset": 0.0, |         "sell_profit_offset": 0.0, | ||||||
|   | |||||||
| @@ -749,7 +749,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order, | |||||||
|     leverage = 1.0 if trading_mode == 'spot' else 5.0 |     leverage = 1.0 if trading_mode == 'spot' else 5.0 | ||||||
|     default_conf_usdt['exchange']['name'] = exchange_name |     default_conf_usdt['exchange']['name'] = exchange_name | ||||||
|     if margin_mode: |     if margin_mode: | ||||||
|         default_conf_usdt['collateral'] = margin_mode |         default_conf_usdt['margin_mode'] = margin_mode | ||||||
|     mocker.patch('freqtrade.exchange.Gateio.validate_ordertypes') |     mocker.patch('freqtrade.exchange.Gateio.validate_ordertypes') | ||||||
|     patch_RPCManager(mocker) |     patch_RPCManager(mocker) | ||||||
|     patch_exchange(mocker, id=exchange_name) |     patch_exchange(mocker, id=exchange_name) | ||||||
| @@ -4809,7 +4809,7 @@ def test_update_funding_fees_schedule(mocker, default_conf, trading_mode, calls, | |||||||
|     patch_exchange(mocker) |     patch_exchange(mocker) | ||||||
|     mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_funding_fees', return_value=True) |     mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_funding_fees', return_value=True) | ||||||
|     default_conf['trading_mode'] = trading_mode |     default_conf['trading_mode'] = trading_mode | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|     freqtrade = get_patched_freqtradebot(mocker, default_conf) |     freqtrade = get_patched_freqtradebot(mocker, default_conf) | ||||||
|  |  | ||||||
|     time_machine.move_to(f"{t2} +00:00") |     time_machine.move_to(f"{t2} +00:00") | ||||||
| @@ -4859,7 +4859,7 @@ def test_update_funding_fees( | |||||||
|     patch_RPCManager(mocker) |     patch_RPCManager(mocker) | ||||||
|     patch_exchange(mocker) |     patch_exchange(mocker) | ||||||
|     default_conf['trading_mode'] = 'futures' |     default_conf['trading_mode'] = 'futures' | ||||||
|     default_conf['collateral'] = 'isolated' |     default_conf['margin_mode'] = 'isolated' | ||||||
|  |  | ||||||
|     date_midnight = arrow.get('2021-09-01 00:00:00') |     date_midnight = arrow.get('2021-09-01 00:00:00') | ||||||
|     date_eight = arrow.get('2021-09-01 08:00:00') |     date_eight = arrow.get('2021-09-01 08:00:00') | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user