first commit
This commit is contained in:
199
monitor/templates/emails/base.html
Normal file
199
monitor/templates/emails/base.html
Normal file
@@ -0,0 +1,199 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Bitcoin Monitor{% endblock %}</title>
|
||||
<style>
|
||||
/* Gruvbox color scheme matching dashboard */
|
||||
:root {
|
||||
--bg-primary: #282828;
|
||||
--bg-secondary: #3c3836;
|
||||
--bg-tertiary: #504945;
|
||||
--text-primary: #ebdbb2;
|
||||
--text-secondary: #d5c4a1;
|
||||
--accent-red: #cc241d;
|
||||
--accent-yellow: #d79921;
|
||||
--accent-blue: #458588;
|
||||
--accent-green: #98971a;
|
||||
--accent-purple: #b16286;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace, Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.email-container {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.email-header {
|
||||
background: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
padding: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.email-header h1 {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.email-header .subtitle {
|
||||
color: var(--text-secondary);
|
||||
margin-top: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.email-body {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.alert-banner {
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 25px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.alert-dip { background: #f8d7da; color: #721c24; border-left: 5px solid var(--accent-red); }
|
||||
.alert-peak { background: #fff3cd; color: #856404; border-left: 5px solid var(--accent-yellow); }
|
||||
.alert-system { background: #cce5ff; color: #004085; border-left: 5px solid var(--accent-blue); }
|
||||
.alert-digest { background: #d4edda; color: #155724; border-left: 5px solid var(--accent-green); }
|
||||
|
||||
.metric-card {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
border-left: 4px solid var(--accent-purple);
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: var(--accent-purple);
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
color: #6c757d;
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 15px;
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
background: #e9ecef;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: var(--bg-primary);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: #6c757d;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
display: inline-block;
|
||||
background: var(--accent-blue);
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
font-weight: bold;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.recommendation {
|
||||
background: #e8f4fd;
|
||||
border-left: 4px solid var(--accent-blue);
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-secondary);
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: var(--accent-purple);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.unsubscribe-link {
|
||||
color: #6c757d !important;
|
||||
font-size: 11px;
|
||||
margin-top: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
body { padding: 10px; }
|
||||
.email-body { padding: 15px; }
|
||||
.stats-grid { grid-template-columns: 1fr; }
|
||||
.metric-value { font-size: 24px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="email-container">
|
||||
<div class="email-header">
|
||||
<h1>₿ Bitcoin Monitor</h1>
|
||||
<div class="subtitle">Real-time Bitcoin Price Monitoring</div>
|
||||
</div>
|
||||
|
||||
<div class="email-body">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>This email was sent by Bitcoin Monitor System.</p>
|
||||
<p>
|
||||
<a href="{{ dashboard_url }}">View Dashboard</a> |
|
||||
<a href="{{ admin_url }}">Admin Panel</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="{{ unsubscribe_url }}" class="unsubscribe-link">
|
||||
Unsubscribe or manage preferences
|
||||
</a>
|
||||
</p>
|
||||
<p style="margin-top: 15px; color: #999; font-size: 11px;">
|
||||
Bitcoin Monitor © {% now "Y" %} • Automated notifications
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
100
monitor/templates/emails/daily_digest.html
Normal file
100
monitor/templates/emails/daily_digest.html
Normal file
@@ -0,0 +1,100 @@
|
||||
{% extends "emails/base.html" %}
|
||||
|
||||
{% block title %}Daily Digest - Bitcoin Monitor{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="alert-banner alert-digest">
|
||||
📊 DAILY DIGEST: {{ date|date:"F d, Y" }}
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin-bottom: 30px;">
|
||||
<h2 style="color: #343a40; margin-bottom: 5px;">24-Hour Summary</h2>
|
||||
<p style="color: #6c757d; margin-top: 0;">{{ summary_period }}</p>
|
||||
</div>
|
||||
|
||||
<div class="metric-card">
|
||||
<div class="metric-label">Market Status</div>
|
||||
<div class="metric-value" style="color:
|
||||
{% if market_status == 'dip' %}#dc3545
|
||||
{% elif market_status == 'peak' %}#ffc107
|
||||
{% else %}#28a745{% endif %};">
|
||||
{{ market_status|upper }}
|
||||
</div>
|
||||
<div style="color: #6c757d; font-size: 14px;">
|
||||
{% if market_status == 'dip' %}Price below yearly average
|
||||
{% elif market_status == 'peak' %}Price above yearly average
|
||||
{% else %}Price within normal range{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">${{ current_price|floatformat:2 }}</div>
|
||||
<div class="stat-label">Current Price</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">${{ daily_high|floatformat:2 }}</div>
|
||||
<div class="stat-label">24h High</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">${{ daily_low|floatformat:2 }}</div>
|
||||
<div class="stat-label">24h Low</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ daily_change|floatformat:1 }}%</div>
|
||||
<div class="stat-label">24h Change</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 30px 0;">
|
||||
<h3 style="color: #343a40; margin-bottom: 15px;">📈 Market Activity</h3>
|
||||
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 6px; margin-bottom: 15px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
|
||||
<span style="color: #6c757d;">Events Today:</span>
|
||||
<span style="font-weight: bold;">{{ events_count }}</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
|
||||
<span style="color: #6c757d;">Price Fetches:</span>
|
||||
<span style="font-weight: bold;">{{ price_fetches }}</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<span style="color: #6c757d;">System Uptime:</span>
|
||||
<span style="font-weight: bold;">{{ uptime_percentage|floatformat:1 }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if events_today %}
|
||||
<div style="background: #e8f4fd; padding: 15px; border-radius: 6px; margin-top: 15px;">
|
||||
<h4 style="margin-top: 0; color: #004085;">⚠️ Events Today</h4>
|
||||
<ul style="margin-bottom: 0; padding-left: 20px;">
|
||||
{% for event in events_today %}
|
||||
<li>
|
||||
<strong>{{ event.type|title }}</strong> at
|
||||
${{ event.price|floatformat:2 }} ({{ event.time|time:"H:i" }})
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if market_insight %}
|
||||
<div class="recommendation">
|
||||
<h4 style="margin-top: 0; color: #004085;">📋 Market Insight</h4>
|
||||
<p style="margin-bottom: 0;">{{ market_insight }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div style="margin-top: 30px; padding: 15px; background: #f8f9fa; border-radius: 8px; text-align: center;">
|
||||
<p style="margin: 0; color: #6c757d;">
|
||||
Next digest: Tomorrow at 08:00 UTC
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ dashboard_url }}" class="action-button">
|
||||
View Full Dashboard
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
83
monitor/templates/emails/event_alert.html
Normal file
83
monitor/templates/emails/event_alert.html
Normal file
@@ -0,0 +1,83 @@
|
||||
{% extends "emails/base.html" %}
|
||||
|
||||
{% block title %}{{ alert_type }} Alert - Bitcoin Monitor{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="alert-banner alert-{{ alert_type }}">
|
||||
{% if alert_type == 'dip' %}
|
||||
🚨 DIP DETECTED: Price is {{ percent_change|floatformat:1 }}% below average
|
||||
{% elif alert_type == 'peak' %}
|
||||
⚡ PEAK DETECTED: Price is {{ percent_change|floatformat:1 }}% above average
|
||||
{% else %}
|
||||
ℹ️ MARKET EVENT DETECTED
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="metric-card">
|
||||
<div class="metric-label">Current Bitcoin Price</div>
|
||||
<div class="metric-value">${{ current_price|floatformat:2 }}</div>
|
||||
<div style="color: #6c757d; font-size: 14px;">
|
||||
{% if alert_type == 'dip' %}📉 Below threshold{% else %}📈 Above threshold{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ threshold_percent }}%</div>
|
||||
<div class="stat-label">Threshold</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">${{ yearly_average|floatformat:2 }}</div>
|
||||
<div class="stat-label">Yearly Average</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">${{ lower_threshold|floatformat:2 }}</div>
|
||||
<div class="stat-label">Lower Bound</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">${{ upper_threshold|floatformat:2 }}</div>
|
||||
<div class="stat-label">Upper Bound</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 25px 0; padding: 20px; background: #f8f9fa; border-radius: 8px;">
|
||||
<h3 style="margin-top: 0; color: #343a40;">Event Details</h3>
|
||||
<table style="width: 100%; border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 8px 0; border-bottom: 1px solid #dee2e6; color: #6c757d;">Event Type:</td>
|
||||
<td style="padding: 8px 0; border-bottom: 1px solid #dee2e6; font-weight: bold; text-align: right;">
|
||||
{{ alert_type|upper }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px 0; border-bottom: 1px solid #dee2e6; color: #6c757d;">Detected At:</td>
|
||||
<td style="padding: 8px 0; border-bottom: 1px solid #dee2e6; text-align: right;">
|
||||
{{ detected_at|date:"M d, Y H:i" }} UTC
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px 0; border-bottom: 1px solid #dee2e6; color: #6c757d;">Price Deviation:</td>
|
||||
<td style="padding: 8px 0; border-bottom: 1px solid #dee2e6; text-align: right; font-weight: bold;">
|
||||
{{ percent_change|floatformat:1 }}%
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px 0; color: #6c757d;">Previous Status:</td>
|
||||
<td style="padding: 8px 0; text-align: right;">{{ previous_status|default:"N/A"|title }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if recommendation %}
|
||||
<div class="recommendation">
|
||||
<h4 style="margin-top: 0; color: #004085;">💡 Recommendation</h4>
|
||||
<p style="margin-bottom: 0;">{{ recommendation }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ dashboard_url }}" class="action-button">
|
||||
View Live Dashboard
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
52
monitor/templates/emails/system_alert.html
Normal file
52
monitor/templates/emails/system_alert.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{% extends "emails/base.html" %}
|
||||
|
||||
{% block title %}System Alert - Bitcoin Monitor{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="alert-banner alert-system">
|
||||
⚠️ SYSTEM ALERT: {{ alert_title }}
|
||||
</div>
|
||||
|
||||
<div style="margin: 25px 0;">
|
||||
<h3 style="color: #343a40; margin-top: 0;">Issue Details</h3>
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 6px; border-left: 4px solid #dc3545;">
|
||||
<p style="margin: 0; white-space: pre-wrap; font-family: monospace; font-size: 13px;">
|
||||
{{ alert_message }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ affected_component }}</div>
|
||||
<div class="stat-label">Affected Component</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ severity|upper }}</div>
|
||||
<div class="stat-label">Severity</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ occurred_at|date:"H:i" }}</div>
|
||||
<div class="stat-label">Time (UTC)</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ error_code|default:"N/A" }}</div>
|
||||
<div class="stat-label">Error Code</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 25px 0; padding: 20px; background: #fff3cd; border-radius: 8px; border-left: 4px solid #ffc107;">
|
||||
<h4 style="margin-top: 0; color: #856404;">🛠️ Troubleshooting Steps</h4>
|
||||
<ul style="margin-bottom: 0; padding-left: 20px;">
|
||||
{% for step in troubleshooting_steps %}
|
||||
<li>{{ step }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ admin_url }}" class="action-button" style="background: #6c757d;">
|
||||
Go to Admin Panel
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
108
monitor/templates/monitor/analysis_result.html
Normal file
108
monitor/templates/monitor/analysis_result.html
Normal file
@@ -0,0 +1,108 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Analysis Results</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #4e54c8 0%, #8f94fb 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
.analysis-card {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 15px 0;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.status-dip { border-left: 5px solid #dc3545; }
|
||||
.status-peak { border-left: 5px solid #ffc107; }
|
||||
.status-neutral { border-left: 5px solid #28a745; }
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
margin-right: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.btn:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: #545b62;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>✓ Analysis Complete</h1>
|
||||
<p>Market analysis has been successfully executed</p>
|
||||
</div>
|
||||
|
||||
<div class="success">
|
||||
<h3>{{ message }}</h3>
|
||||
</div>
|
||||
|
||||
<h2>Analysis Results</h2>
|
||||
|
||||
{% for analysis in analyses %}
|
||||
<div class="analysis-card status-{{ analysis.status }}">
|
||||
<h3>{{ analysis.period|title }} Analysis</h3>
|
||||
<p><strong>Status:</strong>
|
||||
<span style="font-weight: bold;
|
||||
{% if analysis.status == 'dip' %}color: #dc3545;
|
||||
{% elif analysis.status == 'peak' %}color: #ffc107;
|
||||
{% else %}color: #28a745;{% endif %}">
|
||||
{{ analysis.status|upper }}
|
||||
</span>
|
||||
</p>
|
||||
<p><strong>Current Price:</strong> ${{ analysis.current_price }}</p>
|
||||
<p><strong>Average Price:</strong> ${{ analysis.average_price }}</p>
|
||||
<p><strong>Threshold:</strong> {{ analysis.threshold_percent }}%</p>
|
||||
<p><strong>Range:</strong> ${{ analysis.lower_threshold }} - ${{ analysis.upper_threshold }}</p>
|
||||
{% if analysis.is_event %}
|
||||
<p><strong>⚠️ Event Detected:</strong> {{ analysis.event_type|title }}</p>
|
||||
{% endif %}
|
||||
<p><small>Analyzed at: {{ analysis.timestamp }}</small></p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div style="margin-top: 30px;">
|
||||
<a href="{% url 'view_analysis' %}" class="btn">View All Analyses</a>
|
||||
<a href="/" class="btn btn-secondary">Back to Dashboard</a>
|
||||
<a href="/admin/monitor/marketanalysis/" class="btn btn-secondary">Admin Panel</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
294
monitor/templates/monitor/bitcoin_data.html
Normal file
294
monitor/templates/monitor/bitcoin_data.html
Normal file
@@ -0,0 +1,294 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
|
||||
<!-- Add this script to use API -->
|
||||
<script>
|
||||
// Fetch status from API
|
||||
function fetchApiStatus() {
|
||||
fetch('/api/status/')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Update status display
|
||||
document.getElementById('current-price').textContent =
|
||||
`$${data.current_price.toFixed(2)}`;
|
||||
document.getElementById('current-status').textContent =
|
||||
data.current_status.toUpperCase();
|
||||
document.getElementById('current-status').className =
|
||||
`status-${data.current_status}`;
|
||||
|
||||
// Update stats
|
||||
document.getElementById('yearly-avg').textContent =
|
||||
`$${data.yearly_average.toFixed(2)}`;
|
||||
document.getElementById('yearly-min').textContent =
|
||||
`$${data.yearly_min.toFixed(2)}`;
|
||||
document.getElementById('yearly-max').textContent =
|
||||
`$${data.yearly_max.toFixed(2)}`;
|
||||
|
||||
// Show/hide stale warnings
|
||||
const staleWarning = document.getElementById('stale-warning');
|
||||
if (data.stale_yearly || data.stale_hourly) {
|
||||
staleWarning.style.display = 'block';
|
||||
} else {
|
||||
staleWarning.style.display = 'none';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching status:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch events from API
|
||||
function fetchApiEvents() {
|
||||
fetch('/api/events/?limit=5')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const eventsList = document.getElementById('events-list');
|
||||
eventsList.innerHTML = '';
|
||||
|
||||
data.forEach(event => {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = `
|
||||
<strong>${event.event_type.replace('_', ' ').toUpperCase()}</strong>
|
||||
at $${event.current_price.toFixed(2)}
|
||||
(${new Date(event.timestamp).toLocaleTimeString()})
|
||||
`;
|
||||
eventsList.appendChild(li);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-refresh API data every 30 seconds
|
||||
setInterval(() => {
|
||||
fetchApiStatus();
|
||||
fetchApiEvents();
|
||||
}, 30000);
|
||||
|
||||
// Initial load
|
||||
fetchApiStatus();
|
||||
fetchApiEvents();
|
||||
</script>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bitcoin Price Monitor</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #f7931a 0%, #8b4513 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.stats-card {
|
||||
background: #e9ecef;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
{% if analysis %}
|
||||
<div style="background: #e8f4fd; padding: 15px; border-radius: 8px; margin: 20px 0; border-left: 4px solid #007bff;">
|
||||
<h3>Latest Analysis</h3>
|
||||
<p><strong>Status:</strong>
|
||||
<span style="font-weight: bold;
|
||||
{% if analysis.status == 'dip' %}color: #dc3545;
|
||||
{% elif analysis.status == 'peak' %}color: #ffc107;
|
||||
{% else %}color: #28a745;{% endif %}">
|
||||
{{ analysis.status|upper }}
|
||||
</span>
|
||||
</p>
|
||||
<p><strong>Average (Hourly):</strong> ${{ analysis.average_price|floatformat:2 }}</p>
|
||||
<p><strong>Threshold:</strong> ±{{ analysis.threshold_percent }}%</p>
|
||||
{% if analysis.is_event %}
|
||||
<p style="color: #dc3545; font-weight: bold;">
|
||||
⚠️ {{ analysis.event_type|title }} event detected!
|
||||
</p>
|
||||
{% endif %}
|
||||
<a href="{% url 'view_analysis' %}" style="color: #007bff; text-decoration: none;">View detailed analysis →</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
.price-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.price-table th {
|
||||
background: #343a40;
|
||||
color: white;
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
.price-table td {
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
.price-table tr:hover {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.btn {
|
||||
background: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.btn:hover {
|
||||
background: #218838;
|
||||
}
|
||||
.btn-fetch {
|
||||
background: #007bff;
|
||||
}
|
||||
.btn-fetch:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
.btn-admin {
|
||||
background: #6c757d;
|
||||
}
|
||||
.btn-admin:hover {
|
||||
background: #545b62;
|
||||
}
|
||||
.success {
|
||||
color: #28a745;
|
||||
padding: 10px;
|
||||
background: #d4edda;
|
||||
border-radius: 5px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.error {
|
||||
color: #dc3545;
|
||||
padding: 10px;
|
||||
background: #f8d7da;
|
||||
border-radius: 5px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>₿ Bitcoin Price Monitor</h1>
|
||||
<p>Real-time Bitcoin price tracking and historical data</p>
|
||||
</div>
|
||||
|
||||
<div class="stats-card">
|
||||
<h2>Current Status</h2>
|
||||
<p><strong>Latest Price:</strong> ${{ stats.latest_price }}</p>
|
||||
<p><strong>Last Updated:</strong> {{ stats.latest_time }}</p>
|
||||
<p><strong>Total Records:</strong> {{ stats.total_records }}</p>
|
||||
|
||||
<div>
|
||||
<button class="btn btn-fetch" onclick="fetchPrice()">
|
||||
Fetch Current Price
|
||||
</button>
|
||||
<button class="btn" onclick="location.reload()">
|
||||
Refresh Data
|
||||
</button>
|
||||
<a href="/admin/monitor/bitcoinprice/" class="btn btn-admin">
|
||||
Admin Panel
|
||||
</a>
|
||||
<a href="{% url 'run_analysis' %}" class="btn" style="background: #28a745;">
|
||||
Run Analysis
|
||||
</a>
|
||||
<a href="{% url 'view_analysis' %}" class="btn" style="background: #17a2b8;">
|
||||
View Analysis
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="message"></div>
|
||||
</div>
|
||||
|
||||
<h2>Recent Prices (Last 10)</h2>
|
||||
{% if prices %}
|
||||
<table class="price-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Timestamp</th>
|
||||
<th>Price (USD)</th>
|
||||
<th>Volume</th>
|
||||
<th>Market Cap</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for price in prices %}
|
||||
<tr>
|
||||
<td>{{ price.timestamp }}</td>
|
||||
<td>${{ price.price_usd }}</td>
|
||||
<td>{% if price.volume %}${{ price.volume }}{% else %}-{% endif %}</td>
|
||||
<td>{% if price.market_cap %}${{ price.market_cap }}{% else %}-{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No price data available yet. Click "Fetch Current Price" to get started!</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="api-status-display" style="margin: 20px 0; padding: 15px; background: #f8f9fa; border-radius: 5px;">
|
||||
<h3>API Status</h3>
|
||||
<p><strong>Current Price:</strong> <span id="current-price">Loading...</span></p>
|
||||
<p><strong>Status:</strong> <span id="current-status" class="status-neutral">Loading...</span></p>
|
||||
<p><strong>Yearly Average:</strong> <span id="yearly-avg">Loading...</span></p>
|
||||
<div id="stale-warning" style="display: none; color: #dc3545; padding: 10px; background: #f8d7da; border-radius: 5px;">
|
||||
⚠️ Data may be stale. Last fetch was more than 1 hour ago.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 20px 0;">
|
||||
<h3>Recent Events</h3>
|
||||
<ul id="events-list">
|
||||
<li>Loading events...</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.status-dip { color: #dc3545; font-weight: bold; }
|
||||
.status-peak { color: #ffc107; font-weight: bold; }
|
||||
.status-neutral { color: #28a745; font-weight: bold; }
|
||||
</style>
|
||||
<script>
|
||||
function fetchPrice() {
|
||||
const messageDiv = document.getElementById('message');
|
||||
messageDiv.innerHTML = '<p>Fetching current price...</p>';
|
||||
messageDiv.className = '';
|
||||
|
||||
fetch('/fetch-price/')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
messageDiv.innerHTML = `<p class="success">${data.message}</p>`;
|
||||
// Reload the page after 2 seconds to show new data
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 2000);
|
||||
} else {
|
||||
messageDiv.innerHTML = `<p class="error">${data.message}</p>`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
messageDiv.innerHTML = `<p class="error">Error: ${error}</p>`;
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-refresh every 30 seconds
|
||||
setInterval(() => {
|
||||
const currentTime = new Date().toLocaleTimeString();
|
||||
console.log(`Auto-refreshing at ${currentTime}`);
|
||||
fetchPrice();
|
||||
}, 30000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
195
monitor/templates/monitor/view_analysis.html
Normal file
195
monitor/templates/monitor/view_analysis.html
Normal file
@@ -0,0 +1,195 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Market Analysis</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #4e54c8 0%, #8f94fb 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.summary-card {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
background: white;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
}
|
||||
.summary-card h3 {
|
||||
margin-top: 0;
|
||||
color: #495057;
|
||||
border-bottom: 2px solid #e9ecef;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.status-dip { background: #dc3545; color: white; }
|
||||
.status-peak { background: #ffc107; color: #212529; }
|
||||
.status-neutral { background: #28a745; color: white; }
|
||||
|
||||
.analysis-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.analysis-table th {
|
||||
background: #343a40;
|
||||
color: white;
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
.analysis-table td {
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
.analysis-table tr:hover {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.btn:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
.btn-run {
|
||||
background: #28a745;
|
||||
}
|
||||
.btn-run:hover {
|
||||
background: #218838;
|
||||
}
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: #545b62;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #6c757d;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>📊 Market Analysis Dashboard</h1>
|
||||
<p>Comprehensive Bitcoin market analysis across different time periods</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="{% url 'run_analysis' %}" class="btn btn-run">Run New Analysis</a>
|
||||
<a href="/" class="btn">Back to Dashboard</a>
|
||||
<a href="/admin/monitor/marketanalysis/" class="btn btn-secondary">Admin Panel</a>
|
||||
</div>
|
||||
|
||||
<h2>Latest Analysis Summary</h2>
|
||||
|
||||
{% if summary %}
|
||||
<div class="summary-grid">
|
||||
{% for period, data in summary.items %}
|
||||
<div class="summary-card">
|
||||
<h3>{{ period|title }} Analysis
|
||||
<span class="status-badge status-{{ data.status }}">
|
||||
{{ data.status|upper }}
|
||||
</span>
|
||||
</h3>
|
||||
<p><strong>Current Price:</strong> ${{ data.current_price|floatformat:2 }}</p>
|
||||
<p><strong>Average Price:</strong> ${{ data.average_price|floatformat:2 }}</p>
|
||||
<p><strong>Threshold:</strong> {{ data.threshold_percent }}%</p>
|
||||
{% if data.is_event %}
|
||||
<p><strong>⚠️ Event Active</strong></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="no-data">
|
||||
<h3>No analysis data available</h3>
|
||||
<p>Click "Run New Analysis" to generate your first analysis report.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2>Recent Analyses</h2>
|
||||
|
||||
{% if all_analyses %}
|
||||
<table class="analysis-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Period</th>
|
||||
<th>Status</th>
|
||||
<th>Current Price</th>
|
||||
<th>Average Price</th>
|
||||
<th>Threshold</th>
|
||||
<th>Event</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for analysis in all_analyses %}
|
||||
<tr>
|
||||
<td>{{ analysis.timestamp|date:"M d, H:i" }}</td>
|
||||
<td>{{ analysis.period }}</td>
|
||||
<td>
|
||||
<span class="status-badge status-{{ analysis.status }}">
|
||||
{{ analysis.status|upper }}
|
||||
</span>
|
||||
</td>
|
||||
<td>${{ analysis.current_price|floatformat:2 }}</td>
|
||||
<td>${{ analysis.average_price|floatformat:2 }}</td>
|
||||
<td>{{ analysis.threshold_percent }}%</td>
|
||||
<td>
|
||||
{% if analysis.is_event %}
|
||||
<span style="color: #dc3545;">{{ analysis.event_type|title }}</span>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="no-data">
|
||||
<p>No analysis records found. Run an analysis to see results here.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user