diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 6dc8eacf9..5376e06af 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -4,7 +4,7 @@ Freqtrade is the main module of this bot. It contains the class Freqtrade() import copy import logging import traceback -from datetime import datetime, timezone +from datetime import datetime, timezone, timedelta from math import isclose from threading import Lock from typing import Any, Dict, List, Optional @@ -93,6 +93,11 @@ class FreqtradeBot(LoggingMixin): self.active_pair_whitelist = self._refresh_active_whitelist() + self.cluster_trades_enabled = self.config["cluster_trades"]["cluster_trades_enabled"] or False + self.cluster_trade_timeout = self.config["cluster_trades"]["cluster_trade_timeout"] or 2592000000 # 30 days + self.max_cluster_trades = self.config["cluster_trades"]["max_cluster_trades"] or 1 + self.cluster_trades = [] + # Set initial bot state from config initial_state = self.config.get('initial_state') self.state = State[initial_state.upper()] if initial_state else State.STOPPED @@ -344,6 +349,36 @@ class FreqtradeBot(LoggingMixin): except ExchangeError: logger.warning(f"Error updating {order.order_id}.") + def assess_cluster_trades(self, pair) -> bool: + if self.cluster_trades_enabled: + # return true if max cluster trades reached else return false + for cluster in self.cluster_trades: + if cluster[0] == pair: + if len(cluster[1]) >= self.max_cluster_trades: + return True + + return False + + return True + + def manage_cluster_trades(self) -> None: + now = datetime.utcnow() + # remove trades from cluster trades lists after timeout + for cluster in self.cluster_trades: + cluster[1] = [item for item in cluster[1] if now < item + timedelta(seconds = self.cluster_trade_timeout)] + + def add_cluster_trade(self, pair, time) -> None: + if self.cluster_trades_enabled: + # add time of trade to existing pair in cluster trades list + for cluster in self.cluster_trades: + if cluster[0] == pair: + cluster[1].append(time) + return + + # add pair and time to cluster trades list if not found + self.cluster_trades.append([pair, [time]]) + + # # BUY / enter positions / open trades logic and methods # @@ -355,12 +390,16 @@ class FreqtradeBot(LoggingMixin): trades_created = 0 whitelist = copy.deepcopy(self.active_pair_whitelist) + + #update cluster trade lists + self.manage_cluster_trades() + if not whitelist: logger.info("Active pair whitelist is empty.") return trades_created - # Remove pairs for currently opened trades from the whitelist + # Remove pairs for currently opened trades from the whitelist if max cluster trades has been reached for that pair for trade in Trade.get_open_trades(): - if trade.pair in whitelist: + if trade.pair in whitelist and self.assess_cluster_trades(trade.pair): whitelist.remove(trade.pair) logger.debug('Ignoring %s in pair whitelist', trade.pair) @@ -716,6 +755,8 @@ class FreqtradeBot(LoggingMixin): ) trade.orders.append(order_obj) + self.add_cluster_trade(trade.pair, trade.open_date) + # Update fees if order is closed if order_status == 'closed': self.update_trade_state(trade, order_id, order) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 3680dd416..1f630d809 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -75,13 +75,35 @@ class Wallets: current_stake ) + # for trade in open_trades: + # curr = self._exchange.get_pair_base_currency(trade.pair) + # _wallets[curr] = Wallet( + # curr, + # trade.amount, + # 0, + # trade.amount + # ) + + balances = [] for trade in open_trades: curr = self._exchange.get_pair_base_currency(trade.pair) + found = False + for bal in balances: + if curr == bal[0]: + found = True + bal[1] += trade.amount + + if not found: + balances.append([curr, trade.amount]) + + for bal in balances: + curr = bal[0] + amount = bal[1] _wallets[curr] = Wallet( curr, - trade.amount, + amount, 0, - trade.amount + amount ) self._wallets = _wallets