Improve performance of some RPC calls

These don't need orders to be loaded. As a side-effect, this will
also reduce the strain on the database.
This commit is contained in:
Matthias 2022-06-19 16:13:00 +02:00
parent 0809f9aef6
commit 0d967f93ba
3 changed files with 30 additions and 6 deletions

View File

@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional
from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String, from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String,
UniqueConstraint, desc, func) UniqueConstraint, desc, func)
from sqlalchemy.orm import Query, relationship from sqlalchemy.orm import Query, lazyload, relationship
from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, BuySell, LongShort from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, BuySell, LongShort
from freqtrade.enums import ExitType, TradingMode from freqtrade.enums import ExitType, TradingMode
@ -1115,7 +1115,7 @@ class Trade(_DECL_BASE, LocalTrade):
) )
@staticmethod @staticmethod
def get_trades(trade_filter=None) -> Query: def get_trades(trade_filter=None, include_orders: bool = True) -> Query:
""" """
Helper function to query Trades using filters. Helper function to query Trades using filters.
NOTE: Not supported in Backtesting. NOTE: Not supported in Backtesting.
@ -1130,9 +1130,14 @@ class Trade(_DECL_BASE, LocalTrade):
if trade_filter is not None: if trade_filter is not None:
if not isinstance(trade_filter, list): if not isinstance(trade_filter, list):
trade_filter = [trade_filter] trade_filter = [trade_filter]
return Trade.query.filter(*trade_filter) this_query = Trade.query.filter(*trade_filter)
else: else:
return Trade.query this_query = Trade.query
if not include_orders:
# Don't load order relations
# Consider using noload or raiseload instead of lazyload
this_query = this_query.options(lazyload(Trade.orders))
return this_query
@staticmethod @staticmethod
def get_open_order_trades() -> List['Trade']: def get_open_order_trades() -> List['Trade']:

View File

@ -380,7 +380,7 @@ class RPC:
return 'losses' return 'losses'
else: else:
return 'draws' return 'draws'
trades: List[Trade] = Trade.get_trades([Trade.is_open.is_(False)]) trades: List[Trade] = Trade.get_trades([Trade.is_open.is_(False)], include_orders=False)
# Sell reason # Sell reason
exit_reasons = {} exit_reasons = {}
for trade in trades: for trade in trades:
@ -408,7 +408,8 @@ class RPC:
""" Returns cumulative profit statistics """ """ Returns cumulative profit statistics """
trade_filter = ((Trade.is_open.is_(False) & (Trade.close_date >= start_date)) | trade_filter = ((Trade.is_open.is_(False) & (Trade.close_date >= start_date)) |
Trade.is_open.is_(True)) Trade.is_open.is_(True))
trades: List[Trade] = Trade.get_trades(trade_filter).order_by(Trade.id).all() trades: List[Trade] = Trade.get_trades(
trade_filter, include_orders=False).order_by(Trade.id).all()
profit_all_coin = [] profit_all_coin = []
profit_all_ratio = [] profit_all_ratio = []

View File

@ -2075,6 +2075,24 @@ def test_get_trades_proxy(fee, use_db, is_short):
Trade.use_db = True Trade.use_db = True
@pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize('is_short', [True, False])
def test_get_trades__query(fee, is_short):
query = Trade.get_trades([])
# without orders there should be no join issued.
query1 = Trade.get_trades([], include_orders=False)
assert "JOIN orders" in str(query)
assert "JOIN orders" not in str(query1)
create_mock_trades(fee, is_short)
query = Trade.get_trades([])
query1 = Trade.get_trades([], include_orders=False)
assert "JOIN orders" in str(query)
assert "JOIN orders" not in str(query1)
def test_get_trades_backtest(): def test_get_trades_backtest():
Trade.use_db = False Trade.use_db = False
with pytest.raises(NotImplementedError, match=r"`Trade.get_trades\(\)` not .*"): with pytest.raises(NotImplementedError, match=r"`Trade.get_trades\(\)` not .*"):