price vector predictions
This commit is contained in:
@ -3809,6 +3809,69 @@ class TradingOrchestrator:
|
||||
)
|
||||
return (1.0 if simple_correct else -0.5, simple_correct)
|
||||
|
||||
def _calculate_price_vector_loss(
|
||||
self,
|
||||
predicted_vector: dict,
|
||||
actual_price_change_pct: float,
|
||||
time_diff_minutes: float
|
||||
) -> float:
|
||||
"""
|
||||
Calculate training loss for price vector predictions to improve accuracy
|
||||
|
||||
Args:
|
||||
predicted_vector: Dict with 'direction' (-1 to 1) and 'confidence' (0 to 1)
|
||||
actual_price_change_pct: Actual price change percentage
|
||||
time_diff_minutes: Time elapsed since prediction
|
||||
|
||||
Returns:
|
||||
Loss value for training the price vector prediction head
|
||||
"""
|
||||
try:
|
||||
if not predicted_vector or not isinstance(predicted_vector, dict):
|
||||
return 0.0
|
||||
|
||||
predicted_direction = predicted_vector.get('direction', 0.0)
|
||||
predicted_confidence = predicted_vector.get('confidence', 0.0)
|
||||
|
||||
# Skip very weak predictions
|
||||
if abs(predicted_direction) < 0.05 or predicted_confidence < 0.1:
|
||||
return 0.0
|
||||
|
||||
# Calculate actual direction and magnitude
|
||||
actual_direction = 1.0 if actual_price_change_pct > 0.05 else -1.0 if actual_price_change_pct < -0.05 else 0.0
|
||||
actual_magnitude = min(abs(actual_price_change_pct) / 2.0, 1.0) # Normalize to 0-1, cap at 2%
|
||||
|
||||
# DIRECTION LOSS: penalize wrong direction predictions
|
||||
if actual_direction != 0.0:
|
||||
# Expected direction should match actual
|
||||
direction_error = abs(predicted_direction - actual_direction)
|
||||
else:
|
||||
# If no significant movement, direction should be close to 0
|
||||
direction_error = abs(predicted_direction) * 0.5 # Reduced penalty for neutral
|
||||
|
||||
# MAGNITUDE LOSS: penalize inaccurate magnitude predictions
|
||||
# Convert predicted direction+confidence to expected magnitude
|
||||
predicted_magnitude = abs(predicted_direction) * predicted_confidence
|
||||
magnitude_error = abs(predicted_magnitude - actual_magnitude)
|
||||
|
||||
# TIME DECAY: predictions should be accurate quickly
|
||||
time_decay = max(0.1, 1.0 - (time_diff_minutes / 30.0)) # 30min decay window
|
||||
|
||||
# COMBINED LOSS
|
||||
direction_loss = direction_error * 2.0 # Direction is very important
|
||||
magnitude_loss = magnitude_error * 1.0 # Magnitude is important
|
||||
total_loss = (direction_loss + magnitude_loss) * time_decay
|
||||
|
||||
logger.debug(f"PRICE VECTOR LOSS: pred_dir={predicted_direction:.3f}, actual_dir={actual_direction:.3f}, "
|
||||
f"pred_mag={predicted_magnitude:.3f}, actual_mag={actual_magnitude:.3f}, "
|
||||
f"dir_loss={direction_loss:.3f}, mag_loss={magnitude_loss:.3f}, total={total_loss:.3f}")
|
||||
|
||||
return min(total_loss, 5.0) # Cap loss to prevent exploding gradients
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error calculating price vector loss: {e}")
|
||||
return 0.0
|
||||
|
||||
def _calculate_price_vector_bonus(
|
||||
self,
|
||||
predicted_vector: dict,
|
||||
@ -3881,6 +3944,91 @@ class TradingOrchestrator:
|
||||
logger.error(f"Error calculating price vector bonus: {e}")
|
||||
return 0.0
|
||||
|
||||
def _should_execute_action(
|
||||
self,
|
||||
action: str,
|
||||
confidence: float,
|
||||
predicted_vector: dict = None,
|
||||
current_price: float = None,
|
||||
symbol: str = None
|
||||
) -> tuple[bool, str]:
|
||||
"""
|
||||
Intelligent action filtering based on predicted price movement and confidence
|
||||
|
||||
Args:
|
||||
action: Predicted action (BUY/SELL/HOLD)
|
||||
confidence: Model confidence (0 to 1)
|
||||
predicted_vector: Dict with 'direction' and 'confidence'
|
||||
current_price: Current market price
|
||||
symbol: Trading symbol
|
||||
|
||||
Returns:
|
||||
(should_execute, reason)
|
||||
"""
|
||||
try:
|
||||
# Basic confidence threshold
|
||||
min_action_confidence = 0.6 # Require 60% confidence for any action
|
||||
if confidence < min_action_confidence:
|
||||
return False, f"Low action confidence ({confidence:.1%} < {min_action_confidence:.1%})"
|
||||
|
||||
# HOLD actions always allowed
|
||||
if action == "HOLD":
|
||||
return True, "HOLD action approved"
|
||||
|
||||
# Check if we have price vector predictions
|
||||
if not predicted_vector or not isinstance(predicted_vector, dict):
|
||||
# No vector available - use basic confidence only
|
||||
high_confidence_threshold = 0.8
|
||||
if confidence >= high_confidence_threshold:
|
||||
return True, f"High confidence action without vector ({confidence:.1%})"
|
||||
else:
|
||||
return False, f"No price vector available, requires high confidence ({confidence:.1%} < {high_confidence_threshold:.1%})"
|
||||
|
||||
predicted_direction = predicted_vector.get('direction', 0.0)
|
||||
vector_confidence = predicted_vector.get('confidence', 0.0)
|
||||
|
||||
# VECTOR-BASED FILTERING
|
||||
min_vector_confidence = 0.5 # Require 50% vector confidence
|
||||
min_direction_strength = 0.3 # Require 30% direction strength
|
||||
|
||||
if vector_confidence < min_vector_confidence:
|
||||
return False, f"Low vector confidence ({vector_confidence:.1%} < {min_vector_confidence:.1%})"
|
||||
|
||||
if abs(predicted_direction) < min_direction_strength:
|
||||
return False, f"Weak direction prediction ({abs(predicted_direction):.1%} < {min_direction_strength:.1%})"
|
||||
|
||||
# DIRECTION ALIGNMENT CHECK
|
||||
if action == "BUY" and predicted_direction <= 0:
|
||||
return False, f"BUY action misaligned with predicted direction ({predicted_direction:.3f})"
|
||||
|
||||
if action == "SELL" and predicted_direction >= 0:
|
||||
return False, f"SELL action misaligned with predicted direction ({predicted_direction:.3f})"
|
||||
|
||||
# STEEPNESS/MAGNITUDE CHECK (fee-aware)
|
||||
fee_cost = 0.12 # 0.12% round trip fee cost
|
||||
predicted_magnitude = abs(predicted_direction) * vector_confidence * 2.0 # Scale to ~2% max
|
||||
|
||||
if predicted_magnitude < fee_cost * 2.0: # Require 2x fee coverage
|
||||
return False, f"Predicted magnitude too small ({predicted_magnitude:.2f}% < {fee_cost * 2.0:.2f}% minimum)"
|
||||
|
||||
# COMBINED CONFIDENCE CHECK
|
||||
combined_confidence = (confidence + vector_confidence) / 2.0
|
||||
min_combined_confidence = 0.7 # Require 70% combined confidence
|
||||
|
||||
if combined_confidence < min_combined_confidence:
|
||||
return False, f"Low combined confidence ({combined_confidence:.1%} < {min_combined_confidence:.1%})"
|
||||
|
||||
# ALL CHECKS PASSED
|
||||
logger.info(f"ACTION APPROVED: {action} with {confidence:.1%} confidence, "
|
||||
f"vector: {predicted_direction:+.3f} ({vector_confidence:.1%}), "
|
||||
f"predicted magnitude: {predicted_magnitude:.2f}%")
|
||||
|
||||
return True, f"Action approved: strong prediction with adequate magnitude"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in action filtering: {e}")
|
||||
return False, f"Action filtering error: {e}"
|
||||
|
||||
async def _train_model_on_outcome(
|
||||
self,
|
||||
record: Dict,
|
||||
@ -3913,6 +4061,18 @@ class TradingOrchestrator:
|
||||
current_position_pnl=current_pnl,
|
||||
predicted_price_vector=predicted_price_vector,
|
||||
)
|
||||
|
||||
# Calculate price vector training loss if we have vector predictions
|
||||
if predicted_price_vector:
|
||||
vector_loss = self._calculate_price_vector_loss(
|
||||
predicted_price_vector,
|
||||
price_change_pct,
|
||||
record.get("time_diff_minutes", 1.0)
|
||||
)
|
||||
# Store the vector loss for training
|
||||
record["price_vector_loss"] = vector_loss
|
||||
if vector_loss > 0:
|
||||
logger.debug(f"PRICE VECTOR TRAINING: {model_name} vector loss = {vector_loss:.3f}")
|
||||
|
||||
# Train decision fusion model if it's the model being evaluated
|
||||
if model_name == "decision_fusion":
|
||||
|
Reference in New Issue
Block a user