leverage updates on exchange classes
This commit is contained in:
parent
cbaf477bec
commit
57c7926515
1214
freqtrade/data/leverage_brackets.json
Normal file
1214
freqtrade/data/leverage_brackets.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,7 @@
|
|||||||
""" Binance exchange subclass """
|
""" Binance exchange subclass """
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
@ -47,8 +49,8 @@ class Binance(Exchange):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@retrier(retries=0)
|
@retrier(retries=0)
|
||||||
def stoploss(self, pair: str, amount: float,
|
def stoploss(self, pair: str, amount: float, stop_price: float,
|
||||||
stop_price: float, order_types: Dict, side: str) -> Dict:
|
order_types: Dict, side: str, leverage: float) -> Dict:
|
||||||
"""
|
"""
|
||||||
creates a stoploss limit order.
|
creates a stoploss limit order.
|
||||||
this stoploss-limit is binance-specific.
|
this stoploss-limit is binance-specific.
|
||||||
@ -76,7 +78,7 @@ class Binance(Exchange):
|
|||||||
|
|
||||||
if self._config['dry_run']:
|
if self._config['dry_run']:
|
||||||
dry_order = self.create_dry_run_order(
|
dry_order = self.create_dry_run_order(
|
||||||
pair, ordertype, side, amount, stop_price)
|
pair, ordertype, side, amount, stop_price, leverage)
|
||||||
return dry_order
|
return dry_order
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -87,8 +89,15 @@ class Binance(Exchange):
|
|||||||
|
|
||||||
rate = self.price_to_precision(pair, rate)
|
rate = self.price_to_precision(pair, rate)
|
||||||
|
|
||||||
order = self._api.create_order(symbol=pair, type=ordertype, side=side,
|
order = self._api.create_order(
|
||||||
amount=amount, price=rate, params=params)
|
symbol=pair,
|
||||||
|
type=ordertype,
|
||||||
|
side=side,
|
||||||
|
amount=amount,
|
||||||
|
price=rate,
|
||||||
|
params=params,
|
||||||
|
leverage=leverage
|
||||||
|
)
|
||||||
logger.info('stoploss limit order added for %s. '
|
logger.info('stoploss limit order added for %s. '
|
||||||
'stop price: %s. limit: %s', pair, stop_price, rate)
|
'stop price: %s. limit: %s', pair, stop_price, rate)
|
||||||
self._log_exchange_response('create_stoploss_order', order)
|
self._log_exchange_response('create_stoploss_order', order)
|
||||||
@ -119,26 +128,33 @@ class Binance(Exchange):
|
|||||||
Assigns property _leverage_brackets to a dictionary of information about the leverage
|
Assigns property _leverage_brackets to a dictionary of information about the leverage
|
||||||
allowed on each pair
|
allowed on each pair
|
||||||
"""
|
"""
|
||||||
try:
|
if self.trading_mode == TradingMode.FUTURES:
|
||||||
leverage_brackets = self._api.load_leverage_brackets()
|
try:
|
||||||
for pair, brackets in leverage_brackets.items():
|
if self._config['dry_run']:
|
||||||
self._leverage_brackets[pair] = [
|
leverage_brackets_path = Path('data') / 'leverage_brackets.json'
|
||||||
[
|
with open(leverage_brackets_path) as json_file:
|
||||||
min_amount,
|
leverage_brackets = json.load(json_file)
|
||||||
float(margin_req)
|
else:
|
||||||
] for [
|
leverage_brackets = self._api.load_leverage_brackets()
|
||||||
min_amount,
|
|
||||||
margin_req
|
|
||||||
] in brackets
|
|
||||||
]
|
|
||||||
|
|
||||||
except ccxt.DDoSProtection as e:
|
for pair, brackets in leverage_brackets.items():
|
||||||
raise DDosProtection(e) from e
|
self._leverage_brackets[pair] = [
|
||||||
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
[
|
||||||
raise TemporaryError(f'Could not fetch leverage amounts due to'
|
min_amount,
|
||||||
f'{e.__class__.__name__}. Message: {e}') from e
|
float(margin_req)
|
||||||
except ccxt.BaseError as e:
|
] for [
|
||||||
raise OperationalException(e) from e
|
min_amount,
|
||||||
|
margin_req
|
||||||
|
] in brackets
|
||||||
|
]
|
||||||
|
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
|
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
|
||||||
|
raise TemporaryError(f'Could not fetch leverage amounts due to'
|
||||||
|
f'{e.__class__.__name__}. Message: {e}') from e
|
||||||
|
except ccxt.BaseError as e:
|
||||||
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
def get_max_leverage(self, pair: Optional[str], nominal_value: Optional[float]) -> float:
|
def get_max_leverage(self, pair: Optional[str], nominal_value: Optional[float]) -> float:
|
||||||
"""
|
"""
|
||||||
@ -153,10 +169,6 @@ class Binance(Exchange):
|
|||||||
max_lev = 1/margin_req
|
max_lev = 1/margin_req
|
||||||
return max_lev
|
return max_lev
|
||||||
|
|
||||||
def lev_prep(self, pair: str, leverage: float):
|
|
||||||
self.set_margin_mode(pair, self.collateral)
|
|
||||||
self._set_leverage(leverage, pair, self.trading_mode)
|
|
||||||
|
|
||||||
@retrier
|
@retrier
|
||||||
def _set_leverage(
|
def _set_leverage(
|
||||||
self,
|
self,
|
||||||
@ -170,9 +182,11 @@ class Binance(Exchange):
|
|||||||
"""
|
"""
|
||||||
trading_mode = trading_mode or self.trading_mode
|
trading_mode = trading_mode or self.trading_mode
|
||||||
|
|
||||||
|
if self._config['dry_run'] or trading_mode != TradingMode.FUTURES:
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if trading_mode == TradingMode.FUTURES:
|
self._api.set_leverage(symbol=pair, leverage=leverage)
|
||||||
self._api.set_leverage(symbol=pair, leverage=leverage)
|
|
||||||
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:
|
||||||
|
@ -258,6 +258,13 @@ class Exchange:
|
|||||||
"""exchange ccxt precisionMode"""
|
"""exchange ccxt precisionMode"""
|
||||||
return self._api.precisionMode
|
return self._api.precisionMode
|
||||||
|
|
||||||
|
@property
|
||||||
|
def running_live_mode(self) -> bool:
|
||||||
|
return (
|
||||||
|
self._config['runmode'].value not in ('backtest', 'hyperopt') and
|
||||||
|
not self._config['dry_run']
|
||||||
|
)
|
||||||
|
|
||||||
def _log_exchange_response(self, endpoint, response) -> None:
|
def _log_exchange_response(self, endpoint, response) -> None:
|
||||||
""" Log exchange responses """
|
""" Log exchange responses """
|
||||||
if self.log_responses:
|
if self.log_responses:
|
||||||
@ -617,15 +624,13 @@ class Exchange:
|
|||||||
# The value returned should satisfy both limits: for amount (base currency) and
|
# The value returned should satisfy both limits: for amount (base currency) and
|
||||||
# for cost (quote, stake currency), so max() is used here.
|
# for cost (quote, stake currency), so max() is used here.
|
||||||
# See also #2575 at github.
|
# See also #2575 at github.
|
||||||
return self._apply_leverage_to_stake_amount(
|
return self._divide_stake_amount_by_leverage(
|
||||||
max(min_stake_amounts) * amount_reserve_percent,
|
max(min_stake_amounts) * amount_reserve_percent,
|
||||||
leverage or 1.0
|
leverage or 1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
def _apply_leverage_to_stake_amount(self, stake_amount: float, leverage: float):
|
def _divide_stake_amount_by_leverage(self, stake_amount: float, leverage: float):
|
||||||
"""
|
"""
|
||||||
#TODO-lev: Find out how this works on Kraken and FTX
|
|
||||||
# * Should be implemented by child classes if leverage affects the stake_amount
|
|
||||||
Takes the minimum stake amount for a pair with no leverage and returns the minimum
|
Takes the minimum stake amount for a pair with no leverage and returns the minimum
|
||||||
stake amount when leverage is considered
|
stake amount when leverage is considered
|
||||||
:param stake_amount: The stake amount for a pair before leverage is considered
|
:param stake_amount: The stake amount for a pair before leverage is considered
|
||||||
@ -636,7 +641,7 @@ class Exchange:
|
|||||||
# Dry-run methods
|
# Dry-run methods
|
||||||
|
|
||||||
def create_dry_run_order(self, pair: str, ordertype: str, side: str, amount: float,
|
def create_dry_run_order(self, pair: str, ordertype: str, side: str, amount: float,
|
||||||
rate: float, params: Dict = {}) -> Dict[str, Any]:
|
rate: float, leverage: float, params: Dict = {}) -> Dict[str, Any]:
|
||||||
order_id = f'dry_run_{side}_{datetime.now().timestamp()}'
|
order_id = f'dry_run_{side}_{datetime.now().timestamp()}'
|
||||||
_amount = self.amount_to_precision(pair, amount)
|
_amount = self.amount_to_precision(pair, amount)
|
||||||
dry_order: Dict[str, Any] = {
|
dry_order: Dict[str, Any] = {
|
||||||
@ -653,7 +658,8 @@ class Exchange:
|
|||||||
'timestamp': arrow.utcnow().int_timestamp * 1000,
|
'timestamp': arrow.utcnow().int_timestamp * 1000,
|
||||||
'status': "closed" if ordertype == "market" else "open",
|
'status': "closed" if ordertype == "market" else "open",
|
||||||
'fee': None,
|
'fee': None,
|
||||||
'info': {}
|
'info': {},
|
||||||
|
'leverage': leverage
|
||||||
}
|
}
|
||||||
if dry_order["type"] in ["stop_loss_limit", "stop-loss-limit"]:
|
if dry_order["type"] in ["stop_loss_limit", "stop-loss-limit"]:
|
||||||
dry_order["info"] = {"stopPrice": dry_order["price"]}
|
dry_order["info"] = {"stopPrice": dry_order["price"]}
|
||||||
@ -663,7 +669,7 @@ class Exchange:
|
|||||||
average = self.get_dry_market_fill_price(pair, side, amount, rate)
|
average = self.get_dry_market_fill_price(pair, side, amount, rate)
|
||||||
dry_order.update({
|
dry_order.update({
|
||||||
'average': average,
|
'average': average,
|
||||||
'cost': dry_order['amount'] * average,
|
'cost': (dry_order['amount'] * average) / leverage
|
||||||
})
|
})
|
||||||
dry_order = self.add_dry_order_fee(pair, dry_order)
|
dry_order = self.add_dry_order_fee(pair, dry_order)
|
||||||
|
|
||||||
@ -771,7 +777,7 @@ class Exchange:
|
|||||||
|
|
||||||
# Order handling
|
# Order handling
|
||||||
|
|
||||||
def lev_prep(self, pair: str, leverage: float):
|
def _lev_prep(self, pair: str, leverage: float):
|
||||||
self.set_margin_mode(pair, self.collateral)
|
self.set_margin_mode(pair, self.collateral)
|
||||||
self._set_leverage(leverage, pair)
|
self._set_leverage(leverage, pair)
|
||||||
|
|
||||||
@ -783,14 +789,14 @@ class Exchange:
|
|||||||
return params
|
return params
|
||||||
|
|
||||||
def create_order(self, pair: str, ordertype: str, side: str, amount: float,
|
def create_order(self, pair: str, ordertype: str, side: str, amount: float,
|
||||||
rate: float, time_in_force: str = 'gtc', leverage=1.0) -> Dict:
|
rate: float, leverage: float = 1.0, time_in_force: str = 'gtc') -> Dict:
|
||||||
|
# TODO-lev: remove default for leverage
|
||||||
if self._config['dry_run']:
|
if self._config['dry_run']:
|
||||||
dry_order = self.create_dry_run_order(pair, ordertype, side, amount, rate)
|
dry_order = self.create_dry_run_order(pair, ordertype, side, amount, rate, leverage)
|
||||||
return dry_order
|
return dry_order
|
||||||
|
|
||||||
if self.trading_mode != TradingMode.SPOT:
|
if self.trading_mode != TradingMode.SPOT:
|
||||||
self.lev_prep(pair, leverage)
|
self._lev_prep(pair, leverage)
|
||||||
|
|
||||||
params = self._get_params(time_in_force, ordertype, leverage)
|
params = self._get_params(time_in_force, ordertype, leverage)
|
||||||
|
|
||||||
@ -831,8 +837,8 @@ class Exchange:
|
|||||||
"""
|
"""
|
||||||
raise OperationalException(f"stoploss is not implemented for {self.name}.")
|
raise OperationalException(f"stoploss is not implemented for {self.name}.")
|
||||||
|
|
||||||
def stoploss(self, pair: str, amount: float,
|
def stoploss(self, pair: str, amount: float, stop_price: float,
|
||||||
stop_price: float, order_types: Dict, side: str) -> Dict:
|
order_types: Dict, side: str, leverage: float) -> Dict:
|
||||||
"""
|
"""
|
||||||
creates a stoploss order.
|
creates a stoploss order.
|
||||||
The precise ordertype is determined by the order_types dict or exchange default.
|
The precise ordertype is determined by the order_types dict or exchange default.
|
||||||
@ -1595,15 +1601,13 @@ class Exchange:
|
|||||||
self._async_get_trade_history(pair=pair, since=since,
|
self._async_get_trade_history(pair=pair, since=since,
|
||||||
until=until, from_id=from_id))
|
until=until, from_id=from_id))
|
||||||
|
|
||||||
@retrier
|
|
||||||
def fill_leverage_brackets(self):
|
def fill_leverage_brackets(self):
|
||||||
"""
|
"""
|
||||||
#TODO-lev: Should maybe be renamed, leverage_brackets might not be accurate for kraken
|
#TODO-lev: Should maybe be renamed, leverage_brackets might not be accurate for kraken
|
||||||
Assigns property _leverage_brackets to a dictionary of information about the leverage
|
Assigns property _leverage_brackets to a dictionary of information about the leverage
|
||||||
allowed on each pair
|
allowed on each pair
|
||||||
"""
|
"""
|
||||||
raise OperationalException(
|
return
|
||||||
f"{self.name.capitalize()}.fill_leverage_brackets has not been implemented.")
|
|
||||||
|
|
||||||
def get_max_leverage(self, pair: Optional[str], nominal_value: Optional[float]) -> float:
|
def get_max_leverage(self, pair: Optional[str], nominal_value: Optional[float]) -> float:
|
||||||
"""
|
"""
|
||||||
@ -1624,7 +1628,9 @@ class Exchange:
|
|||||||
Set's the leverage before making a trade, in order to not
|
Set's the leverage before making a trade, in order to not
|
||||||
have the same leverage on every trade
|
have the same leverage on every trade
|
||||||
"""
|
"""
|
||||||
if not self.exchange_has("setLeverage"):
|
# TODO-lev: Make a documentation page that says you can't run 2 bots
|
||||||
|
# TODO-lev: on the same account with leverage
|
||||||
|
if self._config['dry_run'] or not self.exchange_has("setLeverage"):
|
||||||
# Some exchanges only support one collateral type
|
# Some exchanges only support one collateral type
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1644,7 +1650,7 @@ class Exchange:
|
|||||||
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 symbol: base/quote currency pair (e.g. "ADA/USDT")
|
:param symbol: base/quote currency pair (e.g. "ADA/USDT")
|
||||||
'''
|
'''
|
||||||
if 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 collateral type
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ class Ftx(Exchange):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@retrier(retries=0)
|
@retrier(retries=0)
|
||||||
def stoploss(self, pair: str, amount: float,
|
def stoploss(self, pair: str, amount: float, stop_price: float,
|
||||||
stop_price: float, order_types: Dict, side: str) -> Dict:
|
order_types: Dict, side: str, leverage: float) -> Dict:
|
||||||
"""
|
"""
|
||||||
Creates a stoploss order.
|
Creates a stoploss order.
|
||||||
depending on order_types.stoploss configuration, uses 'market' or limit order.
|
depending on order_types.stoploss configuration, uses 'market' or limit order.
|
||||||
@ -69,7 +69,7 @@ class Ftx(Exchange):
|
|||||||
|
|
||||||
if self._config['dry_run']:
|
if self._config['dry_run']:
|
||||||
dry_order = self.create_dry_run_order(
|
dry_order = self.create_dry_run_order(
|
||||||
pair, ordertype, side, amount, stop_price)
|
pair, ordertype, side, amount, stop_price, leverage)
|
||||||
return dry_order
|
return dry_order
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -81,8 +81,14 @@ class Ftx(Exchange):
|
|||||||
params['stopPrice'] = stop_price
|
params['stopPrice'] = stop_price
|
||||||
amount = self.amount_to_precision(pair, amount)
|
amount = self.amount_to_precision(pair, amount)
|
||||||
|
|
||||||
order = self._api.create_order(symbol=pair, type=ordertype, side=side,
|
order = self._api.create_order(
|
||||||
amount=amount, params=params)
|
symbol=pair,
|
||||||
|
type=ordertype,
|
||||||
|
side=side,
|
||||||
|
amount=amount,
|
||||||
|
leverage=leverage,
|
||||||
|
params=params
|
||||||
|
)
|
||||||
self._log_exchange_response('create_stoploss_order', order)
|
self._log_exchange_response('create_stoploss_order', order)
|
||||||
logger.info('stoploss order added for %s. '
|
logger.info('stoploss order added for %s. '
|
||||||
'stop price: %s.', pair, stop_price)
|
'stop price: %s.', pair, stop_price)
|
||||||
|
@ -85,8 +85,8 @@ class Kraken(Exchange):
|
|||||||
))
|
))
|
||||||
|
|
||||||
@retrier(retries=0)
|
@retrier(retries=0)
|
||||||
def stoploss(self, pair: str, amount: float,
|
def stoploss(self, pair: str, amount: float, stop_price: float,
|
||||||
stop_price: float, order_types: Dict, side: str) -> Dict:
|
order_types: Dict, side: str, leverage: float) -> Dict:
|
||||||
"""
|
"""
|
||||||
Creates a stoploss market order.
|
Creates a stoploss market order.
|
||||||
Stoploss market orders is the only stoploss type supported by kraken.
|
Stoploss market orders is the only stoploss type supported by kraken.
|
||||||
@ -108,14 +108,21 @@ class Kraken(Exchange):
|
|||||||
|
|
||||||
if self._config['dry_run']:
|
if self._config['dry_run']:
|
||||||
dry_order = self.create_dry_run_order(
|
dry_order = self.create_dry_run_order(
|
||||||
pair, ordertype, side, amount, stop_price)
|
pair, ordertype, side, amount, stop_price, leverage)
|
||||||
return dry_order
|
return dry_order
|
||||||
|
|
||||||
try:
|
try:
|
||||||
amount = self.amount_to_precision(pair, amount)
|
amount = self.amount_to_precision(pair, amount)
|
||||||
|
|
||||||
order = self._api.create_order(symbol=pair, type=ordertype, side=side,
|
order = self._api.create_order(
|
||||||
amount=amount, price=stop_price, params=params)
|
symbol=pair,
|
||||||
|
type=ordertype,
|
||||||
|
side=side,
|
||||||
|
amount=amount,
|
||||||
|
price=stop_price,
|
||||||
|
leverage=leverage,
|
||||||
|
params=params
|
||||||
|
)
|
||||||
self._log_exchange_response('create_stoploss_order', order)
|
self._log_exchange_response('create_stoploss_order', order)
|
||||||
logger.info('stoploss order added for %s. '
|
logger.info('stoploss order added for %s. '
|
||||||
'stop price: %s.', pair, stop_price)
|
'stop price: %s.', pair, stop_price)
|
||||||
|
@ -737,7 +737,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
amount=trade.amount,
|
amount=trade.amount,
|
||||||
stop_price=stop_price,
|
stop_price=stop_price,
|
||||||
order_types=self.strategy.order_types,
|
order_types=self.strategy.order_types,
|
||||||
side=trade.exit_side
|
side=trade.exit_side,
|
||||||
|
leverage=trade.leverage
|
||||||
)
|
)
|
||||||
|
|
||||||
order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair, 'stoploss')
|
order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair, 'stoploss')
|
||||||
|
@ -48,13 +48,20 @@ def test_stoploss_order_binance(
|
|||||||
amount=1,
|
amount=1,
|
||||||
stop_price=190,
|
stop_price=190,
|
||||||
side=side,
|
side=side,
|
||||||
order_types={'stoploss_on_exchange_limit_ratio': 1.05}
|
order_types={'stoploss_on_exchange_limit_ratio': 1.05},
|
||||||
|
leverage=1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
api_mock.create_order.reset_mock()
|
api_mock.create_order.reset_mock()
|
||||||
order_types = {} if limitratio is None else {'stoploss_on_exchange_limit_ratio': limitratio}
|
order_types = {} if limitratio is None else {'stoploss_on_exchange_limit_ratio': limitratio}
|
||||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220,
|
order = exchange.stoploss(
|
||||||
order_types=order_types, side=side)
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types=order_types,
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert 'info' in order
|
assert 'info' in order
|
||||||
@ -71,17 +78,31 @@ def test_stoploss_order_binance(
|
|||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
||||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0)
|
||||||
|
|
||||||
with pytest.raises(InvalidOrderException):
|
with pytest.raises(InvalidOrderException):
|
||||||
api_mock.create_order = MagicMock(
|
api_mock.create_order = MagicMock(
|
||||||
side_effect=ccxt.InvalidOrder("binance Order would trigger immediately."))
|
side_effect=ccxt.InvalidOrder("binance Order would trigger immediately."))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
||||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "binance",
|
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "binance",
|
||||||
"stoploss", "create_order", retries=1,
|
"stoploss", "create_order", retries=1,
|
||||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
pair='ETH/BTC', amount=1, stop_price=220, order_types={},
|
||||||
|
side=side, leverage=1.0)
|
||||||
|
|
||||||
|
|
||||||
def test_stoploss_order_dry_run_binance(default_conf, mocker):
|
def test_stoploss_order_dry_run_binance(default_conf, mocker):
|
||||||
@ -94,12 +115,25 @@ def test_stoploss_order_dry_run_binance(default_conf, mocker):
|
|||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
|
||||||
|
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, side="sell",
|
order = exchange.stoploss(
|
||||||
order_types={'stoploss_on_exchange_limit_ratio': 1.05})
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=190,
|
||||||
|
side="sell",
|
||||||
|
order_types={'stoploss_on_exchange_limit_ratio': 1.05},
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
api_mock.create_order.reset_mock()
|
api_mock.create_order.reset_mock()
|
||||||
|
|
||||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side="sell")
|
order = exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side="sell",
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert 'info' in order
|
assert 'info' in order
|
||||||
|
@ -403,7 +403,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
|||||||
# With Leverage
|
# With Leverage
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss, 3.0)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss, 3.0)
|
||||||
assert isclose(result, expected_result/3)
|
assert isclose(result, expected_result/3)
|
||||||
# TODO-lev: Min stake for base, kraken and ftx
|
|
||||||
|
|
||||||
# min amount is set
|
# min amount is set
|
||||||
markets["ETH/BTC"]["limits"] = {
|
markets["ETH/BTC"]["limits"] = {
|
||||||
@ -420,7 +419,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
|||||||
# With Leverage
|
# With Leverage
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 5.0)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 5.0)
|
||||||
assert isclose(result, expected_result/5)
|
assert isclose(result, expected_result/5)
|
||||||
# TODO-lev: Min stake for base, kraken and ftx
|
|
||||||
|
|
||||||
# min amount and cost are set (cost is minimal)
|
# min amount and cost are set (cost is minimal)
|
||||||
markets["ETH/BTC"]["limits"] = {
|
markets["ETH/BTC"]["limits"] = {
|
||||||
@ -437,7 +435,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
|||||||
# With Leverage
|
# With Leverage
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 10)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 10)
|
||||||
assert isclose(result, expected_result/10)
|
assert isclose(result, expected_result/10)
|
||||||
# TODO-lev: Min stake for base, kraken and ftx
|
|
||||||
|
|
||||||
# min amount and cost are set (amount is minial)
|
# min amount and cost are set (amount is minial)
|
||||||
markets["ETH/BTC"]["limits"] = {
|
markets["ETH/BTC"]["limits"] = {
|
||||||
@ -454,7 +451,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
|||||||
# With Leverage
|
# With Leverage
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 7.0)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 7.0)
|
||||||
assert isclose(result, expected_result/7.0)
|
assert isclose(result, expected_result/7.0)
|
||||||
# TODO-lev: Min stake for base, kraken and ftx
|
|
||||||
|
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4)
|
||||||
expected_result = max(8, 2 * 2) * 1.5
|
expected_result = max(8, 2 * 2) * 1.5
|
||||||
@ -462,7 +458,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
|||||||
# With Leverage
|
# With Leverage
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4, 8.0)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4, 8.0)
|
||||||
assert isclose(result, expected_result/8.0)
|
assert isclose(result, expected_result/8.0)
|
||||||
# TODO-lev: Min stake for base, kraken and ftx
|
|
||||||
|
|
||||||
# Really big stoploss
|
# Really big stoploss
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1)
|
||||||
@ -471,7 +466,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
|||||||
# With Leverage
|
# With Leverage
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1, 12.0)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1, 12.0)
|
||||||
assert isclose(result, expected_result/12)
|
assert isclose(result, expected_result/12)
|
||||||
# TODO-lev: Min stake for base, kraken and ftx
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
|
def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
|
||||||
@ -493,7 +487,6 @@ def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None:
|
|||||||
assert round(result, 8) == round(expected_result, 8)
|
assert round(result, 8) == round(expected_result, 8)
|
||||||
result = exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss, 3.0)
|
result = exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss, 3.0)
|
||||||
assert round(result, 8) == round(expected_result/3, 8)
|
assert round(result, 8) == round(expected_result/3, 8)
|
||||||
# TODO-lev: Min stake for base, kraken and ftx
|
|
||||||
|
|
||||||
|
|
||||||
def test_set_sandbox(default_conf, mocker):
|
def test_set_sandbox(default_conf, mocker):
|
||||||
@ -1004,7 +997,13 @@ def test_create_dry_run_order(default_conf, mocker, side, exchange_name):
|
|||||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||||
|
|
||||||
order = exchange.create_dry_run_order(
|
order = exchange.create_dry_run_order(
|
||||||
pair='ETH/BTC', ordertype='limit', side=side, amount=1, rate=200)
|
pair='ETH/BTC',
|
||||||
|
ordertype='limit',
|
||||||
|
side=side,
|
||||||
|
amount=1,
|
||||||
|
rate=200,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert f'dry_run_{side}_' in order["id"]
|
assert f'dry_run_{side}_' in order["id"]
|
||||||
assert order["side"] == side
|
assert order["side"] == side
|
||||||
@ -1027,7 +1026,13 @@ def test_create_dry_run_order_limit_fill(default_conf, mocker, side, startprice,
|
|||||||
)
|
)
|
||||||
|
|
||||||
order = exchange.create_dry_run_order(
|
order = exchange.create_dry_run_order(
|
||||||
pair='LTC/USDT', ordertype='limit', side=side, amount=1, rate=startprice)
|
pair='LTC/USDT',
|
||||||
|
ordertype='limit',
|
||||||
|
side=side,
|
||||||
|
amount=1,
|
||||||
|
rate=startprice,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
assert order_book_l2_usd.call_count == 1
|
assert order_book_l2_usd.call_count == 1
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert f'dry_run_{side}_' in order["id"]
|
assert f'dry_run_{side}_' in order["id"]
|
||||||
@ -1073,7 +1078,13 @@ def test_create_dry_run_order_market_fill(default_conf, mocker, side, rate, amou
|
|||||||
)
|
)
|
||||||
|
|
||||||
order = exchange.create_dry_run_order(
|
order = exchange.create_dry_run_order(
|
||||||
pair='LTC/USDT', ordertype='market', side=side, amount=amount, rate=rate)
|
pair='LTC/USDT',
|
||||||
|
ordertype='market',
|
||||||
|
side=side,
|
||||||
|
amount=amount,
|
||||||
|
rate=rate,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert f'dry_run_{side}_' in order["id"]
|
assert f'dry_run_{side}_' in order["id"]
|
||||||
assert order["side"] == side
|
assert order["side"] == side
|
||||||
@ -2664,7 +2675,14 @@ def test_get_fee(default_conf, mocker, exchange_name):
|
|||||||
def test_stoploss_order_unsupported_exchange(default_conf, mocker):
|
def test_stoploss_order_unsupported_exchange(default_conf, mocker):
|
||||||
exchange = get_patched_exchange(mocker, default_conf, id='bittrex')
|
exchange = get_patched_exchange(mocker, default_conf, id='bittrex')
|
||||||
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
||||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side="sell")
|
exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side="sell",
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
||||||
exchange.stoploss_adjust(1, {}, side="sell")
|
exchange.stoploss_adjust(1, {}, side="sell")
|
||||||
@ -3024,7 +3042,7 @@ def test_calculate_backoff(retrycount, max_retries, expected):
|
|||||||
(20.0, 5.0, 4.0),
|
(20.0, 5.0, 4.0),
|
||||||
(100.0, 100.0, 1.0)
|
(100.0, 100.0, 1.0)
|
||||||
])
|
])
|
||||||
def test_apply_leverage_to_stake_amount(
|
def test_divide_stake_amount_by_leverage(
|
||||||
exchange,
|
exchange,
|
||||||
stake_amount,
|
stake_amount,
|
||||||
leverage,
|
leverage,
|
||||||
@ -3033,7 +3051,7 @@ def test_apply_leverage_to_stake_amount(
|
|||||||
default_conf
|
default_conf
|
||||||
):
|
):
|
||||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange)
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange)
|
||||||
assert exchange._apply_leverage_to_stake_amount(stake_amount, leverage) == min_stake_with_lev
|
assert exchange._divide_stake_amount_by_leverage(stake_amount, leverage) == min_stake_with_lev
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("exchange_name,trading_mode", [
|
@pytest.mark.parametrize("exchange_name,trading_mode", [
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
from random import randint
|
from random import randint
|
||||||
from unittest.mock import MagicMock, PropertyMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import ccxt
|
import ccxt
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from freqtrade.enums import TradingMode
|
|
||||||
from freqtrade.exceptions import DependencyException, InvalidOrderException
|
from freqtrade.exceptions import DependencyException, InvalidOrderException
|
||||||
from freqtrade.exchange.common import API_FETCH_ORDER_RETRY_COUNT
|
from freqtrade.exchange.common import API_FETCH_ORDER_RETRY_COUNT
|
||||||
from tests.conftest import get_patched_exchange
|
from tests.conftest import get_patched_exchange
|
||||||
@ -14,8 +13,6 @@ from .test_exchange import ccxt_exceptionhandlers
|
|||||||
|
|
||||||
STOPLOSS_ORDERTYPE = 'stop'
|
STOPLOSS_ORDERTYPE = 'stop'
|
||||||
|
|
||||||
# TODO-lev: All these stoploss tests with shorts
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('order_price,exchangelimitratio,side', [
|
@pytest.mark.parametrize('order_price,exchangelimitratio,side', [
|
||||||
(217.8, 1.05, "sell"),
|
(217.8, 1.05, "sell"),
|
||||||
@ -39,8 +36,14 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
|
|||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
||||||
|
|
||||||
# stoploss_on_exchange_limit_ratio is irrelevant for ftx market orders
|
# stoploss_on_exchange_limit_ratio is irrelevant for ftx market orders
|
||||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, side=side,
|
order = exchange.stoploss(
|
||||||
order_types={'stoploss_on_exchange_limit_ratio': exchangelimitratio})
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=190,
|
||||||
|
side=side,
|
||||||
|
order_types={'stoploss_on_exchange_limit_ratio': exchangelimitratio},
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
assert api_mock.create_order.call_args_list[0][1]['symbol'] == 'ETH/BTC'
|
assert api_mock.create_order.call_args_list[0][1]['symbol'] == 'ETH/BTC'
|
||||||
assert api_mock.create_order.call_args_list[0][1]['type'] == STOPLOSS_ORDERTYPE
|
assert api_mock.create_order.call_args_list[0][1]['type'] == STOPLOSS_ORDERTYPE
|
||||||
@ -54,7 +57,14 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
|
|||||||
|
|
||||||
api_mock.create_order.reset_mock()
|
api_mock.create_order.reset_mock()
|
||||||
|
|
||||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
order = exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert 'info' in order
|
assert 'info' in order
|
||||||
@ -67,8 +77,13 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
|
|||||||
assert api_mock.create_order.call_args_list[0][1]['params']['stopPrice'] == 220
|
assert api_mock.create_order.call_args_list[0][1]['params']['stopPrice'] == 220
|
||||||
|
|
||||||
api_mock.create_order.reset_mock()
|
api_mock.create_order.reset_mock()
|
||||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220,
|
order = exchange.stoploss(
|
||||||
order_types={'stoploss': 'limit'}, side=side)
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={'stoploss': 'limit'}, side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert 'info' in order
|
assert 'info' in order
|
||||||
@ -85,17 +100,32 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
|
|||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
||||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
with pytest.raises(InvalidOrderException):
|
with pytest.raises(InvalidOrderException):
|
||||||
api_mock.create_order = MagicMock(
|
api_mock.create_order = MagicMock(
|
||||||
side_effect=ccxt.InvalidOrder("ftx Order would trigger immediately."))
|
side_effect=ccxt.InvalidOrder("ftx Order would trigger immediately."))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'ftx')
|
||||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "ftx",
|
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "ftx",
|
||||||
"stoploss", "create_order", retries=1,
|
"stoploss", "create_order", retries=1,
|
||||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
pair='ETH/BTC', amount=1, stop_price=220, order_types={},
|
||||||
|
side=side, leverage=1.0)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('side', [("sell"), ("buy")])
|
@pytest.mark.parametrize('side', [("sell"), ("buy")])
|
||||||
@ -109,7 +139,14 @@ def test_stoploss_order_dry_run_ftx(default_conf, mocker, side):
|
|||||||
|
|
||||||
api_mock.create_order.reset_mock()
|
api_mock.create_order.reset_mock()
|
||||||
|
|
||||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
order = exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert 'info' in order
|
assert 'info' in order
|
||||||
@ -230,26 +267,3 @@ def test_fill_leverage_brackets_ftx(default_conf, mocker):
|
|||||||
exchange = get_patched_exchange(mocker, default_conf, id="ftx")
|
exchange = get_patched_exchange(mocker, default_conf, id="ftx")
|
||||||
exchange.fill_leverage_brackets()
|
exchange.fill_leverage_brackets()
|
||||||
assert exchange._leverage_brackets == {}
|
assert exchange._leverage_brackets == {}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("trading_mode", [
|
|
||||||
(TradingMode.MARGIN),
|
|
||||||
(TradingMode.FUTURES)
|
|
||||||
])
|
|
||||||
def test__set_leverage(mocker, default_conf, trading_mode):
|
|
||||||
|
|
||||||
api_mock = MagicMock()
|
|
||||||
api_mock.set_leverage = MagicMock()
|
|
||||||
type(api_mock).has = PropertyMock(return_value={'setLeverage': True})
|
|
||||||
|
|
||||||
ccxt_exceptionhandlers(
|
|
||||||
mocker,
|
|
||||||
default_conf,
|
|
||||||
api_mock,
|
|
||||||
"ftx",
|
|
||||||
"_set_leverage",
|
|
||||||
"set_leverage",
|
|
||||||
pair="XRP/USDT",
|
|
||||||
leverage=5.0,
|
|
||||||
trading_mode=trading_mode
|
|
||||||
)
|
|
||||||
|
@ -195,7 +195,9 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr
|
|||||||
order_types={
|
order_types={
|
||||||
'stoploss': ordertype,
|
'stoploss': ordertype,
|
||||||
'stoploss_on_exchange_limit_ratio': 0.99
|
'stoploss_on_exchange_limit_ratio': 0.99
|
||||||
})
|
},
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert 'info' in order
|
assert 'info' in order
|
||||||
@ -219,17 +221,32 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr
|
|||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken')
|
||||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
with pytest.raises(InvalidOrderException):
|
with pytest.raises(InvalidOrderException):
|
||||||
api_mock.create_order = MagicMock(
|
api_mock.create_order = MagicMock(
|
||||||
side_effect=ccxt.InvalidOrder("kraken Order would trigger immediately."))
|
side_effect=ccxt.InvalidOrder("kraken Order would trigger immediately."))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken')
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken')
|
||||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "kraken",
|
ccxt_exceptionhandlers(mocker, default_conf, api_mock, "kraken",
|
||||||
"stoploss", "create_order", retries=1,
|
"stoploss", "create_order", retries=1,
|
||||||
pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
pair='ETH/BTC', amount=1, stop_price=220, order_types={},
|
||||||
|
side=side, leverage=1.0)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('side', ['buy', 'sell'])
|
@pytest.mark.parametrize('side', ['buy', 'sell'])
|
||||||
@ -243,7 +260,14 @@ def test_stoploss_order_dry_run_kraken(default_conf, mocker, side):
|
|||||||
|
|
||||||
api_mock.create_order.reset_mock()
|
api_mock.create_order.reset_mock()
|
||||||
|
|
||||||
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side=side)
|
order = exchange.stoploss(
|
||||||
|
pair='ETH/BTC',
|
||||||
|
amount=1,
|
||||||
|
stop_price=220,
|
||||||
|
order_types={},
|
||||||
|
side=side,
|
||||||
|
leverage=1.0
|
||||||
|
)
|
||||||
|
|
||||||
assert 'id' in order
|
assert 'id' in order
|
||||||
assert 'info' in order
|
assert 'info' in order
|
||||||
|
@ -1349,7 +1349,8 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee,
|
|||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
order_types=freqtrade.strategy.order_types,
|
order_types=freqtrade.strategy.order_types,
|
||||||
stop_price=0.00002346 * 0.95,
|
stop_price=0.00002346 * 0.95,
|
||||||
side="sell"
|
side="sell",
|
||||||
|
leverage=1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
# price fell below stoploss, so dry-run sells trade.
|
# price fell below stoploss, so dry-run sells trade.
|
||||||
@ -1537,7 +1538,8 @@ def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee,
|
|||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
order_types=freqtrade.strategy.order_types,
|
order_types=freqtrade.strategy.order_types,
|
||||||
stop_price=0.00002346 * 0.96,
|
stop_price=0.00002346 * 0.96,
|
||||||
side="sell"
|
side="sell",
|
||||||
|
leverage=1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
# price fell below stoploss, so dry-run sells trade.
|
# price fell below stoploss, so dry-run sells trade.
|
||||||
@ -1661,7 +1663,8 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
|
|||||||
pair='NEO/BTC',
|
pair='NEO/BTC',
|
||||||
order_types=freqtrade.strategy.order_types,
|
order_types=freqtrade.strategy.order_types,
|
||||||
stop_price=0.00002346 * 0.99,
|
stop_price=0.00002346 * 0.99,
|
||||||
side="sell"
|
side="sell",
|
||||||
|
leverage=1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user