Merge branch 'sam_5889' into todo-rpc

This commit is contained in:
aezo.teo 2021-11-14 13:26:32 +08:00
commit 8f66d8f942
14 changed files with 73 additions and 61 deletions

View File

@ -33,9 +33,10 @@ class Binance(Exchange):
_supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [
# TradingMode.SPOT always supported and not required in this list # TradingMode.SPOT always supported and not required in this list
# (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported # TODO-lev: Uncomment once supported
# (TradingMode.FUTURES, Collateral.CROSS), # TODO-lev: Uncomment once supported # (TradingMode.MARGIN, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.ISOLATED) # TODO-lev: Uncomment once supported # (TradingMode.FUTURES, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.ISOLATED)
] ]
@property @property

View File

@ -27,6 +27,7 @@ class Bybit(Exchange):
_supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [
# TradingMode.SPOT always supported and not required in this list # TradingMode.SPOT always supported and not required in this list
# (TradingMode.FUTURES, Collateral.CROSS), # TODO-lev: Uncomment once supported # TODO-lev: Uncomment once supported
# (TradingMode.FUTURES, Collateral.ISOLATED) # TODO-lev: Uncomment once supported # (TradingMode.FUTURES, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.ISOLATED)
] ]

View File

@ -25,8 +25,9 @@ class Ftx(Exchange):
_supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [
# TradingMode.SPOT always supported and not required in this list # TradingMode.SPOT always supported and not required in this list
# (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported # TODO-lev: Uncomment once supported
# (TradingMode.FUTURES, Collateral.CROSS) # TODO-lev: Uncomment once supported # (TradingMode.MARGIN, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.CROSS)
] ]
def market_is_tradable(self, market: Dict[str, Any]) -> bool: def market_is_tradable(self, market: Dict[str, Any]) -> bool:

View File

@ -30,9 +30,10 @@ class Gateio(Exchange):
_supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [
# TradingMode.SPOT always supported and not required in this list # TradingMode.SPOT always supported and not required in this list
# (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported # TODO-lev: Uncomment once supported
# (TradingMode.FUTURES, Collateral.CROSS), # TODO-lev: Uncomment once supported # (TradingMode.MARGIN, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.ISOLATED) # TODO-lev: Uncomment once supported # (TradingMode.FUTURES, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.ISOLATED)
] ]
@property @property

View File

@ -27,8 +27,9 @@ class Kraken(Exchange):
_supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [
# TradingMode.SPOT always supported and not required in this list # TradingMode.SPOT always supported and not required in this list
# (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported # TODO-lev: Uncomment once supported
# (TradingMode.FUTURES, Collateral.CROSS) # TODO-lev: No CCXT support # (TradingMode.MARGIN, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.CROSS)
] ]
def market_is_tradable(self, market: Dict[str, Any]) -> bool: def market_is_tradable(self, market: Dict[str, Any]) -> bool:

View File

@ -21,9 +21,10 @@ class Okex(Exchange):
_supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [
# TradingMode.SPOT always supported and not required in this list # TradingMode.SPOT always supported and not required in this list
# (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported # TODO-lev: Uncomment once supported
# (TradingMode.FUTURES, Collateral.CROSS), # TODO-lev: Uncomment once supported # (TradingMode.MARGIN, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.ISOLATED) # TODO-lev: Uncomment once supported # (TradingMode.FUTURES, Collateral.CROSS),
# (TradingMode.FUTURES, Collateral.ISOLATED)
] ]
@property @property

View File

