|
@@ -113,12 +113,29 @@ class TelegramTradingBot:
|
|
|
def _save_bot_state(self):
|
|
|
"""Save bot state to disk."""
|
|
|
try:
|
|
|
+ # Helper function to safely convert datetime to ISO string
|
|
|
+ def safe_datetime_to_iso(dt):
|
|
|
+ if dt is None:
|
|
|
+ return None
|
|
|
+ try:
|
|
|
+ # Handle both datetime objects and strings
|
|
|
+ if isinstance(dt, str):
|
|
|
+ # If it's already a string, validate it's a valid ISO format
|
|
|
+ datetime.fromisoformat(dt.replace('Z', '+00:00'))
|
|
|
+ return dt
|
|
|
+ else:
|
|
|
+ # Convert datetime object to ISO string
|
|
|
+ return dt.isoformat()
|
|
|
+ except (ValueError, AttributeError) as e:
|
|
|
+ logger.warning(f"⚠️ Invalid datetime value, using None: {dt} - {e}")
|
|
|
+ return None
|
|
|
+
|
|
|
state_data = {
|
|
|
'pending_stop_losses': self.pending_stop_losses,
|
|
|
'last_known_orders': list(self.last_known_orders), # Convert set to list for JSON
|
|
|
'last_known_positions': self.last_known_positions,
|
|
|
- 'last_processed_trade_time': self.last_processed_trade_time.isoformat() if self.last_processed_trade_time else None,
|
|
|
- 'last_deposit_withdrawal_check': self.last_deposit_withdrawal_check.isoformat() if self.last_deposit_withdrawal_check else None,
|
|
|
+ 'last_processed_trade_time': safe_datetime_to_iso(self.last_processed_trade_time),
|
|
|
+ 'last_deposit_withdrawal_check': safe_datetime_to_iso(self.last_deposit_withdrawal_check),
|
|
|
'last_updated': datetime.now().isoformat(),
|
|
|
'version': self.version
|
|
|
}
|
|
@@ -2627,7 +2644,7 @@ This will place a limit {exit_side} order at ${profit_price:,.2f} to capture pro
|
|
|
# Initialize last processed time if first run
|
|
|
if self.last_processed_trade_time is None:
|
|
|
# Set to current time minus 1 hour to catch recent activity
|
|
|
- self.last_processed_trade_time = (datetime.now() - timedelta(hours=1)).isoformat()
|
|
|
+ self.last_processed_trade_time = datetime.now() - timedelta(hours=1)
|
|
|
|
|
|
# Filter for new trades since last check
|
|
|
new_trades = []
|
|
@@ -2638,18 +2655,19 @@ This will place a limit {exit_side} order at ${profit_price:,.2f} to capture pro
|
|
|
if fill_time:
|
|
|
# Convert timestamps to comparable format
|
|
|
try:
|
|
|
- # Convert fill_time to string if it's not already
|
|
|
+ # Convert fill_time to datetime object for comparison
|
|
|
if isinstance(fill_time, (int, float)):
|
|
|
# Assume it's a unix timestamp
|
|
|
- fill_time_str = datetime.fromtimestamp(fill_time / 1000 if fill_time > 1e10 else fill_time).isoformat()
|
|
|
+ fill_datetime = datetime.fromtimestamp(fill_time / 1000 if fill_time > 1e10 else fill_time)
|
|
|
else:
|
|
|
- fill_time_str = str(fill_time)
|
|
|
+ # Try to parse as ISO string
|
|
|
+ fill_datetime = datetime.fromisoformat(str(fill_time).replace('Z', '+00:00'))
|
|
|
|
|
|
- # Compare as strings
|
|
|
- if fill_time_str > self.last_processed_trade_time:
|
|
|
+ # Compare datetime objects
|
|
|
+ if fill_datetime > self.last_processed_trade_time:
|
|
|
new_trades.append(fill)
|
|
|
- if fill_time_str > latest_trade_time:
|
|
|
- latest_trade_time = fill_time_str
|
|
|
+ if fill_datetime > latest_trade_time:
|
|
|
+ latest_trade_time = fill_datetime
|
|
|
except Exception as timestamp_error:
|
|
|
logger.warning(f"⚠️ Error processing timestamp {fill_time}: {timestamp_error}")
|
|
|
continue
|
|
@@ -2661,7 +2679,7 @@ This will place a limit {exit_side} order at ${profit_price:,.2f} to capture pro
|
|
|
for trade in new_trades:
|
|
|
await self._process_external_trade(trade)
|
|
|
|
|
|
- # Update last processed time
|
|
|
+ # Update last processed time (keep as datetime object)
|
|
|
self.last_processed_trade_time = latest_trade_time
|
|
|
|
|
|
# Save state after updating last processed time
|