|
33 | 33 | from freqtrade.exchange import Exchange, timeframe_to_minutes, timeframe_to_msecs
|
34 | 34 | from freqtrade.exchange.exchange_utils import price_to_precision
|
35 | 35 | from freqtrade.loggers import bufferHandler
|
36 |
| -from freqtrade.persistence import KeyStoreKeys, KeyValueStore, PairLocks, Trade |
| 36 | +from freqtrade.persistence import CustomDataWrapper, KeyStoreKeys, KeyValueStore, PairLocks, Trade |
37 | 37 | from freqtrade.persistence.models import PairLock
|
38 | 38 | from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
|
39 | 39 | from freqtrade.rpc.fiat_convert import CryptoToFiatConverter
|
@@ -1115,31 +1115,70 @@ def _rpc_delete(self, trade_id: int) -> dict[str, str | int]:
|
1115 | 1115 | "cancel_order_count": c_count,
|
1116 | 1116 | }
|
1117 | 1117 |
|
1118 |
| - def _rpc_list_custom_data(self, trade_id: int, key: str | None) -> list[dict[str, Any]]: |
1119 |
| - # Query for trade |
1120 |
| - trade = Trade.get_trades(trade_filter=[Trade.id == trade_id]).first() |
1121 |
| - if trade is None: |
1122 |
| - return [] |
1123 |
| - # Query custom_data |
1124 |
| - custom_data = [] |
1125 |
| - if key: |
1126 |
| - data = trade.get_custom_data(key=key) |
1127 |
| - if data: |
1128 |
| - custom_data = [data] |
| 1118 | + def _rpc_list_custom_data( |
| 1119 | + self, trade_id: int | None = None, key: str | None = None, limit: int = 100, offset: int = 0 |
| 1120 | + ) -> list[dict[str, Any]]: |
| 1121 | + """ |
| 1122 | + Fetch custom data for a specific trade, or all open trades if `trade_id` is not provided. |
| 1123 | + Pagination is applied via `limit` and `offset`. |
| 1124 | +
|
| 1125 | + Returns an array of dictionaries, each containing: |
| 1126 | + - "trade_id": the ID of the trade (int) |
| 1127 | + - "custom_data": a list of custom data dicts, each with the fields: |
| 1128 | + "id", "key", "type", "value", "created_at", "updated_at" |
| 1129 | + """ |
| 1130 | + trades: Sequence[Trade] |
| 1131 | + if trade_id is None: |
| 1132 | + # Get all open trades |
| 1133 | + trades = Trade.session.scalars( |
| 1134 | + Trade.get_trades_query([Trade.is_open.is_(True)]) |
| 1135 | + .order_by(Trade.id) |
| 1136 | + .limit(limit) |
| 1137 | + .offset(offset) |
| 1138 | + ).all() |
1129 | 1139 | else:
|
1130 |
| - custom_data = trade.get_all_custom_data() |
1131 |
| - return [ |
1132 |
| - { |
1133 |
| - "id": data_entry.id, |
1134 |
| - "ft_trade_id": data_entry.ft_trade_id, |
1135 |
| - "cd_key": data_entry.cd_key, |
1136 |
| - "cd_type": data_entry.cd_type, |
1137 |
| - "cd_value": data_entry.cd_value, |
1138 |
| - "created_at": data_entry.created_at, |
1139 |
| - "updated_at": data_entry.updated_at, |
1140 |
| - } |
1141 |
| - for data_entry in custom_data |
1142 |
| - ] |
| 1140 | + trades = Trade.get_trades(trade_filter=[Trade.id == trade_id]).all() |
| 1141 | + |
| 1142 | + if not trades: |
| 1143 | + raise RPCException( |
| 1144 | + f"No trade found for trade_id: {trade_id}" if trade_id else "No open trades found." |
| 1145 | + ) |
| 1146 | + |
| 1147 | + results = [] |
| 1148 | + for trade in trades: |
| 1149 | + # Depending on whether a specific key is provided, retrieve custom data accordingly. |
| 1150 | + if key: |
| 1151 | + data = trade.get_custom_data_entry(key=key) |
| 1152 | + # If data exists, wrap it in a list so the output remains consistent. |
| 1153 | + custom_data = [data] if data else [] |
| 1154 | + else: |
| 1155 | + custom_data = trade.get_all_custom_data() |
| 1156 | + |
| 1157 | + # Format and Append result for the trade if any custom data was found. |
| 1158 | + if custom_data: |
| 1159 | + formatted_custom_data = [ |
| 1160 | + { |
| 1161 | + "key": data_entry.cd_key, |
| 1162 | + "type": data_entry.cd_type, |
| 1163 | + "value": CustomDataWrapper._convert_custom_data(data_entry).value, |
| 1164 | + "created_at": data_entry.created_at, |
| 1165 | + "updated_at": data_entry.updated_at, |
| 1166 | + } |
| 1167 | + for data_entry in custom_data |
| 1168 | + ] |
| 1169 | + results.append({"trade_id": trade.id, "custom_data": formatted_custom_data}) |
| 1170 | + |
| 1171 | + # Handle case when there is no custom data found across trades. |
| 1172 | + if not results: |
| 1173 | + message_details = "" |
| 1174 | + if key: |
| 1175 | + message_details += f"with key '{key}' " |
| 1176 | + message_details += ( |
| 1177 | + f"found for Trade ID: {trade_id}." if trade_id else "found for any open trades." |
| 1178 | + ) |
| 1179 | + raise RPCException(f"No custom-data {message_details}") |
| 1180 | + |
| 1181 | + return results |
1143 | 1182 |
|
1144 | 1183 | def _rpc_performance(self) -> list[dict[str, Any]]:
|
1145 | 1184 | """
|
|
0 commit comments