@ -922,8 +922,7 @@ class FreqtradeBot(LoggingMixin):
Check if trade is fulfilled in which case the stoploss Check if trade is fulfilled in which case the stoploss
on exchange should be added immediately if stoploss on exchange on exchange should be added immediately if stoploss on exchange
is enabled. is enabled.
# TODO-lev: liquidation price will always be on exchange, even though # TODO-lev: liquidation price always on exchange, even without stoploss_on_exchange
# TODO-lev: stoploss_on_exchange might not be enabled
""" """
logger.debug('Handling stoploss on exchange %s ...', trade) logger.debug('Handling stoploss on exchange %s ...', trade)
@ -1517,7 +1516,7 @@ class FreqtradeBot(LoggingMixin):
self.wallets.update() self.wallets.update()
if fee_abs != 0 and self.wallets.get_free(trade_base_currency) >= amount: if fee_abs != 0 and self.wallets.get_free(trade_base_currency) >= amount:
# Eat into dust if we own more than base currency # Eat into dust if we own more than base currency
# TODO-lev: won't be in base currency for shorts # TODO-lev: settle currency for futures
logger.info(f"Fee amount for {trade} was in base currency - " logger.info(f"Fee amount for {trade} was in base currency - "
f"Eating Fee {fee_abs} into dust.") f"Eating Fee {fee_abs} into dust.")
elif fee_abs != 0: elif fee_abs != 0:

View File

@ -916,8 +916,8 @@ class Trade(_DECL_BASE, LocalTrade):
max_rate = Column(Float, nullable=True, default=0.0) max_rate = Column(Float, nullable=True, default=0.0)
# Lowest price reached # Lowest price reached
min_rate = Column(Float, nullable=True) min_rate = Column(Float, nullable=True)
sell_reason = Column(String(100), nullable=True) # TODO-lev: Change to close_reason sell_reason = Column(String(100), nullable=True)
sell_order_status = Column(String(100), nullable=True) # TODO-lev: Change to close_order_status sell_order_status = Column(String(100), nullable=True)
strategy = Column(String(100), nullable=True) strategy = Column(String(100), nullable=True)
buy_tag = Column(String(100), nullable=True) buy_tag = Column(String(100), nullable=True)
timeframe = Column(Integer, nullable=True) timeframe = Column(Integer, nullable=True)

View File

@ -488,7 +488,7 @@ def leverage_trade(fee):
open_order_id='dry_run_leverage_buy_12368', open_order_id='dry_run_leverage_buy_12368',
strategy='DefaultStrategy', strategy='DefaultStrategy',
timeframe=5, timeframe=5,
sell_reason='sell_signal', # TODO-lev: Update to exit/close reason sell_reason='sell_signal',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=300), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=300),
close_date=datetime.now(tz=timezone.utc), close_date=datetime.now(tz=timezone.utc),
interest_rate=0.0005 interest_rate=0.0005

View File

@ -586,10 +586,10 @@ def test_api_trades(botclient, mocker, fee, markets, is_short):
assert rc.json()['total_trades'] == 2 assert rc.json()['total_trades'] == 2
# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) @pytest.mark.parametrize('is_short', [True, False])
def test_api_trade_single(botclient, mocker, fee, ticker, markets): def test_api_trade_single(botclient, mocker, fee, ticker, markets, is_short):
ftbot, client = botclient ftbot, client = botclient
patch_get_signal(ftbot) patch_get_signal(ftbot, enter_long=not is_short, enter_short=is_short)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
markets=PropertyMock(return_value=markets), markets=PropertyMock(return_value=markets),
@ -599,7 +599,7 @@ def test_api_trade_single(botclient, mocker, fee, ticker, markets):
assert_response(rc, 404) assert_response(rc, 404)
assert rc.json()['detail'] == 'Trade not found.' assert rc.json()['detail'] == 'Trade not found.'
create_mock_trades(fee, False) create_mock_trades(fee, is_short=is_short)
Trade.query.session.flush() Trade.query.session.flush()
rc = client_get(client, f"{BASE_URI}/trade/3") rc = client_get(client, f"{BASE_URI}/trade/3")
@ -607,10 +607,10 @@ def test_api_trade_single(botclient, mocker, fee, ticker, markets):
assert rc.json()['trade_id'] == 3 assert rc.json()['trade_id'] == 3
# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) @pytest.mark.parametrize('is_short', [True, False])
def test_api_delete_trade(botclient, mocker, fee, markets): def test_api_delete_trade(botclient, mocker, fee, markets, is_short):
ftbot, client = botclient ftbot, client = botclient
patch_get_signal(ftbot) patch_get_signal(ftbot, enter_long=not is_short, enter_short=is_short)
stoploss_mock = MagicMock() stoploss_mock = MagicMock()
cancel_mock = MagicMock() cancel_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
@ -749,10 +749,10 @@ def test_api_profit(botclient, mocker, ticker, fee, markets):
} }
# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) @pytest.mark.parametrize('is_short', [True, False])
def test_api_stats(botclient, mocker, ticker, fee, markets,): def test_api_stats(botclient, mocker, ticker, fee, markets, is_short):
ftbot, client = botclient ftbot, client = botclient
patch_get_signal(ftbot) patch_get_signal(ftbot, enter_long=not is_short, enter_short=is_short)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_balances=MagicMock(return_value=ticker), get_balances=MagicMock(return_value=ticker),
@ -766,7 +766,7 @@ def test_api_stats(botclient, mocker, ticker, fee, markets,):
assert 'durations' in rc.json() assert 'durations' in rc.json()
assert 'sell_reasons' in rc.json() assert 'sell_reasons' in rc.json()
create_mock_trades(fee, False) create_mock_trades(fee, is_short=is_short)
rc = client_get(client, f"{BASE_URI}/stats") rc = client_get(client, f"{BASE_URI}/stats")
assert_response(rc, 200) assert_response(rc, 200)

