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']), ]