diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 92bdbc042..d61553305 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -7,7 +7,7 @@ import logging import time import traceback from datetime import datetime -from typing import Any, Callable, Dict, List, Optional +from typing import Any, Callable, Dict, List, Optional, Tuple import arrow from requests.exceptions import RequestException @@ -159,24 +159,20 @@ class FreqtradeBot(object): self.pairlists.refresh_pairlist() self.active_pair_whitelist = self.pairlists.whitelist - # Calculating Edge positiong + # Calculating Edge positioning if self.edge: self.edge.calculate() self.active_pair_whitelist = self.edge.adjust(self.active_pair_whitelist) # Query trades from persistence layer - trades = Trade.query.filter(Trade.is_open.is_(True)).all() + trades = Trade.get_open_trades() # Extend active-pair whitelist with pairs from open trades - # ensures that tickers are downloaded for open trades - self.active_pair_whitelist.extend([trade.pair for trade in trades - if trade.pair not in self.active_pair_whitelist]) + # It ensures that tickers are downloaded for open trades + self._extend_whitelist_with_trades(self.active_pair_whitelist, trades) - # Create pair-whitelist tuple with (pair, ticker_interval) - pair_whitelist_tuple = [(pair, self.config['ticker_interval']) - for pair in self.active_pair_whitelist] # Refreshing candles - self.dataprovider.refresh(pair_whitelist_tuple, + self.dataprovider.refresh(self._create_pair_whitelist(self.active_pair_whitelist), self.strategy.informative_pairs()) # First process current opened trades @@ -206,6 +202,18 @@ class FreqtradeBot(object): self.state = State.STOPPED return state_changed + def _extend_whitelist_with_trades(self, whitelist: List[str], trades: List[Any]): + """ + Extend whitelist with pairs from open trades + """ + whitelist.extend([trade.pair for trade in trades if trade.pair not in whitelist]) + + def _create_pair_whitelist(self, pairs: List[str]) -> List[Tuple[str, str]]: + """ + Create pair-whitelist tuple with (pair, ticker_interval) + """ + return [(pair, self.config['ticker_interval']) for pair in pairs] + def get_target_bid(self, pair: str) -> float: """ Calculates bid target between current ask price and last price @@ -253,7 +261,7 @@ class FreqtradeBot(object): avaliable_amount = self.wallets.get_free(self.config['stake_currency']) if stake_amount == constants.UNLIMITED_STAKE_AMOUNT: - open_trades = len(Trade.query.filter(Trade.is_open.is_(True)).all()) + open_trades = len(Trade.get_open_trades()) if open_trades >= self.config['max_open_trades']: logger.warning('Can\'t open a new trade: max number of trades is reached') return None @@ -311,7 +319,7 @@ class FreqtradeBot(object): whitelist = copy.deepcopy(self.active_pair_whitelist) # Remove currently opened and latest pairs from whitelist - for trade in Trade.query.filter(Trade.is_open.is_(True)).all(): + for trade in Trade.get_open_trades(): if trade.pair in whitelist: whitelist.remove(trade.pair) logger.debug('Ignoring %s in pair whitelist', trade.pair) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index f9b34fc64..f603b139f 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -5,7 +5,7 @@ This module contains the class to persist trades into SQLite import logging from datetime import datetime from decimal import Decimal -from typing import Any, Dict, Optional +from typing import Any, Dict, List, Optional import arrow from sqlalchemy import (Boolean, Column, DateTime, Float, Integer, String, @@ -371,3 +371,10 @@ class Trade(_DECL_BASE): .filter(Trade.is_open.is_(True))\ .scalar() return total_open_stake_amount or 0 + + @staticmethod + def get_open_trades() -> List[Any]: + """ + Query trades from persistence layer + """ + return Trade.query.filter(Trade.is_open.is_(True)).all() diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index e83d9d41b..5aa9bae35 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -83,7 +83,7 @@ class RPC(object): a remotely exposed function """ # Fetch open trade - trades = Trade.query.filter(Trade.is_open.is_(True)).all() + trades = Trade.get_open_trades() if not trades: raise RPCException('no active trade') else: @@ -118,7 +118,7 @@ class RPC(object): return results def _rpc_status_table(self) -> DataFrame: - trades = Trade.query.filter(Trade.is_open.is_(True)).all() + trades = Trade.get_open_trades() if not trades: raise RPCException('no active order') else: @@ -366,7 +366,7 @@ class RPC(object): if trade_id == 'all': # Execute sell for all open orders - for trade in Trade.query.filter(Trade.is_open.is_(True)).all(): + for trade in Trade.get_open_trades(): _exec_forcesell(trade) Trade.session.flush() return @@ -442,7 +442,7 @@ class RPC(object): if self._freqtrade.state != State.RUNNING: raise RPCException('trader is not running') - return Trade.query.filter(Trade.is_open.is_(True)).all() + return Trade.get_open_trades() def _rpc_whitelist(self) -> Dict: """ Returns the currently active whitelist""" diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index be6efc2ff..a9519e693 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -629,3 +629,48 @@ def test_adjust_stop_loss(limit_buy_order, limit_sell_order, fee): assert round(trade.stop_loss, 8) == 1.26 assert trade.max_rate == 1.4 assert trade.initial_stop_loss == 0.95 + + +def test_get_open(default_conf, fee): + init(default_conf) + + # Simulate dry_run entries + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=123.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=0.123, + exchange='bittrex', + open_order_id='dry_run_buy_12345' + ) + Trade.session.add(trade) + + trade = Trade( + pair='ETC/BTC', + stake_amount=0.001, + amount=123.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=0.123, + exchange='bittrex', + is_open=False, + open_order_id='dry_run_sell_12345' + ) + Trade.session.add(trade) + + # Simulate prod entry + trade = Trade( + pair='ETC/BTC', + stake_amount=0.001, + amount=123.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_rate=0.123, + exchange='bittrex', + open_order_id='prod_buy_12345' + ) + Trade.session.add(trade) + + assert len(Trade.get_open_trades()) == 2