Changed name Collateral -> MarginMode, collateral -> margin_mode, and _supported_trading_mode_margin_pairs -> _supported_trading_margin_pairs
This commit is contained in:
parent
45e533fc3e
commit
30519aa3be
@ -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')
|
||||||
|
Loading…
Reference in New Issue
Block a user