wip wip wip

This commit is contained in:
Dobromir Popov
2025-10-23 18:57:07 +03:00
parent b0771ff34e
commit 0225f4df58
17 changed files with 2739 additions and 756 deletions

View File

@@ -37,7 +37,7 @@ sys.path.insert(0, str(annotate_dir))
try:
from core.annotation_manager import AnnotationManager
from core.training_simulator import TrainingSimulator
from core.real_training_adapter import RealTrainingAdapter
from core.data_loader import HistoricalDataLoader, TimeRangeManager
except ImportError:
# Try alternative import path
@@ -52,14 +52,14 @@ except ImportError:
ann_spec.loader.exec_module(ann_module)
AnnotationManager = ann_module.AnnotationManager
# Load training_simulator
# Load real_training_adapter (NO SIMULATION!)
train_spec = importlib.util.spec_from_file_location(
"training_simulator",
annotate_dir / "core" / "training_simulator.py"
"real_training_adapter",
annotate_dir / "core" / "real_training_adapter.py"
)
train_module = importlib.util.module_from_spec(train_spec)
train_spec.loader.exec_module(train_module)
TrainingSimulator = train_module.TrainingSimulator
RealTrainingAdapter = train_module.RealTrainingAdapter
# Load data_loader
data_spec = importlib.util.spec_from_file_location(
@@ -149,7 +149,8 @@ class AnnotationDashboard:
# Initialize ANNOTATE components
self.annotation_manager = AnnotationManager()
self.training_simulator = TrainingSimulator(self.orchestrator) if self.orchestrator else None
# Use REAL training adapter - NO SIMULATION!
self.training_adapter = RealTrainingAdapter(self.orchestrator, self.data_provider)
# Initialize data loader with existing DataProvider
self.data_loader = HistoricalDataLoader(self.data_provider) if self.data_provider else None
@@ -199,6 +200,14 @@ class AnnotationDashboard:
def _setup_routes(self):
"""Setup Flask routes"""
@self.server.route('/favicon.ico')
def favicon():
"""Serve favicon to prevent 404 errors"""
from flask import Response
# Return a simple 1x1 transparent pixel as favicon
favicon_data = b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x20\x00\x68\x04\x00\x00\x16\x00\x00\x00\x28\x00\x00\x00\x10\x00\x00\x00\x20\x00\x00\x00\x01\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
return Response(favicon_data, mimetype='image/x-icon')
@self.server.route('/')
def index():
"""Main dashboard page - loads existing annotations"""
@@ -267,7 +276,7 @@ class AnnotationDashboard:
<li>Manual trade annotation</li>
<li>Test case generation</li>
<li>Annotation export</li>
<li>Training simulation</li>
<li>Real model training</li>
</ul>
</div>
<div class="col-md-6">
@@ -446,12 +455,25 @@ class AnnotationDashboard:
data = request.get_json()
annotation_id = data['annotation_id']
self.annotation_manager.delete_annotation(annotation_id)
# Delete annotation and check if it was found
deleted = self.annotation_manager.delete_annotation(annotation_id)
return jsonify({'success': True})
if deleted:
return jsonify({
'success': True,
'message': 'Annotation deleted successfully'
})
else:
return jsonify({
'success': False,
'error': {
'code': 'ANNOTATION_NOT_FOUND',
'message': f'Annotation {annotation_id} not found'
}
})
except Exception as e:
logger.error(f"Error deleting annotation: {e}")
logger.error(f"Error deleting annotation: {e}", exc_info=True)
return jsonify({
'success': False,
'error': {
@@ -464,12 +486,11 @@ class AnnotationDashboard:
def clear_all_annotations():
"""Clear all annotations"""
try:
data = request.get_json()
data = request.get_json() or {}
symbol = data.get('symbol', None)
# Get current annotations count
annotations = self.annotation_manager.get_annotations(symbol=symbol)
deleted_count = len(annotations)
# Use the efficient clear_all_annotations method
deleted_count = self.annotation_manager.clear_all_annotations(symbol=symbol)
if deleted_count == 0:
return jsonify({
@@ -478,12 +499,7 @@ class AnnotationDashboard:
'message': 'No annotations to clear'
})
# Clear all annotations
for annotation in annotations:
annotation_id = annotation.annotation_id if hasattr(annotation, 'annotation_id') else annotation.get('annotation_id')
self.annotation_manager.delete_annotation(annotation_id)
logger.info(f"Cleared {deleted_count} annotations")
logger.info(f"Cleared {deleted_count} annotations" + (f" for symbol {symbol}" if symbol else ""))
return jsonify({
'success': True,
@@ -493,6 +509,8 @@ class AnnotationDashboard:
except Exception as e:
logger.error(f"Error clearing all annotations: {e}")
import traceback
logger.error(traceback.format_exc())
return jsonify({
'success': False,
'error': {
@@ -633,12 +651,12 @@ class AnnotationDashboard:
def train_model():
"""Start model training with annotations"""
try:
if not self.training_simulator:
if not self.training_adapter:
return jsonify({
'success': False,
'error': {
'code': 'TRAINING_UNAVAILABLE',
'message': 'Training simulator not available'
'message': 'Real training adapter not available'
}
})
@@ -672,10 +690,10 @@ class AnnotationDashboard:
}
})
logger.info(f"Starting training with {len(test_cases)} test cases for model {model_name}")
logger.info(f"Starting REAL training with {len(test_cases)} test cases for model {model_name}")
# Start training
training_id = self.training_simulator.start_training(
# Start REAL training (NO SIMULATION!)
training_id = self.training_adapter.start_training(
model_name=model_name,
test_cases=test_cases
)
@@ -700,19 +718,19 @@ class AnnotationDashboard:
def get_training_progress():
"""Get training progress"""
try:
if not self.training_simulator:
if not self.training_adapter:
return jsonify({
'success': False,
'error': {
'code': 'TRAINING_UNAVAILABLE',
'message': 'Training simulator not available'
'message': 'Real training adapter not available'
}
})
data = request.get_json()
training_id = data['training_id']
progress = self.training_simulator.get_training_progress(training_id)
progress = self.training_adapter.get_training_progress(training_id)
return jsonify({
'success': True,
@@ -733,16 +751,16 @@ class AnnotationDashboard:
def get_available_models():
"""Get list of available models"""
try:
if not self.training_simulator:
if not self.training_adapter:
return jsonify({
'success': False,
'error': {
'code': 'TRAINING_UNAVAILABLE',
'message': 'Training simulator not available'
'message': 'Real training adapter not available'
}
})
models = self.training_simulator.get_available_models()
models = self.training_adapter.get_available_models()
return jsonify({
'success': True,
@@ -767,17 +785,17 @@ class AnnotationDashboard:
model_name = data.get('model_name')
symbol = data.get('symbol', 'ETH/USDT')
if not self.training_simulator:
if not self.training_adapter:
return jsonify({
'success': False,
'error': {
'code': 'TRAINING_UNAVAILABLE',
'message': 'Training simulator not available'
'message': 'Real training adapter not available'
}
})
# Start real-time inference
inference_id = self.training_simulator.start_realtime_inference(
# Start real-time inference using orchestrator
inference_id = self.training_adapter.start_realtime_inference(
model_name=model_name,
symbol=symbol,
data_provider=self.data_provider
@@ -805,16 +823,16 @@ class AnnotationDashboard:
data = request.get_json()
inference_id = data.get('inference_id')
if not self.training_simulator:
if not self.training_adapter:
return jsonify({
'success': False,
'error': {
'code': 'TRAINING_UNAVAILABLE',
'message': 'Training simulator not available'
'message': 'Real training adapter not available'
}
})
self.training_simulator.stop_realtime_inference(inference_id)
self.training_adapter.stop_realtime_inference(inference_id)
return jsonify({
'success': True
@@ -834,16 +852,16 @@ class AnnotationDashboard:
def get_realtime_signals():
"""Get latest real-time inference signals"""
try:
if not self.training_simulator:
if not self.training_adapter:
return jsonify({
'success': False,
'error': {
'code': 'TRAINING_UNAVAILABLE',
'message': 'Training simulator not available'
'message': 'Real training adapter not available'
}
})
signals = self.training_simulator.get_latest_signals()
signals = self.training_adapter.get_latest_signals()
return jsonify({
'success': True,

View File

@@ -24,12 +24,12 @@
<div class="col-md-2">
{% include 'components/control_panel.html' %}
</div>
<!-- Main Chart Area -->
<div class="col-md-8">
{% include 'components/chart_panel.html' %}
</div>
<!-- Right Sidebar - Annotations & Training -->
<div class="col-md-2">
{% include 'components/annotation_list.html' %}
@@ -62,43 +62,43 @@
window.appState = {
currentSymbol: '{{ current_symbol }}',
currentTimeframes: {{ timeframes | tojson }},
annotations: {{ annotations | tojson }},
pendingAnnotation: null,
annotations: { { annotations | tojson } },
pendingAnnotation: null,
chartManager: null,
annotationManager: null,
timeNavigator: null,
trainingController: null
annotationManager: null,
timeNavigator: null,
trainingController: null
};
// Initialize components when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
// Initialize chart manager
window.appState.chartManager = new ChartManager('chart-container', window.appState.currentTimeframes);
// Initialize annotation manager
window.appState.annotationManager = new AnnotationManager(window.appState.chartManager);
// Initialize time navigator
window.appState.timeNavigator = new TimeNavigator(window.appState.chartManager);
// Initialize training controller
window.appState.trainingController = new TrainingController();
// Load initial data
loadInitialData();
// Setup keyboard shortcuts
setupKeyboardShortcuts();
// Setup global functions
setupGlobalFunctions();
});
// Initialize components when DOM is ready
document.addEventListener('DOMContentLoaded', function () {
// Initialize chart manager
window.appState.chartManager = new ChartManager('chart-container', window.appState.currentTimeframes);
// Initialize annotation manager
window.appState.annotationManager = new AnnotationManager(window.appState.chartManager);
// Initialize time navigator
window.appState.timeNavigator = new TimeNavigator(window.appState.chartManager);
// Initialize training controller
window.appState.trainingController = new TrainingController();
// Setup global functions FIRST (before loading data)
setupGlobalFunctions();
// Load initial data (may call renderAnnotationsList which needs deleteAnnotation)
loadInitialData();
// Setup keyboard shortcuts
setupKeyboardShortcuts();
});
function loadInitialData() {
// Fetch initial chart data
fetch('/api/chart-data', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: appState.currentSymbol,
timeframes: appState.currentTimeframes,
@@ -106,32 +106,32 @@
end_time: null
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
window.appState.chartManager.initializeCharts(data.chart_data);
// Load existing annotations
console.log('Loading', window.appState.annotations.length, 'existing annotations');
window.appState.annotations.forEach(annotation => {
window.appState.chartManager.addAnnotation(annotation);
});
// Update annotation list
if (typeof renderAnnotationsList === 'function') {
renderAnnotationsList(window.appState.annotations);
.then(response => response.json())
.then(data => {
if (data.success) {
window.appState.chartManager.initializeCharts(data.chart_data);
// Load existing annotations
console.log('Loading', window.appState.annotations.length, 'existing annotations');
window.appState.annotations.forEach(annotation => {
window.appState.chartManager.addAnnotation(annotation);
});
// Update annotation list
if (typeof renderAnnotationsList === 'function') {
renderAnnotationsList(window.appState.annotations);
}
} else {
showError('Failed to load chart data: ' + data.error.message);
}
} else {
showError('Failed to load chart data: ' + data.error.message);
}
})
.catch(error => {
showError('Network error: ' + error.message);
});
})
.catch(error => {
showError('Network error: ' + error.message);
});
}
function setupKeyboardShortcuts() {
document.addEventListener('keydown', function(e) {
document.addEventListener('keydown', function (e) {
// Arrow left - navigate backward
if (e.key === 'ArrowLeft') {
e.preventDefault();
@@ -172,7 +172,7 @@
}
});
}
function showError(message) {
// Create toast notification
const toast = document.createElement('div');
@@ -187,16 +187,16 @@
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
`;
// Add to page and show
document.body.appendChild(toast);
const bsToast = new bootstrap.Toast(toast);
bsToast.show();
// Remove after hidden
toast.addEventListener('hidden.bs.toast', () => toast.remove());
}
function showSuccess(message) {
const toast = document.createElement('div');
toast.className = 'toast align-items-center text-white bg-success border-0';
@@ -210,13 +210,13 @@
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
`;
document.body.appendChild(toast);
const bsToast = new bootstrap.Toast(toast);
bsToast.show();
toast.addEventListener('hidden.bs.toast', () => toast.remove());
}
function setupGlobalFunctions() {
// Make functions globally available
window.showError = showError;
@@ -224,14 +224,21 @@
window.renderAnnotationsList = renderAnnotationsList;
window.deleteAnnotation = deleteAnnotation;
window.highlightAnnotation = highlightAnnotation;
// Verify functions are set
console.log('Global functions setup complete:');
console.log(' - window.deleteAnnotation:', typeof window.deleteAnnotation);
console.log(' - window.renderAnnotationsList:', typeof window.renderAnnotationsList);
console.log(' - window.showError:', typeof window.showError);
console.log(' - window.showSuccess:', typeof window.showSuccess);
}
function renderAnnotationsList(annotations) {
const listElement = document.getElementById('annotations-list');
if (!listElement) return;
listElement.innerHTML = '';
annotations.forEach(annotation => {
const item = document.createElement('div');
item.className = 'annotation-item mb-2 p-2 border rounded';
@@ -259,43 +266,67 @@
listElement.appendChild(item);
});
}
function deleteAnnotation(annotationId) {
if (!confirm('Delete this annotation?')) return;
console.log('deleteAnnotation called with ID:', annotationId);
if (!confirm('Delete this annotation?')) {
console.log('Delete cancelled by user');
return;
}
console.log('Sending delete request to API...');
fetch('/api/delete-annotation', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({annotation_id: annotationId})
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ annotation_id: annotationId })
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Remove from app state
window.appState.annotations = window.appState.annotations.filter(a => a.annotation_id !== annotationId);
// Update UI
renderAnnotationsList(window.appState.annotations);
// Remove from chart
if (window.appState.chartManager) {
window.appState.chartManager.removeAnnotation(annotationId);
.then(response => {
console.log('Delete response status:', response.status);
return response.json();
})
.then(data => {
console.log('Delete response data:', data);
if (data.success) {
// Remove from app state
if (window.appState && window.appState.annotations) {
window.appState.annotations = window.appState.annotations.filter(
a => a.annotation_id !== annotationId
);
console.log('Removed from appState, remaining:', window.appState.annotations.length);
}
// Update UI
if (typeof renderAnnotationsList === 'function') {
renderAnnotationsList(window.appState.annotations);
console.log('UI updated');
} else {
console.error('renderAnnotationsList function not found');
}
// Remove from chart
if (window.appState && window.appState.chartManager) {
window.appState.chartManager.removeAnnotation(annotationId);
console.log('Removed from chart');
}
showSuccess('Annotation deleted successfully');
} else {
console.error('Delete failed:', data.error);
showError('Failed to delete annotation: ' + (data.error ? data.error.message : 'Unknown error'));
}
showSuccess('Annotation deleted');
} else {
showError('Failed to delete annotation: ' + data.error.message);
}
})
.catch(error => {
showError('Network error: ' + error.message);
});
})
.catch(error => {
console.error('Delete error:', error);
showError('Network error: ' + error.message);
});
}
function highlightAnnotation(annotationId) {
if (window.appState.chartManager) {
window.appState.chartManager.highlightAnnotation(annotationId);
}
}
</script>
{% endblock %}
{% endblock %}

View File

@@ -5,6 +5,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Manual Trade Annotation{% endblock %}</title>
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23007bff'%3E%3Cpath d='M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z'/%3E%3C/svg%3E">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">

View File

@@ -165,7 +165,15 @@
item.querySelector('.delete-annotation-btn').addEventListener('click', function(e) {
e.stopPropagation();
deleteAnnotation(annotation.annotation_id);
console.log('Delete button clicked for:', annotation.annotation_id);
// Use window.deleteAnnotation to ensure we get the global function
if (typeof window.deleteAnnotation === 'function') {
window.deleteAnnotation(annotation.annotation_id);
} else {
console.error('window.deleteAnnotation is not a function:', typeof window.deleteAnnotation);
alert('Delete function not available. Please refresh the page.');
}
});
listContainer.appendChild(item);
@@ -204,32 +212,5 @@
});
}
function deleteAnnotation(annotationId) {
if (!confirm('Are you sure you want to delete this annotation?')) {
return;
}
fetch('/api/delete-annotation', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({annotation_id: annotationId})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Remove from UI
appState.annotations = appState.annotations.filter(a => a.annotation_id !== annotationId);
renderAnnotationsList(appState.annotations);
if (appState.chartManager) {
appState.chartManager.removeAnnotation(annotationId);
}
showSuccess('Annotation deleted');
} else {
showError('Failed to delete annotation: ' + data.error.message);
}
})
.catch(error => {
showError('Network error: ' + error.message);
});
}
// Note: deleteAnnotation is defined in annotation_dashboard.html to avoid duplication
</script>