remove usage of .query from regular models
This commit is contained in:
		| @@ -7,7 +7,8 @@ from datetime import datetime, timedelta, timezone | |||||||
| from math import isclose | from math import isclose | ||||||
| from typing import Any, ClassVar, Dict, List, Optional, cast | from typing import Any, ClassVar, Dict, List, Optional, cast | ||||||
|  |  | ||||||
| from sqlalchemy import Enum, Float, ForeignKey, Integer, String, UniqueConstraint, desc, func | from sqlalchemy import (Enum, Float, ForeignKey, Integer, Result, Select, String, UniqueConstraint, | ||||||
|  |                         desc, func, select) | ||||||
| from sqlalchemy.orm import (Mapped, Query, QueryPropertyDescriptor, lazyload, mapped_column, | from sqlalchemy.orm import (Mapped, Query, QueryPropertyDescriptor, lazyload, mapped_column, | ||||||
|                             relationship) |                             relationship) | ||||||
|  |  | ||||||
| @@ -1153,7 +1154,9 @@ class LocalTrade(): | |||||||
|         get open trade count |         get open trade count | ||||||
|         """ |         """ | ||||||
|         if Trade.use_db: |         if Trade.use_db: | ||||||
|             return Trade.query.filter(Trade.is_open.is_(True)).count() |             return Trade._session.scalar( | ||||||
|  |                 select(func.count(Trade.id)).filter(Trade.is_open.is_(True)) | ||||||
|  |             ) | ||||||
|         else: |         else: | ||||||
|             return LocalTrade.bt_open_open_trade_count |             return LocalTrade.bt_open_open_trade_count | ||||||
|  |  | ||||||
| @@ -1287,18 +1290,18 @@ class Trade(ModelBase, LocalTrade): | |||||||
|     def delete(self) -> None: |     def delete(self) -> None: | ||||||
|  |  | ||||||
|         for order in self.orders: |         for order in self.orders: | ||||||
|             Order.query.session.delete(order) |             Order._session.delete(order) | ||||||
|  |  | ||||||
|         Trade.query.session.delete(self) |         Trade._session.delete(self) | ||||||
|         Trade.commit() |         Trade.commit() | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def commit(): |     def commit(): | ||||||
|         Trade.query.session.commit() |         Trade._session.commit() | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def rollback(): |     def rollback(): | ||||||
|         Trade.query.session.rollback() |         Trade._session.rollback() | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def get_trades_proxy(*, pair: Optional[str] = None, is_open: Optional[bool] = None, |     def get_trades_proxy(*, pair: Optional[str] = None, is_open: Optional[bool] = None, | ||||||
| @@ -1332,7 +1335,7 @@ class Trade(ModelBase, LocalTrade): | |||||||
|             ) |             ) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def get_trades(trade_filter=None, include_orders: bool = True) -> Query['Trade']: |     def get_trades_query(trade_filter=None, include_orders: bool = True) -> Select['Trade']: | ||||||
|         """ |         """ | ||||||
|         Helper function to query Trades using filters. |         Helper function to query Trades using filters. | ||||||
|         NOTE: Not supported in Backtesting. |         NOTE: Not supported in Backtesting. | ||||||
| @@ -1347,15 +1350,28 @@ class Trade(ModelBase, 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] | ||||||
|             this_query = Trade.query.filter(*trade_filter) |             this_query = select(Trade).filter(*trade_filter) | ||||||
|         else: |         else: | ||||||
|             this_query = Trade.query |             this_query = select(Trade) | ||||||
|         if not include_orders: |         if not include_orders: | ||||||
|             # Don't load order relations |             # Don't load order relations | ||||||
|             # Consider using noload or raiseload instead of lazyload |             # Consider using noload or raiseload instead of lazyload | ||||||
|             this_query = this_query.options(lazyload(Trade.orders)) |             this_query = this_query.options(lazyload(Trade.orders)) | ||||||
|         return this_query |         return this_query | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def get_trades(trade_filter=None, include_orders: bool = True) -> Query['Trade']: | ||||||
|  |         """ | ||||||
|  |         Helper function to query Trades using filters. | ||||||
|  |         NOTE: Not supported in Backtesting. | ||||||
|  |         :param trade_filter: Optional filter to apply to trades | ||||||
|  |                              Can be either a Filter object, or a List of filters | ||||||
|  |                              e.g. `(trade_filter=[Trade.id == trade_id, Trade.is_open.is_(True),])` | ||||||
|  |                              e.g. `(trade_filter=Trade.id == trade_id)` | ||||||
|  |         :return: unsorted query object | ||||||
|  |         """ | ||||||
|  |         return Trade._session.execute(Trade.get_trades_query(trade_filter, include_orders)) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def get_open_order_trades() -> List['Trade']: |     def get_open_order_trades() -> List['Trade']: | ||||||
|         """ |         """ | ||||||
| @@ -1392,8 +1408,9 @@ class Trade(ModelBase, LocalTrade): | |||||||
|         Retrieves total realized profit |         Retrieves total realized profit | ||||||
|         """ |         """ | ||||||
|         if Trade.use_db: |         if Trade.use_db: | ||||||
|             total_profit = Trade.query.with_entities( |             total_profit = Trade._session.scalar( | ||||||
|                 func.sum(Trade.close_profit_abs)).filter(Trade.is_open.is_(False)).scalar() |                 select(func.sum(Trade.close_profit_abs)).filter(Trade.is_open.is_(False)) | ||||||
|  |             ) | ||||||
|         else: |         else: | ||||||
|             total_profit = sum( |             total_profit = sum( | ||||||
|                 t.close_profit_abs for t in LocalTrade.get_trades_proxy(is_open=False)) |                 t.close_profit_abs for t in LocalTrade.get_trades_proxy(is_open=False)) | ||||||
| @@ -1406,8 +1423,9 @@ class Trade(ModelBase, LocalTrade): | |||||||
|         in stake currency |         in stake currency | ||||||
|         """ |         """ | ||||||
|         if Trade.use_db: |         if Trade.use_db: | ||||||
|             total_open_stake_amount = Trade.query.with_entities( |             total_open_stake_amount = Trade._session.scalar( | ||||||
|                 func.sum(Trade.stake_amount)).filter(Trade.is_open.is_(True)).scalar() |                 select(func.sum(Trade.stake_amount)).filter(Trade.is_open.is_(True)) | ||||||
|  |             ) | ||||||
|         else: |         else: | ||||||
|             total_open_stake_amount = sum( |             total_open_stake_amount = sum( | ||||||
|                 t.stake_amount for t in LocalTrade.get_trades_proxy(is_open=True)) |                 t.stake_amount for t in LocalTrade.get_trades_proxy(is_open=True)) | ||||||
| @@ -1423,15 +1441,18 @@ class Trade(ModelBase, LocalTrade): | |||||||
|         if minutes: |         if minutes: | ||||||
|             start_date = datetime.now(timezone.utc) - timedelta(minutes=minutes) |             start_date = datetime.now(timezone.utc) - timedelta(minutes=minutes) | ||||||
|             filters.append(Trade.close_date >= start_date) |             filters.append(Trade.close_date >= start_date) | ||||||
|         pair_rates = Trade.query.with_entities( |  | ||||||
|  |         pair_rates = Trade._session.execute( | ||||||
|  |             select( | ||||||
|                 Trade.pair, |                 Trade.pair, | ||||||
|                 func.sum(Trade.close_profit).label('profit_sum'), |                 func.sum(Trade.close_profit).label('profit_sum'), | ||||||
|                 func.sum(Trade.close_profit_abs).label('profit_sum_abs'), |                 func.sum(Trade.close_profit_abs).label('profit_sum_abs'), | ||||||
|                 func.count(Trade.pair).label('count') |                 func.count(Trade.pair).label('count') | ||||||
|         ).filter(*filters)\ |             ).filter(*filters) | ||||||
|             .group_by(Trade.pair) \ |             .group_by(Trade.pair) | ||||||
|             .order_by(desc('profit_sum_abs')) \ |             .order_by(desc('profit_sum_abs')) | ||||||
|             .all() |             ).all() | ||||||
|  |  | ||||||
|         return [ |         return [ | ||||||
|             { |             { | ||||||
|                 'pair': pair, |                 'pair': pair, | ||||||
| @@ -1456,15 +1477,16 @@ class Trade(ModelBase, LocalTrade): | |||||||
|         if (pair is not None): |         if (pair is not None): | ||||||
|             filters.append(Trade.pair == pair) |             filters.append(Trade.pair == pair) | ||||||
|  |  | ||||||
|         enter_tag_perf = Trade.query.with_entities( |         enter_tag_perf = Trade._session.execute( | ||||||
|  |             select( | ||||||
|                 Trade.enter_tag, |                 Trade.enter_tag, | ||||||
|                 func.sum(Trade.close_profit).label('profit_sum'), |                 func.sum(Trade.close_profit).label('profit_sum'), | ||||||
|                 func.sum(Trade.close_profit_abs).label('profit_sum_abs'), |                 func.sum(Trade.close_profit_abs).label('profit_sum_abs'), | ||||||
|                 func.count(Trade.pair).label('count') |                 func.count(Trade.pair).label('count') | ||||||
|         ).filter(*filters)\ |             ).filter(*filters) | ||||||
|             .group_by(Trade.enter_tag) \ |             .group_by(Trade.enter_tag) | ||||||
|             .order_by(desc('profit_sum_abs')) \ |             .order_by(desc('profit_sum_abs')) | ||||||
|             .all() |         ).all() | ||||||
|  |  | ||||||
|         return [ |         return [ | ||||||
|             { |             { | ||||||
| @@ -1488,16 +1510,16 @@ class Trade(ModelBase, LocalTrade): | |||||||
|         filters: List = [Trade.is_open.is_(False)] |         filters: List = [Trade.is_open.is_(False)] | ||||||
|         if (pair is not None): |         if (pair is not None): | ||||||
|             filters.append(Trade.pair == pair) |             filters.append(Trade.pair == pair) | ||||||
|  |         sell_tag_perf = Trade._session.execute( | ||||||
|         sell_tag_perf = Trade.query.with_entities( |             select( | ||||||
|                 Trade.exit_reason, |                 Trade.exit_reason, | ||||||
|                 func.sum(Trade.close_profit).label('profit_sum'), |                 func.sum(Trade.close_profit).label('profit_sum'), | ||||||
|                 func.sum(Trade.close_profit_abs).label('profit_sum_abs'), |                 func.sum(Trade.close_profit_abs).label('profit_sum_abs'), | ||||||
|                 func.count(Trade.pair).label('count') |                 func.count(Trade.pair).label('count') | ||||||
|         ).filter(*filters)\ |             ).filter(*filters) | ||||||
|             .group_by(Trade.exit_reason) \ |             .group_by(Trade.exit_reason) | ||||||
|             .order_by(desc('profit_sum_abs')) \ |             .order_by(desc('profit_sum_abs')) | ||||||
|             .all() |         ).all() | ||||||
|  |  | ||||||
|         return [ |         return [ | ||||||
|             { |             { | ||||||
| @@ -1521,18 +1543,18 @@ class Trade(ModelBase, LocalTrade): | |||||||
|         filters: List = [Trade.is_open.is_(False)] |         filters: List = [Trade.is_open.is_(False)] | ||||||
|         if (pair is not None): |         if (pair is not None): | ||||||
|             filters.append(Trade.pair == pair) |             filters.append(Trade.pair == pair) | ||||||
|  |         mix_tag_perf = Trade._session.execute( | ||||||
|         mix_tag_perf = Trade.query.with_entities( |             select( | ||||||
|                 Trade.id, |                 Trade.id, | ||||||
|                 Trade.enter_tag, |                 Trade.enter_tag, | ||||||
|                 Trade.exit_reason, |                 Trade.exit_reason, | ||||||
|                 func.sum(Trade.close_profit).label('profit_sum'), |                 func.sum(Trade.close_profit).label('profit_sum'), | ||||||
|                 func.sum(Trade.close_profit_abs).label('profit_sum_abs'), |                 func.sum(Trade.close_profit_abs).label('profit_sum_abs'), | ||||||
|                 func.count(Trade.pair).label('count') |                 func.count(Trade.pair).label('count') | ||||||
|         ).filter(*filters)\ |             ).filter(*filters) | ||||||
|             .group_by(Trade.id) \ |             .group_by(Trade.id) | ||||||
|             .order_by(desc('profit_sum_abs')) \ |             .order_by(desc('profit_sum_abs')) | ||||||
|             .all() |         ).all() | ||||||
|  |  | ||||||
|         return_list: List[Dict] = [] |         return_list: List[Dict] = [] | ||||||
|         for id, enter_tag, exit_reason, profit, profit_abs, count in mix_tag_perf: |         for id, enter_tag, exit_reason, profit, profit_abs, count in mix_tag_perf: | ||||||
| @@ -1568,11 +1590,15 @@ class Trade(ModelBase, LocalTrade): | |||||||
|         NOTE: Not supported in Backtesting. |         NOTE: Not supported in Backtesting. | ||||||
|         :returns: Tuple containing (pair, profit_sum) |         :returns: Tuple containing (pair, profit_sum) | ||||||
|         """ |         """ | ||||||
|         best_pair = Trade.query.with_entities( |         best_pair = Trade._session.execute( | ||||||
|             Trade.pair, func.sum(Trade.close_profit).label('profit_sum') |             select( | ||||||
|         ).filter(Trade.is_open.is_(False) & (Trade.close_date >= start_date)) \ |                 Trade.pair, | ||||||
|             .group_by(Trade.pair) \ |                 func.sum(Trade.close_profit).label('profit_sum') | ||||||
|             .order_by(desc('profit_sum')).first() |             ).filter(Trade.is_open.is_(False) & (Trade.close_date >= start_date)) | ||||||
|  |             .group_by(Trade.pair) | ||||||
|  |             .order_by(desc('profit_sum')) | ||||||
|  |         ).first() | ||||||
|  |  | ||||||
|         return best_pair |         return best_pair | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import logging | |||||||
| from abc import abstractmethod | from abc import abstractmethod | ||||||
| from datetime import date, datetime, timedelta, timezone | from datetime import date, datetime, timedelta, timezone | ||||||
| from math import isnan | from math import isnan | ||||||
| from typing import Any, Dict, Generator, List, Optional, Tuple, Union | from typing import Any, Dict, Generator, List, Optional, Sequence, Tuple, Union | ||||||
|  |  | ||||||
| import arrow | import arrow | ||||||
| import psutil | import psutil | ||||||
| @@ -13,6 +13,7 @@ from dateutil.relativedelta import relativedelta | |||||||
| from dateutil.tz import tzlocal | from dateutil.tz import tzlocal | ||||||
| from numpy import NAN, inf, int64, mean | from numpy import NAN, inf, int64, mean | ||||||
| from pandas import DataFrame, NaT | from pandas import DataFrame, NaT | ||||||
|  | from sqlalchemy import func, select | ||||||
|  |  | ||||||
| from freqtrade import __version__ | from freqtrade import __version__ | ||||||
| from freqtrade.configuration.timerange import TimeRange | from freqtrade.configuration.timerange import TimeRange | ||||||
| @@ -339,11 +340,18 @@ class RPC: | |||||||
|         for day in range(0, timescale): |         for day in range(0, timescale): | ||||||
|             profitday = start_date - time_offset(day) |             profitday = start_date - time_offset(day) | ||||||
|             # Only query for necessary columns for performance reasons. |             # Only query for necessary columns for performance reasons. | ||||||
|             trades = Trade.query.session.query(Trade.close_profit_abs).filter( |             trades = Trade._session.execute( | ||||||
|                 Trade.is_open.is_(False), |                 select(Trade.close_profit_abs) | ||||||
|  |                 .filter(Trade.is_open.is_(False), | ||||||
|                         Trade.close_date >= profitday, |                         Trade.close_date >= profitday, | ||||||
|                 Trade.close_date < (profitday + time_offset(1)) |                         Trade.close_date < (profitday + time_offset(1))) | ||||||
|             ).order_by(Trade.close_date).all() |                 .order_by(Trade.close_date) | ||||||
|  |             ).all() | ||||||
|  |             # trades = Trade.query.session.query(Trade.close_profit_abs).filter( | ||||||
|  |             #     Trade.is_open.is_(False), | ||||||
|  |             #     Trade.close_date >= profitday, | ||||||
|  |             #     Trade.close_date < (profitday + time_offset(1)) | ||||||
|  |             # ).order_by(Trade.close_date).all() | ||||||
|  |  | ||||||
|             curdayprofit = sum( |             curdayprofit = sum( | ||||||
|                 trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) |                 trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) | ||||||
| @@ -381,14 +389,19 @@ class RPC: | |||||||
|         """ Returns the X last trades """ |         """ Returns the X last trades """ | ||||||
|         order_by: Any = Trade.id if order_by_id else Trade.close_date.desc() |         order_by: Any = Trade.id if order_by_id else Trade.close_date.desc() | ||||||
|         if limit: |         if limit: | ||||||
|             trades = Trade.get_trades([Trade.is_open.is_(False)]).order_by( |             trades = Trade._session.execute( | ||||||
|                 order_by).limit(limit).offset(offset) |                 Trade.get_trades_query([Trade.is_open.is_(False)]) | ||||||
|  |                 .order_by(order_by) | ||||||
|  |                 .limit(limit) | ||||||
|  |                 .offset(offset)) | ||||||
|         else: |         else: | ||||||
|             trades = Trade.get_trades([Trade.is_open.is_(False)]).order_by( |             trades = Trade._session.execute( | ||||||
|                 Trade.close_date.desc()) |                 Trade.get_trades_query([Trade.is_open.is_(False)]) | ||||||
|  |                 .order_by(Trade.close_date.desc())) | ||||||
|  |  | ||||||
|         output = [trade.to_json() for trade in trades] |         output = [trade.to_json() for trade in trades] | ||||||
|         total_trades = Trade.get_trades([Trade.is_open.is_(False)]).count() |         total_trades = Trade._session.scalar( | ||||||
|  |             select(func.count(Trade.id)).filter(Trade.is_open.is_(False))) | ||||||
|  |  | ||||||
|         return { |         return { | ||||||
|             "trades": output, |             "trades": output, | ||||||
| @@ -436,8 +449,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( |         trades: Sequence[Trade] = Trade._session.execute(Trade.get_trades_query( | ||||||
|             trade_filter, include_orders=False).order_by(Trade.id).all() |             trade_filter, include_orders=False).order_by(Trade.id)).all() | ||||||
|  |  | ||||||
|         profit_all_coin = [] |         profit_all_coin = [] | ||||||
|         profit_all_ratio = [] |         profit_all_ratio = [] | ||||||
|   | |||||||
| @@ -1793,17 +1793,17 @@ def test_get_trades_proxy(fee, use_db, is_short): | |||||||
| @pytest.mark.usefixtures("init_persistence") | @pytest.mark.usefixtures("init_persistence") | ||||||
| @pytest.mark.parametrize('is_short', [True, False]) | @pytest.mark.parametrize('is_short', [True, False]) | ||||||
| def test_get_trades__query(fee, is_short): | def test_get_trades__query(fee, is_short): | ||||||
|     query = Trade.get_trades([]) |     query = Trade.get_trades_query([]) | ||||||
|     # without orders there should be no join issued. |     # without orders there should be no join issued. | ||||||
|     query1 = Trade.get_trades([], include_orders=False) |     query1 = Trade.get_trades_query([], include_orders=False) | ||||||
|  |  | ||||||
|     # Empty "with-options -> default - selectin" |     # Empty "with-options -> default - selectin" | ||||||
|     assert query._with_options == () |     assert query._with_options == () | ||||||
|     assert query1._with_options != () |     assert query1._with_options != () | ||||||
|  |  | ||||||
|     create_mock_trades(fee, is_short) |     create_mock_trades(fee, is_short) | ||||||
|     query = Trade.get_trades([]) |     query = Trade.get_trades_query([]) | ||||||
|     query1 = Trade.get_trades([], include_orders=False) |     query1 = Trade.get_trades_query([], include_orders=False) | ||||||
|  |  | ||||||
|     assert query._with_options == () |     assert query._with_options == () | ||||||
|     assert query1._with_options != () |     assert query1._with_options != () | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user