View File

@ -1294,8 +1294,8 @@ def test_telegram_trades(mocker, update, default_conf, fee):
msg_mock.call_args_list[0][0][0])) msg_mock.call_args_list[0][0][0]))
# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) @pytest.mark.parametrize('is_short', [True, False])
def test_telegram_delete_trade(mocker, update, default_conf, fee): def test_telegram_delete_trade(mocker, update, default_conf, fee, is_short):
telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf)
context = MagicMock() context = MagicMock()
@ -1305,7 +1305,7 @@ def test_telegram_delete_trade(mocker, update, default_conf, fee):
assert "Trade-id not set." in msg_mock.call_args_list[0][0][0] assert "Trade-id not set." in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock() msg_mock.reset_mock()
create_mock_trades(fee, False) create_mock_trades(fee, is_short)
context = MagicMock() context = MagicMock()
context.args = [1] context.args = [1]

View File

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import pytest
from pandas import DataFrame from pandas import DataFrame
from freqtrade.persistence.models import Trade from freqtrade.persistence.models import Trade
@ -16,7 +17,11 @@ def test_strategy_test_v2_structure():
assert hasattr(StrategyTestV3, 'populate_sell_trend') assert hasattr(StrategyTestV3, 'populate_sell_trend')
def test_strategy_test_v2(result, fee): @pytest.mark.parametrize('is_short,side', [
(True, 'short'),
(False, 'long'),
])
def test_strategy_test_v2(result, fee, is_short, side):
strategy = StrategyTestV3({}) strategy = StrategyTestV3({})
metadata = {'pair': 'ETH/BTC'} metadata = {'pair': 'ETH/BTC'}
@ -32,16 +37,18 @@ def test_strategy_test_v2(result, fee):
open_rate=19_000, open_rate=19_000,
amount=0.1, amount=0.1,
pair='ETH/BTC', pair='ETH/BTC',
fee_open=fee.return_value fee_open=fee.return_value,
is_short=is_short
) )
assert strategy.confirm_trade_entry(pair='ETH/BTC', order_type='limit', amount=0.1, assert strategy.confirm_trade_entry(pair='ETH/BTC', order_type='limit', amount=0.1,
rate=20000, time_in_force='gtc', rate=20000, time_in_force='gtc',
current_time=datetime.utcnow(), side='long') is True current_time=datetime.utcnow(),
side=side) is True
assert strategy.confirm_trade_exit(pair='ETH/BTC', trade=trade, order_type='limit', amount=0.1, assert strategy.confirm_trade_exit(pair='ETH/BTC', trade=trade, order_type='limit', amount=0.1,
rate=20000, time_in_force='gtc', sell_reason='roi', rate=20000, time_in_force='gtc', sell_reason='roi',
current_time=datetime.utcnow()) is True current_time=datetime.utcnow(),
side=side) is True
# TODO-lev: Test for shorts?
assert strategy.custom_stoploss(pair='ETH/BTC', trade=trade, current_time=datetime.now(), assert strategy.custom_stoploss(pair='ETH/BTC', trade=trade, current_time=datetime.now(),
current_rate=20_000, current_profit=0.05) == strategy.stoploss current_rate=20_000, current_profit=0.05) == strategy.stoploss

