Merge branch 'freqtrade:develop' into strategy_utils

This commit is contained in:
hippocritical 2023-03-18 20:15:12 +01:00 committed by GitHub
commit 763f4f4a3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 363 additions and 306 deletions

View File

@ -1,7 +1,7 @@
import logging
from typing import Any, Dict
from sqlalchemy import func
from sqlalchemy import func, select
from freqtrade.configuration.config_setup import setup_utils_configuration
from freqtrade.enums import RunMode
@ -20,7 +20,7 @@ def start_convert_db(args: Dict[str, Any]) -> None:
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
init_db(config['db_url'])
session_target = Trade._session
session_target = Trade.session
init_db(config['db_url_from'])
logger.info("Starting db migration.")
@ -36,16 +36,16 @@ def start_convert_db(args: Dict[str, Any]) -> None:
session_target.commit()
for pairlock in PairLock.query:
for pairlock in PairLock.get_all_locks():
pairlock_count += 1
make_transient(pairlock)
session_target.add(pairlock)
session_target.commit()
# Update sequences
max_trade_id = session_target.query(func.max(Trade.id)).scalar()
max_order_id = session_target.query(func.max(Order.id)).scalar()
max_pairlock_id = session_target.query(func.max(PairLock.id)).scalar()
max_trade_id = session_target.scalar(select(func.max(Trade.id)))
max_order_id = session_target.scalar(select(func.max(Order.id)))
max_pairlock_id = session_target.scalar(select(func.max(PairLock.id)))
set_sequence_ids(session_target.get_bind(),
trade_id=max_trade_id,

View File

@ -373,7 +373,7 @@ def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataF
filters = []
if strategy:
filters.append(Trade.strategy == strategy)
trades = trade_list_to_dataframe(Trade.get_trades(filters).all())
trades = trade_list_to_dataframe(list(Trade.get_trades(filters).all()))
return trades

View File

@ -251,7 +251,7 @@ class FreqaiDataKitchen:
(drop_index == 0) & (drop_index_labels == 0)
]
logger.info(
f"dropped {len(unfiltered_df) - len(filtered_df)} training points"
f"{self.pair}: dropped {len(unfiltered_df) - len(filtered_df)} training points"
f" due to NaNs in populated dataset {len(unfiltered_df)}."
)
if (1 - len(filtered_df) / len(unfiltered_df)) > 0.1 and self.live:
@ -675,7 +675,7 @@ class FreqaiDataKitchen:
]
logger.info(
f"SVM tossed {len(y_pred) - kept_points.sum()}"
f"{self.pair}: SVM tossed {len(y_pred) - kept_points.sum()}"
f" test points from {len(y_pred)} total points."
)
@ -949,7 +949,7 @@ class FreqaiDataKitchen:
if (len(do_predict) - do_predict.sum()) > 0:
logger.info(
f"DI tossed {len(do_predict) - do_predict.sum()} predictions for "
f"{self.pair}: DI tossed {len(do_predict) - do_predict.sum()} predictions for "
"being too far from training data."
)

View File

@ -104,6 +104,7 @@ class IFreqaiModel(ABC):
self.data_provider: Optional[DataProvider] = None
self.max_system_threads = max(int(psutil.cpu_count() * 2 - 2), 1)
self.can_short = True # overridden in start() with strategy.can_short
self.model: Any = None
record_params(config, self.full_path)
@ -338,13 +339,14 @@ class IFreqaiModel(ABC):
except Exception as msg:
logger.warning(
f"Training {pair} raised exception {msg.__class__.__name__}. "
f"Message: {msg}, skipping.")
f"Message: {msg}, skipping.", exc_info=True)
self.model = None
self.dd.pair_dict[pair]["trained_timestamp"] = int(
tr_train.stopts)
if self.plot_features:
if self.plot_features and self.model is not None:
plot_feature_importance(self.model, pair, dk, self.plot_features)
if self.save_backtest_models:
if self.save_backtest_models and self.model is not None:
logger.info('Saving backtest model to disk.')
self.dd.save_data(self.model, pair, dk)
else:

View File

@ -819,7 +819,7 @@ class FreqtradeBot(LoggingMixin):
trade.orders.append(order_obj)
trade.recalc_trade_from_orders()
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
# Updating wallets

View File

@ -54,12 +54,9 @@ def init_db(db_url: str) -> None:
# https://docs.sqlalchemy.org/en/13/orm/contextual.html#thread-local-scope
# Scoped sessions proxy requests to the appropriate thread-local session.
# We should use the scoped_session object - not a seperately initialized version
Trade._session = scoped_session(sessionmaker(bind=engine, autoflush=False))
Order._session = Trade._session
PairLock._session = Trade._session
Trade.query = Trade._session.query_property()
Order.query = Trade._session.query_property()
PairLock.query = Trade._session.query_property()
Trade.session = scoped_session(sessionmaker(bind=engine, autoflush=False))
Order.session = Trade.session
PairLock.session = Trade.session
previous_tables = inspect(engine).get_table_names()
ModelBase.metadata.create_all(engine)

View File

