Fix int64 JSON serialization error in SocketIO responses

- Add utils.py with sanitize_for_json() function to convert numpy types
  (int64, float64, bool_, ndarray) to native Python types
- Handle inf/nan values by converting to None
- Update backtesting.py to use shared sanitize_for_json utility
- Update app.py strategy_events emit to sanitize data before sending
- Remove empty root BrighterTrading.db and add *.db to gitignore

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rob 2026-03-01 17:58:24 -04:00
parent 4e14463465
commit 3644c219d4
5 changed files with 72 additions and 20 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@ flask_session/
# Ignore databases
data/
data/*.db
*.db
# Ignore configuration files
config/

View File

View File

@ -18,6 +18,7 @@ from email_validator import validate_email, EmailNotValidError # noqa: E402
# Local application imports
from BrighterTrades import BrighterTrades # noqa: E402
from utils import sanitize_for_json # noqa: E402
# Set up logging
log_level_name = os.getenv('BRIGHTER_LOG_LEVEL', 'INFO').upper()
@ -128,11 +129,11 @@ def strategy_execution_loop():
# Emit events to the user's room
user_name = brighter_trades.users.get_username(user_id=user_id)
if user_name:
socketio.emit('strategy_events', {
socketio.emit('strategy_events', sanitize_for_json({
'strategy_id': strategy_id,
'mode': mode,
'events': events
}, room=user_name)
}), room=user_name)
except Exception as e:
logger.warning(f"Could not get price for {symbol}: {e}")

View File

@ -17,6 +17,7 @@ from mapped_strategy import MappedStrategy
import numpy as np
import pandas as pd
import signal
from utils import sanitize_for_json
# Configure logging
logger = logging.getLogger(__name__)
@ -821,26 +822,15 @@ class Backtester:
}
def sanitize_results(self, results):
import math
for key, value in results.items():
if isinstance(value, float) and (math.isinf(value) or math.isnan(value)):
results[key] = None # Replace `inf` or `nan` with `None`
elif isinstance(value, list):
results[key] = self.sanitize_results_in_list(value)
elif isinstance(value, dict):
results[key] = self.sanitize_results(value)
return results
"""
Recursively sanitize a dictionary for JSON serialization.
Converts numpy types to native Python types and handles inf/nan.
"""
return sanitize_for_json(results)
def sanitize_results_in_list(self, results_list):
sanitized_list = []
for item in results_list:
if isinstance(item, dict):
sanitized_list.append(self.sanitize_results(item))
elif isinstance(item, float) and (math.isinf(item) or math.isnan(item)):
sanitized_list.append(None)
else:
sanitized_list.append(item)
return sanitized_list
"""Sanitize a list for JSON serialization."""
return sanitize_for_json(results_list)
def update_strategy_stats(self, tbl_key: str, results: dict):
"""

60
src/utils.py Normal file
View File

@ -0,0 +1,60 @@
"""
Utility functions for BrighterTrading.
"""
import math
import numpy as np
def sanitize_for_json(value):
"""
Convert a value to a JSON-serializable type.
Handles numpy types, inf, nan, and nested structures.
:param value: Any value that needs to be JSON serialized
:return: JSON-serializable value
"""
# Handle None
if value is None:
return None
# Handle numpy integer types
if isinstance(value, np.integer):
return int(value)
# Handle numpy floating types
elif isinstance(value, np.floating):
float_val = float(value)
if math.isinf(float_val) or math.isnan(float_val):
return None
return float_val
# Handle numpy boolean
elif isinstance(value, np.bool_):
return bool(value)
# Handle numpy arrays
elif isinstance(value, np.ndarray):
return [sanitize_for_json(v) for v in value.tolist()]
# Handle regular floats with inf/nan
elif isinstance(value, float):
if math.isinf(value) or math.isnan(value):
return None
return value
# Handle nested dicts
elif isinstance(value, dict):
return {k: sanitize_for_json(v) for k, v in value.items()}
# Handle lists
elif isinstance(value, list):
return [sanitize_for_json(v) for v in value]
# Handle tuples
elif isinstance(value, tuple):
return tuple(sanitize_for_json(v) for v in value)
# Return other types as-is (str, int, bool, etc.)
return value
def sanitize_dict_for_json(data: dict) -> dict:
"""
Sanitize a dictionary for JSON serialization.
Convenience wrapper around sanitize_for_json for dictionaries.
:param data: Dictionary to sanitize
:return: JSON-serializable dictionary
"""
return sanitize_for_json(data)