mirror of
https://github.com/freqtrade/freqtrade.git
synced 2026-05-05 07:58:12 +00:00
Merge pull request #11000 from freqtrade/feat/multi_wallet
Dry-run multi-wallet support
This commit is contained in:
@@ -39,13 +39,34 @@ def test_loss_calculation_prefer_correct_trade_count(hyperopt_conf, hyperopt_res
|
||||
hyperopt_conf.update({"hyperopt_loss": "ShortTradeDurHyperOptLoss"})
|
||||
hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf)
|
||||
correct = hl.hyperopt_loss_function(
|
||||
hyperopt_results, 600, datetime(2019, 1, 1), datetime(2019, 5, 1)
|
||||
results=hyperopt_results,
|
||||
trade_count=600,
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=hyperopt_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()},
|
||||
starting_balance=hyperopt_conf["dry_run_wallet"],
|
||||
)
|
||||
over = hl.hyperopt_loss_function(
|
||||
hyperopt_results, 600 + 100, datetime(2019, 1, 1), datetime(2019, 5, 1)
|
||||
results=hyperopt_results,
|
||||
trade_count=600 + 100,
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=hyperopt_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()},
|
||||
starting_balance=hyperopt_conf["dry_run_wallet"],
|
||||
)
|
||||
under = hl.hyperopt_loss_function(
|
||||
hyperopt_results, 600 - 100, datetime(2019, 1, 1), datetime(2019, 5, 1)
|
||||
results=hyperopt_results,
|
||||
trade_count=600 - 100,
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=hyperopt_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()},
|
||||
starting_balance=hyperopt_conf["dry_run_wallet"],
|
||||
)
|
||||
assert over > correct
|
||||
assert under > correct
|
||||
@@ -58,9 +79,25 @@ def test_loss_calculation_prefer_shorter_trades(hyperopt_conf, hyperopt_results)
|
||||
hyperopt_conf.update({"hyperopt_loss": "ShortTradeDurHyperOptLoss"})
|
||||
hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf)
|
||||
longer = hl.hyperopt_loss_function(
|
||||
hyperopt_results, 100, datetime(2019, 1, 1), datetime(2019, 5, 1)
|
||||
results=hyperopt_results,
|
||||
trade_count=100,
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=hyperopt_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()},
|
||||
starting_balance=hyperopt_conf["dry_run_wallet"],
|
||||
)
|
||||
shorter = hl.hyperopt_loss_function(
|
||||
results=resultsb,
|
||||
trade_count=100,
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=hyperopt_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": resultsb["profit_abs"].sum()},
|
||||
starting_balance=hyperopt_conf["dry_run_wallet"],
|
||||
)
|
||||
shorter = hl.hyperopt_loss_function(resultsb, 100, datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
assert shorter < longer
|
||||
|
||||
|
||||
@@ -73,11 +110,34 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) ->
|
||||
hyperopt_conf.update({"hyperopt_loss": "ShortTradeDurHyperOptLoss"})
|
||||
hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf)
|
||||
correct = hl.hyperopt_loss_function(
|
||||
hyperopt_results, 600, datetime(2019, 1, 1), datetime(2019, 5, 1)
|
||||
results=hyperopt_results,
|
||||
trade_count=600,
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=hyperopt_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()},
|
||||
starting_balance=hyperopt_conf["dry_run_wallet"],
|
||||
)
|
||||
over = hl.hyperopt_loss_function(
|
||||
results=results_over,
|
||||
trade_count=600,
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=hyperopt_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": results_over["profit_abs"].sum()},
|
||||
starting_balance=hyperopt_conf["dry_run_wallet"],
|
||||
)
|
||||
over = hl.hyperopt_loss_function(results_over, 600, datetime(2019, 1, 1), datetime(2019, 5, 1))
|
||||
under = hl.hyperopt_loss_function(
|
||||
results_under, 600, datetime(2019, 1, 1), datetime(2019, 5, 1)
|
||||
results=results_under,
|
||||
trade_count=600,
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=hyperopt_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": results_under["profit_abs"].sum()},
|
||||
starting_balance=hyperopt_conf["dry_run_wallet"],
|
||||
)
|
||||
assert over < correct
|
||||
assert under > correct
|
||||
@@ -109,31 +169,34 @@ def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunct
|
||||
default_conf.update({"hyperopt_loss": lossfunction})
|
||||
hl = HyperOptLossResolver.load_hyperoptloss(default_conf)
|
||||
correct = hl.hyperopt_loss_function(
|
||||
hyperopt_results,
|
||||
results=hyperopt_results,
|
||||
trade_count=len(hyperopt_results),
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=default_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()},
|
||||
starting_balance=default_conf["dry_run_wallet"],
|
||||
)
|
||||
over = hl.hyperopt_loss_function(
|
||||
results_over,
|
||||
results=results_over,
|
||||
trade_count=len(results_over),
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=default_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": results_over["profit_abs"].sum()},
|
||||
starting_balance=default_conf["dry_run_wallet"],
|
||||
)
|
||||
under = hl.hyperopt_loss_function(
|
||||
results_under,
|
||||
results=results_under,
|
||||
trade_count=len(results_under),
|
||||
min_date=datetime(2019, 1, 1),
|
||||
max_date=datetime(2019, 5, 1),
|
||||
config=default_conf,
|
||||
processed=None,
|
||||
backtest_stats={"profit_total": results_under["profit_abs"].sum()},
|
||||
starting_balance=default_conf["dry_run_wallet"],
|
||||
)
|
||||
assert over < correct
|
||||
assert under > correct
|
||||
|
||||
@@ -530,6 +530,13 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers):
|
||||
"total": 5.0,
|
||||
"used": 4.0,
|
||||
},
|
||||
# Invalid coin not in tickers list.
|
||||
# This triggers a 2nd call to get_tickers
|
||||
"NotACoin": {
|
||||
"free": 0.0,
|
||||
"total": 2.0,
|
||||
"used": 0.0,
|
||||
},
|
||||
"USDT": {
|
||||
"free": 50.0,
|
||||
"total": 100.0,
|
||||
@@ -590,8 +597,10 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers):
|
||||
|
||||
assert pytest.approx(result["total"]) == 2824.83464
|
||||
assert pytest.approx(result["value"]) == 2824.83464 * 1.2
|
||||
assert tickers.call_count == 1
|
||||
assert tickers.call_count == 2
|
||||
assert tickers.call_args_list[0][1]["cached"] is True
|
||||
# Testing futures - so we should get spot tickers
|
||||
assert tickers.call_args_list[1][1]["market_type"] == "spot"
|
||||
assert "USD" == result["symbol"]
|
||||
assert result["currencies"] == [
|
||||
{
|
||||
@@ -622,6 +631,20 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers):
|
||||
"is_bot_managed": False,
|
||||
"is_position": False,
|
||||
},
|
||||
{
|
||||
"currency": "NotACoin",
|
||||
"balance": 2.0,
|
||||
"bot_owned": 0,
|
||||
"est_stake": 0,
|
||||
"est_stake_bot": 0,
|
||||
"free": 0.0,
|
||||
"is_bot_managed": False,
|
||||
"is_position": False,
|
||||
"position": 0,
|
||||
"side": "long",
|
||||
"stake": "USDT",
|
||||
"used": 0.0,
|
||||
},
|
||||
{
|
||||
"currency": "USDT",
|
||||
"free": 50.0,
|
||||
|
||||
@@ -168,7 +168,7 @@ def test_get_trade_stake_amount_unlimited_amount(
|
||||
assert result == 0
|
||||
|
||||
freqtrade.config["dry_run_wallet"] = 200
|
||||
freqtrade.wallets._start_cap = 200
|
||||
freqtrade.wallets._start_cap["BTC"] = 200
|
||||
result = freqtrade.wallets.get_trade_stake_amount("XRP/USDT", 3)
|
||||
assert round(result, 4) == round(result2, 4)
|
||||
|
||||
@@ -451,3 +451,63 @@ def test_check_exit_amount_futures(mocker, default_conf, fee):
|
||||
assert freqtrade.wallets.check_exit_amount(trade) is False
|
||||
assert total_mock.call_count == 0
|
||||
assert update_mock.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"config,wallets",
|
||||
[
|
||||
(
|
||||
{"stake_currency": "USDT", "dry_run_wallet": 1000.0},
|
||||
{"USDT": {"currency": "USDT", "free": 1000.0, "used": 0.0, "total": 1000.0}},
|
||||
),
|
||||
(
|
||||
{"stake_currency": "USDT", "dry_run_wallet": {"USDT": 1000.0, "BTC": 0.1, "ETH": 2.0}},
|
||||
{
|
||||
"USDT": {"currency": "USDT", "free": 1000.0, "used": 0.0, "total": 1000.0},
|
||||
"BTC": {"currency": "BTC", "free": 0.1, "used": 0.0, "total": 0.1},
|
||||
"ETH": {"currency": "ETH", "free": 2.0, "used": 0.0, "total": 2.0},
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_dry_run_wallet_initialization(mocker, default_conf_usdt, config, wallets):
|
||||
default_conf_usdt.update(config)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
|
||||
# Verify each wallet matches the expected values
|
||||
for currency, expected_wallet in wallets.items():
|
||||
wallet = freqtrade.wallets._wallets[currency]
|
||||
assert wallet.currency == expected_wallet["currency"]
|
||||
assert wallet.free == expected_wallet["free"]
|
||||
assert wallet.used == expected_wallet["used"]
|
||||
assert wallet.total == expected_wallet["total"]
|
||||
|
||||
# Verify no extra wallets were created
|
||||
assert len(freqtrade.wallets._wallets) == len(wallets)
|
||||
|
||||
# Create a trade and verify the new currency is added to the wallets
|
||||
mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=0.0)
|
||||
mocker.patch(f"{EXMS}.get_rate", return_value=2.22)
|
||||
mocker.patch(
|
||||
f"{EXMS}.fetch_ticker",
|
||||
return_value={
|
||||
"bid": 0.20,
|
||||
"ask": 0.22,
|
||||
"last": 0.22,
|
||||
},
|
||||
)
|
||||
freqtrade.execute_entry("NEO/USDT", 100.0)
|
||||
|
||||
# Update wallets and verify NEO is now included
|
||||
freqtrade.wallets.update()
|
||||
assert "NEO" in freqtrade.wallets._wallets
|
||||
|
||||
assert freqtrade.wallets._wallets["NEO"].total == 45.04504504 # 100 USDT / 0.22
|
||||
assert freqtrade.wallets._wallets["NEO"].used == 0.0
|
||||
assert freqtrade.wallets._wallets["NEO"].free == 45.04504504
|
||||
|
||||
# Verify USDT wallet was reduced by trade amount
|
||||
assert (
|
||||
pytest.approx(freqtrade.wallets._wallets["USDT"].total) == wallets["USDT"]["total"] - 100.0
|
||||
)
|
||||
assert len(freqtrade.wallets._wallets) == len(wallets) + 1 # Original wallets + NEO
|
||||
|
||||
Reference in New Issue
Block a user