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:
Dobromir Popov
2025-07-02 01:56:50 +03:00
parent 5eda20acc8
commit 6acc1c9296
5 changed files with 1691 additions and 0 deletions

View 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>