mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 10:21:59 +00:00
Merge pull request #4671 from freqtrade/fix/sqlalchemy
sqlalchemy database locked bug
This commit is contained in:
commit
431f0a3db4
|
@ -187,7 +187,7 @@ class FreqtradeBot(LoggingMixin):
|
|||
if self.get_free_open_trades():
|
||||
self.enter_positions()
|
||||
|
||||
Trade.session.flush()
|
||||
Trade.query.session.flush()
|
||||
|
||||
def process_stopped(self) -> None:
|
||||
"""
|
||||
|
@ -621,8 +621,8 @@ class FreqtradeBot(LoggingMixin):
|
|||
if order_status == 'closed':
|
||||
self.update_trade_state(trade, order_id, order)
|
||||
|
||||
Trade.session.add(trade)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.add(trade)
|
||||
Trade.query.session.flush()
|
||||
|
||||
# Updating wallets
|
||||
self.wallets.update()
|
||||
|
@ -1205,7 +1205,7 @@ class FreqtradeBot(LoggingMixin):
|
|||
# In case of market sell orders the order can be closed immediately
|
||||
if order.get('status', 'unknown') == 'closed':
|
||||
self.update_trade_state(trade, trade.open_order_id, order)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.flush()
|
||||
|
||||
# Lock pair for one candle to prevent immediate rebuys
|
||||
self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc),
|
||||
|
|
|
@ -59,13 +59,10 @@ def init_db(db_url: str, clean_open_orders: bool = False) -> 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=True, autocommit=True))
|
||||
Trade.query = Trade.session.query_property()
|
||||
# Copy session attributes to order object too
|
||||
Order.session = Trade.session
|
||||
Order.query = Order.session.query_property()
|
||||
PairLock.session = Trade.session
|
||||
PairLock.query = PairLock.session.query_property()
|
||||
Trade._session = scoped_session(sessionmaker(bind=engine, autoflush=True, autocommit=True))
|
||||
Trade.query = Trade._session.query_property()
|
||||
Order.query = Trade._session.query_property()
|
||||
PairLock.query = Trade._session.query_property()
|
||||
|
||||
previous_tables = inspect(engine).get_table_names()
|
||||
_DECL_BASE.metadata.create_all(engine)
|
||||
|
@ -81,7 +78,7 @@ def cleanup_db() -> None:
|
|||
Flushes all pending operations to disk.
|
||||
:return: None
|
||||
"""
|
||||
Trade.session.flush()
|
||||
Trade.query.session.flush()
|
||||
|
||||
|
||||
def clean_dry_run_db() -> None:
|
||||
|
@ -677,7 +674,7 @@ class LocalTrade():
|
|||
in stake currency
|
||||
"""
|
||||
if Trade.use_db:
|
||||
total_open_stake_amount = Trade.session.query(
|
||||
total_open_stake_amount = Trade.query.with_entities(
|
||||
func.sum(Trade.stake_amount)).filter(Trade.is_open.is_(True)).scalar()
|
||||
else:
|
||||
total_open_stake_amount = sum(
|
||||
|
@ -689,7 +686,7 @@ class LocalTrade():
|
|||
"""
|
||||
Returns List of dicts containing all Trades, including profit and trade count
|
||||
"""
|
||||
pair_rates = Trade.session.query(
|
||||
pair_rates = Trade.query.with_entities(
|
||||
Trade.pair,
|
||||
func.sum(Trade.close_profit).label('profit_sum'),
|
||||
func.count(Trade.pair).label('count')
|
||||
|
@ -712,7 +709,7 @@ class LocalTrade():
|
|||
Get best pair with closed trade.
|
||||
:returns: Tuple containing (pair, profit_sum)
|
||||
"""
|
||||
best_pair = Trade.session.query(
|
||||
best_pair = Trade.query.with_entities(
|
||||
Trade.pair, func.sum(Trade.close_profit).label('profit_sum')
|
||||
).filter(Trade.is_open.is_(False)) \
|
||||
.group_by(Trade.pair) \
|
||||
|
@ -805,10 +802,10 @@ class Trade(_DECL_BASE, LocalTrade):
|
|||
def delete(self) -> None:
|
||||
|
||||
for order in self.orders:
|
||||
Order.session.delete(order)
|
||||
Order.query.session.delete(order)
|
||||
|
||||
Trade.session.delete(self)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.delete(self)
|
||||
Trade.query.session.flush()
|
||||
|
||||
@staticmethod
|
||||
def get_trades_proxy(*, pair: str = None, is_open: bool = None,
|
||||
|
|
|
@ -48,8 +48,8 @@ class PairLocks():
|
|||
active=True
|
||||
)
|
||||
if PairLocks.use_db:
|
||||
PairLock.session.add(lock)
|
||||
PairLock.session.flush()
|
||||
PairLock.query.session.add(lock)
|
||||
PairLock.query.session.flush()
|
||||
else:
|
||||
PairLocks.locks.append(lock)
|
||||
|
||||
|
@ -99,7 +99,7 @@ class PairLocks():
|
|||
for lock in locks:
|
||||
lock.active = False
|
||||
if PairLocks.use_db:
|
||||
PairLock.session.flush()
|
||||
PairLock.query.session.flush()
|
||||
|
||||
@staticmethod
|
||||
def is_global_lock(now: Optional[datetime] = None) -> bool:
|
||||
|
|
|
@ -558,7 +558,7 @@ class RPC:
|
|||
# Execute sell for all open orders
|
||||
for trade in Trade.get_open_trades():
|
||||
_exec_forcesell(trade)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.flush()
|
||||
self._freqtrade.wallets.update()
|
||||
return {'result': 'Created sell orders for all open trades.'}
|
||||
|
||||
|
@ -571,7 +571,7 @@ class RPC:
|
|||
raise RPCException('invalid argument')
|
||||
|
||||
_exec_forcesell(trade)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.flush()
|
||||
self._freqtrade.wallets.update()
|
||||
return {'result': f'Created sell order for trade {trade_id}.'}
|
||||
|
||||
|
@ -696,7 +696,7 @@ class RPC:
|
|||
lock.lock_end_time = datetime.now(timezone.utc)
|
||||
|
||||
# session is always the same
|
||||
PairLock.session.flush()
|
||||
PairLock.query.session.flush()
|
||||
|
||||
return self._rpc_locks()
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ def create_mock_trades(fee, use_db: bool = True):
|
|||
"""
|
||||
def add_trade(trade):
|
||||
if use_db:
|
||||
Trade.session.add(trade)
|
||||
Trade.query.session.add(trade)
|
||||
else:
|
||||
LocalTrade.add_bt_trade(trade)
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog):
|
|||
assert not log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=200, min_ago_close=30,
|
||||
))
|
||||
|
@ -100,12 +100,12 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog):
|
|||
assert not log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
# This trade does not count, as it's closed too long ago
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'BCH/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=250, min_ago_close=100,
|
||||
))
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'ETH/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=240, min_ago_close=30,
|
||||
))
|
||||
|
@ -114,7 +114,7 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog):
|
|||
assert not log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'LTC/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=180, min_ago_close=30,
|
||||
))
|
||||
|
@ -148,7 +148,7 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair
|
|||
assert not log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
pair, fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=200, min_ago_close=30, profit_rate=0.9,
|
||||
))
|
||||
|
@ -158,12 +158,12 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair
|
|||
assert not log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
# This trade does not count, as it's closed too long ago
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
pair, fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=250, min_ago_close=100, profit_rate=0.9,
|
||||
))
|
||||
# Trade does not count for per pair stop as it's the wrong pair.
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'ETH/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=240, min_ago_close=30, profit_rate=0.9,
|
||||
))
|
||||
|
@ -178,7 +178,7 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair
|
|||
caplog.clear()
|
||||
|
||||
# 2nd Trade that counts with correct pair
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
pair, fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=180, min_ago_close=30, profit_rate=0.9,
|
||||
))
|
||||
|
@ -203,7 +203,7 @@ def test_CooldownPeriod(mocker, default_conf, fee, caplog):
|
|||
assert not log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=200, min_ago_close=30,
|
||||
))
|
||||
|
@ -213,7 +213,7 @@ def test_CooldownPeriod(mocker, default_conf, fee, caplog):
|
|||
assert PairLocks.is_pair_locked('XRP/BTC')
|
||||
assert not PairLocks.is_global_lock()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'ETH/BTC', fee.return_value, False, sell_reason=SellType.ROI.value,
|
||||
min_ago_open=205, min_ago_close=35,
|
||||
))
|
||||
|
@ -242,7 +242,7 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog):
|
|||
assert not log_has_re(message, caplog)
|
||||
caplog.clear()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=800, min_ago_close=450, profit_rate=0.9,
|
||||
))
|
||||
|
@ -253,7 +253,7 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog):
|
|||
assert not PairLocks.is_pair_locked('XRP/BTC')
|
||||
assert not PairLocks.is_global_lock()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=200, min_ago_close=120, profit_rate=0.9,
|
||||
))
|
||||
|
@ -265,14 +265,14 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog):
|
|||
assert not PairLocks.is_global_lock()
|
||||
|
||||
# Add positive trade
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.ROI.value,
|
||||
min_ago_open=20, min_ago_close=10, profit_rate=1.15,
|
||||
))
|
||||
assert not freqtrade.protections.stop_per_pair('XRP/BTC')
|
||||
assert not PairLocks.is_pair_locked('XRP/BTC')
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=110, min_ago_close=20, profit_rate=0.8,
|
||||
))
|
||||
|
@ -300,15 +300,15 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog):
|
|||
assert not freqtrade.protections.stop_per_pair('XRP/BTC')
|
||||
caplog.clear()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=1000, min_ago_close=900, profit_rate=1.1,
|
||||
))
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'ETH/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=1000, min_ago_close=900, profit_rate=1.1,
|
||||
))
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'NEO/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=1000, min_ago_close=900, profit_rate=1.1,
|
||||
))
|
||||
|
@ -316,7 +316,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog):
|
|||
assert not freqtrade.protections.global_stop()
|
||||
assert not freqtrade.protections.stop_per_pair('XRP/BTC')
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=500, min_ago_close=400, profit_rate=0.9,
|
||||
))
|
||||
|
@ -326,7 +326,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog):
|
|||
assert not PairLocks.is_pair_locked('XRP/BTC')
|
||||
assert not PairLocks.is_global_lock()
|
||||
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.STOP_LOSS.value,
|
||||
min_ago_open=1200, min_ago_close=1100, profit_rate=0.5,
|
||||
))
|
||||
|
@ -339,7 +339,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog):
|
|||
assert not log_has_re(message, caplog)
|
||||
|
||||
# Winning trade ... (should not lock, does not change drawdown!)
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.ROI.value,
|
||||
min_ago_open=320, min_ago_close=410, profit_rate=1.5,
|
||||
))
|
||||
|
@ -349,7 +349,7 @@ def test_MaxDrawdown(mocker, default_conf, fee, caplog):
|
|||
caplog.clear()
|
||||
|
||||
# Add additional negative trade, causing a loss of > 15%
|
||||
Trade.session.add(generate_mock_trade(
|
||||
Trade.query.session.add(generate_mock_trade(
|
||||
'XRP/BTC', fee.return_value, False, sell_reason=SellType.ROI.value,
|
||||
min_ago_open=20, min_ago_close=10, profit_rate=0.8,
|
||||
))
|
||||
|
|
|
@ -510,7 +510,7 @@ def test_api_trades(botclient, mocker, fee, markets):
|
|||
assert rc.json()['trades_count'] == 0
|
||||
|
||||
create_mock_trades(fee)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.flush()
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/trades")
|
||||
assert_response(rc)
|
||||
|
@ -538,7 +538,7 @@ def test_api_delete_trade(botclient, mocker, fee, markets):
|
|||
assert_response(rc, 502)
|
||||
|
||||
create_mock_trades(fee)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.flush()
|
||||
ftbot.strategy.order_types['stoploss_on_exchange'] = True
|
||||
trades = Trade.query.all()
|
||||
trades[1].stoploss_order_id = '1234'
|
||||
|
@ -720,7 +720,7 @@ def test_api_performance(botclient, mocker, ticker, fee):
|
|||
|
||||
)
|
||||
trade.close_profit = trade.calc_profit_ratio()
|
||||
Trade.session.add(trade)
|
||||
Trade.query.session.add(trade)
|
||||
|
||||
trade = Trade(
|
||||
pair='XRP/ETH',
|
||||
|
@ -735,8 +735,8 @@ def test_api_performance(botclient, mocker, ticker, fee):
|
|||
close_rate=0.391
|
||||
)
|
||||
trade.close_profit = trade.calc_profit_ratio()
|
||||
Trade.session.add(trade)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.add(trade)
|
||||
Trade.query.session.flush()
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/performance")
|
||||
assert_response(rc)
|
||||
|
@ -764,7 +764,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets):
|
|||
trades = Trade.get_open_trades()
|
||||
trades[0].open_order_id = None
|
||||
ftbot.exit_positions(trades)
|
||||
Trade.session.flush()
|
||||
Trade.query.session.flush()
|
||||
|
||||
rc = client_get(client, f"{BASE_URI}/status")
|
||||
assert_response(rc)
|
||||
|
|
|
@ -768,7 +768,7 @@ def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order,
|
|||
assert pair not in default_conf['exchange']['pair_whitelist']
|
||||
|
||||
# create open trade not in whitelist
|
||||
Trade.session.add(Trade(
|
||||
Trade.query.session.add(Trade(
|
||||
pair=pair,
|
||||
stake_amount=0.001,
|
||||
fee_open=fee.return_value,
|
||||
|
@ -778,7 +778,7 @@ def test_process_trade_no_whitelist_pair(default_conf, ticker, limit_buy_order,
|
|||
open_rate=0.01,
|
||||
exchange='bittrex',
|
||||
))
|
||||
Trade.session.add(Trade(
|
||||
Trade.query.session.add(Trade(
|
||||
pair='ETH/BTC',
|
||||
stake_amount=0.001,
|
||||
fee_open=fee.return_value,
|
||||
|
@ -1779,7 +1779,6 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_
|
|||
# fetch_order should not be called!!
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', MagicMock(side_effect=ValueError))
|
||||
patch_exchange(mocker)
|
||||
Trade.session = MagicMock()
|
||||
amount = sum(x['amount'] for x in trades_for_order)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
trade = Trade(
|
||||
|
@ -1805,7 +1804,6 @@ def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_
|
|||
# fetch_order should not be called!!
|
||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order', MagicMock(side_effect=ValueError))
|
||||
patch_exchange(mocker)
|
||||
Trade.session = MagicMock()
|
||||
amount = sum(x['amount'] for x in trades_for_order)
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
trade = Trade(
|
||||
|
@ -1868,7 +1866,6 @@ def test_update_trade_state_sell(default_conf, trades_for_order, limit_sell_orde
|
|||
mocker.patch('freqtrade.wallets.Wallets.update', wallet_mock)
|
||||
|
||||
patch_exchange(mocker)
|
||||
Trade.session = MagicMock()
|
||||
amount = limit_sell_order["amount"]
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
wallet_mock.reset_mock()
|
||||
|
@ -2110,7 +2107,7 @@ def test_check_handle_timedout_buy_usercustom(default_conf, ticker, limit_buy_or
|
|||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# Ensure default is to return empty (so not mocked yet)
|
||||
freqtrade.check_handle_timedout()
|
||||
|
@ -2161,7 +2158,7 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, op
|
|||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
freqtrade.strategy.check_buy_timeout = MagicMock(return_value=False)
|
||||
# check it does cancel buy orders over the time limit
|
||||
|
@ -2191,7 +2188,7 @@ def test_check_handle_cancelled_buy(default_conf, ticker, limit_buy_order_old, o
|
|||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# check it does cancel buy orders over the time limit
|
||||
freqtrade.check_handle_timedout()
|
||||
|
@ -2218,7 +2215,7 @@ def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_ord
|
|||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# check it does cancel buy orders over the time limit
|
||||
freqtrade.check_handle_timedout()
|
||||
|
@ -2248,7 +2245,7 @@ def test_check_handle_timedout_sell_usercustom(default_conf, ticker, limit_sell_
|
|||
open_trade.close_profit_abs = 0.001
|
||||
open_trade.is_open = False
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
# Ensure default is false
|
||||
freqtrade.check_handle_timedout()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
|
@ -2296,7 +2293,7 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old,
|
|||
open_trade.close_profit_abs = 0.001
|
||||
open_trade.is_open = False
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
freqtrade.strategy.check_sell_timeout = MagicMock(return_value=False)
|
||||
# check it does cancel sell orders over the time limit
|
||||
|
@ -2327,7 +2324,7 @@ def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old,
|
|||
open_trade.close_date = arrow.utcnow().shift(minutes=-601).datetime
|
||||
open_trade.is_open = False
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# check it does cancel sell orders over the time limit
|
||||
freqtrade.check_handle_timedout()
|
||||
|
@ -2353,7 +2350,7 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old
|
|||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
# check it does cancel buy orders over the time limit
|
||||
# note this is for a partially-complete buy order
|
||||
|
@ -2386,7 +2383,7 @@ def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, cap
|
|||
|
||||
open_trade.fee_open = fee()
|
||||
open_trade.fee_close = fee()
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
# cancelling a half-filled order should update the amount to the bought amount
|
||||
# and apply fees if necessary.
|
||||
freqtrade.check_handle_timedout()
|
||||
|
@ -2426,7 +2423,7 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade,
|
|||
|
||||
open_trade.fee_open = fee()
|
||||
open_trade.fee_close = fee()
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
# cancelling a half-filled order should update the amount to the bought amount
|
||||
# and apply fees if necessary.
|
||||
freqtrade.check_handle_timedout()
|
||||
|
@ -2463,7 +2460,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocke
|
|||
)
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
Trade.session.add(open_trade)
|
||||
Trade.query.session.add(open_trade)
|
||||
|
||||
freqtrade.check_handle_timedout()
|
||||
assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, "
|
||||
|
@ -2486,7 +2483,6 @@ def test_handle_cancel_buy(mocker, caplog, default_conf, limit_buy_order) -> Non
|
|||
freqtrade = FreqtradeBot(default_conf)
|
||||
freqtrade._notify_buy_cancel = MagicMock()
|
||||
|
||||
Trade.session = MagicMock()
|
||||
trade = MagicMock()
|
||||
trade.pair = 'LTC/ETH'
|
||||
limit_buy_order['filled'] = 0.0
|
||||
|
@ -2520,7 +2516,6 @@ def test_handle_cancel_buy_exchanges(mocker, caplog, default_conf,
|
|||
nofiy_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot._notify_buy_cancel')
|
||||
freqtrade = FreqtradeBot(default_conf)
|
||||
|
||||
Trade.session = MagicMock()
|
||||
reason = CANCEL_REASON['TIMEOUT']
|
||||
trade = MagicMock()
|
||||
trade.pair = 'LTC/ETH'
|
||||
|
@ -2549,7 +2544,6 @@ def test_handle_cancel_buy_corder_empty(mocker, default_conf, limit_buy_order,
|
|||
freqtrade = FreqtradeBot(default_conf)
|
||||
freqtrade._notify_buy_cancel = MagicMock()
|
||||
|
||||
Trade.session = MagicMock()
|
||||
trade = MagicMock()
|
||||
trade.pair = 'LTC/ETH'
|
||||
limit_buy_order['filled'] = 0.0
|
||||
|
@ -2812,7 +2806,6 @@ def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee, c
|
|||
freqtrade.enter_positions()
|
||||
|
||||
trade = Trade.query.first()
|
||||
Trade.session = MagicMock()
|
||||
PairLock.session = MagicMock()
|
||||
|
||||
freqtrade.config['dry_run'] = False
|
||||
|
@ -4422,7 +4415,7 @@ def test_reupdate_buy_order_fees(mocker, default_conf, fee, caplog):
|
|||
open_rate=0.01,
|
||||
exchange='bittrex',
|
||||
)
|
||||
Trade.session.add(trade)
|
||||
Trade.query.session.add(trade)
|
||||
|
||||
freqtrade.reupdate_buy_order_fees(trade)
|
||||
assert log_has_re(r"Trying to reupdate buy fees for .*", caplog)
|
||||
|
|
|
@ -89,7 +89,6 @@ def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee,
|
|||
freqtrade.strategy.confirm_trade_entry.reset_mock()
|
||||
assert freqtrade.strategy.confirm_trade_exit.call_count == 0
|
||||
wallets_mock.reset_mock()
|
||||
Trade.session = MagicMock()
|
||||
|
||||
trades = Trade.query.all()
|
||||
# Make sure stoploss-order is open and trade is bought (since we mock update_trade_state)
|
||||
|
|
|
@ -18,8 +18,8 @@ from tests.conftest import create_mock_trades, log_has, log_has_re
|
|||
def test_init_create_session(default_conf):
|
||||
# Check if init create a session
|
||||
init_db(default_conf['db_url'], default_conf['dry_run'])
|
||||
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):
|
||||
|
@ -403,7 +403,7 @@ def test_clean_dry_run_db(default_conf, fee):
|
|||
exchange='bittrex',
|
||||
open_order_id='dry_run_buy_12345'
|
||||
)
|
||||
Trade.session.add(trade)
|
||||
Trade.query.session.add(trade)
|
||||
|
||||
trade = Trade(
|
||||
pair='ETC/BTC',
|
||||
|
@ -415,7 +415,7 @@ def test_clean_dry_run_db(default_conf, fee):
|
|||
exchange='bittrex',
|
||||
open_order_id='dry_run_sell_12345'
|
||||
)
|
||||
Trade.session.add(trade)
|
||||
Trade.query.session.add(trade)
|
||||
|
||||
# Simulate prod entry
|
||||
trade = Trade(
|
||||
|
@ -428,7 +428,7 @@ def test_clean_dry_run_db(default_conf, fee):
|
|||
exchange='bittrex',
|
||||
open_order_id='prod_buy_12345'
|
||||
)
|
||||
Trade.session.add(trade)
|
||||
Trade.query.session.add(trade)
|
||||
|
||||
# We have 3 entries: 2 dry_run, 1 prod
|
||||
assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 3
|
||||
|
@ -933,7 +933,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.session.add(trade)
|
||||
Trade.query.session.add(trade)
|
||||
|
||||
# Lower stoploss
|
||||
Trade.stoploss_reinitialization(0.06)
|
||||
|
|
Loading…
Reference in New Issue
Block a user