@ -1,8 +1,8 @@
from datetime import datetime, timezone
from typing import Any, ClassVar, Dict, Optional
from sqlalchemy import String, or_
from sqlalchemy.orm import Mapped, Query, QueryPropertyDescriptor, mapped_column
from sqlalchemy import ScalarResult, String, or_, select
from sqlalchemy.orm import Mapped, mapped_column
from freqtrade.constants import DATETIME_PRINT_FORMAT
from freqtrade.persistence.base import ModelBase, SessionType
@ -13,8 +13,7 @@ class PairLock(ModelBase):
Pair Locks database model.
"""
__tablename__ = 'pairlocks'
query: ClassVar[QueryPropertyDescriptor]
_session: ClassVar[SessionType]
session: ClassVar[SessionType]
id: Mapped[int] = mapped_column(primary_key=True)
@ -37,7 +36,8 @@ class PairLock(ModelBase):
f'lock_end_time={lock_end_time}, reason={self.reason}, active={self.active})')
@staticmethod
def query_pair_locks(pair: Optional[str], now: datetime, side: str = '*') -> Query:
def query_pair_locks(
pair: Optional[str], now: datetime, side: str = '*') -> ScalarResult['PairLock']:
"""
Get all currently active locks for this pair
:param pair: Pair to check for. Returns all current locks if pair is empty
@ -53,9 +53,11 @@ class PairLock(ModelBase):
else:
filters.append(PairLock.side == '*')
return PairLock.query.filter(
*filters
)
return PairLock.session.scalars(select(PairLock).filter(*filters))
@staticmethod
def get_all_locks() -> ScalarResult['PairLock']:
return PairLock.session.scalars(select(PairLock))
def to_json(self) -> Dict[str, Any]:
return {

View File

@ -1,6 +1,8 @@
import logging
from datetime import datetime, timezone
from typing import List, Optional
from typing import List, Optional, Sequence
from sqlalchemy import select
from freqtrade.exchange import timeframe_to_next_date
from freqtrade.persistence.models import PairLock
@ -51,15 +53,15 @@ class PairLocks():
active=True
)
if PairLocks.use_db:
PairLock.query.session.add(lock)
PairLock.query.session.commit()
PairLock.session.add(lock)
PairLock.session.commit()
else:
PairLocks.locks.append(lock)
return lock
@staticmethod
def get_pair_locks(
pair: Optional[str], now: Optional[datetime] = None, side: str = '*') -> List[PairLock]:
def get_pair_locks(pair: Optional[str], now: Optional[datetime] = None,
side: str = '*') -> Sequence[PairLock]:
"""
Get all currently active locks for this pair
:param pair: Pair to check for. Returns all current locks if pair is empty
@ -106,7 +108,7 @@ class PairLocks():
for lock in locks:
lock.active = False
if PairLocks.use_db:
PairLock.query.session.commit()
PairLock.session.commit()
@staticmethod
def unlock_reason(reason: str, now: Optional[datetime] = None) -> None:
@ -126,11 +128,11 @@ class PairLocks():
PairLock.active.is_(True),
PairLock.reason == reason
]
locks = PairLock.query.filter(*filters)
locks = PairLock.session.scalars(select(PairLock).filter(*filters)).all()
for lock in locks:
logger.info(f"Releasing lock for {lock.pair} with reason '{reason}'.")
lock.active = False
PairLock.query.session.commit()
PairLock.session.commit()
else:
# used in backtesting mode; don't show log messages for speed
locksb = PairLocks.get_pair_locks(None)
@ -165,11 +167,11 @@ class PairLocks():
)
@staticmethod
def get_all_locks() -> List[PairLock]:
def get_all_locks() -> Sequence[PairLock]:
"""
Return all locks, also locks with expired end date
"""
if PairLocks.use_db:
return PairLock.query.all()
return PairLock.get_all_locks().all()
else:
return PairLocks.locks

View File

@ -5,11 +5,11 @@ import logging
from collections import defaultdict
from datetime import datetime, timedelta, timezone
from math import isclose
from typing import Any, ClassVar, Dict, List, Optional, cast
from typing import Any, ClassVar, Dict, List, Optional, Sequence, cast
from sqlalchemy import Enum, Float, ForeignKey, Integer, String, UniqueConstraint, desc, func
from sqlalchemy.orm import (Mapped, Query, QueryPropertyDescriptor, lazyload, mapped_column,
relationship)
from sqlalchemy import (Enum, Float, ForeignKey, Integer, ScalarResult, Select, String,
UniqueConstraint, desc, func, select)
from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship
from freqtrade.constants import (DATETIME_PRINT_FORMAT, MATH_CLOSE_PREC, NON_OPEN_EXCHANGE_STATES,
BuySell, LongShort)
@ -36,8 +36,7 @@ class Order(ModelBase):
Mirrors CCXT Order structure
"""
__tablename__ = 'orders'
query: ClassVar[QueryPropertyDescriptor]
_session: ClassVar[SessionType]
session: ClassVar[SessionType]
# Uniqueness should be ensured over pair, order_id
# its likely that order_id is unique per Pair on some exchanges.
@ -263,12 +262,12 @@ class Order(ModelBase):
return o
@staticmethod
def get_open_orders() -> List['Order']:
def get_open_orders() -> Sequence['Order']:
"""
Retrieve open orders from the database
:return: List of open orders
"""
return Order.query.filter(Order.ft_is_open.is_(True)).all()
return Order.session.scalars(select(Order).filter(Order.ft_is_open.is_(True))).all()
@staticmethod
def order_by_id(order_id: str) -> Optional['Order']:
@ -276,7 +275,7 @@ class Order(ModelBase):
Retrieve order based on order_id
:return: Order or None
"""
return Order.query.filter(Order.order_id == order_id).first()
return Order.session.scalars(select(Order).filter(Order.order_id == order_id)).first()
class LocalTrade():
@ -1153,7 +1152,9 @@ class LocalTrade():
get open trade count
"""
if Trade.use_db:
return Trade.query.filter(Trade.is_open.is_(True)).count()
return Trade.session.execute(
select(func.count(Trade.id)).filter(Trade.is_open.is_(True))
).scalar_one()
else:
return LocalTrade.bt_open_open_trade_count
@ -1186,8 +1187,7 @@ class Trade(ModelBase, LocalTrade):
Note: Fields must be aligned with LocalTrade class
"""
__tablename__ = 'trades'
query: ClassVar[QueryPropertyDescriptor]
_session: ClassVar[SessionType]
session: ClassVar[SessionType]
use_db: bool = True
@ -1287,18 +1287,18 @@ class Trade(ModelBase, LocalTrade):
def delete(self) -> None:
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()
@staticmethod
def commit():
Trade.query.session.commit()
Trade.session.commit()
@staticmethod
def rollback():
Trade.query.session.rollback()
Trade.session.rollback()
@staticmethod
def get_trades_proxy(*, pair: Optional[str] = None, is_open: Optional[bool] = None,
@ -1332,7 +1332,7 @@ class Trade(ModelBase, LocalTrade):
)
@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:
"""
Helper function to query Trades using filters.
NOTE: Not supported in Backtesting.
@ -1347,22 +1347,35 @@ class Trade(ModelBase, LocalTrade):
if trade_filter is not None:
if not isinstance(trade_filter, list):
trade_filter = [trade_filter]
this_query = Trade.query.filter(*trade_filter)
this_query = select(Trade).filter(*trade_filter)
else:
this_query = Trade.query
this_query = select(Trade)
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
def get_trades(trade_filter=None, include_orders: bool = True) -> ScalarResult['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.scalars(Trade.get_trades_query(trade_filter, include_orders))
@staticmethod
def get_open_order_trades() -> List['Trade']:
"""
Returns all open trades
NOTE: Not supported in Backtesting.
"""
return Trade.get_trades(Trade.open_order_id.isnot(None)).all()
return cast(List[Trade], Trade.get_trades(Trade.open_order_id.isnot(None)).all())
@staticmethod
def get_open_trades_without_assigned_fees():
@ -1392,11 +1405,12 @@ class Trade(ModelBase, LocalTrade):
Retrieves total realized profit
"""
if Trade.use_db:
total_profit = Trade.query.with_entities(
func.sum(Trade.close_profit_abs)).filter(Trade.is_open.is_(False)).scalar()
total_profit: float = Trade.session.execute(
select(func.sum(Trade.close_profit_abs)).filter(Trade.is_open.is_(False))
).scalar_one()
else:
total_profit = sum(
t.close_profit_abs for t in LocalTrade.get_trades_proxy(is_open=False))
total_profit = sum(t.close_profit_abs # type: ignore
for t in LocalTrade.get_trades_proxy(is_open=False))
return total_profit or 0
@staticmethod
@ -1406,8 +1420,9 @@ class Trade(ModelBase, LocalTrade):
in stake currency
"""
if Trade.use_db:
total_open_stake_amount = Trade.query.with_entities(
func.sum(Trade.stake_amount)).filter(Trade.is_open.is_(True)).scalar()
total_open_stake_amount = Trade.session.scalar(
select(func.sum(Trade.stake_amount)).filter(Trade.is_open.is_(True))
)
else:
total_open_stake_amount = sum(
t.stake_amount for t in LocalTrade.get_trades_proxy(is_open=True))
@ -1423,15 +1438,18 @@ class Trade(ModelBase, LocalTrade):
if minutes:
start_date = datetime.now(timezone.utc) - timedelta(minutes=minutes)
filters.append(Trade.close_date >= start_date)
pair_rates = Trade.query.with_entities(
pair_rates = Trade.session.execute(
select(
Trade.pair,
func.sum(Trade.close_profit).label('profit_sum'),
func.sum(Trade.close_profit_abs).label('profit_sum_abs'),
func.count(Trade.pair).label('count')
).filter(*filters)\
.group_by(Trade.pair) \
.order_by(desc('profit_sum_abs')) \
.all()
).filter(*filters)
.group_by(Trade.pair)
.order_by(desc('profit_sum_abs'))
).all()
return [
{
'pair': pair,
@ -1456,15 +1474,16 @@ class Trade(ModelBase, LocalTrade):
if (pair is not None):
filters.append(Trade.pair == pair)
enter_tag_perf = Trade.query.with_entities(
enter_tag_perf = Trade.session.execute(
select(
Trade.enter_tag,
func.sum(Trade.close_profit).label('profit_sum'),
func.sum(Trade.close_profit_abs).label('profit_sum_abs'),
func.count(Trade.pair).label('count')
).filter(*filters)\
.group_by(Trade.enter_tag) \
.order_by(desc('profit_sum_abs')) \
.all()
).filter(*filters)
.group_by(Trade.enter_tag)
.order_by(desc('profit_sum_abs'))
).all()
return [
{
@ -1488,16 +1507,16 @@ class Trade(ModelBase, LocalTrade):
filters: List = [Trade.is_open.is_(False)]
if (pair is not None):
filters.append(Trade.pair == pair)
sell_tag_perf = Trade.query.with_entities(
sell_tag_perf = Trade.session.execute(
select(
Trade.exit_reason,
func.sum(Trade.close_profit).label('profit_sum'),
func.sum(Trade.close_profit_abs).label('profit_sum_abs'),
func.count(Trade.pair).label('count')
).filter(*filters)\
.group_by(Trade.exit_reason) \
.order_by(desc('profit_sum_abs')) \
.all()
).filter(*filters)
.group_by(Trade.exit_reason)
.order_by(desc('profit_sum_abs'))
).all()
return [
{
@ -1521,18 +1540,18 @@ class Trade(ModelBase, LocalTrade):
filters: List = [Trade.is_open.is_(False)]
if (pair is not None):
filters.append(Trade.pair == pair)
mix_tag_perf = Trade.query.with_entities(
mix_tag_perf = Trade.session.execute(
select(
Trade.id,
Trade.enter_tag,
Trade.exit_reason,
func.sum(Trade.close_profit).label('profit_sum'),
func.sum(Trade.close_profit_abs).label('profit_sum_abs'),
func.count(Trade.pair).label('count')
).filter(*filters)\
.group_by(Trade.id) \
.order_by(desc('profit_sum_abs')) \
.all()
).filter(*filters)
.group_by(Trade.id)
.order_by(desc('profit_sum_abs'))
).all()
return_list: List[Dict] = []
for id, enter_tag, exit_reason, profit, profit_abs, count in mix_tag_perf:
@ -1568,11 +1587,15 @@ class Trade(ModelBase, LocalTrade):
NOTE: Not supported in Backtesting.
:returns: Tuple containing (pair, profit_sum)
"""
best_pair = Trade.query.with_entities(
Trade.pair, func.sum(Trade.close_profit).label('profit_sum')
).filter(Trade.is_open.is_(False) & (Trade.close_date >= start_date)) \
.group_by(Trade.pair) \
.order_by(desc('profit_sum')).first()
best_pair = Trade.session.execute(
select(
Trade.pair,
func.sum(Trade.close_profit).label('profit_sum')
).filter(Trade.is_open.is_(False) & (Trade.close_date >= start_date))
.group_by(Trade.pair)
.order_by(desc('profit_sum'))
).first()
return best_pair
@staticmethod
@ -1582,12 +1605,13 @@ class Trade(ModelBase, LocalTrade):
NOTE: Not supported in Backtesting.
:returns: Tuple containing (pair, profit_sum)
"""
trading_volume = Order.query.with_entities(
trading_volume = Trade.session.execute(
select(
func.sum(Order.cost).label('volume')
).filter(
Order.order_filled_date >= start_date,
Order.status == 'closed'
).scalar()
)).scalar_one()
return trading_volume
@staticmethod

View File

@ -5,7 +5,7 @@ import logging
from abc import abstractmethod
from datetime import date, datetime, timedelta, timezone
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 psutil
@ -13,6 +13,7 @@ from dateutil.relativedelta import relativedelta
from dateutil.tz import tzlocal
from numpy import NAN, inf, int64, mean
from pandas import DataFrame, NaT
from sqlalchemy import func, select
from freqtrade import __version__
from freqtrade.configuration.timerange import TimeRange
@ -122,7 +123,8 @@ class RPC:
if config['max_open_trades'] != float('inf') else -1),
'minimal_roi': config['minimal_roi'].copy() if 'minimal_roi' in config else {},
'stoploss': config.get('stoploss'),
'stoploss_on_exchange': config.get('stoploss_on_exchange', False),
'stoploss_on_exchange': config.get('order_types',
{}).get('stoploss_on_exchange', False),
'trailing_stop': config.get('trailing_stop'),
'trailing_stop_positive': config.get('trailing_stop_positive'),
'trailing_stop_positive_offset': config.get('trailing_stop_positive_offset'),
@ -158,7 +160,7 @@ class RPC:
"""
# Fetch open trades
if trade_ids:
trades: List[Trade] = Trade.get_trades(trade_filter=Trade.id.in_(trade_ids)).all()
trades: Sequence[Trade] = Trade.get_trades(trade_filter=Trade.id.in_(trade_ids)).all()
else:
trades = Trade.get_open_trades()
@ -339,11 +341,13 @@ class RPC:
for day in range(0, timescale):
profitday = start_date - time_offset(day)
# Only query for necessary columns for performance reasons.
trades = Trade.query.session.query(Trade.close_profit_abs).filter(
Trade.is_open.is_(False),
trades = Trade.session.execute(
select(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()
Trade.close_date < (profitday + time_offset(1)))
.order_by(Trade.close_date)
).all()
curdayprofit = sum(
trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None)
@ -381,14 +385,19 @@ class RPC:
""" Returns the X last trades """
order_by: Any = Trade.id if order_by_id else Trade.close_date.desc()
if limit:
trades = Trade.get_trades([Trade.is_open.is_(False)]).order_by(
order_by).limit(limit).offset(offset)
trades = Trade.session.scalars(
Trade.get_trades_query([Trade.is_open.is_(False)])
.order_by(order_by)
.limit(limit)
.offset(offset))
else:
trades = Trade.get_trades([Trade.is_open.is_(False)]).order_by(
Trade.close_date.desc())
trades = Trade.session.scalars(
Trade.get_trades_query([Trade.is_open.is_(False)])
.order_by(Trade.close_date.desc()))
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 {
"trades": output,
@ -436,8 +445,8 @@ class RPC:
""" Returns cumulative profit statistics """
trade_filter = ((Trade.is_open.is_(False) & (Trade.close_date >= start_date)) |
Trade.is_open.is_(True))
trades: List[Trade] = Trade.get_trades(
trade_filter, include_orders=False).order_by(Trade.id).all()
trades: Sequence[Trade] = Trade.session.scalars(Trade.get_trades_query(
trade_filter, include_orders=False).order_by(Trade.id)).all()
profit_all_coin = []
profit_all_ratio = []
@ -946,12 +955,12 @@ class RPC:
def _rpc_delete_lock(self, lockid: Optional[int] = None,
pair: Optional[str] = None) -> Dict[str, Any]:
""" Delete specific lock(s) """
locks = []
locks: Sequence[PairLock] = []
if pair:
locks = PairLocks.get_pair_locks(pair)
if lockid:
locks = PairLock.query.filter(PairLock.id == lockid).all()
locks = PairLock.session.scalars(select(PairLock).filter(PairLock.id == lockid)).all()
for lock in locks:
lock.active = False

View File

@ -1,6 +1,7 @@
import logging
from packaging import version
from sqlalchemy import select
from freqtrade.constants import Config
from freqtrade.enums.tradingmode import TradingMode
@ -44,7 +45,7 @@ def _migrate_binance_futures_db(config: Config):
# Should symbol be migrated too?
# order.symbol = new_pair
Trade.commit()
pls = PairLock.query.filter(PairLock.pair.notlike('%:%'))
pls = PairLock.session.scalars(select(PairLock).filter(PairLock.pair.notlike('%:%'))).all()
for pl in pls:
pl.pair = f"{pl.pair}:{config['stake_currency']}"
# print(pls)

View File

@ -299,7 +299,7 @@ def create_mock_trades(fee, is_short: Optional[bool] = False, use_db: bool = Tru
"""
def add_trade(trade):
if use_db:
Trade.query.session.add(trade)
Trade.session.add(trade)
else:
LocalTrade.add_bt_trade(trade)
is_short1 = is_short if is_short is not None else True
@ -332,11 +332,11 @@ def create_mock_trades_with_leverage(fee, use_db: bool = True):
Create some fake trades ...
"""
if use_db:
Trade.query.session.rollback()
Trade.session.rollback()
def add_trade(trade):
if use_db:
Trade.query.session.add(trade)
Trade.session.add(trade)
else:
LocalTrade.add_bt_trade(trade)
@ -366,7 +366,7 @@ def create_mock_trades_with_leverage(fee, use_db: bool = True):
add_trade(trade)
if use_db:
Trade.query.session.flush()
Trade.session.flush()
def create_mock_trades_usdt(fee, is_short: Optional[bool] = False, use_db: bool = True):
@ -375,7 +375,7 @@ def create_mock_trades_usdt(fee, is_short: Optional[bool] = False, use_db: bool
"""
def add_trade(trade):
if use_db:
Trade.query.session.add(trade)
Trade.session.add(trade)
else:
LocalTrade.add_bt_trade(trade)

View File

@ -4,7 +4,7 @@ from pathlib import Path
from unittest.mock import MagicMock
import pytest
from sqlalchemy import create_engine, text
from sqlalchemy import create_engine, select, text
from freqtrade.constants import DEFAULT_DB_PROD_URL
from freqtrade.enums import TradingMode
@ -21,8 +21,8 @@ spot, margin, futures = TradingMode.SPOT, TradingMode.MARGIN, TradingMode.FUTURE
def test_init_create_session(default_conf):
# Check if init create a session
init_db(default_conf['db_url'])
assert hasattr(Trade, '_session')
assert 'scoped_session' in type(Trade._session).__name__
assert hasattr(Trade, 'session')
assert 'scoped_session' in type(Trade.session).__name__
def test_init_custom_db_url(default_conf, tmpdir):
@ -34,7 +34,7 @@ def test_init_custom_db_url(default_conf, tmpdir):
init_db(default_conf['db_url'])
assert Path(filename).is_file()
r = Trade._session.execute(text("PRAGMA journal_mode"))
r = Trade.session.execute(text("PRAGMA journal_mode"))
assert r.first() == ('wal',)
@ -235,8 +235,9 @@ def test_migrate_new(mocker, default_conf, fee, caplog):
# Run init to test migration
init_db(default_conf['db_url'])
assert len(Trade.query.filter(Trade.id == 1).all()) == 1
trade = Trade.query.filter(Trade.id == 1).first()
trades = Trade.session.scalars(select(Trade).filter(Trade.id == 1)).all()
assert len(trades) == 1
trade = trades[0]
assert trade.fee_open == fee.return_value
assert trade.fee_close == fee.return_value
assert trade.open_rate_requested is None
@ -404,9 +405,9 @@ def test_migrate_pairlocks(mocker, default_conf, fee, caplog):
init_db(default_conf['db_url'])
assert len(PairLock.query.all()) == 2
assert len(PairLock.query.filter(PairLock.pair == '*').all()) == 1
pairlocks = PairLock.query.filter(PairLock.pair == 'ETH/BTC').all()
assert len(PairLock.get_all_locks().all()) == 2
assert len(PairLock.session.scalars(select(PairLock).filter(PairLock.pair == '*')).all()) == 1
pairlocks = PairLock.session.scalars(select(PairLock).filter(PairLock.pair == 'ETH/BTC')).all()
assert len(pairlocks) == 1
pairlocks[0].pair == 'ETH/BTC'
pairlocks[0].side == '*'

View File

@ -4,6 +4,7 @@ from types import FunctionType
import arrow
import pytest
from sqlalchemy import select
from freqtrade.constants import DATETIME_PRINT_FORMAT
from freqtrade.enums import TradingMode
@ -1494,7 +1495,7 @@ def test_stoploss_reinitialization(default_conf, fee):
assert trade.stop_loss_pct == -0.05
assert trade.initial_stop_loss == 0.95
assert trade.initial_stop_loss_pct == -0.05
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
# Lower stoploss
@ -1556,7 +1557,7 @@ def test_stoploss_reinitialization_leverage(default_conf, fee):
assert trade.stop_loss_pct == -0.1
assert trade.initial_stop_loss == 0.98
assert trade.initial_stop_loss_pct == -0.1
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
# Lower stoploss
@ -1618,7 +1619,7 @@ def test_stoploss_reinitialization_short(default_conf, fee):
assert trade.stop_loss_pct == -0.1
assert trade.initial_stop_loss == 1.02
assert trade.initial_stop_loss_pct == -0.1
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
# Lower stoploss
Trade.stoploss_reinitialization(-0.15)
@ -1793,17 +1794,17 @@ def test_get_trades_proxy(fee, use_db, is_short):
@pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize('is_short', [True, False])
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.
query1 = Trade.get_trades([], include_orders=False)
query1 = Trade.get_trades_query([], include_orders=False)
# Empty "with-options -> default - selectin"
assert query._with_options == ()
assert query1._with_options != ()
create_mock_trades(fee, is_short)
query = Trade.get_trades([])
query1 = Trade.get_trades([], include_orders=False)
query = Trade.get_trades_query([])
query1 = Trade.get_trades_query([], include_orders=False)
assert query._with_options == ()
assert query1._with_options != ()
@ -2016,6 +2017,7 @@ def test_Trade_object_idem():
'get_open_trades_without_assigned_fees',
'get_open_order_trades',
'get_trades',
'get_trades_query',
'get_exit_reason_performance',
'get_enter_tag_performance',
'get_mix_tag_performance',
@ -2443,8 +2445,8 @@ def test_order_to_ccxt(limit_buy_order_open):
order = Order.parse_from_ccxt_object(limit_buy_order_open, 'mocked', 'buy')
order.ft_trade_id = 1
order.query.session.add(order)
Order.query.session.commit()
order.session.add(order)
Order.session.commit()
order_resp = Order.order_by_id(limit_buy_order_open['id'])
assert order_resp
@ -2546,7 +2548,7 @@ def test_recalc_trade_from_orders_dca(data) -> None:
leverage=1.0,
trading_mode=TradingMode.SPOT
)
Trade.query.session.add(trade)
Trade.session.add(trade)
for idx, (order, result) in enumerate(data['orders']):
amount = order[1]
@ -2575,11 +2577,11 @@ def test_recalc_trade_from_orders_dca(data) -> None:
trade.recalc_trade_from_orders()
Trade.commit()
orders1 = Order.query.all()
orders1 = Order.session.scalars(select(Order)).all()
assert orders1
assert len(orders1) == idx + 1
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert len(trade.orders) == idx + 1
if idx < len(data) - 1:
@ -2596,6 +2598,6 @@ def test_recalc_trade_from_orders_dca(data) -> None:
assert pytest.approx(trade.close_profit_abs) == data['end_profit']
assert pytest.approx(trade.close_profit) == data['end_profit_ratio']
assert not trade.is_open
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id is None

View File

@ -711,8 +711,8 @@ def test_PrecisionFilter_error(mocker, whitelist_conf) -> None:
def test_PerformanceFilter_error(mocker, whitelist_conf, caplog) -> None:
whitelist_conf['pairlists'] = [{"method": "StaticPairList"}, {"method": "PerformanceFilter"}]
if hasattr(Trade, 'query'):
del Trade.query
if hasattr(Trade, 'session'):
del Trade.session
mocker.patch(f'{EXMS}.exchange_has', MagicMock(return_value=True))
exchange = get_patched_exchange(mocker, whitelist_conf)
pm = PairListManager(exchange, whitelist_conf, MagicMock())

View File

@ -14,7 +14,7 @@ def test_PairLocks(use_db):
PairLocks.use_db = use_db
# No lock should be present
if use_db:
assert len(PairLock.query.all()) == 0
assert len(PairLock.get_all_locks().all()) == 0
assert PairLocks.use_db == use_db
@ -88,13 +88,13 @@ def test_PairLocks(use_db):
if use_db:
locks = PairLocks.get_all_locks()
locks_db = PairLock.query.all()
locks_db = PairLock.get_all_locks().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
assert len(PairLock.get_all_locks().all()) == 0
# Reset use-db variable
PairLocks.reset_locks()
PairLocks.use_db = True
@ -107,7 +107,7 @@ def test_PairLocks_getlongestlock(use_db):
# No lock should be present
PairLocks.use_db = use_db
if use_db:
assert len(PairLock.query.all()) == 0
assert len(PairLock.get_all_locks().all()) == 0
assert PairLocks.use_db == use_db
@ -139,7 +139,7 @@ def test_PairLocks_reason(use_db):
PairLocks.use_db = use_db
# No lock should be present
if use_db:
assert len(PairLock.query.all()) == 0
assert len(PairLock.get_all_locks().all()) == 0
assert PairLocks.use_db == use_db

View File

@ -74,7 +74,7 @@ def generate_mock_trade(pair: str, fee: float, is_open: bool,
trade.close(close_price)
trade.exit_reason = exit_reason
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
return trade

View File

@ -4,6 +4,7 @@ from unittest.mock import ANY, MagicMock, PropertyMock
import pytest
from numpy import isnan
from sqlalchemy import select
from freqtrade.edge import PairInfo
from freqtrade.enums import SignalDirection, State, TradingMode
@ -354,7 +355,7 @@ def test_rpc_delete_trade(mocker, default_conf, fee, markets, caplog, is_short):
with pytest.raises(RPCException, match='invalid argument'):
rpc._rpc_delete('200')
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
trades[1].stoploss_order_id = '1234'
trades[2].stoploss_order_id = '1234'
assert len(trades) > 2
@ -717,7 +718,7 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
mocker.patch(f'{EXMS}._dry_is_price_crossed', MagicMock(return_value=False))
freqtradebot.enter_positions()
# make an limit-buy open trade
trade = Trade.query.filter(Trade.id == '3').first()
trade = Trade.session.scalars(select(Trade).filter(Trade.id == '3')).first()
filled_amount = trade.amount / 2
# Fetch order - it's open first, and closed after cancel_order is called.
mocker.patch(
@ -753,7 +754,7 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
freqtradebot.config['max_open_trades'] = 3
freqtradebot.enter_positions()
trade = Trade.query.filter(Trade.id == '2').first()
trade = Trade.session.scalars(select(Trade).filter(Trade.id == '2')).first()
amount = trade.amount
# make an limit-buy open trade, if there is no 'filled', don't sell it
mocker.patch(
@ -771,7 +772,7 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
assert cancel_order_mock.call_count == 2
assert trade.amount == amount
trade = Trade.query.filter(Trade.id == '3').first()
trade = Trade.session.scalars(select(Trade).filter(Trade.id == '3')).first()
# make an limit-sell open trade
mocker.patch(

View File

@ -14,6 +14,7 @@ from fastapi import FastAPI, WebSocketDisconnect
from fastapi.exceptions import HTTPException
from fastapi.testclient import TestClient
from requests.auth import _basic_auth_str
from sqlalchemy import select
from freqtrade.__init__ import __version__
from freqtrade.enums import CandleType, RunMode, State, TradingMode
@ -624,7 +625,7 @@ def test_api_trades(botclient, mocker, fee, markets, is_short):
assert rc.json()['offset'] == 0
create_mock_trades(fee, is_short=is_short)
Trade.query.session.flush()
Trade.session.flush()
rc = client_get(client, f"{BASE_URI}/trades")
assert_response(rc)
@ -652,7 +653,7 @@ def test_api_trade_single(botclient, mocker, fee, ticker, markets, is_short):
assert_response(rc, 404)
assert rc.json()['detail'] == 'Trade not found.'
Trade.query.session.rollback()
Trade.rollback()
create_mock_trades(fee, is_short=is_short)
rc = client_get(client, f"{BASE_URI}/trade/3")
@ -677,7 +678,7 @@ def test_api_delete_trade(botclient, mocker, fee, markets, is_short):
create_mock_trades(fee, is_short=is_short)
ftbot.strategy.order_types['stoploss_on_exchange'] = True
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
trades[1].stoploss_order_id = '1234'
Trade.commit()
assert len(trades) > 2
@ -685,7 +686,7 @@ def test_api_delete_trade(botclient, mocker, fee, markets, is_short):
rc = client_delete(client, f"{BASE_URI}/trades/1")
assert_response(rc)
assert rc.json()['result_msg'] == 'Deleted trade 1. Closed 1 open orders.'
assert len(trades) - 1 == len(Trade.query.all())
assert len(trades) - 1 == len(Trade.session.scalars(select(Trade)).all())
assert cancel_mock.call_count == 1
cancel_mock.reset_mock()
@ -694,11 +695,11 @@ def test_api_delete_trade(botclient, mocker, fee, markets, is_short):
assert_response(rc, 502)
assert cancel_mock.call_count == 0
assert len(trades) - 1 == len(Trade.query.all())
assert len(trades) - 1 == len(Trade.session.scalars(select(Trade)).all())
rc = client_delete(client, f"{BASE_URI}/trades/2")
assert_response(rc)
assert rc.json()['result_msg'] == 'Deleted trade 2. Closed 2 open orders.'
assert len(trades) - 2 == len(Trade.query.all())
assert len(trades) - 2 == len(Trade.session.scalars(select(Trade)).all())
assert stoploss_mock.call_count == 1
rc = client_delete(client, f"{BASE_URI}/trades/502")
@ -943,7 +944,7 @@ def test_api_performance(botclient, fee):
)
trade.close_profit = trade.calc_profit_ratio(trade.close_rate)
trade.close_profit_abs = trade.calc_profit(trade.close_rate)
Trade.query.session.add(trade)
Trade.session.add(trade)
trade = Trade(
pair='XRP/ETH',
@ -960,7 +961,7 @@ def test_api_performance(botclient, fee):
trade.close_profit = trade.calc_profit_ratio(trade.close_rate)
trade.close_profit_abs = trade.calc_profit(trade.close_rate)
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
rc = client_get(client, f"{BASE_URI}/performance")
@ -1290,7 +1291,7 @@ def test_api_forceexit(botclient, mocker, ticker, fee, markets):
data={"tradeid": "1"})
assert_response(rc, 502)
assert rc.json() == {"error": "Error querying /api/v1/forceexit: invalid argument"}
Trade.query.session.rollback()
Trade.rollback()
create_mock_trades(fee)
trade = Trade.get_trades([Trade.id == 5]).first()
@ -1299,7 +1300,7 @@ def test_api_forceexit(botclient, mocker, ticker, fee, markets):
data={"tradeid": "5", "ordertype": "market", "amount": 23})
assert_response(rc)
assert rc.json() == {'result': 'Created sell order for trade 5.'}
Trade.query.session.rollback()
Trade.rollback()
trade = Trade.get_trades([Trade.id == 5]).first()
assert pytest.approx(trade.amount) == 100
@ -1309,7 +1310,7 @@ def test_api_forceexit(botclient, mocker, ticker, fee, markets):
data={"tradeid": "5"})
assert_response(rc)
assert rc.json() == {'result': 'Created sell order for trade 5.'}
Trade.query.session.rollback()
Trade.rollback()
trade = Trade.get_trades([Trade.id == 5]).first()
assert trade.is_open is False

View File

@ -14,6 +14,7 @@ import arrow
import pytest
import time_machine
from pandas import DataFrame
from sqlalchemy import select
from telegram import Chat, Message, ReplyKeyboardMarkup, Update
from telegram.error import BadRequest, NetworkError, TelegramError
@ -692,7 +693,7 @@ def test_profit_handle(default_conf_usdt, update, ticker_usdt, ticker_sell_up, f
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
context = MagicMock()
# Test with invalid 2nd argument (should silently pass)
@ -945,7 +946,7 @@ def test_telegram_forceexit_handle(default_conf, update, ticker, fee,
# Create some test data
freqtradebot.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
# Increase the price and sell it
@ -1020,7 +1021,7 @@ def test_telegram_force_exit_down_handle(default_conf, update, ticker, fee,
fetch_ticker=ticker_sell_down
)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
# /forceexit 1

View File

@ -10,6 +10,7 @@ from unittest.mock import ANY, MagicMock, PropertyMock, patch
import arrow
import pytest
from pandas import DataFrame
from sqlalchemy import select
from freqtrade.constants import CANCEL_REASON, UNLIMITED_STAKE_AMOUNT
from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, RPCMessageType, RunMode,
@ -247,7 +248,7 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker,
patch_get_signal(freqtrade)
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
caplog.clear()
#############################################
ticker_val.update({
@ -278,7 +279,7 @@ def test_total_open_trades_stakes(mocker, default_conf_usdt, ticker_usdt, fee) -
freqtrade = FreqtradeBot(default_conf_usdt)
patch_get_signal(freqtrade)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade is not None
assert trade.stake_amount == 60.0
@ -286,7 +287,7 @@ def test_total_open_trades_stakes(mocker, default_conf_usdt, ticker_usdt, fee) -
assert trade.open_date is not None
freqtrade.enter_positions()
trade = Trade.query.order_by(Trade.id.desc()).first()
trade = Trade.session.scalars(select(Trade).order_by(Trade.id.desc())).first()
assert trade is not None
assert trade.stake_amount == 60.0
@ -317,7 +318,7 @@ def test_create_trade(default_conf_usdt, ticker_usdt, limit_order,
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
freqtrade.create_trade('ETH/USDT')
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade is not None
assert pytest.approx(trade.stake_amount) == 60.0
@ -568,12 +569,12 @@ def test_process_trade_creation(default_conf_usdt, ticker_usdt, limit_order, lim
freqtrade = FreqtradeBot(default_conf_usdt)
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
trades = Trade.get_open_trades()
assert not trades
freqtrade.process()
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
trades = Trade.get_open_trades()
assert len(trades) == 1
trade = trades[0]
assert trade is not None
@ -640,11 +641,11 @@ def test_process_trade_handling(default_conf_usdt, ticker_usdt, limit_buy_order_
freqtrade = FreqtradeBot(default_conf_usdt)
patch_get_signal(freqtrade)
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
trades = Trade.get_open_trades()
assert not trades
freqtrade.process()
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
trades = Trade.get_open_trades()
assert len(trades) == 1
# Nothing happened ...
@ -671,7 +672,7 @@ def test_process_trade_no_whitelist_pair(default_conf_usdt, ticker_usdt, limit_b
assert pair not in default_conf_usdt['exchange']['pair_whitelist']
# create open trade not in whitelist
Trade.query.session.add(Trade(
Trade.session.add(Trade(
pair=pair,
stake_amount=0.001,
fee_open=fee.return_value,
@ -681,7 +682,7 @@ def test_process_trade_no_whitelist_pair(default_conf_usdt, ticker_usdt, limit_b
open_rate=0.01,
exchange='binance',
))
Trade.query.session.add(Trade(
Trade.session.add(Trade(
pair='ETH/USDT',
stake_amount=0.001,
fee_open=fee.return_value,
@ -838,7 +839,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
# Should create an open trade with an open order id
# As the order is not fulfilled yet
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
assert trade.is_open is True
@ -865,7 +866,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
mocker.patch(f'{EXMS}.create_order', MagicMock(return_value=order))
assert freqtrade.execute_entry(pair, stake_amount, is_short=is_short)
trade = Trade.query.all()[2]
trade = Trade.session.scalars(select(Trade)).all()[2]
trade.is_short = is_short
assert trade
assert trade.open_order_id is None
@ -883,7 +884,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
order['id'] = '555'
mocker.patch(f'{EXMS}.create_order', MagicMock(return_value=order))
assert freqtrade.execute_entry(pair, stake_amount)
trade = Trade.query.all()[3]
trade = Trade.session.scalars(select(Trade)).all()[3]
trade.is_short = is_short
assert trade
assert trade.open_order_id is None
@ -896,7 +897,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
freqtrade.strategy.custom_stake_amount = lambda **kwargs: 150.0
assert freqtrade.execute_entry(pair, stake_amount, is_short=is_short)
trade = Trade.query.all()[4]
trade = Trade.session.scalars(select(Trade)).all()[4]
trade.is_short = is_short
assert trade
assert pytest.approx(trade.stake_amount) == 150
@ -905,7 +906,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
order['id'] = '557'
freqtrade.strategy.custom_stake_amount = lambda **kwargs: 20 / 0
assert freqtrade.execute_entry(pair, stake_amount, is_short=is_short)
trade = Trade.query.all()[5]
trade = Trade.session.scalars(select(Trade)).all()[5]
trade.is_short = is_short
assert trade
assert pytest.approx(trade.stake_amount) == 2.0
@ -934,7 +935,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
order['id'] = '5566'
freqtrade.strategy.custom_entry_price = lambda **kwargs: 0.508
assert freqtrade.execute_entry(pair, stake_amount, is_short=is_short)
trade = Trade.query.all()[6]
trade = Trade.session.scalars(select(Trade)).all()[6]
trade.is_short = is_short
assert trade
assert trade.open_rate_requested == 0.508
@ -951,7 +952,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
)
assert freqtrade.execute_entry(pair, stake_amount, is_short=is_short)
trade = Trade.query.all()[7]
trade = Trade.session.scalars(select(Trade)).all()[7]
trade.is_short = is_short
assert trade
assert trade.open_rate_requested == 10
@ -961,7 +962,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
order['id'] = '5568'
freqtrade.strategy.custom_entry_price = lambda **kwargs: "string price"
assert freqtrade.execute_entry(pair, stake_amount, is_short=is_short)
trade = Trade.query.all()[8]
trade = Trade.session.scalars(select(Trade)).all()[8]
# Trade(id=9, pair=ETH/USDT, amount=0.20000000, is_short=False,
# leverage=1.0, open_rate=10.00000000, open_since=...)
# Trade(id=9, pair=ETH/USDT, amount=0.60000000, is_short=True,
@ -982,7 +983,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
freqtrade.exchange.get_max_pair_stake_amount = MagicMock(return_value=500)
assert freqtrade.execute_entry(pair, 2000, is_short=is_short)
trade = Trade.query.all()[9]
trade = Trade.session.scalars(select(Trade)).all()[9]
trade.is_short = is_short
assert pytest.approx(trade.stake_amount) == 500
@ -991,7 +992,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
freqtrade.strategy.leverage.reset_mock()
assert freqtrade.execute_entry(pair, 200, leverage_=3)
assert freqtrade.strategy.leverage.call_count == 0
trade = Trade.query.all()[10]
trade = Trade.session.scalars(select(Trade)).all()[10]
assert trade.leverage == 1 if trading_mode == 'spot' else 3
@ -1053,7 +1054,7 @@ def test_execute_entry_min_leverage(mocker, default_conf_usdt, fee, limit_order,
freqtrade.strategy.leverage = MagicMock(return_value=5.0)
assert freqtrade.execute_entry(pair, stake_amount, is_short=is_short)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade.leverage == 5.0
# assert trade.stake_amount == 2
@ -1158,7 +1159,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_
# as a trade actually happened
caplog.clear()
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
trade.is_open = True
trade.open_order_id = None
@ -1271,7 +1272,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog,
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
trade.is_open = True
trade.open_order_id = None
@ -1316,7 +1317,7 @@ def test_create_stoploss_order_invalid_order(
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
caplog.clear()
freqtrade.create_stoploss_order(trade, 200)
@ -1367,7 +1368,7 @@ def test_create_stoploss_order_insufficient_funds(
freqtrade.strategy.order_types['stoploss_on_exchange'] = True
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
caplog.clear()
freqtrade.create_stoploss_order(trade, 200)
@ -1435,7 +1436,7 @@ def test_handle_stoploss_on_exchange_trailing(
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
trade.is_open = True
trade.open_order_id = None
@ -1554,7 +1555,7 @@ def test_handle_stoploss_on_exchange_trailing_error(
freqtrade.strategy.order_types['stoploss_on_exchange_interval'] = 60
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
trade.is_open = True
trade.open_order_id = None
@ -1668,7 +1669,7 @@ def test_handle_stoploss_on_exchange_custom_stop(
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
trade.is_open = True
trade.open_order_id = None
@ -1796,7 +1797,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_orde
freqtrade.active_pair_whitelist = freqtrade.edge.adjust(freqtrade.active_pair_whitelist)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_open = True
trade.open_order_id = None
trade.stoploss_order_id = 100
@ -2162,7 +2163,7 @@ def test_handle_trade(
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
@ -2217,7 +2218,7 @@ def test_handle_overlapping_signals(
freqtrade.enter_positions()
# Buy and Sell triggering, so doing nothing ...
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
nb_trades = len(trades)
assert nb_trades == 0
@ -2225,7 +2226,7 @@ def test_handle_overlapping_signals(
# Buy is triggering, so buying ...
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
freqtrade.enter_positions()
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
for trade in trades:
trade.is_short = is_short
nb_trades = len(trades)
@ -2235,7 +2236,7 @@ def test_handle_overlapping_signals(
# Buy and Sell are not triggering, so doing nothing ...
patch_get_signal(freqtrade, enter_long=False)
assert freqtrade.handle_trade(trades[0]) is False
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
for trade in trades:
trade.is_short = is_short
nb_trades = len(trades)
@ -2248,7 +2249,7 @@ def test_handle_overlapping_signals(
else:
patch_get_signal(freqtrade, enter_long=True, exit_long=True)
assert freqtrade.handle_trade(trades[0]) is False
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
for trade in trades:
trade.is_short = is_short
nb_trades = len(trades)
@ -2260,7 +2261,7 @@ def test_handle_overlapping_signals(
patch_get_signal(freqtrade, enter_long=False, exit_short=True)
else:
patch_get_signal(freqtrade, enter_long=False, exit_long=True)
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
for trade in trades:
trade.is_short = is_short
assert freqtrade.handle_trade(trades[0]) is True
@ -2291,7 +2292,7 @@ def test_handle_trade_roi(default_conf_usdt, ticker_usdt, limit_order_open, fee,
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
trade.is_open = True
@ -2333,7 +2334,7 @@ def test_handle_trade_use_exit_signal(
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
trade.is_open = True
@ -2370,7 +2371,7 @@ def test_close_trade(
# Create trade and sell it
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
@ -2427,7 +2428,7 @@ def test_manage_open_orders_entry_usercustom(
open_trade.is_short = is_short
open_trade.orders[0].side = 'sell' if is_short else 'buy'
open_trade.orders[0].ft_order_side = 'sell' if is_short else 'buy'
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
# Ensure default is to return empty (so not mocked yet)
@ -2438,7 +2439,8 @@ def test_manage_open_orders_entry_usercustom(
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False)
freqtrade.manage_open_orders()
assert cancel_order_mock.call_count == 0
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
nb_trades = len(trades)
assert nb_trades == 1
assert freqtrade.strategy.check_entry_timeout.call_count == 1
@ -2446,7 +2448,8 @@ def test_manage_open_orders_entry_usercustom(
freqtrade.manage_open_orders()
assert cancel_order_mock.call_count == 0
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
nb_trades = len(trades)
assert nb_trades == 1
assert freqtrade.strategy.check_entry_timeout.call_count == 1
@ -2456,7 +2459,8 @@ def test_manage_open_orders_entry_usercustom(
freqtrade.manage_open_orders()
assert cancel_order_wr_mock.call_count == 1
assert rpc_mock.call_count == 2
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
nb_trades = len(trades)
assert nb_trades == 0
assert freqtrade.strategy.check_entry_timeout.call_count == 1
@ -2486,7 +2490,7 @@ def test_manage_open_orders_entry(
freqtrade = FreqtradeBot(default_conf_usdt)
open_trade.is_short = is_short
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False)
@ -2495,7 +2499,8 @@ def test_manage_open_orders_entry(
freqtrade.manage_open_orders()
assert cancel_order_mock.call_count == 1
assert rpc_mock.call_count == 2
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
nb_trades = len(trades)
assert nb_trades == 0
# Custom user buy-timeout is never called
@ -2524,7 +2529,7 @@ def test_adjust_entry_cancel(
)
open_trade.is_short = is_short
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
# Timeout to not interfere
@ -2533,9 +2538,10 @@ def test_adjust_entry_cancel(
# check that order is cancelled
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=None)
freqtrade.manage_open_orders()
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
assert len(trades) == 0
assert len(Order.query.all()) == 0
assert len(Order.session.scalars(select(Order)).all()) == 0
assert log_has_re(
f"{'Sell' if is_short else 'Buy'} order user requested order cancel*", caplog)
assert log_has_re(
@ -2565,7 +2571,7 @@ def test_adjust_entry_maintain_replace(
)
open_trade.is_short = is_short
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
# Timeout to not interfere
@ -2574,7 +2580,8 @@ def test_adjust_entry_maintain_replace(
# Check that order is maintained
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=old_order['price'])
freqtrade.manage_open_orders()
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
assert len(trades) == 1
assert len(Order.get_open_orders()) == 1
# Entry adjustment is called
@ -2584,9 +2591,10 @@ def test_adjust_entry_maintain_replace(
freqtrade.get_valid_enter_price_and_stake = MagicMock(return_value={100, 10, 1})
freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1234)
freqtrade.manage_open_orders()
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
assert len(trades) == 1
nb_all_orders = len(Order.query.all())
nb_all_orders = len(Order.session.scalars(select(Order)).all())
assert nb_all_orders == 2
# New order seems to be in closed status?
# nb_open_orders = len(Order.get_open_orders())
@ -2618,14 +2626,15 @@ def test_check_handle_cancelled_buy(
freqtrade = FreqtradeBot(default_conf_usdt)
open_trade.orders = []
open_trade.is_short = is_short
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
# check it does cancel buy orders over the time limit
freqtrade.manage_open_orders()
assert cancel_order_mock.call_count == 0
assert rpc_mock.call_count == 2
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
assert len(trades) == 0
assert log_has_re(
f"{'Sell' if is_short else 'Buy'} order cancelled on exchange for Trade.*", caplog)
@ -2649,14 +2658,15 @@ def test_manage_open_orders_buy_exception(
freqtrade = FreqtradeBot(default_conf_usdt)
open_trade.is_short = is_short
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
# check it does cancel buy orders over the time limit
freqtrade.manage_open_orders()
assert cancel_order_mock.call_count == 0
assert rpc_mock.call_count == 1
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
nb_trades = len(trades)
assert nb_trades == 1
@ -2691,7 +2701,7 @@ def test_manage_open_orders_exit_usercustom(
open_trade_usdt.close_date = arrow.utcnow().shift(minutes=-601).datetime
open_trade_usdt.close_profit_abs = 0.001
Trade.query.session.add(open_trade_usdt)
Trade.session.add(open_trade_usdt)
Trade.commit()
# Ensure default is false
freqtrade.manage_open_orders()
@ -2771,7 +2781,7 @@ def test_manage_open_orders_exit(
open_trade_usdt.close_profit_abs = 0.001
open_trade_usdt.is_short = is_short
Trade.query.session.add(open_trade_usdt)
Trade.session.add(open_trade_usdt)
Trade.commit()
freqtrade.strategy.check_exit_timeout = MagicMock(return_value=False)
@ -2811,7 +2821,7 @@ def test_check_handle_cancelled_exit(
open_trade_usdt.close_date = arrow.utcnow().shift(minutes=-601).datetime
open_trade_usdt.is_short = is_short
Trade.query.session.add(open_trade_usdt)
Trade.session.add(open_trade_usdt)
Trade.commit()
# check it does cancel sell orders over the time limit
@ -2848,7 +2858,7 @@ def test_manage_open_orders_partial(
)
freqtrade = FreqtradeBot(default_conf_usdt)
prior_stake = open_trade.stake_amount
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
# check it does cancel buy orders over the time limit
@ -2856,7 +2866,8 @@ def test_manage_open_orders_partial(
freqtrade.manage_open_orders()
assert cancel_order_mock.call_count == 1
assert rpc_mock.call_count == 3
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
assert len(trades) == 1
assert trades[0].amount == 23.0
assert trades[0].stake_amount == open_trade.open_rate * trades[0].amount / leverage
@ -2893,7 +2904,7 @@ def test_manage_open_orders_partial_fee(
open_trade.fee_open = fee()
open_trade.fee_close = fee()
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
# cancelling a half-filled order should update the amount to the bought amount
# and apply fees if necessary.
@ -2903,7 +2914,8 @@ def test_manage_open_orders_partial_fee(
assert cancel_order_mock.call_count == 1
assert rpc_mock.call_count == 3
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
assert len(trades) == 1
# Verify that trade has been updated
assert trades[0].amount == (limit_buy_order_old_partial['amount'] -
@ -2943,7 +2955,7 @@ def test_manage_open_orders_partial_except(
open_trade.fee_open = fee()
open_trade.fee_close = fee()
Trade.query.session.add(open_trade)
Trade.session.add(open_trade)
Trade.commit()
# cancelling a half-filled order should update the amount to the bought amount
# and apply fees if necessary.
@ -2953,7 +2965,8 @@ def test_manage_open_orders_partial_except(
assert cancel_order_mock.call_count == 1
assert rpc_mock.call_count == 3
trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all()
trades = Trade.session.scalars(
select(Trade).filter(Trade.open_order_id.is_(open_trade.open_order_id))).all()
assert len(trades) == 1
# Verify that trade has been updated
@ -2982,7 +2995,7 @@ def test_manage_open_orders_exception(default_conf_usdt, ticker_usdt, open_trade
)
freqtrade = FreqtradeBot(default_conf_usdt)
Trade.query.session.add(open_trade_usdt)
Trade.session.add(open_trade_usdt)
Trade.commit()
caplog.clear()
@ -3011,7 +3024,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_
freqtrade._notify_enter_cancel = MagicMock()
trade = mock_trade_usdt_4(fee, is_short)
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
l_order['filled'] = 0.0
@ -3061,7 +3074,7 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_sho
reason = CANCEL_REASON['TIMEOUT']
trade = mock_trade_usdt_4(fee, is_short)
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
assert freqtrade.handle_cancel_enter(trade, limit_buy_order_canceled_empty, reason)
assert cancel_order_mock.call_count == 0
@ -3095,7 +3108,7 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order
freqtrade = FreqtradeBot(default_conf_usdt)
freqtrade._notify_enter_cancel = MagicMock()
trade = mock_trade_usdt_4(fee, is_short)
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
l_order['filled'] = 0.0
l_order['status'] = 'open'
@ -3261,7 +3274,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_
freqtrade.enter_positions()
rpc_mock.reset_mock()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade.is_short == is_short
assert trade
assert freqtrade.strategy.confirm_trade_exit.call_count == 0
@ -3342,7 +3355,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd
# Create some test data
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
@ -3415,7 +3428,7 @@ def test_execute_trade_exit_custom_exit_price(
freqtrade.enter_positions()
rpc_mock.reset_mock()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
assert freqtrade.strategy.confirm_trade_exit.call_count == 0
@ -3492,7 +3505,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run(
# Create some test data
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade.is_short == is_short
assert trade
@ -3566,7 +3579,7 @@ def test_execute_trade_exit_sloe_cancel_exception(
patch_get_signal(freqtrade)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
PairLock.session = MagicMock()
freqtrade.config['dry_run'] = False
@ -3611,7 +3624,7 @@ def test_execute_trade_exit_with_stoploss_on_exchange(
# Create some test data
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
trades = [trade]
@ -3631,7 +3644,7 @@ def test_execute_trade_exit_with_stoploss_on_exchange(
exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS)
)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
assert cancel_order.call_count == 1
@ -3669,7 +3682,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(
# Create some test data
freqtrade.enter_positions()
freqtrade.manage_open_orders()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trades = [trade]
assert trade.stoploss_order_id is None
@ -3755,7 +3768,7 @@ def test_execute_trade_exit_market_order(
# Create some test data
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
@ -3830,7 +3843,7 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf_usdt, ticker_u
# Create some test data
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
@ -3898,7 +3911,7 @@ def test_exit_profit_only(
exit_type=ExitType.NONE))
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade.is_short == is_short
oobj = Order.parse_from_ccxt_object(limit_order[eside], limit_order[eside]['symbol'], eside)
trade.update_order(limit_order[eside])
@ -3941,7 +3954,7 @@ def test_sell_not_enough_balance(default_conf_usdt, limit_order, limit_order_ope
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
amnt = trade.amount
oobj = Order.parse_from_ccxt_object(limit_order['buy'], limit_order['buy']['symbol'], 'buy')
@ -4009,7 +4022,7 @@ def test_locked_pairs(default_conf_usdt, ticker_usdt, fee,
# Create some test data
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
assert trade
@ -4064,7 +4077,7 @@ def test_ignore_roi_if_entry_signal(default_conf_usdt, limit_order, limit_order_
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
oobj = Order.parse_from_ccxt_object(
limit_order[eside], limit_order[eside]['symbol'], eside)
@ -4114,7 +4127,7 @@ def test_trailing_stop_loss(default_conf_usdt, limit_order_open,
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade.is_short == is_short
assert freqtrade.handle_trade(trade) is False
@ -4189,7 +4202,7 @@ def test_trailing_stop_loss_positive(
freqtrade.strategy.min_roi_reached = MagicMock(return_value=False)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade.is_short == is_short
oobj = Order.parse_from_ccxt_object(limit_order[eside], limit_order[eside]['symbol'], eside)
trade.update_order(limit_order[eside])
@ -4286,7 +4299,7 @@ def test_disable_ignore_roi_if_entry_signal(default_conf_usdt, limit_order, limi
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
oobj = Order.parse_from_ccxt_object(
@ -4752,7 +4765,7 @@ def test_order_book_depth_of_market(
patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short)
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
if is_high_delta:
assert trade is None
else:
@ -4763,7 +4776,7 @@ def test_order_book_depth_of_market(
assert trade.open_date is not None
assert trade.exchange == 'binance'
assert len(Trade.query.all()) == 1
assert len(Trade.session.scalars(select(Trade)).all()) == 1
# Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(
@ -4860,7 +4873,7 @@ def test_order_book_exit_pricing(
freqtrade.enter_positions()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
time.sleep(0.01) # Race condition fix
@ -4932,7 +4945,7 @@ def test_sync_wallet_dry_run(mocker, default_conf_usdt, ticker_usdt, fee, limit_
n = bot.enter_positions()
assert n == 2
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
assert len(trades) == 2
bot.config['max_open_trades'] = 3
@ -4965,7 +4978,7 @@ def test_cancel_all_open_orders(mocker, default_conf_usdt, fee, limit_order, lim
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
create_mock_trades(fee, is_short=is_short)
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
assert len(trades) == MOCK_TRADE_COUNT
freqtrade.cancel_all_open_orders()
assert buy_mock.call_count == buy_calls
@ -4981,7 +4994,7 @@ def test_check_for_open_trades(mocker, default_conf_usdt, fee, is_short):
assert freqtrade.rpc.send_msg.call_count == 0
create_mock_trades(fee, is_short)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
trade.is_short = is_short
trade.is_open = True
@ -5149,7 +5162,7 @@ def test_reupdate_enter_order_fees(mocker, default_conf_usdt, fee, caplog, is_sh
exchange='binance',
is_short=is_short
)
Trade.query.session.add(trade)
Trade.session.add(trade)
freqtrade.handle_insufficient_funds(trade)
# assert log_has_re(r"Trying to reupdate buy fees for .*", caplog)
@ -5546,10 +5559,10 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
assert freqtrade.execute_entry(pair, stake_amount)
# Should create an closed trade with an no open order id
# Order is filled and trade is open
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 1
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
@ -5559,7 +5572,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
# Assume it does nothing since order is closed and trade is open
freqtrade.update_trades_without_assigned_fees()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
@ -5569,7 +5582,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
freqtrade.manage_open_orders()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
@ -5595,10 +5608,10 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
mocker.patch(f'{EXMS}.fetch_order_or_stoploss_order', MagicMock(return_value=open_dca_order_1))
assert freqtrade.execute_entry(pair, stake_amount, trade=trade)
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 2
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id == '651'
assert trade.open_rate == 11
@ -5628,14 +5641,14 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
mocker.patch(f'{EXMS}.fetch_order_or_stoploss_order', fetch_order_mm)
freqtrade.update_trades_without_assigned_fees()
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 2
# Assert that the trade is found as open and without fees
trades: List[Trade] = Trade.get_open_trades_without_assigned_fees()
assert len(trades) == 1
# Assert trade is as expected
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id == '651'
assert trade.open_rate == 11
@ -5672,14 +5685,14 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
freqtrade.manage_open_orders()
# Assert trade is as expected (averaged dca)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id is None
assert pytest.approx(trade.open_rate) == 9.90909090909
assert trade.amount == 22
assert pytest.approx(trade.stake_amount) == 218
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 2
@ -5714,14 +5727,14 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
assert freqtrade.execute_entry(pair, stake_amount, trade=trade)
# Assert trade is as expected (averaged dca)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id is None
assert pytest.approx(trade.open_rate) == 8.729729729729
assert trade.amount == 37
assert trade.stake_amount == 323
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 3
@ -5752,7 +5765,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
sub_trade_amt=15)
# Assert trade is as expected (averaged dca)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id is None
assert trade.is_open
@ -5760,7 +5773,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
assert trade.stake_amount == 192.05405405405406
assert pytest.approx(trade.open_rate) == 8.729729729729
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 4
@ -5825,10 +5838,10 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
assert freqtrade.execute_entry(pair, amount)
# Should create an closed trade with an no open order id
# Order is filled and trade is open
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 1
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
@ -5838,7 +5851,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
# Assume it does nothing since order is closed and trade is open
freqtrade.update_trades_without_assigned_fees()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
@ -5848,7 +5861,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
freqtrade.manage_open_orders()
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
@ -5884,7 +5897,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
assert len(trades) == 1
# Assert trade is as expected (averaged dca)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id is None
assert trade.amount == 50
@ -5893,7 +5906,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
assert pytest.approx(trade.realized_profit) == -152.375
assert pytest.approx(trade.close_profit_abs) == -152.375
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 2
# Make sure the closed order is found as the second order.
@ -5926,7 +5939,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
sub_trade_amt=amount)
# Assert trade is as expected (averaged dca)
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id is None
assert trade.amount == 50
@ -5935,7 +5948,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
# Trade fully realized
assert pytest.approx(trade.realized_profit) == 94.25
assert pytest.approx(trade.close_profit_abs) == 94.25
orders = Order.query.all()
orders = Order.session.scalars(select(Order)).all()
assert orders
assert len(orders) == 3
@ -6020,11 +6033,11 @@ def test_position_adjust3(mocker, default_conf_usdt, fee, data) -> None:
exit_check=ExitCheckTuple(exit_type=ExitType.PARTIAL_EXIT),
sub_trade_amt=amount)
orders1 = Order.query.all()
orders1 = Order.session.scalars(select(Order)).all()
assert orders1
assert len(orders1) == idx + 1
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
if idx < len(data) - 1:
assert trade.is_open is True
@ -6039,7 +6052,7 @@ def test_position_adjust3(mocker, default_conf_usdt, fee, data) -> None:
order_obj = trade.select_order(order[0], False)
assert order_obj.order_id == f'60{idx}'
trade = Trade.query.first()
trade = Trade.session.scalars(select(Trade)).first()
assert trade
assert trade.open_order_id is None
assert trade.is_open is False

View File

@ -1,6 +1,7 @@
from unittest.mock import MagicMock
import pytest
from sqlalchemy import select
from freqtrade.enums import ExitCheckTuple, ExitType, TradingMode
from freqtrade.persistence import Trade
@ -91,7 +92,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee,
assert freqtrade.strategy.confirm_trade_exit.call_count == 0
wallets_mock.reset_mock()
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
# Make sure stoploss-order is open and trade is bought (since we mock update_trade_state)
for trade in trades:
stoploss_order_closed['id'] = '3'
@ -179,13 +180,13 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, mocker, balance_rati
n = freqtrade.enter_positions()
assert n == 4
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
assert len(trades) == 4
assert freqtrade.wallets.get_trade_stake_amount('XRP/BTC') == result1
rpc._rpc_force_entry('TKN/BTC', None)
trades = Trade.query.all()
trades = Trade.session.scalars(select(Trade)).all()
assert len(trades) == 5
for trade in trades: