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:
parent
4e14463465
commit
3644c219d4
|
|
@ -10,6 +10,7 @@ flask_session/
|
||||||
# Ignore databases
|
# Ignore databases
|
||||||
data/
|
data/
|
||||||
data/*.db
|
data/*.db
|
||||||
|
*.db
|
||||||
|
|
||||||
# Ignore configuration files
|
# Ignore configuration files
|
||||||
config/
|
config/
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ from email_validator import validate_email, EmailNotValidError # noqa: E402
|
||||||
|
|
||||||
# Local application imports
|
# Local application imports
|
||||||
from BrighterTrades import BrighterTrades # noqa: E402
|
from BrighterTrades import BrighterTrades # noqa: E402
|
||||||
|
from utils import sanitize_for_json # noqa: E402
|
||||||
|
|
||||||
# Set up logging
|
# Set up logging
|
||||||
log_level_name = os.getenv('BRIGHTER_LOG_LEVEL', 'INFO').upper()
|
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
|
# Emit events to the user's room
|
||||||
user_name = brighter_trades.users.get_username(user_id=user_id)
|
user_name = brighter_trades.users.get_username(user_id=user_id)
|
||||||
if user_name:
|
if user_name:
|
||||||
socketio.emit('strategy_events', {
|
socketio.emit('strategy_events', sanitize_for_json({
|
||||||
'strategy_id': strategy_id,
|
'strategy_id': strategy_id,
|
||||||
'mode': mode,
|
'mode': mode,
|
||||||
'events': events
|
'events': events
|
||||||
}, room=user_name)
|
}), room=user_name)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Could not get price for {symbol}: {e}")
|
logger.warning(f"Could not get price for {symbol}: {e}")
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ from mapped_strategy import MappedStrategy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import signal
|
import signal
|
||||||
|
from utils import sanitize_for_json
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -821,26 +822,15 @@ class Backtester:
|
||||||
}
|
}
|
||||||
|
|
||||||
def sanitize_results(self, results):
|
def sanitize_results(self, results):
|
||||||
import math
|
"""
|
||||||
for key, value in results.items():
|
Recursively sanitize a dictionary for JSON serialization.
|
||||||
if isinstance(value, float) and (math.isinf(value) or math.isnan(value)):
|
Converts numpy types to native Python types and handles inf/nan.
|
||||||
results[key] = None # Replace `inf` or `nan` with `None`
|
"""
|
||||||
elif isinstance(value, list):
|
return sanitize_for_json(results)
|
||||||
results[key] = self.sanitize_results_in_list(value)
|
|
||||||
elif isinstance(value, dict):
|
|
||||||
results[key] = self.sanitize_results(value)
|
|
||||||
return results
|
|
||||||
|
|
||||||
def sanitize_results_in_list(self, results_list):
|
def sanitize_results_in_list(self, results_list):
|
||||||
sanitized_list = []
|
"""Sanitize a list for JSON serialization."""
|
||||||
for item in results_list:
|
return sanitize_for_json(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
|
|
||||||
|
|
||||||
def update_strategy_stats(self, tbl_key: str, results: dict):
|
def update_strategy_stats(self, tbl_key: str, results: dict):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
Loading…
Reference in New Issue