View File

@ -1907,12 +1907,12 @@ def test_get_total_closed_profit(fee, use_db):
@pytest.mark.usefixtures("init_persistence") @pytest.mark.usefixtures("init_persistence")
# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) @pytest.mark.parametrize('is_short', [True, False])
@pytest.mark.parametrize('use_db', [True, False]) @pytest.mark.parametrize('use_db', [True, False])
def test_get_trades_proxy(fee, use_db): def test_get_trades_proxy(fee, use_db, is_short):
Trade.use_db = use_db Trade.use_db = use_db
Trade.reset_trades() Trade.reset_trades()
create_mock_trades(fee, False, use_db) create_mock_trades(fee, is_short, use_db)
trades = Trade.get_trades_proxy() trades = Trade.get_trades_proxy()
assert len(trades) == 6 assert len(trades) == 6
@ -2042,48 +2042,48 @@ def test_update_order_from_ccxt(caplog):
@pytest.mark.usefixtures("init_persistence") @pytest.mark.usefixtures("init_persistence")
# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) @pytest.mark.parametrize('is_short', [True, False])
def test_select_order(fee): def test_select_order(fee, is_short):
create_mock_trades(fee, False) create_mock_trades(fee, is_short)
trades = Trade.get_trades().all() trades = Trade.get_trades().all()
# Open buy order, no sell order # Open buy order, no sell order
order = trades[0].select_order('buy', True) order = trades[0].select_order(trades[0].enter_side, True)
assert order is None assert order is None
order = trades[0].select_order('buy', False) order = trades[0].select_order(trades[0].enter_side, False)
assert order is not None assert order is not None
order = trades[0].select_order('sell', None) order = trades[0].select_order(trades[0].exit_side, None)
assert order is None assert order is None
# closed buy order, and open sell order # closed buy order, and open sell order
order = trades[1].select_order('buy', True) order = trades[1].select_order(trades[1].enter_side, True)
assert order is None assert order is None
order = trades[1].select_order('buy', False) order = trades[1].select_order(trades[1].enter_side, False)
assert order is not None assert order is not None
order = trades[1].select_order('buy', None) order = trades[1].select_order(trades[1].enter_side, None)
assert order is not None assert order is not None
order = trades[1].select_order('sell', True) order = trades[1].select_order(trades[1].exit_side, True)
assert order is None assert order is None
order = trades[1].select_order('sell', False) order = trades[1].select_order(trades[1].exit_side, False)
assert order is not None assert order is not None
# Has open buy order # Has open buy order
order = trades[3].select_order('buy', True) order = trades[3].select_order(trades[3].enter_side, True)
assert order is not None assert order is not None
order = trades[3].select_order('buy', False) order = trades[3].select_order(trades[3].enter_side, False)
assert order is None assert order is None
# Open sell order # Open sell order
order = trades[4].select_order('buy', True) order = trades[4].select_order(trades[4].enter_side, True)
assert order is None assert order is None
order = trades[4].select_order('buy', False) order = trades[4].select_order(trades[4].enter_side, False)
assert order is not None assert order is not None
order = trades[4].select_order('sell', True) order = trades[4].select_order(trades[4].exit_side, True)
assert order is not None assert order is not None
assert order.ft_order_side == 'stoploss' assert order.ft_order_side == 'stoploss'
order = trades[4].select_order('sell', False) order = trades[4].select_order(trades[4].exit_side, False)
assert order is None assert order is None