Add ability to set unlimited stake_amount
This commit is contained in:
parent
13d6297b9f
commit
9be98cd8f7
@ -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.
|
| `max_open_trades` | 3 | Yes | Number of trades open your bot will have.
|
||||||
| `stake_currency` | BTC | Yes | Crypto-currency used for trading.
|
| `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. 'unlimited' is used to allow a 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
|
| `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.
|
| `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.
|
| `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode.
|
||||||
|
@ -32,7 +32,10 @@ CONF_SCHEMA = {
|
|||||||
'max_open_trades': {'type': 'integer', 'minimum': 0},
|
'max_open_trades': {'type': 'integer', 'minimum': 0},
|
||||||
'ticker_interval': {'type': 'string', 'enum': list(TICKER_INTERVAL_MINUTES.keys())},
|
'ticker_interval': {'type': 'string', 'enum': list(TICKER_INTERVAL_MINUTES.keys())},
|
||||||
'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT']},
|
'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT']},
|
||||||
'stake_amount': {'type': 'number', 'minimum': 0.0005},
|
'stake_amount': {'anyOf': [
|
||||||
|
{'type': 'integer', 'minimum': 0.0005},
|
||||||
|
{'constant': 'unlimited'}
|
||||||
|
]},
|
||||||
'fiat_display_currency': {'type': 'string', 'enum': ['AUD', 'BRL', 'CAD', 'CHF',
|
'fiat_display_currency': {'type': 'string', 'enum': ['AUD', 'BRL', 'CAD', 'CHF',
|
||||||
'CLP', 'CNY', 'CZK', 'DKK',
|
'CLP', 'CNY', 'CZK', 'DKK',
|
||||||
'EUR', 'GBP', 'HKD', 'HUF',
|
'EUR', 'GBP', 'HKD', 'HUF',
|
||||||
|
@ -255,6 +255,24 @@ class FreqtradeBot(object):
|
|||||||
balance = self.config['bid_strategy']['ask_last_balance']
|
balance = self.config['bid_strategy']['ask_last_balance']
|
||||||
return ticker['ask'] + balance * (ticker['last'] - ticker['ask'])
|
return ticker['ask'] + balance * (ticker['last'] - ticker['ask'])
|
||||||
|
|
||||||
|
def _get_trade_stake_amount(self) -> float:
|
||||||
|
stake_amount = self.config['stake_amount']
|
||||||
|
avaliable_amount = exchange.get_balance(self.config['stake_currency'])
|
||||||
|
|
||||||
|
if stake_amount == 'unlimited':
|
||||||
|
open_trades = len(Trade.query.filter(Trade.is_open.is_(True)).all())
|
||||||
|
if open_trades == self.config['max_open_trades']:
|
||||||
|
return 0
|
||||||
|
return avaliable_amount / (self.config['max_open_trades'] - open_trades)
|
||||||
|
|
||||||
|
# Check if stake_amount is fulfilled
|
||||||
|
if avaliable_amount < stake_amount:
|
||||||
|
raise DependencyException(
|
||||||
|
'stake amount is not fulfilled (currency={})'.format(self.config['stake_currency'])
|
||||||
|
)
|
||||||
|
|
||||||
|
return stake_amount
|
||||||
|
|
||||||
def create_trade(self) -> bool:
|
def create_trade(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Checks the implemented trading indicator(s) for a randomly picked pair,
|
Checks the implemented trading indicator(s) for a randomly picked pair,
|
||||||
@ -263,19 +281,14 @@ class FreqtradeBot(object):
|
|||||||
:param interval: Ticker interval used for Analyze
|
:param interval: Ticker interval used for Analyze
|
||||||
:return: True if a trade object has been created and persisted, False otherwise
|
: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()
|
interval = self.analyze.get_ticker_interval()
|
||||||
|
stake_amount = self._get_trade_stake_amount()
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
'Checking buy signals to create a new trade with stake_amount: %f ...',
|
'Checking buy signals to create a new trade with stake_amount: %f ...',
|
||||||
stake_amount
|
stake_amount
|
||||||
)
|
)
|
||||||
whitelist = copy.deepcopy(self.config['exchange']['pair_whitelist'])
|
whitelist = copy.deepcopy(self.config['exchange']['pair_whitelist'])
|
||||||
# Check if stake_amount is fulfilled
|
|
||||||
if exchange.get_balance(self.config['stake_currency']) < stake_amount:
|
|
||||||
raise DependencyException(
|
|
||||||
'stake amount is not fulfilled (currency={})'.format(self.config['stake_currency'])
|
|
||||||
)
|
|
||||||
|
|
||||||
# Remove currently opened and latest pairs from whitelist
|
# Remove currently opened and latest pairs from whitelist
|
||||||
for trade in Trade.query.filter(Trade.is_open.is_(True)).all():
|
for trade in Trade.query.filter(Trade.is_open.is_(True)).all():
|
||||||
|
@ -13,7 +13,7 @@ from pandas import DataFrame
|
|||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
import freqtrade.optimize as optimize
|
import freqtrade.optimize as optimize
|
||||||
from freqtrade import exchange
|
from freqtrade import exchange, DependencyException
|
||||||
from freqtrade.analyze import Analyze
|
from freqtrade.analyze import Analyze
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.configuration import Configuration
|
from freqtrade.configuration import Configuration
|
||||||
@ -296,6 +296,9 @@ def setup_configuration(args: Namespace) -> Dict[str, Any]:
|
|||||||
config['exchange']['key'] = ''
|
config['exchange']['key'] = ''
|
||||||
config['exchange']['secret'] = ''
|
config['exchange']['secret'] = ''
|
||||||
|
|
||||||
|
if config['stake_amount'] == 'unlimited':
|
||||||
|
raise DependencyException('stake amount could not be "unlimited" for backtesting')
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@ -220,6 +220,115 @@ def test_refresh_whitelist() -> None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_trade_stake_amount(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||||
|
"""
|
||||||
|
Test get_trade_stake_amount() method
|
||||||
|
"""
|
||||||
|
patch_get_signal(mocker)
|
||||||
|
patch_RPCManager(mocker)
|
||||||
|
patch_coinmarketcap(mocker)
|
||||||
|
mocker.patch.multiple(
|
||||||
|
'freqtrade.freqtradebot.exchange',
|
||||||
|
validate_pairs=MagicMock(),
|
||||||
|
get_ticker=ticker,
|
||||||
|
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
|
||||||
|
get_fee=fee,
|
||||||
|
)
|
||||||
|
|
||||||
|
conf = deepcopy(default_conf)
|
||||||
|
|
||||||
|
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
|
result = freqtrade._get_trade_stake_amount()
|
||||||
|
assert(result == 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_get_signal(mocker)
|
||||||
|
patch_RPCManager(mocker)
|
||||||
|
patch_coinmarketcap(mocker)
|
||||||
|
mocker.patch.multiple(
|
||||||
|
'freqtrade.freqtradebot.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'] * 0.5),
|
||||||
|
get_fee=fee,
|
||||||
|
)
|
||||||
|
|
||||||
|
conf = deepcopy(default_conf)
|
||||||
|
|
||||||
|
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
|
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,
|
||||||
|
mocker) -> None:
|
||||||
|
"""
|
||||||
|
Test get_trade_stake_amount() method
|
||||||
|
"""
|
||||||
|
patch_get_signal(mocker)
|
||||||
|
patch_RPCManager(mocker)
|
||||||
|
patch_coinmarketcap(mocker)
|
||||||
|
mocker.patch.multiple(
|
||||||
|
'freqtrade.freqtradebot.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,
|
||||||
|
)
|
||||||
|
|
||||||
|
conf = deepcopy(default_conf)
|
||||||
|
conf['stake_amount'] = 'unlimited'
|
||||||
|
conf['max_open_trades'] = 2
|
||||||
|
|
||||||
|
freqtrade = FreqtradeBot(conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||||
|
"""
|
||||||
|
Test create_trade() method
|
||||||
|
"""
|
||||||
|
patch_get_signal(mocker)
|
||||||
|
patch_RPCManager(mocker)
|
||||||
|
patch_coinmarketcap(mocker)
|
||||||
|
mocker.patch.multiple(
|
||||||
|
'freqtrade.freqtradebot.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'] * 0.5),
|
||||||
|
get_fee=fee,
|
||||||
|
)
|
||||||
|
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
||||||
|
|
||||||
|
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
||||||
|
freqtrade.create_trade()
|
||||||
|
|
||||||
|
|
||||||
def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||||
"""
|
"""
|
||||||
Test create_trade() method
|
Test create_trade() method
|
||||||
@ -281,27 +390,6 @@ def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order, fee,
|
|||||||
assert rate * amount >= conf['stake_amount']
|
assert rate * amount >= conf['stake_amount']
|
||||||
|
|
||||||
|
|
||||||
def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
|
||||||
"""
|
|
||||||
Test create_trade() method
|
|
||||||
"""
|
|
||||||
patch_get_signal(mocker)
|
|
||||||
patch_RPCManager(mocker)
|
|
||||||
patch_coinmarketcap(mocker)
|
|
||||||
mocker.patch.multiple(
|
|
||||||
'freqtrade.freqtradebot.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'] * 0.5),
|
|
||||||
get_fee=fee,
|
|
||||||
)
|
|
||||||
freqtrade = FreqtradeBot(default_conf, create_engine('sqlite://'))
|
|
||||||
|
|
||||||
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
|
||||||
freqtrade.create_trade()
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, mocker) -> None:
|
||||||
"""
|
"""
|
||||||
Test create_trade() method
|
Test create_trade() method
|
||||||
|
Loading…
Reference in New Issue
Block a user