168 lines
5.5 KiB
Python
168 lines
5.5 KiB
Python
from django.db import models
|
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
|
from decimal import Decimal
|
|
|
|
class BitcoinPrice(models.Model):
|
|
"""
|
|
Stores historical Bitcoin price data.
|
|
"""
|
|
timestamp = models.DateTimeField(auto_now_add=True)
|
|
price_usd = models.DecimalField(max_digits=20, decimal_places=2)
|
|
volume = models.DecimalField(max_digits=30, decimal_places=2, null=True, blank=True)
|
|
market_cap = models.DecimalField(max_digits=30, decimal_places=2, null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
return f"Bitcoin: ${self.price_usd} at {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
|
|
|
|
class Meta:
|
|
ordering = ['-timestamp'] # Newest first
|
|
|
|
|
|
|
|
class MarketAnalysis(models.Model):
|
|
"""
|
|
Stores market analysis results.
|
|
"""
|
|
STATUS_CHOICES = [
|
|
('dip', 'Dip'),
|
|
('peak', 'Peak'),
|
|
('neutral', 'Neutral'),
|
|
]
|
|
|
|
timestamp = models.DateTimeField(auto_now_add=True)
|
|
period = models.CharField(max_length=10, choices=[
|
|
('hourly', 'Hourly'),
|
|
('daily', 'Daily'),
|
|
('weekly', 'Weekly'),
|
|
('yearly', 'Yearly'),
|
|
], default='hourly')
|
|
|
|
# Price statistics
|
|
current_price = models.DecimalField(max_digits=20, decimal_places=2)
|
|
average_price = models.DecimalField(max_digits=20, decimal_places=2)
|
|
min_price = models.DecimalField(max_digits=20, decimal_places=2)
|
|
max_price = models.DecimalField(max_digits=20, decimal_places=2)
|
|
|
|
# Analysis results
|
|
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='neutral')
|
|
threshold_percent = models.DecimalField(
|
|
max_digits=5,
|
|
decimal_places=2,
|
|
default=15.0,
|
|
validators=[MinValueValidator(Decimal('0.01')), MaxValueValidator(Decimal('100'))]
|
|
)
|
|
|
|
# Calculated thresholds
|
|
lower_threshold = models.DecimalField(max_digits=20, decimal_places=2)
|
|
upper_threshold = models.DecimalField(max_digits=20, decimal_places=2)
|
|
|
|
# Event tracking
|
|
is_event = models.BooleanField(default=False)
|
|
event_type = models.CharField(max_length=20, blank=True, choices=[
|
|
('dip_below', 'Dip Below Threshold'),
|
|
('rise_above', 'Rise Above Threshold'),
|
|
('neutralized', 'Neutralized'),
|
|
])
|
|
|
|
def __str__(self):
|
|
return f"Analysis: {self.status.upper()} at ${self.current_price}"
|
|
|
|
class Meta:
|
|
ordering = ['-timestamp']
|
|
verbose_name_plural = "Market Analyses"
|
|
|
|
class SystemStatus(models.Model):
|
|
"""
|
|
Tracks system health and status for monitoring.
|
|
"""
|
|
timestamp = models.DateTimeField(auto_now_add=True)
|
|
|
|
# Update status
|
|
last_hourly_update = models.DateTimeField(null=True, blank=True)
|
|
last_successful_fetch = models.DateTimeField(null=True, blank=True)
|
|
|
|
# Current status
|
|
current_price = models.DecimalField(
|
|
max_digits=20, decimal_places=2, null=True, blank=True
|
|
)
|
|
|
|
# Error tracking
|
|
last_error = models.TextField(blank=True)
|
|
is_stale = models.BooleanField(default=True)
|
|
is_healthy = models.BooleanField(default=True)
|
|
|
|
class Meta:
|
|
ordering = ['-timestamp']
|
|
verbose_name_plural = "System Statuses"
|
|
|
|
def __str__(self):
|
|
status = "Healthy" if self.is_healthy else "Unhealthy"
|
|
return f"System Status: {status} at {self.timestamp}"
|
|
|
|
class NotificationPreference(models.Model):
|
|
"""
|
|
Stores notification preferences for each email address.
|
|
"""
|
|
email_address = models.EmailField(unique=True)
|
|
receive_event_alerts = models.BooleanField(
|
|
default=True,
|
|
help_text="Receive immediate alerts for threshold events"
|
|
)
|
|
receive_system_alerts = models.BooleanField(
|
|
default=True,
|
|
help_text="Receive alerts for system failures and issues"
|
|
)
|
|
receive_daily_digest = models.BooleanField(
|
|
default=True,
|
|
help_text="Receive daily summary email at 8 AM"
|
|
)
|
|
is_active = models.BooleanField(default=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
def __str__(self):
|
|
return f"{self.email_address} (Active: {self.is_active})"
|
|
|
|
class Meta:
|
|
ordering = ['-created_at']
|
|
|
|
|
|
class EmailNotification(models.Model):
|
|
"""
|
|
Records of all emails sent by the system.
|
|
"""
|
|
NOTIFICATION_TYPES = [
|
|
('event', 'Event Alert'),
|
|
('system', 'System Alert'),
|
|
('digest', 'Daily Digest'),
|
|
('test', 'Test Email'),
|
|
]
|
|
|
|
STATUS_CHOICES = [
|
|
('pending', 'Pending'),
|
|
('sent', 'Sent'),
|
|
('failed', 'Failed'),
|
|
('retrying', 'Retrying'),
|
|
]
|
|
|
|
recipient = models.EmailField()
|
|
subject = models.CharField(max_length=255)
|
|
notification_type = models.CharField(max_length=20, choices=NOTIFICATION_TYPES)
|
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
|
|
content_html = models.TextField(blank=True)
|
|
content_text = models.TextField(blank=True)
|
|
error_message = models.TextField(blank=True)
|
|
sent_at = models.DateTimeField(null=True, blank=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
retry_count = models.IntegerField(default=0)
|
|
|
|
def __str__(self):
|
|
return f"{self.notification_type} to {self.recipient} - {self.status}"
|
|
|
|
class Meta:
|
|
ordering = ['-created_at']
|
|
indexes = [
|
|
models.Index(fields=['recipient', 'created_at']),
|
|
models.Index(fields=['notification_type', 'status']),
|
|
]
|