From e245f80e1893a1b70ff9d86f019a42b2b541652c Mon Sep 17 00:00:00 2001 From: rob Date: Sat, 28 Feb 2026 16:47:13 -0400 Subject: [PATCH] Phase 1: Repair runtime breakpoints - Fix set_new_candle() to update cached candle instead of raising - Fix trades.update() type mismatch: pass {symbol: price} dict - Fix StrategyInstance.trades collision: rename list to trade_history - Add missing ExchangeInterface methods for trade status/qty/price - Add get_user_balance stub for paper trading Co-Authored-By: Claude Opus 4.5 --- src/BrighterTrades.py | 7 ++++- src/ExchangeInterface.py | 55 ++++++++++++++++++++++++++++++++++++++++ src/StrategyInstance.py | 2 +- src/candles.py | 26 ++++++++----------- 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/BrighterTrades.py b/src/BrighterTrades.py index b42fa69..8edd42a 100644 --- a/src/BrighterTrades.py +++ b/src/BrighterTrades.py @@ -343,7 +343,12 @@ class BrighterTrades: self.candles.set_new_candle(cdata) # i_updates = self.indicators.update_indicators() state_changes = self.signals.process_all_signals(self.indicators) - trade_updates = self.trades.update(float(cdata['close'])) + + # Build price updates dict: trades.update expects {symbol: price} + symbol = cdata.get('symbol', cdata.get('market', 'BTC/USDT')) + price_updates = {symbol: float(cdata['close'])} + trade_updates = self.trades.update(price_updates) + # stg_updates = self.strategies.update() updates = {} diff --git a/src/ExchangeInterface.py b/src/ExchangeInterface.py index 79cdaca..9b55637 100644 --- a/src/ExchangeInterface.py +++ b/src/ExchangeInterface.py @@ -317,3 +317,58 @@ class ExchangeInterface: return self.default_exchange.get_price(symbol=symbol) else: raise ValueError(f'No implementation for price source: {price_source}') + + def get_trade_status(self, trade) -> str: + """ + Get the status of a trade order. + + For paper/backtest modes, assumes immediate fill (returns 'FILLED'). + For live mode, should query the exchange. + + :param trade: The trade object. + :return: Status string ('FILLED', 'PARTIALLY_FILLED', 'PENDING', etc.) + """ + # If order is None, it hasn't been placed yet + if trade.order is None: + return 'PENDING' + + # For paper trading / backtesting, assume immediate fill + # TODO: For live trading, query exchange via get_trade_info + return 'FILLED' + + def get_trade_executed_qty(self, trade) -> float: + """ + Get the executed quantity of a trade order. + + For paper/backtest modes, returns the full order quantity (assumes full fill). + + :param trade: The trade object. + :return: Executed quantity. + """ + # For paper trading / backtesting, assume full fill + return trade.base_order_qty + + def get_trade_executed_price(self, trade) -> float: + """ + Get the executed price of a trade order. + + For paper/backtest modes, returns the order price. + + :param trade: The trade object. + :return: Executed price. + """ + # For paper trading / backtesting, use order price + return trade.order_price + + def get_user_balance(self, user_id: int) -> float: + """ + Get the balance for a user. + + Stub implementation for paper trading. + + :param user_id: The user ID. + :return: Balance amount (default 10000.0 for paper trading). + """ + # TODO: Implement proper balance tracking per user + # For paper trading, return a default balance + return 10000.0 diff --git a/src/StrategyInstance.py b/src/StrategyInstance.py index 98109dc..c7f0104 100644 --- a/src/StrategyInstance.py +++ b/src/StrategyInstance.py @@ -52,7 +52,7 @@ class StrategyInstance: self.exit: bool = False self.exit_method: str = 'all' self.start_time = dt.datetime.now() - self.trades = [] # List to store trade details + self.trade_history = [] # List to store trade details (not the Trades manager) self.orders = [] # List to store order details self.profit_loss = 0.0 # Total P&L self.statistics = { diff --git a/src/candles.py b/src/candles.py index 8504c1e..81f9def 100644 --- a/src/candles.py +++ b/src/candles.py @@ -79,25 +79,19 @@ class Candles: # Return the results. The start_datetime was approximate, so we may have retrieved an extra result. return self.convert_candles(candles[-num_candles:]) - def set_new_candle(self, cdata): + def set_new_candle(self, cdata: dict) -> bool: """ - Sets the last candle and updates the latest values list. + Updates the cached last candle with new candle data. + Called when live price data arrives via WebSocket. - :param cdata: A list of data for a single candle.[ot,o,h,l,c,ct,...] - :return: True. todo: This method probably wont be needed. + :param cdata: Dictionary containing candle data with keys like + 'time', 'open', 'high', 'low', 'close', 'volume', 'symbol', etc. + :return: True if the candle was updated. """ - raise ValueError('set_new_candle') - # this will probably rename to update_cache() - - # - # if cdata[4] < self.cashed_candlesticks[-2][4]: - # color = 'rgba(255,82,82, 0.8)' # Red - # else: - # color = 'rgba(0, 150, 136, 0.8)' # Green - # self.cashed_vol.append({'time': cdata['time'], 'value': cdata['vol'], "color": color}) - # self.cashed_vol.pop(0) - # return True - # + # Update the cached last candle + self.cached_last_candle = cdata + log.debug(f"Candle updated: {cdata.get('symbol', 'unknown')} @ {cdata.get('close', 0)}") + return True def set_cache(self, symbol=None, interval=None, exchange_name=None, user_name=None): """ This method requests a chart from memory to ensure the data is initialized.