Merge pull request #9665 from freqtrade/no-db-context

Add No db context to protect certain functions that run in a backtest-like mode
This commit is contained in:
Matthias
2024-01-11 06:53:51 +01:00
committed by GitHub
6 changed files with 81 additions and 21 deletions

View File

@@ -15,6 +15,7 @@ def start_test_pairlist(args: Dict[str, Any]) -> None:
""" """
Test Pairlist configuration Test Pairlist configuration
""" """
from freqtrade.persistence import FtNoDBContext
from freqtrade.plugins.pairlistmanager import PairListManager from freqtrade.plugins.pairlistmanager import PairListManager
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
@@ -24,11 +25,12 @@ def start_test_pairlist(args: Dict[str, Any]) -> None:
if not quote_currencies: if not quote_currencies:
quote_currencies = [config.get('stake_currency')] quote_currencies = [config.get('stake_currency')]
results = {} results = {}
for curr in quote_currencies: with FtNoDBContext():
config['stake_currency'] = curr for curr in quote_currencies:
pairlists = PairListManager(exchange, config) config['stake_currency'] = curr
pairlists.refresh_pairlist() pairlists = PairListManager(exchange, config)
results[curr] = pairlists.whitelist pairlists.refresh_pairlist()
results[curr] = pairlists.whitelist
for curr, pairlist in results.items(): for curr, pairlist in results.items():
if not args.get('print_one_column', False) and not args.get('list_pairs_print_json', False): if not args.get('print_one_column', False) and not args.get('list_pairs_print_json', False):

View File

@@ -33,7 +33,8 @@ from freqtrade.optimize.optimize_reports import (generate_backtest_stats, genera
show_backtest_results, show_backtest_results,
store_backtest_analysis_results, store_backtest_analysis_results,
store_backtest_stats) store_backtest_stats)
from freqtrade.persistence import LocalTrade, Order, PairLocks, Trade from freqtrade.persistence import (LocalTrade, Order, PairLocks, Trade, disable_database_use,
enable_database_use)
from freqtrade.plugins.pairlistmanager import PairListManager from freqtrade.plugins.pairlistmanager import PairListManager
from freqtrade.plugins.protectionmanager import ProtectionManager from freqtrade.plugins.protectionmanager import ProtectionManager
from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.resolvers import ExchangeResolver, StrategyResolver
@@ -177,8 +178,7 @@ class Backtesting:
@staticmethod @staticmethod
def cleanup(): def cleanup():
LoggingMixin.show_output = True LoggingMixin.show_output = True
PairLocks.use_db = True enable_database_use()
Trade.use_db = True
def init_backtest_detail(self) -> None: def init_backtest_detail(self) -> None:
# Load detail timeframe if specified # Load detail timeframe if specified
@@ -325,9 +325,7 @@ class Backtesting:
self.futures_data = {} self.futures_data = {}
def disable_database_use(self): def disable_database_use(self):
PairLocks.use_db = False disable_database_use(self.timeframe)
PairLocks.timeframe = self.timeframe
Trade.use_db = False
def prepare_backtest(self, enable_protections): def prepare_backtest(self, enable_protections):
""" """

View File

@@ -4,3 +4,5 @@ from freqtrade.persistence.key_value_store import KeyStoreKeys, KeyValueStore
from freqtrade.persistence.models import init_db from freqtrade.persistence.models import init_db
from freqtrade.persistence.pairlock_middleware import PairLocks from freqtrade.persistence.pairlock_middleware import PairLocks
from freqtrade.persistence.trade_model import LocalTrade, Order, Trade from freqtrade.persistence.trade_model import LocalTrade, Order, Trade
from freqtrade.persistence.usedb_context import (FtNoDBContext, disable_database_use,
enable_database_use)

View File

@@ -0,0 +1,33 @@
from freqtrade.persistence.pairlock_middleware import PairLocks
from freqtrade.persistence.trade_model import Trade
def disable_database_use(timeframe: str) -> None:
"""
Disable database usage for PairLocks and Trade models.
Used for backtesting, and some other utility commands.
"""
PairLocks.use_db = False
PairLocks.timeframe = timeframe
Trade.use_db = False
def enable_database_use() -> None:
"""
Cleanup function to restore database usage.
"""
PairLocks.use_db = True
PairLocks.timeframe = ''
Trade.use_db = True
class FtNoDBContext:
def __init__(self, timeframe: str = ''):
self.timeframe = timeframe
def __enter__(self):
disable_database_use(self.timeframe)
def __exit__(self, exc_type, exc_val, exc_tb):
enable_database_use()

View File

@@ -7,6 +7,7 @@ from fastapi.exceptions import HTTPException
from freqtrade.constants import Config from freqtrade.constants import Config
from freqtrade.enums import CandleType from freqtrade.enums import CandleType
from freqtrade.exceptions import OperationalException from freqtrade.exceptions import OperationalException
from freqtrade.persistence import FtNoDBContext
from freqtrade.rpc.api_server.api_schemas import (BackgroundTaskStatus, BgJobStarted, from freqtrade.rpc.api_server.api_schemas import (BackgroundTaskStatus, BgJobStarted,
ExchangeModePayloadMixin, PairListsPayload, ExchangeModePayloadMixin, PairListsPayload,
PairListsResponse, WhitelistEvaluateResponse) PairListsResponse, WhitelistEvaluateResponse)
@@ -57,16 +58,16 @@ def __run_pairlist(job_id: str, config_loc: Config):
ApiBG.jobs[job_id]['is_running'] = True ApiBG.jobs[job_id]['is_running'] = True
from freqtrade.plugins.pairlistmanager import PairListManager from freqtrade.plugins.pairlistmanager import PairListManager
with FtNoDBContext():
exchange = get_exchange(config_loc) exchange = get_exchange(config_loc)
pairlists = PairListManager(exchange, config_loc) pairlists = PairListManager(exchange, config_loc)
pairlists.refresh_pairlist() pairlists.refresh_pairlist()
ApiBG.jobs[job_id]['result'] = { ApiBG.jobs[job_id]['result'] = {
'method': pairlists.name_list, 'method': pairlists.name_list,
'length': len(pairlists.whitelist), 'length': len(pairlists.whitelist),
'whitelist': pairlists.whitelist 'whitelist': pairlists.whitelist
} }
ApiBG.jobs[job_id]['status'] = 'success' ApiBG.jobs[job_id]['status'] = 'success'
except (OperationalException, Exception) as e: except (OperationalException, Exception) as e:
logger.exception(e) logger.exception(e)
ApiBG.jobs[job_id]['error'] = str(e) ApiBG.jobs[job_id]['error'] = str(e)

View File

@@ -0,0 +1,24 @@
import pytest
from freqtrade.persistence import FtNoDBContext, PairLocks, Trade
@pytest.mark.parametrize('timeframe', ['', '5m', '1d'])
def test_FtNoDBContext(timeframe):
PairLocks.timeframe = ''
assert Trade.use_db is True
assert PairLocks.use_db is True
assert PairLocks.timeframe == ''
with FtNoDBContext(timeframe):
assert Trade.use_db is False
assert PairLocks.use_db is False
assert PairLocks.timeframe == timeframe
with FtNoDBContext():
assert Trade.use_db is False
assert PairLocks.use_db is False
assert PairLocks.timeframe == ''
assert Trade.use_db is True
assert PairLocks.use_db is True