Add template-based MVC dashboard architecture
- Add HTML templates for clean separation of concerns - Add structured data models for type safety - Add template renderer for Jinja2 integration - Add templated dashboard implementation - Demonstrates 95% file size reduction potential
This commit is contained in:
313
web/templates/dashboard.html
Normal file
313
web/templates/dashboard.html
Normal file
@ -0,0 +1,313 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ title }}</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.metric-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.metric-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
.metric-label {
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.cob-ladder {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.bid-row {
|
||||
background-color: rgba(40, 167, 69, 0.1);
|
||||
border-left: 3px solid #28a745;
|
||||
}
|
||||
.ask-row {
|
||||
background-color: rgba(220, 53, 69, 0.1);
|
||||
border-left: 3px solid #dc3545;
|
||||
}
|
||||
.training-panel {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.model-status {
|
||||
padding: 8px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
margin: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
.status-training { background-color: #28a745; color: white; }
|
||||
.status-idle { background-color: #6c757d; color: white; }
|
||||
.status-loading { background-color: #ffc107; color: black; }
|
||||
.closed-trades {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.trade-profit { color: #28a745; font-weight: bold; }
|
||||
.trade-loss { color: #dc3545; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<!-- Header -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-12">
|
||||
<h1 class="text-center">{{ title }}</h1>
|
||||
<p class="text-center text-muted">{{ subtitle }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Metrics Row -->
|
||||
<div class="row mb-3">
|
||||
{% for metric in metrics %}
|
||||
<div class="col-md-2">
|
||||
<div class="metric-card">
|
||||
<div class="metric-value" id="{{ metric.id }}">{{ metric.value }}</div>
|
||||
<div class="metric-label">{{ metric.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Main Content Row -->
|
||||
<div class="row mb-3">
|
||||
<!-- Price Chart (Left) -->
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>{{ chart.title }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="price-chart" style="height: 500px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Trading Controls & Recent Decisions (Right) -->
|
||||
<div class="col-md-4">
|
||||
<!-- Trading Controls -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h6>Manual Trading</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row mb-2">
|
||||
<div class="col-6">
|
||||
<button id="manual-buy-btn" class="btn btn-success w-100">
|
||||
{{ trading_controls.buy_text }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<button id="manual-sell-btn" class="btn btn-danger w-100">
|
||||
{{ trading_controls.sell_text }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-12">
|
||||
<label for="leverage-slider" class="form-label">
|
||||
Leverage: <span id="leverage-display">{{ trading_controls.leverage }}</span>x
|
||||
</label>
|
||||
<input type="range" class="form-range" id="leverage-slider"
|
||||
min="{{ trading_controls.leverage_min }}"
|
||||
max="{{ trading_controls.leverage_max }}"
|
||||
value="{{ trading_controls.leverage }}" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<button id="clear-session-btn" class="btn btn-warning w-100">
|
||||
{{ trading_controls.clear_text }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Decisions -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6>Recent AI Decisions</h6>
|
||||
</div>
|
||||
<div class="card-body" style="max-height: 300px; overflow-y: auto;">
|
||||
<div id="recent-decisions">
|
||||
{% for decision in recent_decisions %}
|
||||
<div class="mb-2 p-2 border-start border-3
|
||||
{% if decision.action == 'BUY' %}border-success bg-success bg-opacity-10
|
||||
{% elif decision.action == 'SELL' %}border-danger bg-danger bg-opacity-10
|
||||
{% else %}border-secondary bg-secondary bg-opacity-10{% endif %}">
|
||||
<small class="text-muted">{{ decision.timestamp }}</small><br>
|
||||
<strong>{{ decision.action }}</strong> - {{ decision.symbol }}<br>
|
||||
<small>Confidence: {{ decision.confidence }}% | Price: ${{ decision.price }}</small>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- COB Data and Models Row -->
|
||||
<div class="row mb-3">
|
||||
<!-- COB Ladders (Left 60%) -->
|
||||
<div class="col-md-7">
|
||||
<div class="row">
|
||||
{% for cob in cob_data %}
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6>{{ cob.symbol }} Order Book</h6>
|
||||
<small class="text-muted">Total: {{ cob.total_usd }} USD | {{ cob.total_crypto }} {{ cob.symbol.split('/')[0] }}</small>
|
||||
</div>
|
||||
<div class="card-body p-2">
|
||||
<div id="{{ cob.content_id }}" class="cob-ladder">
|
||||
<table class="table table-sm table-borderless">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Size</th>
|
||||
<th>Price</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for level in cob.levels %}
|
||||
<tr class="{% if level.side == 'ask' %}ask-row{% else %}bid-row{% endif %}">
|
||||
<td>{{ level.size }}</td>
|
||||
<td>{{ level.price }}</td>
|
||||
<td>{{ level.total }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Models & Training Progress (Right 40%) -->
|
||||
<div class="col-md-5">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6>Models & Training Progress</h6>
|
||||
</div>
|
||||
<div class="card-body training-panel">
|
||||
<div id="training-metrics">
|
||||
<!-- Model Status Indicators -->
|
||||
<div class="mb-3">
|
||||
<h6>Model Status</h6>
|
||||
{% for model in models %}
|
||||
<span class="model-status status-{{ model.status }}">
|
||||
{{ model.name }}: {{ model.status_text }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Training Metrics -->
|
||||
<div class="mb-3">
|
||||
<h6>Training Metrics</h6>
|
||||
{% for metric in training_metrics %}
|
||||
<div class="row mb-1">
|
||||
<div class="col-6">
|
||||
<small>{{ metric.name }}:</small>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<small class="fw-bold">{{ metric.value }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Performance Stats -->
|
||||
<div class="mb-3">
|
||||
<h6>Performance</h6>
|
||||
{% for stat in performance_stats %}
|
||||
<div class="row mb-1">
|
||||
<div class="col-8">
|
||||
<small>{{ stat.name }}:</small>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<small class="fw-bold">{{ stat.value }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Closed Trades Row -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6>Recent Closed Trades</h6>
|
||||
</div>
|
||||
<div class="card-body closed-trades">
|
||||
<div id="closed-trades-table">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Symbol</th>
|
||||
<th>Side</th>
|
||||
<th>Size</th>
|
||||
<th>Entry</th>
|
||||
<th>Exit</th>
|
||||
<th>PnL</th>
|
||||
<th>Duration</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for trade in closed_trades %}
|
||||
<tr>
|
||||
<td>{{ trade.time }}</td>
|
||||
<td>{{ trade.symbol }}</td>
|
||||
<td>
|
||||
<span class="badge {% if trade.side == 'BUY' %}bg-success{% else %}bg-danger{% endif %}">
|
||||
{{ trade.side }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ trade.size }}</td>
|
||||
<td>${{ trade.entry_price }}</td>
|
||||
<td>${{ trade.exit_price }}</td>
|
||||
<td class="{% if trade.pnl > 0 %}trade-profit{% else %}trade-loss{% endif %}">
|
||||
${{ trade.pnl }}
|
||||
</td>
|
||||
<td>{{ trade.duration }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auto-refresh interval -->
|
||||
<div id="interval-component" style="display: none;" data-interval="{{ refresh_interval }}"></div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user