test cases
This commit is contained in:
@ -663,9 +663,9 @@ class CleanTradingDashboard:
|
||||
color='rgba(0, 255, 100, 0.9)',
|
||||
line=dict(width=3, color='green')
|
||||
),
|
||||
name='✅ EXECUTED BUY',
|
||||
name='EXECUTED BUY',
|
||||
showlegend=True,
|
||||
hovertemplate="<b>✅ EXECUTED BUY TRADE</b><br>" +
|
||||
hovertemplate="<b>EXECUTED BUY TRADE</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
@ -687,9 +687,9 @@ class CleanTradingDashboard:
|
||||
color='rgba(255, 100, 100, 0.9)',
|
||||
line=dict(width=3, color='red')
|
||||
),
|
||||
name='✅ EXECUTED SELL',
|
||||
showlegend=True,
|
||||
hovertemplate="<b>✅ EXECUTED SELL TRADE</b><br>" +
|
||||
name='EXECUTED SELL',
|
||||
showlegend=True,
|
||||
hovertemplate="<b>EXECUTED SELL TRADE</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
@ -768,9 +768,9 @@ class CleanTradingDashboard:
|
||||
color='rgba(0, 255, 100, 1.0)',
|
||||
line=dict(width=2, color='green')
|
||||
),
|
||||
name='✅ BUY (Executed)',
|
||||
name='BUY (Executed)',
|
||||
showlegend=False,
|
||||
hovertemplate="<b>✅ BUY EXECUTED</b><br>" +
|
||||
hovertemplate="<b>BUY EXECUTED</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
@ -822,9 +822,9 @@ class CleanTradingDashboard:
|
||||
color='rgba(255, 100, 100, 1.0)',
|
||||
line=dict(width=2, color='red')
|
||||
),
|
||||
name='✅ SELL (Executed)',
|
||||
name='SELL (Executed)',
|
||||
showlegend=False,
|
||||
hovertemplate="<b>✅ SELL EXECUTED</b><br>" +
|
||||
hovertemplate="<b>SELL EXECUTED</b><br>" +
|
||||
"Price: $%{y:.2f}<br>" +
|
||||
"Time: %{x}<br>" +
|
||||
"Confidence: %{customdata:.1%}<extra></extra>",
|
||||
@ -1540,8 +1540,16 @@ class CleanTradingDashboard:
|
||||
logger.warning("No current price available for manual trade")
|
||||
return
|
||||
|
||||
# CAPTURE ALL MODEL INPUTS FOR COLD START TRAINING
|
||||
model_inputs = self._capture_comprehensive_model_inputs(symbol, action, current_price)
|
||||
# CAPTURE ALL MODEL INPUTS FOR COLD START TRAINING using core TradeDataManager
|
||||
try:
|
||||
from core.trade_data_manager import TradeDataManager
|
||||
trade_data_manager = TradeDataManager()
|
||||
model_inputs = trade_data_manager.capture_comprehensive_model_inputs(
|
||||
symbol, action, current_price, self.orchestrator, self.data_provider
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to capture model inputs via TradeDataManager: {e}")
|
||||
model_inputs = {}
|
||||
|
||||
# Create manual trading decision
|
||||
decision = {
|
||||
@ -1588,8 +1596,13 @@ class CleanTradingDashboard:
|
||||
# Add to closed trades for display
|
||||
self.closed_trades.append(trade_record)
|
||||
|
||||
# Store for cold start training when trade closes
|
||||
self._store_trade_for_training(trade_record)
|
||||
# Store for cold start training when trade closes using core TradeDataManager
|
||||
try:
|
||||
case_id = trade_data_manager.store_trade_for_training(trade_record)
|
||||
if case_id:
|
||||
logger.info(f"Trade stored for training with case ID: {case_id}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to store trade for training: {e}")
|
||||
|
||||
# Update session metrics
|
||||
if action == 'BUY':
|
||||
@ -1600,8 +1613,17 @@ class CleanTradingDashboard:
|
||||
self.session_pnl += demo_pnl
|
||||
trade_record['pnl'] = demo_pnl
|
||||
|
||||
# TRIGGER COLD START TRAINING on profitable demo trade
|
||||
self._trigger_cold_start_training(trade_record, demo_pnl)
|
||||
# TRIGGER COLD START TRAINING on profitable demo trade using core TrainingIntegration
|
||||
try:
|
||||
from core.training_integration import TrainingIntegration
|
||||
training_integration = TrainingIntegration(self.orchestrator)
|
||||
training_success = training_integration.trigger_cold_start_training(trade_record, case_id)
|
||||
if training_success:
|
||||
logger.info("Cold start training completed successfully")
|
||||
else:
|
||||
logger.warning("Cold start training failed")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to trigger cold start training: {e}")
|
||||
|
||||
else:
|
||||
decision['executed'] = False
|
||||
@ -1625,89 +1647,7 @@ class CleanTradingDashboard:
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing manual {action}: {e}")
|
||||
|
||||
def _capture_comprehensive_model_inputs(self, symbol: str, action: str, current_price: float) -> Dict[str, Any]:
|
||||
"""Capture comprehensive model inputs for cold start training"""
|
||||
try:
|
||||
logger.info(f"Capturing model inputs for {action} trade on {symbol} at ${current_price:.2f}")
|
||||
|
||||
model_inputs = {
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'symbol': symbol,
|
||||
'action': action,
|
||||
'price': current_price,
|
||||
'capture_type': 'trade_execution'
|
||||
}
|
||||
|
||||
# 1. Market State Features
|
||||
try:
|
||||
market_state = self._get_comprehensive_market_state(symbol, current_price)
|
||||
model_inputs['market_state'] = market_state
|
||||
logger.debug(f"Captured market state: {len(market_state)} features")
|
||||
except Exception as e:
|
||||
logger.warning(f"Error capturing market state: {e}")
|
||||
model_inputs['market_state'] = {}
|
||||
|
||||
# 2. CNN Features and Predictions
|
||||
try:
|
||||
cnn_data = self._get_cnn_features_and_predictions(symbol)
|
||||
model_inputs['cnn_features'] = cnn_data.get('features', {})
|
||||
model_inputs['cnn_predictions'] = cnn_data.get('predictions', {})
|
||||
logger.debug(f"Captured CNN data: {len(cnn_data)} items")
|
||||
except Exception as e:
|
||||
logger.warning(f"Error capturing CNN data: {e}")
|
||||
model_inputs['cnn_features'] = {}
|
||||
model_inputs['cnn_predictions'] = {}
|
||||
|
||||
# 3. DQN/RL State Features
|
||||
try:
|
||||
dqn_state = self._get_dqn_state_features(symbol, current_price)
|
||||
model_inputs['dqn_state'] = dqn_state
|
||||
logger.debug(f"Captured DQN state: {len(dqn_state) if dqn_state else 0} features")
|
||||
except Exception as e:
|
||||
logger.warning(f"Error capturing DQN state: {e}")
|
||||
model_inputs['dqn_state'] = {}
|
||||
|
||||
# 4. COB (Order Book) Features
|
||||
try:
|
||||
cob_data = self._get_cob_features_for_training(symbol)
|
||||
model_inputs['cob_features'] = cob_data
|
||||
logger.debug(f"Captured COB features: {len(cob_data) if cob_data else 0} features")
|
||||
except Exception as e:
|
||||
logger.warning(f"Error capturing COB features: {e}")
|
||||
model_inputs['cob_features'] = {}
|
||||
|
||||
# 5. Technical Indicators
|
||||
try:
|
||||
technical_indicators = self._get_technical_indicators(symbol)
|
||||
model_inputs['technical_indicators'] = technical_indicators
|
||||
logger.debug(f"Captured technical indicators: {len(technical_indicators)} indicators")
|
||||
except Exception as e:
|
||||
logger.warning(f"Error capturing technical indicators: {e}")
|
||||
model_inputs['technical_indicators'] = {}
|
||||
|
||||
# 6. Recent Price History (for context)
|
||||
try:
|
||||
price_history = self._get_recent_price_history(symbol, periods=50)
|
||||
model_inputs['price_history'] = price_history
|
||||
logger.debug(f"Captured price history: {len(price_history)} periods")
|
||||
except Exception as e:
|
||||
logger.warning(f"Error capturing price history: {e}")
|
||||
model_inputs['price_history'] = []
|
||||
|
||||
total_features = sum(len(v) if isinstance(v, (dict, list)) else 1 for v in model_inputs.values())
|
||||
logger.info(f"✅ Captured {total_features} total features for cold start training")
|
||||
|
||||
return model_inputs
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error capturing model inputs: {e}")
|
||||
return {
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'symbol': symbol,
|
||||
'action': action,
|
||||
'price': current_price,
|
||||
'error': str(e)
|
||||
}
|
||||
# Model input capture moved to core.trade_data_manager.TradeDataManager
|
||||
|
||||
def _get_comprehensive_market_state(self, symbol: str, current_price: float) -> Dict[str, float]:
|
||||
"""Get comprehensive market state features"""
|
||||
@ -1885,150 +1825,9 @@ class CleanTradingDashboard:
|
||||
logger.debug(f"Error getting price history: {e}")
|
||||
return []
|
||||
|
||||
def _store_trade_for_training(self, trade_record: Dict[str, Any]):
|
||||
"""Store trade for future cold start training"""
|
||||
try:
|
||||
# Create training data storage directory
|
||||
import os
|
||||
training_dir = "training_data"
|
||||
os.makedirs(training_dir, exist_ok=True)
|
||||
|
||||
# Store trade data with timestamp
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"trade_{trade_record['symbol'].replace('/', '')}_{timestamp}.json"
|
||||
filepath = os.path.join(training_dir, filename)
|
||||
|
||||
import json
|
||||
with open(filepath, 'w') as f:
|
||||
json.dump(trade_record, f, indent=2, default=str)
|
||||
|
||||
logger.info(f"✅ Stored trade data for training: {filepath}")
|
||||
|
||||
# Also store in memory for immediate access
|
||||
if not hasattr(self, 'stored_trades'):
|
||||
self.stored_trades = []
|
||||
|
||||
self.stored_trades.append(trade_record)
|
||||
|
||||
# Keep only last 100 trades in memory
|
||||
if len(self.stored_trades) > 100:
|
||||
self.stored_trades = self.stored_trades[-100:]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error storing trade for training: {e}")
|
||||
# Trade storage moved to core.trade_data_manager.TradeDataManager
|
||||
|
||||
def _trigger_cold_start_training(self, trade_record: Dict[str, Any], pnl: float):
|
||||
"""Trigger cold start training when we have trade outcome"""
|
||||
try:
|
||||
logger.info(f"🔥 TRIGGERING COLD START TRAINING")
|
||||
logger.info(f"Trade: {trade_record['side']} {trade_record['symbol']} @ ${trade_record['entry_price']:.2f}")
|
||||
logger.info(f"P&L: ${pnl:.4f} ({'PROFIT' if pnl > 0 else 'LOSS'})")
|
||||
|
||||
# Calculate reward based on P&L
|
||||
reward = self._calculate_training_reward(pnl, trade_record)
|
||||
|
||||
# Send to DQN agent if available
|
||||
if hasattr(self.orchestrator, 'sensitivity_dqn_agent') and self.orchestrator.sensitivity_dqn_agent:
|
||||
self._train_dqn_on_trade_outcome(trade_record, reward)
|
||||
|
||||
# Send to CNN if available
|
||||
if hasattr(self.orchestrator, 'williams_structure') and self.orchestrator.williams_structure:
|
||||
self._train_cnn_on_trade_outcome(trade_record, reward)
|
||||
|
||||
# Send to COB RL if available
|
||||
if hasattr(self.orchestrator, 'cob_integration') and self.orchestrator.cob_integration:
|
||||
self._train_cob_rl_on_trade_outcome(trade_record, reward)
|
||||
|
||||
logger.info(f"✅ Cold start training triggered with reward: {reward:.4f}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error triggering cold start training: {e}")
|
||||
|
||||
def _calculate_training_reward(self, pnl: float, trade_record: Dict[str, Any]) -> float:
|
||||
"""Calculate training reward based on trade outcome"""
|
||||
try:
|
||||
# Base reward from P&L
|
||||
base_reward = pnl * 100 # Scale up for training
|
||||
|
||||
# Confidence adjustment (higher confidence wrong predictions get bigger penalties)
|
||||
confidence = trade_record.get('confidence', 0.5)
|
||||
if pnl < 0: # Loss
|
||||
confidence_penalty = confidence * 2 # Higher confidence losses hurt more
|
||||
base_reward *= (1 + confidence_penalty)
|
||||
else: # Profit
|
||||
confidence_bonus = confidence * 0.5 # Higher confidence wins get small bonus
|
||||
base_reward *= (1 + confidence_bonus)
|
||||
|
||||
# Time-based adjustment (faster profits are better)
|
||||
# For demo trades, just use a small bonus
|
||||
time_bonus = 0.1 if pnl > 0 else 0
|
||||
|
||||
final_reward = base_reward + time_bonus
|
||||
|
||||
logger.debug(f"Reward calculation: P&L={pnl:.4f}, Confidence={confidence:.2f}, Final={final_reward:.4f}")
|
||||
|
||||
return final_reward
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Error calculating reward: {e}")
|
||||
return pnl # Fallback to simple P&L
|
||||
|
||||
def _train_dqn_on_trade_outcome(self, trade_record: Dict[str, Any], reward: float):
|
||||
"""Train DQN agent on trade outcome"""
|
||||
try:
|
||||
dqn_agent = self.orchestrator.sensitivity_dqn_agent
|
||||
|
||||
# Get the state that was used for the decision
|
||||
model_inputs = trade_record.get('model_inputs_at_entry', {})
|
||||
dqn_state = model_inputs.get('dqn_state', {}).get('state_vector', [])
|
||||
|
||||
if not dqn_state:
|
||||
logger.debug("No DQN state available for training")
|
||||
return
|
||||
|
||||
# Convert to numpy array
|
||||
state = np.array(dqn_state, dtype=np.float32)
|
||||
|
||||
# Map action to DQN action space
|
||||
action = 1 if trade_record['side'] == 'BUY' else 0
|
||||
|
||||
# Create next state (current market state after trade)
|
||||
current_state = self._get_dqn_state_features(trade_record['symbol'], trade_record['entry_price'])
|
||||
next_state = np.array(current_state.get('state_vector', state), dtype=np.float32)
|
||||
|
||||
# Add experience to DQN memory
|
||||
dqn_agent.remember(state, action, reward, next_state, True) # done=True for completed trade
|
||||
|
||||
# Trigger training if enough experiences
|
||||
if len(dqn_agent.memory) >= dqn_agent.batch_size:
|
||||
loss = dqn_agent.replay()
|
||||
if loss:
|
||||
logger.info(f"🧠 DQN trained on trade outcome - Loss: {loss:.6f}, Reward: {reward:.4f}")
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Error training DQN on trade outcome: {e}")
|
||||
|
||||
def _train_cnn_on_trade_outcome(self, trade_record: Dict[str, Any], reward: float):
|
||||
"""Train CNN on trade outcome (simplified for now)"""
|
||||
try:
|
||||
# CNN training requires more complex setup - log for now
|
||||
logger.info(f"📊 CNN training opportunity: {trade_record['side']} with reward {reward:.4f}")
|
||||
|
||||
# In future: extract CNN features from model_inputs and create training sample
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Error training CNN on trade outcome: {e}")
|
||||
|
||||
def _train_cob_rl_on_trade_outcome(self, trade_record: Dict[str, Any], reward: float):
|
||||
"""Train COB RL on trade outcome (simplified for now)"""
|
||||
try:
|
||||
# COB RL training requires accessing the 400M parameter model - log for now
|
||||
logger.info(f"📈 COB RL training opportunity: {trade_record['side']} with reward {reward:.4f}")
|
||||
|
||||
# In future: access COB RL model and create training sample
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Error training COB RL on trade outcome: {e}")
|
||||
# Cold start training moved to core.training_integration.TrainingIntegration
|
||||
|
||||
def _clear_session(self):
|
||||
"""Clear session data"""
|
||||
@ -2487,11 +2286,153 @@ class CleanTradingDashboard:
|
||||
except Exception as e:
|
||||
logger.error(f"Error handling universal stream data: {e}")
|
||||
|
||||
# Factory function for easy creation
|
||||
def _update_case_index(self, case_dir: str, case_id: str, case_summary: Dict[str, Any], case_type: str):
|
||||
"""Update the case index file with new case information"""
|
||||
try:
|
||||
import json
|
||||
import os
|
||||
|
||||
index_filepath = os.path.join(case_dir, "case_index.json")
|
||||
|
||||
# Load existing index or create new one
|
||||
if os.path.exists(index_filepath):
|
||||
with open(index_filepath, 'r') as f:
|
||||
index_data = json.load(f)
|
||||
else:
|
||||
index_data = {
|
||||
"cases": [],
|
||||
"last_updated": datetime.now().isoformat(),
|
||||
"case_type": case_type,
|
||||
"total_cases": 0
|
||||
}
|
||||
|
||||
# Add new case to index
|
||||
pnl = case_summary.get('pnl', 0)
|
||||
training_priority = 1 # Default priority
|
||||
|
||||
# Calculate training priority based on P&L and confidence
|
||||
if case_type == "negative":
|
||||
# Higher priority for bigger losses
|
||||
if abs(pnl) > 10:
|
||||
training_priority = 5 # Very high priority
|
||||
elif abs(pnl) > 5:
|
||||
training_priority = 4
|
||||
elif abs(pnl) > 1:
|
||||
training_priority = 3
|
||||
else:
|
||||
training_priority = 2
|
||||
else: # positive
|
||||
# Higher priority for high-confidence profitable trades
|
||||
confidence = case_summary.get('confidence', 0)
|
||||
if pnl > 5 and confidence > 0.8:
|
||||
training_priority = 5
|
||||
elif pnl > 1 and confidence > 0.6:
|
||||
training_priority = 4
|
||||
elif pnl > 0.5:
|
||||
training_priority = 3
|
||||
else:
|
||||
training_priority = 2
|
||||
|
||||
case_entry = {
|
||||
"case_id": case_id,
|
||||
"timestamp": case_summary['timestamp'],
|
||||
"symbol": case_summary['symbol'],
|
||||
"side": case_summary['side'],
|
||||
"entry_price": case_summary['entry_price'],
|
||||
"pnl": pnl,
|
||||
"confidence": case_summary.get('confidence', 0),
|
||||
"trade_type": case_summary.get('trade_type', 'unknown'),
|
||||
"training_priority": training_priority,
|
||||
"retraining_count": 0,
|
||||
"model_inputs_captured": case_summary.get('model_inputs_captured', False),
|
||||
"feature_counts": case_summary.get('feature_counts', {}),
|
||||
"created_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
# Add to cases list
|
||||
index_data["cases"].append(case_entry)
|
||||
index_data["last_updated"] = datetime.now().isoformat()
|
||||
index_data["total_cases"] = len(index_data["cases"])
|
||||
|
||||
# Sort by training priority (highest first) and timestamp (newest first)
|
||||
index_data["cases"].sort(key=lambda x: (-x['training_priority'], -time.mktime(datetime.fromisoformat(x['timestamp']).timetuple())))
|
||||
|
||||
# Keep only last 1000 cases to prevent index from getting too large
|
||||
if len(index_data["cases"]) > 1000:
|
||||
index_data["cases"] = index_data["cases"][:1000]
|
||||
index_data["total_cases"] = 1000
|
||||
|
||||
# Save updated index
|
||||
with open(index_filepath, 'w') as f:
|
||||
json.dump(index_data, f, indent=2, default=str)
|
||||
|
||||
logger.debug(f"Updated {case_type} case index: {len(index_data['cases'])} total cases")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating case index: {e}")
|
||||
|
||||
def get_testcase_summary(self) -> Dict[str, Any]:
|
||||
"""Get summary of stored testcases for display"""
|
||||
try:
|
||||
import os
|
||||
import json
|
||||
|
||||
summary = {
|
||||
'positive_cases': 0,
|
||||
'negative_cases': 0,
|
||||
'total_cases': 0,
|
||||
'latest_cases': [],
|
||||
'high_priority_cases': 0
|
||||
}
|
||||
|
||||
base_dir = "testcases"
|
||||
|
||||
for case_type in ['positive', 'negative']:
|
||||
case_dir = os.path.join(base_dir, case_type)
|
||||
index_filepath = os.path.join(case_dir, "case_index.json")
|
||||
|
||||
if os.path.exists(index_filepath):
|
||||
with open(index_filepath, 'r') as f:
|
||||
index_data = json.load(f)
|
||||
|
||||
case_count = len(index_data.get('cases', []))
|
||||
summary[f'{case_type}_cases'] = case_count
|
||||
summary['total_cases'] += case_count
|
||||
|
||||
# Get high priority cases
|
||||
high_priority = len([c for c in index_data.get('cases', []) if c.get('training_priority', 1) >= 4])
|
||||
summary['high_priority_cases'] += high_priority
|
||||
|
||||
# Get latest cases
|
||||
latest = index_data.get('cases', [])[:5] # Top 5 latest
|
||||
for case in latest:
|
||||
case['case_type'] = case_type
|
||||
summary['latest_cases'].extend(latest)
|
||||
|
||||
# Sort latest cases by timestamp
|
||||
summary['latest_cases'].sort(key=lambda x: x.get('timestamp', ''), reverse=True)
|
||||
|
||||
# Keep only top 10 latest cases
|
||||
summary['latest_cases'] = summary['latest_cases'][:10]
|
||||
|
||||
return summary
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting testcase summary: {e}")
|
||||
return {
|
||||
'positive_cases': 0,
|
||||
'negative_cases': 0,
|
||||
'total_cases': 0,
|
||||
'latest_cases': [],
|
||||
'high_priority_cases': 0,
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
|
||||
def create_clean_dashboard(data_provider=None, orchestrator=None, trading_executor=None):
|
||||
"""Create a clean trading dashboard instance"""
|
||||
"""Factory function to create a CleanTradingDashboard instance"""
|
||||
return CleanTradingDashboard(
|
||||
data_provider=data_provider,
|
||||
orchestrator=orchestrator,
|
||||
trading_executor=trading_executor
|
||||
)
|
||||
)
|
Reference in New Issue
Block a user