Merge pull request #4454 from freqtrade/backtest_compound_speed

Backtest compound, wallet, ...
This commit is contained in:
Matthias
2021-03-10 10:07:40 +01:00
committed by GitHub
38 changed files with 715 additions and 315 deletions

View File

@@ -19,7 +19,7 @@ from freqtrade.data.converter import ohlcv_to_dataframe
from freqtrade.edge import Edge, PairInfo
from freqtrade.exchange import Exchange
from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.persistence import Trade, init_db
from freqtrade.persistence import LocalTrade, Trade, init_db
from freqtrade.resolvers import ExchangeResolver
from freqtrade.worker import Worker
from tests.conftest_trades import (mock_trade_1, mock_trade_2, mock_trade_3, mock_trade_4,
@@ -183,28 +183,34 @@ def patch_get_signal(freqtrade: FreqtradeBot, value=(True, False)) -> None:
freqtrade.exchange.refresh_latest_ohlcv = lambda p: None
def create_mock_trades(fee):
def create_mock_trades(fee, use_db: bool = True):
"""
Create some fake trades ...
"""
def add_trade(trade):
if use_db:
Trade.session.add(trade)
else:
LocalTrade.trades.append(trade)
# Simulate dry_run entries
trade = mock_trade_1(fee)
Trade.session.add(trade)
add_trade(trade)
trade = mock_trade_2(fee)
Trade.session.add(trade)
add_trade(trade)
trade = mock_trade_3(fee)
Trade.session.add(trade)
add_trade(trade)
trade = mock_trade_4(fee)
Trade.session.add(trade)
add_trade(trade)
trade = mock_trade_5(fee)
Trade.session.add(trade)
add_trade(trade)
trade = mock_trade_6(fee)
Trade.session.add(trade)
add_trade(trade)
@pytest.fixture(autouse=True)
@@ -255,6 +261,7 @@ def get_default_conf(testdatadir):
"20": 0.02,
"0": 0.04
},
"dry_run_wallet": 1000,
"stoploss": -0.10,
"unfilledtimeout": {
"buy": 10,

View File

@@ -28,6 +28,7 @@ def mock_trade_1(fee):
amount_requested=123.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
is_open=True,
open_rate=0.123,
exchange='bittrex',
open_order_id='dry_run_buy_12345',
@@ -81,6 +82,7 @@ def mock_trade_2(fee):
open_rate=0.123,
close_rate=0.128,
close_profit=0.005,
close_profit_abs=0.000584127,
exchange='bittrex',
is_open=False,
open_order_id='dry_run_sell_12345',
@@ -140,6 +142,7 @@ def mock_trade_3(fee):
open_rate=0.05,
close_rate=0.06,
close_profit=0.01,
close_profit_abs=0.000155,
exchange='bittrex',
is_open=False,
strategy='DefaultStrategy',
@@ -180,6 +183,7 @@ def mock_trade_4(fee):
amount_requested=124.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
is_open=True,
open_rate=0.123,
exchange='bittrex',
open_order_id='prod_buy_12345',
@@ -230,6 +234,7 @@ def mock_trade_5(fee):
amount_requested=124.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
is_open=True,
open_rate=0.123,
exchange='bittrex',
strategy='SampleStrategy',
@@ -281,6 +286,7 @@ def mock_trade_6(fee):
amount_requested=2.0,
fee_open=fee.return_value,
fee_close=fee.return_value,
is_open=True,
open_rate=0.15,
exchange='bittrex',
strategy='SampleStrategy',

View File

@@ -274,15 +274,17 @@ def test_create_cum_profit1(testdatadir):
def test_calculate_max_drawdown(testdatadir):
filename = testdatadir / "backtest-result_test.json"
bt_data = load_backtest_data(filename)
drawdown, h, low = calculate_max_drawdown(bt_data)
drawdown, hdate, lowdate, hval, lval = calculate_max_drawdown(bt_data)
assert isinstance(drawdown, float)
assert pytest.approx(drawdown) == 0.21142322
assert isinstance(h, Timestamp)
assert isinstance(low, Timestamp)
assert h == Timestamp('2018-01-24 14:25:00', tz='UTC')
assert low == Timestamp('2018-01-30 04:45:00', tz='UTC')
assert isinstance(hdate, Timestamp)
assert isinstance(lowdate, Timestamp)
assert isinstance(hval, float)
assert isinstance(lval, float)
assert hdate == Timestamp('2018-01-24 14:25:00', tz='UTC')
assert lowdate == Timestamp('2018-01-30 04:45:00', tz='UTC')
with pytest.raises(ValueError, match='Trade dataframe empty.'):
drawdown, h, low = calculate_max_drawdown(DataFrame())
drawdown, hdate, lowdate, hval, lval = calculate_max_drawdown(DataFrame())
def test_calculate_csum(testdatadir):
@@ -294,6 +296,10 @@ def test_calculate_csum(testdatadir):
assert isinstance(csum_max, float)
assert csum_min < 0.01
assert csum_max > 0.02
csum_min1, csum_max1 = calculate_csum(bt_data, 5)
assert csum_min1 == csum_min + 5
assert csum_max1 == csum_max + 5
with pytest.raises(ValueError, match='Trade dataframe empty.'):
csum_min, csum_max = calculate_csum(DataFrame())
@@ -310,13 +316,16 @@ def test_calculate_max_drawdown2():
# sort by profit and reset index
df = df.sort_values('profit').reset_index(drop=True)
df1 = df.copy()
drawdown, h, low = calculate_max_drawdown(df, date_col='open_date', value_col='profit')
drawdown, hdate, ldate, hval, lval = calculate_max_drawdown(
df, date_col='open_date', value_col='profit')
# Ensure df has not been altered.
assert df.equals(df1)
assert isinstance(drawdown, float)
# High must be before low
assert h < low
assert hdate < ldate
# High value must be higher than low value
assert hval > lval
assert drawdown == 0.091755
df = DataFrame(zip(values[:5], dates[:5]), columns=['profit', 'open_date'])

View File

@@ -1,6 +1,5 @@
# pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103, C0330, unused-argument
import logging
from unittest.mock import MagicMock
import pytest
@@ -489,7 +488,8 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
default_conf["trailing_stop_positive_offset"] = data.trailing_stop_positive_offset
default_conf["ask_strategy"] = {"use_sell_signal": data.use_sell_signal}
mocker.patch("freqtrade.exchange.Exchange.get_fee", MagicMock(return_value=0.0))
mocker.patch("freqtrade.exchange.Exchange.get_fee", return_value=0.0)
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
patch_exchange(mocker)
frame = _build_backtest_dataframe(data.data)
backtesting = Backtesting(default_conf)
@@ -503,7 +503,6 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
min_date, max_date = get_timerange({pair: frame})
results = backtesting.backtest(
processed=data_processed,
stake_amount=default_conf['stake_amount'],
start_date=min_date,
end_date=max_date,
max_open_trades=10,
@@ -514,6 +513,6 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
for c, trade in enumerate(data.trades):
res = results.iloc[c]
assert res.sell_reason == trade.sell_reason
assert res.sell_reason == trade.sell_reason.value
assert res.open_date == _get_frame_time_from_offset(trade.open_tick)
assert res.close_date == _get_frame_time_from_offset(trade.close_tick)

View File

@@ -9,7 +9,6 @@ import pandas as pd
import pytest
from arrow import Arrow
from freqtrade import constants
from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_backtesting
from freqtrade.configuration import TimeRange
from freqtrade.data import history
@@ -19,6 +18,7 @@ from freqtrade.data.dataprovider import DataProvider
from freqtrade.data.history import get_timerange
from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.optimize.backtesting import Backtesting
from freqtrade.persistence import LocalTrade
from freqtrade.resolvers import StrategyResolver
from freqtrade.state import RunMode
from freqtrade.strategy.interface import SellType
@@ -90,7 +90,6 @@ def simple_backtest(config, contour, mocker, testdatadir) -> None:
assert isinstance(processed, dict)
results = backtesting.backtest(
processed=processed,
stake_amount=config['stake_amount'],
start_date=min_date,
end_date=max_date,
max_open_trades=1,
@@ -111,7 +110,6 @@ def _make_backtest_conf(mocker, datadir, conf=None, pair='UNITTEST/BTC'):
min_date, max_date = get_timerange(processed)
return {
'processed': processed,
'stake_amount': conf['stake_amount'],
'start_date': min_date,
'end_date': max_date,
'max_open_trades': 10,
@@ -233,8 +231,7 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
assert log_has('Parameter --fee detected, setting fee to: {} ...'.format(config['fee']), caplog)
def test_setup_optimize_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None:
default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
def test_setup_optimize_configuration_stake_amount(mocker, default_conf, caplog) -> None:
patched_configuration_load_config_file(mocker, default_conf)
@@ -242,9 +239,21 @@ def test_setup_optimize_configuration_unlimited_stake_amount(mocker, default_con
'backtesting',
'--config', 'config.json',
'--strategy', 'DefaultStrategy',
'--stake-amount', '1',
'--starting-balance', '2'
]
with pytest.raises(DependencyException, match=r'.`stake_amount`.*'):
conf = setup_optimize_configuration(get_args(args), RunMode.BACKTEST)
assert isinstance(conf, dict)
args = [
'backtesting',
'--config', 'config.json',
'--strategy', 'DefaultStrategy',
'--stake-amount', '1',
'--starting-balance', '0.5'
]
with pytest.raises(OperationalException, match=r"Starting balance .* smaller .*"):
setup_optimize_configuration(get_args(args), RunMode.BACKTEST)
@@ -448,9 +457,48 @@ def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, ti
Backtesting(default_conf)
def test_backtest__enter_trade(default_conf, fee, mocker, testdatadir) -> None:
default_conf['ask_strategy']['use_sell_signal'] = False
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
patch_exchange(mocker)
default_conf['stake_amount'] = 'unlimited'
backtesting = Backtesting(default_conf)
pair = 'UNITTEST/BTC'
row = [
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0),
1, # Sell
0.001, # Open
0.0011, # Close
0, # Sell
0.00099, # Low
0.0012, # High
]
trade = backtesting._enter_trade(pair, row=row, max_open_trades=2, open_trade_count=0)
assert isinstance(trade, LocalTrade)
assert trade.stake_amount == 495
trade = backtesting._enter_trade(pair, row=row, max_open_trades=2, open_trade_count=2)
assert trade is None
# Stake-amount too high!
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=600.0)
trade = backtesting._enter_trade(pair, row=row, max_open_trades=2, open_trade_count=0)
assert trade is None
# Stake-amount too high!
mocker.patch("freqtrade.wallets.Wallets.get_trade_stake_amount",
side_effect=DependencyException)
trade = backtesting._enter_trade(pair, row=row, max_open_trades=2, open_trade_count=0)
assert trade is None
def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
default_conf['ask_strategy']['use_sell_signal'] = False
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
pair = 'UNITTEST/BTC'
@@ -461,7 +509,6 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
min_date, max_date = get_timerange(processed)
results = backtesting.backtest(
processed=processed,
stake_amount=default_conf['stake_amount'],
start_date=min_date,
end_date=max_date,
max_open_trades=10,
@@ -486,7 +533,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
'trade_duration': [235, 40],
'profit_ratio': [0.0, 0.0],
'profit_abs': [0.0, 0.0],
'sell_reason': [SellType.ROI, SellType.ROI],
'sell_reason': [SellType.ROI.value, SellType.ROI.value],
'initial_stop_loss_abs': [0.0940005, 0.09272236],
'initial_stop_loss_ratio': [-0.1, -0.1],
'stop_loss_abs': [0.0940005, 0.09272236],
@@ -512,6 +559,7 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None:
def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None:
default_conf['ask_strategy']['use_sell_signal'] = False
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
@@ -523,7 +571,6 @@ def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None
min_date, max_date = get_timerange(processed)
results = backtesting.backtest(
processed=processed,
stake_amount=default_conf['stake_amount'],
start_date=min_date,
end_date=max_date,
max_open_trades=1,
@@ -558,6 +605,7 @@ def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatad
default_conf['enable_protections'] = True
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
tests = [
['sine', 9],
['raise', 10],
@@ -589,6 +637,7 @@ def test_backtest_pricecontours(default_conf, fee, mocker, testdatadir,
default_conf['protections'] = protections
default_conf['enable_protections'] = True
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
# While buy-signals are unrealistic, running backtesting
# over and over again should not cause different results
@@ -626,6 +675,7 @@ def test_backtest_only_sell(mocker, default_conf, testdatadir):
def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir):
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
backtest_conf = _make_backtest_conf(mocker, conf=default_conf,
pair='UNITTEST/BTC', datadir=testdatadir)
@@ -658,6 +708,7 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
dataframe['sell'] = np.where((dataframe.index + multi - 2) % multi == 0, 1, 0)
return dataframe
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001)
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
patch_exchange(mocker)
@@ -678,7 +729,6 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
min_date, max_date = get_timerange(processed)
backtest_conf = {
'processed': processed,
'stake_amount': default_conf['stake_amount'],
'start_date': min_date,
'end_date': max_date,
'max_open_trades': 3,
@@ -694,7 +744,6 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
backtest_conf = {
'processed': processed,
'stake_amount': default_conf['stake_amount'],
'start_date': min_date,
'end_date': max_date,
'max_open_trades': 1,
@@ -822,6 +871,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
'2018-01-30 05:35:00', ], utc=True),
'trade_duration': [235, 40],
'is_open': [False, False],
'stake_amount': [0.01, 0.01],
'open_rate': [0.104445, 0.10302485],
'close_rate': [0.104969, 0.103541],
'sell_reason': [SellType.ROI, SellType.ROI]
@@ -838,6 +888,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
'2018-01-30 08:30:00'], utc=True),
'trade_duration': [47, 40, 20],
'is_open': [False, False, False],
'stake_amount': [0.01, 0.01, 0.01],
'open_rate': [0.104445, 0.10302485, 0.122541],
'close_rate': [0.104969, 0.103541, 0.123541],
'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]

View File

@@ -12,10 +12,9 @@ import pytest
from arrow import Arrow
from filelock import Timeout
from freqtrade import constants
from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_hyperopt
from freqtrade.data.history import load_data
from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.exceptions import OperationalException
from freqtrade.optimize.hyperopt import Hyperopt
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
from freqtrade.state import RunMode
@@ -130,8 +129,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
assert log_has('Parameter --print-all detected ...', caplog)
def test_setup_hyperopt_configuration_unlimited_stake_amount(mocker, default_conf) -> None:
default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
def test_setup_hyperopt_configuration_stake_amount(mocker, default_conf) -> None:
patched_configuration_load_config_file(mocker, default_conf)
@@ -139,9 +137,20 @@ def test_setup_hyperopt_configuration_unlimited_stake_amount(mocker, default_con
'hyperopt',
'--config', 'config.json',
'--hyperopt', 'DefaultHyperOpt',
'--stake-amount', '1',
'--starting-balance', '2'
]
conf = setup_optimize_configuration(get_args(args), RunMode.HYPEROPT)
assert isinstance(conf, dict)
with pytest.raises(DependencyException, match=r'.`stake_amount`.*'):
args = [
'hyperopt',
'--config', 'config.json',
'--strategy', 'DefaultStrategy',
'--stake-amount', '1',
'--starting-balance', '0.5'
]
with pytest.raises(OperationalException, match=r"Starting balance .* smaller .*"):
setup_optimize_configuration(get_args(args), RunMode.HYPEROPT)

View File

@@ -48,7 +48,7 @@ def test_text_table_bt_results():
)
pair_results = generate_pair_metrics(data={'ETH/BTC': {}}, stake_currency='BTC',
max_open_trades=2, results=results)
starting_balance=4, results=results)
assert text_table_bt_results(pair_results, stake_currency='BTC') == result_str
@@ -73,11 +73,13 @@ def test_generate_backtest_stats(default_conf, testdatadir):
"close_rate": [0.002546, 0.003014, 0.003103, 0.003217],
"trade_duration": [123, 34, 31, 14],
"is_open": [False, False, False, True],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"sell_reason": [SellType.ROI, SellType.STOP_LOSS,
SellType.ROI, SellType.FORCE_SELL]
}),
'config': default_conf,
'locks': [],
'final_balance': 1000.02,
'backtest_start_time': Arrow.utcnow().int_timestamp,
'backtest_end_time': Arrow.utcnow().int_timestamp,
}
@@ -100,6 +102,7 @@ def test_generate_backtest_stats(default_conf, testdatadir):
# Above sample had no loosing trade
assert strat_stats['max_drawdown'] == 0.0
# Retry with losing trade
results = {'DefStrat': {
'results': pd.DataFrame(
{"pair": ["UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC"],
@@ -116,18 +119,31 @@ def test_generate_backtest_stats(default_conf, testdatadir):
"open_rate": [0.002543, 0.003003, 0.003089, 0.003214],
"close_rate": [0.002546, 0.003014, 0.0032903, 0.003217],
"trade_duration": [123, 34, 31, 14],
"open_at_end": [False, False, False, True],
"sell_reason": [SellType.ROI, SellType.STOP_LOSS,
SellType.ROI, SellType.FORCE_SELL]
"is_open": [False, False, False, True],
"stake_amount": [0.01, 0.01, 0.01, 0.01],
"sell_reason": [SellType.ROI, SellType.ROI,
SellType.STOP_LOSS, SellType.FORCE_SELL]
}),
'config': default_conf}
'config': default_conf,
'locks': [],
'final_balance': 1000.02,
'backtest_start_time': Arrow.utcnow().int_timestamp,
'backtest_end_time': Arrow.utcnow().int_timestamp,
}
}
assert strat_stats['max_drawdown'] == 0.0
assert strat_stats['drawdown_start'] == datetime(1970, 1, 1, tzinfo=timezone.utc)
assert strat_stats['drawdown_end'] == datetime(1970, 1, 1, tzinfo=timezone.utc)
assert strat_stats['drawdown_end_ts'] == 0
assert strat_stats['drawdown_start_ts'] == 0
stats = generate_backtest_stats(btdata, results, min_date, max_date)
assert isinstance(stats, dict)
assert 'strategy' in stats
assert 'DefStrat' in stats['strategy']
assert 'strategy_comparison' in stats
strat_stats = stats['strategy']['DefStrat']
assert strat_stats['max_drawdown'] == 0.013803
assert strat_stats['drawdown_start'] == datetime(2017, 11, 14, 22, 10, tzinfo=timezone.utc)
assert strat_stats['drawdown_end'] == datetime(2017, 11, 14, 22, 43, tzinfo=timezone.utc)
assert strat_stats['drawdown_end_ts'] == 1510699380000
assert strat_stats['drawdown_start_ts'] == 1510697400000
assert strat_stats['pairlist'] == ['UNITTEST/BTC']
# Test storing stats
@@ -189,7 +205,7 @@ def test_generate_pair_metrics():
)
pair_results = generate_pair_metrics(data={'ETH/BTC': {}}, stake_currency='BTC',
max_open_trades=2, results=results)
starting_balance=2, results=results)
assert isinstance(pair_results, list)
assert len(pair_results) == 2
assert pair_results[-1]['key'] == 'TOTAL'
@@ -265,7 +281,7 @@ def test_generate_sell_reason_stats():
'wins': [2, 0, 0],
'draws': [0, 0, 0],
'losses': [0, 0, 1],
'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS]
'sell_reason': [SellType.ROI.value, SellType.ROI.value, SellType.STOP_LOSS.value]
}
)
@@ -291,6 +307,7 @@ def test_generate_sell_reason_stats():
def test_text_table_strategy(default_conf):
default_conf['max_open_trades'] = 2
default_conf['dry_run_wallet'] = 3
results = {}
results['TestStrategy1'] = {'results': pd.DataFrame(
{
@@ -323,9 +340,9 @@ def test_text_table_strategy(default_conf):
'|---------------+--------+----------------+----------------+------------------+'
'----------------+----------------+--------+---------+----------|\n'
'| TestStrategy1 | 3 | 20.00 | 60.00 | 1.10000000 |'
' 30.00 | 0:17:00 | 3 | 0 | 0 |\n'
' 36.67 | 0:17:00 | 3 | 0 | 0 |\n'
'| TestStrategy2 | 3 | 30.00 | 90.00 | 1.30000000 |'
' 45.00 | 0:20:00 | 3 | 0 | 0 |'
' 43.33 | 0:20:00 | 3 | 0 | 0 |'
)
strategy_results = generate_strategy_metrics(all_results=results)

View File

@@ -73,9 +73,13 @@ def test_PairLocks(use_db):
assert PairLocks.is_pair_locked('XRP/USDT', lock_time + timedelta(minutes=-50))
if use_db:
assert len(PairLock.query.all()) > 0
locks = PairLocks.get_all_locks()
locks_db = PairLock.query.all()
assert len(locks) == len(locks_db)
assert len(locks_db) > 0
else:
# Nothing was pushed to the database
assert len(PairLocks.get_all_locks()) > 0
assert len(PairLock.query.all()) == 0
# Reset use-db variable
PairLocks.reset_locks()

View File

@@ -430,7 +430,8 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
'--enable-position-stacking',
'--disable-max-market-positions',
'--timerange', ':100',
'--export', '/bar/foo'
'--export', '/bar/foo',
'--stake-amount', 'unlimited'
]
args = Arguments(arglist).get_parsed_arg()
@@ -463,6 +464,8 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
assert 'export' in config
assert log_has('Parameter --export detected: {} ...'.format(config['export']), caplog)
assert 'stake_amount' in config
assert config['stake_amount'] == 'unlimited'
def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> None:

View File

@@ -2243,6 +2243,7 @@ def test_check_handle_timedout_sell_usercustom(default_conf, ticker, limit_sell_
open_trade.open_date = arrow.utcnow().shift(hours=-5).datetime
open_trade.close_date = arrow.utcnow().shift(minutes=-601).datetime
open_trade.close_profit_abs = 0.001
open_trade.is_open = False
Trade.session.add(open_trade)
@@ -2290,6 +2291,7 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old,
open_trade.open_date = arrow.utcnow().shift(hours=-5).datetime
open_trade.close_date = arrow.utcnow().shift(minutes=-601).datetime
open_trade.close_profit_abs = 0.001
open_trade.is_open = False
Trade.session.add(open_trade)

View File

@@ -1,5 +1,6 @@
# pragma pylint: disable=missing-docstring, C0103
import logging
from types import FunctionType
from unittest.mock import MagicMock
import arrow
@@ -8,7 +9,7 @@ from sqlalchemy import create_engine
from freqtrade import constants
from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.persistence import Order, Trade, clean_dry_run_db, init_db
from freqtrade.persistence import LocalTrade, Order, Trade, clean_dry_run_db, init_db
from tests.conftest import create_mock_trades, log_has, log_has_re
@@ -1039,14 +1040,18 @@ def test_fee_updated(fee):
@pytest.mark.usefixtures("init_persistence")
def test_total_open_trades_stakes(fee):
@pytest.mark.parametrize('use_db', [True, False])
def test_total_open_trades_stakes(fee, use_db):
Trade.use_db = use_db
res = Trade.total_open_trades_stakes()
assert res == 0
create_mock_trades(fee)
create_mock_trades(fee, use_db)
res = Trade.total_open_trades_stakes()
assert res == 0.004
Trade.use_db = True
@pytest.mark.usefixtures("init_persistence")
def test_get_overall_performance(fee):
@@ -1172,3 +1177,25 @@ def test_select_order(fee):
assert order.ft_order_side == 'stoploss'
order = trades[4].select_order('sell', False)
assert order is None
def test_Trade_object_idem():
assert issubclass(Trade, LocalTrade)
trade = vars(Trade)
localtrade = vars(LocalTrade)
# Parent (LocalTrade) should have the same attributes
for item in trade:
# Exclude private attributes and open_date (as it's not assigned a default)
if (not item.startswith('_')
and item not in ('delete', 'session', 'query', 'open_date')):
assert item in localtrade
# Fails if only a column is added without corresponding parent field
for item in localtrade:
if (not item.startswith('__')
and item not in ('trades', )
and type(getattr(LocalTrade, item)) not in (property, FunctionType)):
assert item in trade