Merge pull request #760 from arudov/feature-unlimited-stake_amount
Feature unlimited stake amount
This commit is contained in:
commit
107f3ed35b
@ -16,7 +16,7 @@ The table below will list all configuration parameters.
|
||||
|----------|---------|----------|-------------|
|
||||
| `max_open_trades` | 3 | Yes | Number of trades open your bot will have.
|
||||
| `stake_currency` | BTC | Yes | Crypto-currency used for trading.
|
||||
| `stake_amount` | 0.05 | Yes | Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged.
|
||||
| `stake_amount` | 0.05 | Yes | Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged. Set it to 'unlimited' to allow the bot to use all avaliable balance.
|
||||
| `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | No | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes
|
||||
| `fiat_display_currency` | USD | Yes | Fiat currency used to show your profits. More information below.
|
||||
| `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode.
|
||||
@ -44,6 +44,13 @@ The table below will list all configuration parameters.
|
||||
The definition of each config parameters is in
|
||||
[misc.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/misc.py#L205).
|
||||
|
||||
### Understand stake_amount
|
||||
`stake_amount` is an amount of crypto-currency your bot will use for each trade.
|
||||
The minimal value is 0.0005. If there is not enough crypto-currency in
|
||||
the account an exception is generated.
|
||||
To allow the bot to trade all the avaliable `stake_currency` in your account set `stake_amount` = `unlimited`.
|
||||
In this case a trade amount is calclulated as `currency_balanse / (max_open_trades - current_open_trades)`.
|
||||
|
||||
### Understand minimal_roi
|
||||
`minimal_roi` is a JSON object where the key is a duration
|
||||
in minutes and the value is the minimum ROI in percent.
|
||||
|
@ -98,6 +98,13 @@ class Analyze(object):
|
||||
"""
|
||||
return self.strategy.ticker_interval
|
||||
|
||||
def get_stoploss(self) -> float:
|
||||
"""
|
||||
Return stoploss to use
|
||||
:return: Strategy stoploss value to use
|
||||
"""
|
||||
return self.strategy.stoploss
|
||||
|
||||
def analyze_ticker(self, ticker_history: List[Dict]) -> DataFrame:
|
||||
"""
|
||||
Parses the given ticker history and returns a populated DataFrame
|
||||
|
@ -262,17 +262,15 @@ class Arguments(object):
|
||||
stop: int = 0
|
||||
if stype[0]:
|
||||
starts = rvals[index]
|
||||
if stype[0] == 'date':
|
||||
start = int(starts) if len(starts) == 10 \
|
||||
else arrow.get(starts, 'YYYYMMDD').timestamp
|
||||
if stype[0] == 'date' and len(starts) == 8:
|
||||
start = arrow.get(starts, 'YYYYMMDD').timestamp
|
||||
else:
|
||||
start = int(starts)
|
||||
index += 1
|
||||
if stype[1]:
|
||||
stops = rvals[index]
|
||||
if stype[1] == 'date':
|
||||
stop = int(stops) if len(stops) == 10 \
|
||||
else arrow.get(stops, 'YYYYMMDD').timestamp
|
||||
if stype[1] == 'date' and len(stops) == 8:
|
||||
stop = arrow.get(stops, 'YYYYMMDD').timestamp
|
||||
else:
|
||||
stop = int(stops)
|
||||
return TimeRange(stype[0], stype[1], start, stop)
|
||||
|
@ -11,6 +11,8 @@ RETRY_TIMEOUT = 30 # sec
|
||||
DEFAULT_STRATEGY = 'DefaultStrategy'
|
||||
DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite'
|
||||
DEFAULT_DB_DRYRUN_URL = 'sqlite://'
|
||||
UNLIMITED_STAKE_AMOUNT = 'unlimited'
|
||||
|
||||
|
||||
TICKER_INTERVAL_MINUTES = {
|
||||
'1m': 1,
|
||||
@ -44,7 +46,11 @@ CONF_SCHEMA = {
|
||||
'max_open_trades': {'type': 'integer', 'minimum': 0},
|
||||
'ticker_interval': {'type': 'string', 'enum': list(TICKER_INTERVAL_MINUTES.keys())},
|
||||
'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT', 'EUR', 'USD']},
|
||||
'stake_amount': {'type': 'number', 'minimum': 0.0005},
|
||||
'stake_amount': {
|
||||
"type": ["number", "string"],
|
||||
"minimum": 0.0005,
|
||||
"pattern": UNLIMITED_STAKE_AMOUNT
|
||||
},
|
||||
'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT},
|
||||
'dry_run': {'type': 'boolean'},
|
||||
'minimal_roi': {
|
||||
|
@ -244,14 +244,66 @@ class FreqtradeBot(object):
|
||||
balance = self.config['bid_strategy']['ask_last_balance']
|
||||
return ticker['ask'] + balance * (ticker['last'] - ticker['ask'])
|
||||
|
||||
def _get_trade_stake_amount(self) -> Optional[float]:
|
||||
stake_amount = self.config['stake_amount']
|
||||
avaliable_amount = self.exchange.get_balance(self.config['stake_currency'])
|
||||
|
||||
if stake_amount == constants.UNLIMITED_STAKE_AMOUNT:
|
||||
open_trades = len(Trade.query.filter(Trade.is_open.is_(True)).all())
|
||||
if open_trades >= self.config['max_open_trades']:
|
||||
logger.warning('Can\'t open a new trade: max number of trades is reached')
|
||||
return None
|
||||
return avaliable_amount / (self.config['max_open_trades'] - open_trades)
|
||||
|
||||
# Check if stake_amount is fulfilled
|
||||
if avaliable_amount < stake_amount:
|
||||
raise DependencyException(
|
||||
'Available balance(%f %s) is lower than stake amount(%f %s)' % (
|
||||
avaliable_amount, self.config['stake_currency'],
|
||||
stake_amount, self.config['stake_currency'])
|
||||
)
|
||||
|
||||
return stake_amount
|
||||
|
||||
def _get_min_pair_stake_amount(self, pair: str, price: float) -> Optional[float]:
|
||||
markets = self.exchange.get_markets()
|
||||
markets = [m for m in markets if m['symbol'] == pair]
|
||||
if not markets:
|
||||
raise ValueError(f'Can\'t get market information for symbol {pair}')
|
||||
|
||||
market = markets[0]
|
||||
|
||||
if 'limits' not in market:
|
||||
return None
|
||||
|
||||
min_stake_amounts = []
|
||||
if 'cost' in market['limits'] and 'min' in market['limits']['cost']:
|
||||
min_stake_amounts.append(market['limits']['cost']['min'])
|
||||
|
||||
if 'amount' in market['limits'] and 'min' in market['limits']['amount']:
|
||||
min_stake_amounts.append(market['limits']['amount']['min'] * price)
|
||||
|
||||
if not min_stake_amounts:
|
||||
return None
|
||||
|
||||
amount_reserve_percent = 1 - 0.05 # reserve 5% + stoploss
|
||||
if self.analyze.get_stoploss() is not None:
|
||||
amount_reserve_percent += self.analyze.get_stoploss()
|
||||
# it should not be more than 50%
|
||||
amount_reserve_percent = max(amount_reserve_percent, 0.5)
|
||||
return min(min_stake_amounts)/amount_reserve_percent
|
||||
|
||||
def create_trade(self) -> bool:
|
||||
"""
|
||||
Checks the implemented trading indicator(s) for a randomly picked pair,
|
||||
if one pair triggers the buy_signal a new trade record gets created
|
||||
:return: True if a trade object has been created and persisted, False otherwise
|
||||
"""
|
||||
stake_amount = self.config['stake_amount']
|
||||
interval = self.analyze.get_ticker_interval()
|
||||
stake_amount = self._get_trade_stake_amount()
|
||||
|
||||
if not stake_amount:
|
||||
return False
|
||||
stake_currency = self.config['stake_currency']
|
||||
fiat_currency = self.config['fiat_display_currency']
|
||||
exc_name = self.exchange.name
|
||||
@ -261,10 +313,6 @@ class FreqtradeBot(object):
|
||||
stake_amount
|
||||
)
|
||||
whitelist = copy.deepcopy(self.config['exchange']['pair_whitelist'])
|
||||
# Check if stake_amount is fulfilled
|
||||
if self.exchange.get_balance(stake_currency) < stake_amount:
|
||||
raise DependencyException(
|
||||
f'stake amount is not fulfilled (currency={stake_currency})')
|
||||
|
||||
# Remove currently opened and latest pairs from whitelist
|
||||
for trade in Trade.query.filter(Trade.is_open.is_(True)).all():
|
||||
@ -285,8 +333,18 @@ class FreqtradeBot(object):
|
||||
return False
|
||||
pair_s = pair.replace('_', '/')
|
||||
pair_url = self.exchange.get_pair_detail_url(pair)
|
||||
|
||||
# Calculate amount
|
||||
buy_limit = self.get_target_bid(self.exchange.get_ticker(pair))
|
||||
|
||||
min_stake_amount = self._get_min_pair_stake_amount(pair_s, buy_limit)
|
||||
if min_stake_amount is not None and min_stake_amount > stake_amount:
|
||||
logger.warning(
|
||||
f'Can\'t open a new trade for {pair_s}: stake amount'
|
||||
f' is too small ({stake_amount} < {min_stake_amount})'
|
||||
)
|
||||
return False
|
||||
|
||||
amount = stake_amount / buy_limit
|
||||
|
||||
order_id = self.exchange.buy(pair, buy_limit, amount)['id']
|
||||
|
@ -14,6 +14,7 @@ from pandas import DataFrame
|
||||
from tabulate import tabulate
|
||||
|
||||
import freqtrade.optimize as optimize
|
||||
from freqtrade import constants, DependencyException
|
||||
from freqtrade.exchange import Exchange
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.arguments import Arguments
|
||||
@ -341,6 +342,10 @@ def setup_configuration(args: Namespace) -> Dict[str, Any]:
|
||||
config['exchange']['key'] = ''
|
||||
config['exchange']['secret'] = ''
|
||||
|
||||
if config['stake_amount'] == constants.UNLIMITED_STAKE_AMOUNT:
|
||||
raise DependencyException('stake amount could not be "%s" for backtesting' %
|
||||
constants.UNLIMITED_STAKE_AMOUNT)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
|
@ -189,7 +189,10 @@ def markets():
|
||||
'max': 1000,
|
||||
},
|
||||
'price': 500000,
|
||||
'cost': 500000,
|
||||
'cost': {
|
||||
'min': 1,
|
||||
'max': 500000,
|
||||
},
|
||||
},
|
||||
'info': '',
|
||||
},
|
||||
@ -211,7 +214,10 @@ def markets():
|
||||
'max': 1000,
|
||||
},
|
||||
'price': 500000,
|
||||
'cost': 500000,
|
||||
'cost': {
|
||||
'min': 1,
|
||||
'max': 500000,
|
||||
},
|
||||
},
|
||||
'info': '',
|
||||
},
|
||||
@ -233,7 +239,85 @@ def markets():
|
||||
'max': 1000,
|
||||
},
|
||||
'price': 500000,
|
||||
'cost': 500000,
|
||||
'cost': {
|
||||
'min': 1,
|
||||
'max': 500000,
|
||||
},
|
||||
},
|
||||
'info': '',
|
||||
},
|
||||
{
|
||||
'id': 'ltcbtc',
|
||||
'symbol': 'LTC/BTC',
|
||||
'base': 'LTC',
|
||||
'quote': 'BTC',
|
||||
'active': False,
|
||||
'precision': {
|
||||
'price': 8,
|
||||
'amount': 8,
|
||||
'cost': 8,
|
||||
},
|
||||
'lot': 0.00000001,
|
||||
'limits': {
|
||||
'amount': {
|
||||
'min': 0.01,
|
||||
'max': 1000,
|
||||
},
|
||||
'price': 500000,
|
||||
'cost': {
|
||||
'min': 1,
|
||||
'max': 500000,
|
||||
},
|
||||
},
|
||||
'info': '',
|
||||
},
|
||||
{
|
||||
'id': 'xrpbtc',
|
||||
'symbol': 'XRP/BTC',
|
||||
'base': 'XRP',
|
||||
'quote': 'BTC',
|
||||
'active': False,
|
||||
'precision': {
|
||||
'price': 8,
|
||||
'amount': 8,
|
||||
'cost': 8,
|
||||
},
|
||||
'lot': 0.00000001,
|
||||
'limits': {
|
||||
'amount': {
|
||||
'min': 0.01,
|
||||
'max': 1000,
|
||||
},
|
||||
'price': 500000,
|
||||
'cost': {
|
||||
'min': 1,
|
||||
'max': 500000,
|
||||
},
|
||||
},
|
||||
'info': '',
|
||||
},
|
||||
{
|
||||
'id': 'neobtc',
|
||||
'symbol': 'NEO/BTC',
|
||||
'base': 'NEO',
|
||||
'quote': 'BTC',
|
||||
'active': False,
|
||||
'precision': {
|
||||
'price': 8,
|
||||
'amount': 8,
|
||||
'cost': 8,
|
||||
},
|
||||
'lot': 0.00000001,
|
||||
'limits': {
|
||||
'amount': {
|
||||
'min': 0.01,
|
||||
'max': 1000,
|
||||
},
|
||||
'price': 500000,
|
||||
'cost': {
|
||||
'min': 1,
|
||||
'max': 500000,
|
||||
},
|
||||
},
|
||||
'info': '',
|
||||
}
|
||||
|
@ -672,7 +672,7 @@ def test_get_markets(default_conf, mocker, markets):
|
||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||
ret = exchange.get_markets()
|
||||
assert isinstance(ret, list)
|
||||
assert len(ret) == 3
|
||||
assert len(ret) == 6
|
||||
|
||||
assert ret[0]["id"] == "ethbtc"
|
||||
assert ret[0]["symbol"] == "ETH/BTC"
|
||||
|
@ -3,6 +3,7 @@
|
||||
import json
|
||||
import math
|
||||
import random
|
||||
import pytest
|
||||
from copy import deepcopy
|
||||
from typing import List
|
||||
from unittest.mock import MagicMock
|
||||
@ -11,7 +12,7 @@ import numpy as np
|
||||
import pandas as pd
|
||||
from arrow import Arrow
|
||||
|
||||
from freqtrade import optimize
|
||||
from freqtrade import optimize, constants, DependencyException
|
||||
from freqtrade.analyze import Analyze
|
||||
from freqtrade.arguments import Arguments, TimeRange
|
||||
from freqtrade.optimize.backtesting import Backtesting, start, setup_configuration
|
||||
@ -268,6 +269,28 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
||||
)
|
||||
|
||||
|
||||
def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None:
|
||||
"""
|
||||
Test setup_configuration() function
|
||||
"""
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
||||
|
||||
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
|
||||
read_data=json.dumps(conf)
|
||||
))
|
||||
|
||||
args = [
|
||||
'--config', 'config.json',
|
||||
'--strategy', 'DefaultStrategy',
|
||||
'backtesting'
|
||||
]
|
||||
|
||||
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
||||
setup_configuration(get_args(args))
|
||||
|
||||
|
||||
def test_start(mocker, fee, default_conf, caplog) -> None:
|
||||
"""
|
||||
Test start() function
|
||||
|
@ -25,7 +25,7 @@ def prec_satoshi(a, b) -> float:
|
||||
|
||||
|
||||
# Unit tests
|
||||
def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
def test_rpc_trade_status(default_conf, ticker, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test rpc_trade_status() method
|
||||
"""
|
||||
@ -36,7 +36,8 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -71,7 +72,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
||||
assert trade.find('[ETH/BTC]') >= 0
|
||||
|
||||
|
||||
def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test rpc_status_table() method
|
||||
"""
|
||||
@ -82,7 +83,8 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -104,7 +106,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
||||
|
||||
|
||||
def test_rpc_daily_profit(default_conf, update, ticker, fee,
|
||||
limit_buy_order, limit_sell_order, mocker) -> None:
|
||||
limit_buy_order, limit_sell_order, markets, mocker) -> None:
|
||||
"""
|
||||
Test rpc_daily_profit() method
|
||||
"""
|
||||
@ -115,7 +117,8 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -155,7 +158,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
|
||||
|
||||
|
||||
def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
||||
limit_buy_order, limit_sell_order, mocker) -> None:
|
||||
limit_buy_order, limit_sell_order, markets, mocker) -> None:
|
||||
"""
|
||||
Test rpc_trade_statistics() method
|
||||
"""
|
||||
@ -170,7 +173,8 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -230,7 +234,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
||||
|
||||
# Test that rpc_trade_statistics can handle trades that lacks
|
||||
# trade.open_rate (it is set to None)
|
||||
def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
|
||||
def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, markets,
|
||||
ticker_sell_up, limit_buy_order, limit_sell_order):
|
||||
"""
|
||||
Test rpc_trade_statistics() method
|
||||
@ -246,7 +250,8 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -386,7 +391,7 @@ def test_rpc_stop(mocker, default_conf) -> None:
|
||||
assert freqtradebot.state == State.STOPPED
|
||||
|
||||
|
||||
def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None:
|
||||
def test_rpc_forcesell(default_conf, ticker, fee, mocker, markets) -> None:
|
||||
"""
|
||||
Test rpc_forcesell() method
|
||||
"""
|
||||
@ -408,6 +413,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None:
|
||||
}
|
||||
),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -489,7 +495,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None:
|
||||
|
||||
|
||||
def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
||||
limit_sell_order, mocker) -> None:
|
||||
limit_sell_order, markets, mocker) -> None:
|
||||
"""
|
||||
Test rpc_performance() method
|
||||
"""
|
||||
@ -501,7 +507,8 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
||||
validate_pairs=MagicMock(),
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -527,7 +534,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
||||
assert prec_satoshi(res[0]['profit'], 6.2)
|
||||
|
||||
|
||||
def test_rpc_count(mocker, default_conf, ticker, fee) -> None:
|
||||
def test_rpc_count(mocker, default_conf, ticker, fee, markets) -> None:
|
||||
"""
|
||||
Test rpc_count() method
|
||||
"""
|
||||
@ -540,6 +547,7 @@ def test_rpc_count(mocker, default_conf, ticker, fee) -> None:
|
||||
get_balances=MagicMock(return_value=ticker),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
|
@ -185,7 +185,7 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None:
|
||||
)
|
||||
|
||||
|
||||
def test_status(default_conf, update, mocker, fee, ticker) -> None:
|
||||
def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
|
||||
"""
|
||||
Test _status() method
|
||||
"""
|
||||
@ -202,6 +202,7 @@ def test_status(default_conf, update, mocker, fee, ticker) -> None:
|
||||
get_ticker=ticker,
|
||||
get_pair_detail_url=MagicMock(),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
msg_mock = MagicMock()
|
||||
status_table = MagicMock()
|
||||
@ -230,7 +231,7 @@ def test_status(default_conf, update, mocker, fee, ticker) -> None:
|
||||
assert status_table.call_count == 1
|
||||
|
||||
|
||||
def test_status_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test _status() method
|
||||
"""
|
||||
@ -241,6 +242,7 @@ def test_status_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
msg_mock = MagicMock()
|
||||
status_table = MagicMock()
|
||||
@ -276,7 +278,7 @@ def test_status_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
assert '[ETH/BTC]' in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test _status_table() method
|
||||
"""
|
||||
@ -288,6 +290,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': 'mocked_order_id'}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
@ -329,7 +332,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
|
||||
|
||||
def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
|
||||
limit_sell_order, mocker) -> None:
|
||||
limit_sell_order, markets, mocker) -> None:
|
||||
"""
|
||||
Test _daily() method
|
||||
"""
|
||||
@ -343,7 +346,8 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
@ -441,7 +445,7 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
|
||||
|
||||
|
||||
def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
|
||||
limit_buy_order, limit_sell_order, mocker) -> None:
|
||||
limit_buy_order, limit_sell_order, markets, mocker) -> None:
|
||||
"""
|
||||
Test _profit() method
|
||||
"""
|
||||
@ -452,7 +456,8 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
msg_mock = MagicMock()
|
||||
mocker.patch.multiple(
|
||||
@ -705,7 +710,8 @@ def test_reload_conf_handle(default_conf, update, mocker) -> None:
|
||||
assert 'Reloading config' in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_forcesell_handle(default_conf, update, ticker, fee, ticker_sell_up, mocker) -> None:
|
||||
def test_forcesell_handle(default_conf, update, ticker, fee,
|
||||
ticker_sell_up, markets, mocker) -> None:
|
||||
"""
|
||||
Test _forcesell() method
|
||||
"""
|
||||
@ -718,7 +724,8 @@ def test_forcesell_handle(default_conf, update, ticker, fee, ticker_sell_up, moc
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -745,7 +752,8 @@ def test_forcesell_handle(default_conf, update, ticker, fee, ticker_sell_up, moc
|
||||
assert '0.919 USD' in rpc_mock.call_args_list[-1][0][0]
|
||||
|
||||
|
||||
def test_forcesell_down_handle(default_conf, update, ticker, fee, ticker_sell_down, mocker) -> None:
|
||||
def test_forcesell_down_handle(default_conf, update, ticker, fee,
|
||||
ticker_sell_down, markets, mocker) -> None:
|
||||
"""
|
||||
Test _forcesell() method
|
||||
"""
|
||||
@ -758,7 +766,8 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, ticker_sell_do
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -789,7 +798,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, ticker_sell_do
|
||||
assert '-0.824 USD' in rpc_mock.call_args_list[-1][0][0]
|
||||
|
||||
|
||||
def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test _forcesell() method
|
||||
"""
|
||||
@ -803,7 +812,8 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -867,7 +877,7 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
|
||||
|
||||
|
||||
def test_performance_handle(default_conf, update, ticker, fee,
|
||||
limit_buy_order, limit_sell_order, mocker) -> None:
|
||||
limit_buy_order, limit_sell_order, markets, mocker) -> None:
|
||||
"""
|
||||
Test _performance() method
|
||||
"""
|
||||
@ -883,7 +893,8 @@ def test_performance_handle(default_conf, update, ticker, fee,
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
@ -931,7 +942,7 @@ def test_performance_handle_invalid(default_conf, update, mocker) -> None:
|
||||
assert 'not running' in msg_mock.call_args_list[0][0][0]
|
||||
|
||||
|
||||
def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test _count() method
|
||||
"""
|
||||
@ -947,7 +958,8 @@ def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': 'mocked_order_id'})
|
||||
buy=MagicMock(return_value={'id': 'mocked_order_id'}),
|
||||
get_markets=markets
|
||||
)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
freqtradebot = FreqtradeBot(default_conf)
|
||||
|
@ -55,6 +55,18 @@ def test_load_config_missing_attributes(default_conf) -> None:
|
||||
configuration._validate_config(conf)
|
||||
|
||||
|
||||
def test_load_config_incorrect_stake_amount(default_conf) -> None:
|
||||
"""
|
||||
Test the configuration validator with a missing attribute
|
||||
"""
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = 'fake'
|
||||
|
||||
with pytest.raises(ValidationError, match=r'.*\'fake\' does not match \'unlimited\'.*'):
|
||||
configuration = Configuration(Namespace())
|
||||
configuration._validate_config(conf)
|
||||
|
||||
|
||||
def test_load_config_file(default_conf, mocker, caplog) -> None:
|
||||
"""
|
||||
Test Configuration._load_config_file() method
|
||||
|
@ -14,7 +14,7 @@ import arrow
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from freqtrade import DependencyException, OperationalException, TemporaryError
|
||||
from freqtrade import constants, DependencyException, OperationalException, TemporaryError
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.state import State
|
||||
@ -216,7 +216,210 @@ def test_refresh_whitelist() -> None:
|
||||
pass
|
||||
|
||||
|
||||
def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||
def test_get_trade_stake_amount(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||
"""
|
||||
Test get_trade_stake_amount() method
|
||||
"""
|
||||
|
||||
patch_RPCManager(mocker)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_balance=MagicMock(return_value=default_conf['stake_amount'] * 2)
|
||||
)
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
result = freqtrade._get_trade_stake_amount()
|
||||
assert(result == default_conf['stake_amount'])
|
||||
|
||||
|
||||
def test_get_trade_stake_amount_no_stake_amount(default_conf,
|
||||
ticker,
|
||||
limit_buy_order,
|
||||
fee,
|
||||
mocker) -> None:
|
||||
"""
|
||||
Test get_trade_stake_amount() method
|
||||
"""
|
||||
patch_RPCManager(mocker)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_balance=MagicMock(return_value=default_conf['stake_amount'] * 0.5)
|
||||
)
|
||||
|
||||
# test defined stake amount
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
||||
freqtrade._get_trade_stake_amount()
|
||||
|
||||
|
||||
def test_get_trade_stake_amount_unlimited_amount(default_conf,
|
||||
ticker,
|
||||
limit_buy_order,
|
||||
fee,
|
||||
markets,
|
||||
mocker) -> None:
|
||||
"""
|
||||
Test get_trade_stake_amount() method
|
||||
"""
|
||||
patch_get_signal(mocker)
|
||||
patch_RPCManager(mocker)
|
||||
patch_coinmarketcap(mocker)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_balance=MagicMock(return_value=default_conf['stake_amount']),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
||||
conf['max_open_trades'] = 2
|
||||
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
# no open trades, order amount should be 'balance / max_open_trades'
|
||||
result = freqtrade._get_trade_stake_amount()
|
||||
assert result == default_conf['stake_amount'] / conf['max_open_trades']
|
||||
|
||||
# create one trade, order amount should be 'balance / (max_open_trades - num_open_trades)'
|
||||
freqtrade.create_trade()
|
||||
|
||||
result = freqtrade._get_trade_stake_amount()
|
||||
assert result == default_conf['stake_amount'] / (conf['max_open_trades'] - 1)
|
||||
|
||||
# create 2 trades, order amount should be None
|
||||
freqtrade.create_trade()
|
||||
|
||||
result = freqtrade._get_trade_stake_amount()
|
||||
assert result is None
|
||||
|
||||
# set max_open_trades = None, so do not trade
|
||||
conf['max_open_trades'] = 0
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
result = freqtrade._get_trade_stake_amount()
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
|
||||
"""
|
||||
Test get_trade_stake_amount() method
|
||||
"""
|
||||
|
||||
patch_RPCManager(mocker)
|
||||
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
|
||||
mocker.patch('freqtrade.freqtradebot.Analyze.get_stoploss', MagicMock(return_value=-0.05))
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
# no pair found
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_markets',
|
||||
MagicMock(return_value=[{
|
||||
'symbol': 'ETH/BTC'
|
||||
}])
|
||||
)
|
||||
with pytest.raises(ValueError, match=r'.*get market information.*'):
|
||||
freqtrade._get_min_pair_stake_amount('BNB/BTC', 1)
|
||||
|
||||
# no 'limits' section
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_markets',
|
||||
MagicMock(return_value=[{
|
||||
'symbol': 'ETH/BTC'
|
||||
}])
|
||||
)
|
||||
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
|
||||
assert result is None
|
||||
|
||||
# empty 'limits' section
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_markets',
|
||||
MagicMock(return_value=[{
|
||||
'symbol': 'ETH/BTC',
|
||||
'limits': {}
|
||||
}])
|
||||
)
|
||||
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
|
||||
assert result is None
|
||||
|
||||
# empty 'cost'/'amount' section
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_markets',
|
||||
MagicMock(return_value=[{
|
||||
'symbol': 'ETH/BTC',
|
||||
'limits': {
|
||||
'cost': {},
|
||||
'amount': {}
|
||||
}
|
||||
}])
|
||||
)
|
||||
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
|
||||
assert result is None
|
||||
|
||||
# min cost is set
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_markets',
|
||||
MagicMock(return_value=[{
|
||||
'symbol': 'ETH/BTC',
|
||||
'limits': {
|
||||
'cost': {'min': 2},
|
||||
'amount': {}
|
||||
}
|
||||
}])
|
||||
)
|
||||
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
|
||||
assert result == 2 / 0.9
|
||||
|
||||
# min amount is set
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_markets',
|
||||
MagicMock(return_value=[{
|
||||
'symbol': 'ETH/BTC',
|
||||
'limits': {
|
||||
'cost': {},
|
||||
'amount': {'min': 2}
|
||||
}
|
||||
}])
|
||||
)
|
||||
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == 2 * 2 / 0.9
|
||||
|
||||
# min amount and cost are set (cost is minimal)
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_markets',
|
||||
MagicMock(return_value=[{
|
||||
'symbol': 'ETH/BTC',
|
||||
'limits': {
|
||||
'cost': {'min': 2},
|
||||
'amount': {'min': 2}
|
||||
}
|
||||
}])
|
||||
)
|
||||
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == min(2, 2 * 2) / 0.9
|
||||
|
||||
# min amount and cost are set (amount is minial)
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.get_markets',
|
||||
MagicMock(return_value=[{
|
||||
'symbol': 'ETH/BTC',
|
||||
'limits': {
|
||||
'cost': {'min': 8},
|
||||
'amount': {'min': 2}
|
||||
}
|
||||
}])
|
||||
)
|
||||
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
|
||||
assert result == min(8, 2 * 2) / 0.9
|
||||
|
||||
|
||||
def test_create_trade(default_conf, ticker, limit_buy_order, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
@ -229,6 +432,7 @@ def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> Non
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
# Save state of current whitelist
|
||||
@ -252,32 +456,8 @@ def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> Non
|
||||
assert whitelist == default_conf['exchange']['pair_whitelist']
|
||||
|
||||
|
||||
def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
patch_get_signal(mocker)
|
||||
patch_RPCManager(mocker)
|
||||
patch_coinmarketcap(mocker)
|
||||
buy_mock = MagicMock(return_value={'id': limit_buy_order['id']})
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
buy=buy_mock,
|
||||
get_fee=fee,
|
||||
)
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = 0.0005
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
freqtrade.create_trade()
|
||||
rate, amount = buy_mock.call_args[0][1], buy_mock.call_args[0][2]
|
||||
assert rate * amount >= conf['stake_amount']
|
||||
|
||||
|
||||
def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||
def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
@ -291,6 +471,7 @@ def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, fee
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_balance=MagicMock(return_value=default_conf['stake_amount'] * 0.5),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
@ -298,7 +479,87 @@ def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, fee
|
||||
freqtrade.create_trade()
|
||||
|
||||
|
||||
def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||
def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
patch_get_signal(mocker)
|
||||
patch_RPCManager(mocker)
|
||||
patch_coinmarketcap(mocker)
|
||||
buy_mock = MagicMock(return_value={'id': limit_buy_order['id']})
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
buy=buy_mock,
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = 0.0005
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
freqtrade.create_trade()
|
||||
rate, amount = buy_mock.call_args[0][1], buy_mock.call_args[0][2]
|
||||
assert rate * amount >= conf['stake_amount']
|
||||
|
||||
|
||||
def test_create_trade_too_small_stake_amount(default_conf, ticker, limit_buy_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
patch_get_signal(mocker)
|
||||
patch_RPCManager(mocker)
|
||||
patch_coinmarketcap(mocker)
|
||||
buy_mock = MagicMock(return_value={'id': limit_buy_order['id']})
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
buy=buy_mock,
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
conf['stake_amount'] = 0.000000005
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
result = freqtrade.create_trade()
|
||||
assert result is False
|
||||
|
||||
|
||||
def test_create_trade_limit_reached(default_conf, ticker, limit_buy_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
patch_get_signal(mocker)
|
||||
patch_RPCManager(mocker)
|
||||
patch_coinmarketcap(mocker)
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_balance=MagicMock(return_value=default_conf['stake_amount']),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
conf = deepcopy(default_conf)
|
||||
conf['max_open_trades'] = 0
|
||||
conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
||||
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
|
||||
assert freqtrade.create_trade() is False
|
||||
assert freqtrade._get_trade_stake_amount() is None
|
||||
|
||||
|
||||
def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
@ -311,6 +572,7 @@ def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, mocke
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
@ -325,7 +587,7 @@ def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, mocke
|
||||
|
||||
|
||||
def test_create_trade_no_pairs_after_blacklist(default_conf, ticker,
|
||||
limit_buy_order, fee, mocker) -> None:
|
||||
limit_buy_order, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test create_trade() method
|
||||
"""
|
||||
@ -338,6 +600,7 @@ def test_create_trade_no_pairs_after_blacklist(default_conf, ticker,
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
@ -616,7 +879,8 @@ def test_process_maybe_execute_sell_exception(mocker, default_conf,
|
||||
assert log_has('Unable to sell trade: ', caplog.record_tuples)
|
||||
|
||||
|
||||
def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mocker) -> None:
|
||||
def test_handle_trade(default_conf, limit_buy_order, limit_sell_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test check_handle() method
|
||||
"""
|
||||
@ -632,7 +896,8 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mock
|
||||
}),
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
patch_coinmarketcap(mocker, value={'price_usd': 15000.0})
|
||||
|
||||
@ -660,7 +925,8 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mock
|
||||
assert trade.close_date is not None
|
||||
|
||||
|
||||
def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||
def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test check_handle() method
|
||||
"""
|
||||
@ -677,6 +943,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee,
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
freqtrade = FreqtradeBot(conf)
|
||||
@ -718,7 +985,8 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee,
|
||||
assert freqtrade.handle_trade(trades[0]) is True
|
||||
|
||||
|
||||
def test_handle_trade_roi(default_conf, ticker, limit_buy_order, fee, mocker, caplog) -> None:
|
||||
def test_handle_trade_roi(default_conf, ticker, limit_buy_order,
|
||||
fee, mocker, markets, caplog) -> None:
|
||||
"""
|
||||
Test check_handle() method
|
||||
"""
|
||||
@ -735,6 +1003,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, fee, mocker, ca
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
mocker.patch('freqtrade.freqtradebot.Analyze.min_roi_reached', return_value=True)
|
||||
@ -755,7 +1024,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, fee, mocker, ca
|
||||
|
||||
|
||||
def test_handle_trade_experimental(
|
||||
default_conf, ticker, limit_buy_order, fee, mocker, caplog) -> None:
|
||||
default_conf, ticker, limit_buy_order, fee, mocker, markets, caplog) -> None:
|
||||
"""
|
||||
Test check_handle() method
|
||||
"""
|
||||
@ -772,6 +1041,7 @@ def test_handle_trade_experimental(
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
mocker.patch('freqtrade.freqtradebot.Analyze.min_roi_reached', return_value=False)
|
||||
|
||||
@ -789,7 +1059,8 @@ def test_handle_trade_experimental(
|
||||
assert log_has('Sell signal received. Selling..', caplog.record_tuples)
|
||||
|
||||
|
||||
def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, fee, mocker) -> None:
|
||||
def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test check_handle() method
|
||||
"""
|
||||
@ -802,6 +1073,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, fe
|
||||
get_ticker=ticker,
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
@ -1040,7 +1312,7 @@ def test_handle_timedout_limit_sell(mocker, default_conf) -> None:
|
||||
assert cancel_order_mock.call_count == 1
|
||||
|
||||
|
||||
def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> None:
|
||||
def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, mocker) -> None:
|
||||
"""
|
||||
Test execute_sell() method with a ticker going UP
|
||||
"""
|
||||
@ -1051,7 +1323,8 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> N
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
mocker.patch('freqtrade.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
@ -1081,7 +1354,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> N
|
||||
assert '0.919 USD' in rpc_mock.call_args_list[-1][0][0]
|
||||
|
||||
|
||||
def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker) -> None:
|
||||
def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets, mocker) -> None:
|
||||
"""
|
||||
Test execute_sell() method with a ticker going DOWN
|
||||
"""
|
||||
@ -1093,7 +1366,8 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker)
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
@ -1122,7 +1396,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker)
|
||||
|
||||
|
||||
def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
|
||||
ticker_sell_up, mocker) -> None:
|
||||
ticker_sell_up, markets, mocker) -> None:
|
||||
"""
|
||||
Test execute_sell() method with a ticker going DOWN and with a bot config empty
|
||||
"""
|
||||
@ -1133,7 +1407,8 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
@ -1163,7 +1438,7 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
|
||||
|
||||
|
||||
def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee,
|
||||
ticker_sell_down, mocker) -> None:
|
||||
ticker_sell_down, markets, mocker) -> None:
|
||||
"""
|
||||
Test execute_sell() method with a ticker going DOWN and with a bot config empty
|
||||
"""
|
||||
@ -1174,7 +1449,8 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee,
|
||||
'freqtrade.exchange.Exchange',
|
||||
validate_pairs=MagicMock(),
|
||||
get_ticker=ticker,
|
||||
get_fee=fee
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
@ -1201,7 +1477,8 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee,
|
||||
assert 'loss: -5.48%, -0.00005492' in rpc_mock.call_args_list[-1][0][0]
|
||||
|
||||
|
||||
def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, fee, mocker) -> None:
|
||||
def test_sell_profit_only_enable_profit(default_conf, limit_buy_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test sell_profit_only feature when enabled
|
||||
"""
|
||||
@ -1219,6 +1496,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, fee, mock
|
||||
}),
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
conf = deepcopy(default_conf)
|
||||
conf['experimental'] = {
|
||||
@ -1234,7 +1512,8 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, fee, mock
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
|
||||
|
||||
def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, fee, mocker) -> None:
|
||||
def test_sell_profit_only_disable_profit(default_conf, limit_buy_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test sell_profit_only feature when disabled
|
||||
"""
|
||||
@ -1252,6 +1531,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, fee, moc
|
||||
}),
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
conf = deepcopy(default_conf)
|
||||
conf['experimental'] = {
|
||||
@ -1267,7 +1547,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, fee, moc
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
|
||||
|
||||
def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, mocker) -> None:
|
||||
def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test sell_profit_only feature when enabled and we have a loss
|
||||
"""
|
||||
@ -1285,6 +1565,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, mocker
|
||||
}),
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
conf = deepcopy(default_conf)
|
||||
conf['experimental'] = {
|
||||
@ -1300,7 +1581,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, mocker
|
||||
assert freqtrade.handle_trade(trade) is False
|
||||
|
||||
|
||||
def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocker) -> None:
|
||||
def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test sell_profit_only feature when enabled and we have a loss
|
||||
"""
|
||||
@ -1373,7 +1654,8 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, mocker) ->
|
||||
assert freqtrade.handle_trade(trade) is True
|
||||
|
||||
|
||||
def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, mocker) -> None:
|
||||
def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order,
|
||||
fee, markets, mocker) -> None:
|
||||
"""
|
||||
Test sell_profit_only feature when enabled and we have a loss
|
||||
"""
|
||||
@ -1391,6 +1673,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, mo
|
||||
}),
|
||||
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||
get_fee=fee,
|
||||
get_markets=markets
|
||||
)
|
||||
|
||||
conf = deepcopy(default_conf)
|
||||
|
Loading…
Reference in New Issue
Block a user