leverage updates on exchange classes

This commit is contained in:
Sam Germain 2021-09-16 23:05:13 -06:00
parent cbaf477bec
commit 57c7926515
11 changed files with 1467 additions and 126 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
""" Binance exchange subclass """
import json
import logging
from pathlib import Path
from typing import Dict, List, Optional, Tuple
import arrow
@ -47,8 +49,8 @@ class Binance(Exchange):
)
@retrier(retries=0)
def stoploss(self, pair: str, amount: float,
stop_price: float, order_types: Dict, side: str) -> Dict:
def stoploss(self, pair: str, amount: float, stop_price: float,
order_types: Dict, side: str, leverage: float) -> Dict:
"""
creates a stoploss limit order.
this stoploss-limit is binance-specific.
@ -76,7 +78,7 @@ class Binance(Exchange):
if self._config['dry_run']:
dry_order = self.create_dry_run_order(
pair, ordertype, side, amount, stop_price)
pair, ordertype, side, amount, stop_price, leverage)
return dry_order
try:
@ -87,8 +89,15 @@ class Binance(Exchange):
rate = self.price_to_precision(pair, rate)
order = self._api.create_order(symbol=pair, type=ordertype, side=side,
amount=amount, price=rate, params=params)
order = self._api.create_order(
symbol=pair,
type=ordertype,
side=side,
amount=amount,
price=rate,
params=params,
leverage=leverage
)
logger.info('stoploss limit order added for %s. '
'stop price: %s. limit: %s', pair, stop_price, rate)
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
allowed on each pair
"""
try:
leverage_brackets = self._api.load_leverage_brackets()
for pair, brackets in leverage_brackets.items():
self._leverage_brackets[pair] = [
[
min_amount,
float(margin_req)
] for [
min_amount,
margin_req
] in brackets
]
if self.trading_mode == TradingMode.FUTURES:
try:
if self._config['dry_run']:
leverage_brackets_path = Path('data') / 'leverage_brackets.json'
with open(leverage_brackets_path) as json_file:
leverage_brackets = json.load(json_file)
else:
leverage_brackets = self._api.load_leverage_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
for pair, brackets in leverage_brackets.items():
self._leverage_brackets[pair] = [
[
min_amount,
float(margin_req)
] for [
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:
"""
@ -153,10 +169,6 @@ class Binance(Exchange):
max_lev = 1/margin_req
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
def _set_leverage(
self,
@ -170,9 +182,11 @@ class Binance(Exchange):
"""
trading_mode = trading_mode or self.trading_mode
if self._config['dry_run'] or trading_mode != TradingMode.FUTURES:
return
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:
raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e:

View File

@ -258,6 +258,13 @@ class Exchange:
"""exchange ccxt 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:
""" Log exchange responses """
if self.log_responses:
@ -617,15 +624,13 @@ class Exchange:
# The value returned should satisfy both limits: for amount (base currency) and
# for cost (quote, stake currency), so max() is used here.
# 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,
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
stake amount when 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
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()}'
_amount = self.amount_to_precision(pair, amount)
dry_order: Dict[str, Any] = {
@ -653,7 +658,8 @@ class Exchange:
'timestamp': arrow.utcnow().int_timestamp * 1000,
'status': "closed" if ordertype == "market" else "open",
'fee': None,
'info': {}
'info': {},
'leverage': leverage
}
if dry_order["type"] in ["stop_loss_limit", "stop-loss-limit"]:
dry_order["info"] = {"stopPrice": dry_order["price"]}
@ -663,7 +669,7 @@ class Exchange:
average = self.get_dry_market_fill_price(pair, side, amount, rate)
dry_order.update({
'average': average,
'cost': dry_order['amount'] * average,
'cost': (dry_order['amount'] * average) / leverage
})
dry_order = self.add_dry_order_fee(pair, dry_order)
@ -771,7 +777,7 @@ class Exchange:
# 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_leverage(leverage, pair)
@ -783,14 +789,14 @@ class Exchange:
return params
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']:
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
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)
@ -831,8 +837,8 @@ class Exchange:
"""
raise OperationalException(f"stoploss is not implemented for {self.name}.")
def stoploss(self, pair: str, amount: float,
stop_price: float, order_types: Dict, side: str) -> Dict:
def stoploss(self, pair: str, amount: float, stop_price: float,
order_types: Dict, side: str, leverage: float) -> Dict:
"""
creates a stoploss order.
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,
until=until, from_id=from_id))
@retrier
def fill_leverage_brackets(self):
"""
#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
allowed on each pair
"""
raise OperationalException(
f"{self.name.capitalize()}.fill_leverage_brackets has not been implemented.")
return
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
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
return
@ -1644,7 +1650,7 @@ class Exchange:
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")
'''
if not self.exchange_has("setMarginMode"):
if self._config['dry_run'] or not self.exchange_has("setMarginMode"):
# Some exchanges only support one collateral type
return

View File

@ -49,8 +49,8 @@ class Ftx(Exchange):
)
@retrier(retries=0)
def stoploss(self, pair: str, amount: float,
stop_price: float, order_types: Dict, side: str) -> Dict:
def stoploss(self, pair: str, amount: float, stop_price: float,
order_types: Dict, side: str, leverage: float) -> Dict:
"""
Creates a stoploss order.
depending on order_types.stoploss configuration, uses 'market' or limit order.
@ -69,7 +69,7 @@ class Ftx(Exchange):
if self._config['dry_run']:
dry_order = self.create_dry_run_order(
pair, ordertype, side, amount, stop_price)
pair, ordertype, side, amount, stop_price, leverage)
return dry_order
try:
@ -81,8 +81,14 @@ class Ftx(Exchange):
params['stopPrice'] = stop_price
amount = self.amount_to_precision(pair, amount)
order = self._api.create_order(symbol=pair, type=ordertype, side=side,
amount=amount, params=params)
order = self._api.create_order(
symbol=pair,
type=ordertype,
side=side,
amount=amount,
leverage=leverage,
params=params
)
self._log_exchange_response('create_stoploss_order', order)
logger.info('stoploss order added for %s. '
'stop price: %s.', pair, stop_price)

View File

@ -85,8 +85,8 @@ class Kraken(Exchange):
))
@retrier(retries=0)
def stoploss(self, pair: str, amount: float,
stop_price: float, order_types: Dict, side: str) -> Dict:
def stoploss(self, pair: str, amount: float, stop_price: float,
order_types: Dict, side: str, leverage: float) -> Dict:
"""
Creates a stoploss market order.
Stoploss market orders is the only stoploss type supported by kraken.
@ -108,14 +108,21 @@ class Kraken(Exchange):
if self._config['dry_run']:
dry_order = self.create_dry_run_order(
pair, ordertype, side, amount, stop_price)
pair, ordertype, side, amount, stop_price, leverage)
return dry_order
try:
amount = self.amount_to_precision(pair, amount)
order = self._api.create_order(symbol=pair, type=ordertype, side=side,
amount=amount, price=stop_price, params=params)
order = self._api.create_order(
symbol=pair,
type=ordertype,
side=side,
amount=amount,
price=stop_price,
leverage=leverage,
params=params
)
self._log_exchange_response('create_stoploss_order', order)
logger.info('stoploss order added for %s. '
'stop price: %s.', pair, stop_price)

View File

@ -737,7 +737,8 @@ class FreqtradeBot(LoggingMixin):
amount=trade.amount,
stop_price=stop_price,
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')

View File

@ -48,13 +48,20 @@ def test_stoploss_order_binance(
amount=1,
stop_price=190,
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()
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_types=order_types, side=side)
order = exchange.stoploss(
pair='ETH/BTC',
amount=1,
stop_price=220,
order_types=order_types,
side=side,
leverage=1.0
)
assert 'id' in order
assert 'info' in order
@ -71,17 +78,31 @@ def test_stoploss_order_binance(
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
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):
api_mock.create_order = MagicMock(
side_effect=ccxt.InvalidOrder("binance Order would trigger immediately."))
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",
"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):
@ -94,12 +115,25 @@ def test_stoploss_order_dry_run_binance(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'binance')
with pytest.raises(OperationalException):
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, side="sell",
order_types={'stoploss_on_exchange_limit_ratio': 1.05})
order = exchange.stoploss(
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()
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 'info' in order

View File

@ -403,7 +403,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
# With Leverage
result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss, 3.0)
assert isclose(result, expected_result/3)
# TODO-lev: Min stake for base, kraken and ftx
# min amount is set
markets["ETH/BTC"]["limits"] = {
@ -420,7 +419,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
# With Leverage
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 5.0)
assert isclose(result, expected_result/5)
# TODO-lev: Min stake for base, kraken and ftx
# min amount and cost are set (cost is minimal)
markets["ETH/BTC"]["limits"] = {
@ -437,7 +435,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
# With Leverage
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 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)
markets["ETH/BTC"]["limits"] = {
@ -454,7 +451,6 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
# With Leverage
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss, 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)
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
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -0.4, 8.0)
assert isclose(result, expected_result/8.0)
# TODO-lev: Min stake for base, kraken and ftx
# Really big stoploss
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
result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, -1, 12.0)
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:
@ -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)
result = exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss, 3.0)
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):
@ -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)
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 f'dry_run_{side}_' in order["id"]
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(
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 'id' in order
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(
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 f'dry_run_{side}_' in order["id"]
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):
exchange = get_patched_exchange(mocker, default_conf, id='bittrex')
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 .*"):
exchange.stoploss_adjust(1, {}, side="sell")
@ -3024,7 +3042,7 @@ def test_calculate_backoff(retrycount, max_retries, expected):
(20.0, 5.0, 4.0),
(100.0, 100.0, 1.0)
])
def test_apply_leverage_to_stake_amount(
def test_divide_stake_amount_by_leverage(
exchange,
stake_amount,
leverage,
@ -3033,7 +3051,7 @@ def test_apply_leverage_to_stake_amount(
default_conf
):
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", [

View File

@ -1,10 +1,9 @@
from random import randint
from unittest.mock import MagicMock, PropertyMock
from unittest.mock import MagicMock
import ccxt
import pytest
from freqtrade.enums import TradingMode
from freqtrade.exceptions import DependencyException, InvalidOrderException
from freqtrade.exchange.common import API_FETCH_ORDER_RETRY_COUNT
from tests.conftest import get_patched_exchange
@ -14,8 +13,6 @@ from .test_exchange import ccxt_exceptionhandlers
STOPLOSS_ORDERTYPE = 'stop'
# TODO-lev: All these stoploss tests with shorts
@pytest.mark.parametrize('order_price,exchangelimitratio,side', [
(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')
# 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_types={'stoploss_on_exchange_limit_ratio': exchangelimitratio})
order = exchange.stoploss(
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]['type'] == STOPLOSS_ORDERTYPE
@ -54,7 +57,14 @@ def test_stoploss_order_ftx(default_conf, mocker, order_price, exchangelimitrati
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 '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
api_mock.create_order.reset_mock()
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220,
order_types={'stoploss': 'limit'}, side=side)
order = exchange.stoploss(
pair='ETH/BTC',
amount=1,
stop_price=220,
order_types={'stoploss': 'limit'}, side=side,
leverage=1.0
)
assert 'id' 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):
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
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):
api_mock.create_order = MagicMock(
side_effect=ccxt.InvalidOrder("ftx Order would trigger immediately."))
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",
"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")])
@ -109,7 +139,14 @@ def test_stoploss_order_dry_run_ftx(default_conf, mocker, side):
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 '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.fill_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
)

View File

@ -195,7 +195,9 @@ def test_stoploss_order_kraken(default_conf, mocker, ordertype, side, adjustedpr
order_types={
'stoploss': ordertype,
'stoploss_on_exchange_limit_ratio': 0.99
})
},
leverage=1.0
)
assert 'id' 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):
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
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):
api_mock.create_order = MagicMock(
side_effect=ccxt.InvalidOrder("kraken Order would trigger immediately."))
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",
"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'])
@ -243,7 +260,14 @@ def test_stoploss_order_dry_run_kraken(default_conf, mocker, side):
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 'info' in order

View File

@ -1349,7 +1349,8 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee,
pair='ETH/BTC',
order_types=freqtrade.strategy.order_types,
stop_price=0.00002346 * 0.95,
side="sell"
side="sell",
leverage=1.0
)
# 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',
order_types=freqtrade.strategy.order_types,
stop_price=0.00002346 * 0.96,
side="sell"
side="sell",
leverage=1.0
)
# 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',
order_types=freqtrade.strategy.order_types,
stop_price=0.00002346 * 0.99,
side="sell"
side="sell",
leverage=1.0
)