strange_doge_rf.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import requests
  2. import pandas as pd
  3. import numpy as np
  4. from sklearn.ensemble import IsolationForest
  5. import time
  6. import schedule
  7. import smtplib
  8. from email.mime.text import MIMEText
  9. from email.mime.multipart import MIMEMultipart
  10. from datetime import datetime
  11. import os
  12. # Configuration
  13. CRYPTO = 'dogecoin' # CoinGecko ID for DOGE
  14. CURRENCY = 'usd' # Base currency
  15. CURRENT_PRICE_URL = f'https://api.coingecko.com/api/v3/simple/price?ids={CRYPTO}&vs_currencies={CURRENCY}'
  16. HISTORICAL_URL = f'https://api.coingecko.com/api/v3/coins/{CRYPTO}/market_chart?vs_currency={CURRENCY}&days=30 # &interval=hourly'
  17. CHECK_INTERVAL_SECONDS = 60 # Check every 60 seconds
  18. RETRAIN_INTERVAL_MINUTES = 60 # Retrain model every 60 minutes
  19. ANOMALY_THRESHOLD = -0.5 # Isolation Forest score < -0.5 indicates anomaly (range: -1 to 1)
  20. HISTORY_WINDOW = 1000 # Max historical points to keep (for memory efficiency)
  21. CSV_FILE = 'doge_price_history.csv' # For persistence
  22. # Email configuration (replace with your details)
  23. EMAIL_FROM = 'vortify-lc@algometic.com'
  24. EMAIL_TO = 'larry1chan@qq.com'
  25. EMAIL_PASSWORD = 'g33kPoppy!'
  26. SMTP_SERVER = 'hwsmtp.exmail.qq.com'
  27. SMTP_PORT = 465
  28. # Global variables
  29. price_df = pd.DataFrame(columns=['timestamp', 'price']) # Historical prices
  30. model = None # Isolation Forest model
  31. def fetch_historical_data():
  32. """Fetch historical hourly price data from CoinGecko."""
  33. try:
  34. response = requests.get(HISTORICAL_URL)
  35. response.raise_for_status()
  36. data = response.json()
  37. prices = data['prices'] # List of [timestamp_ms, price]
  38. df = pd.DataFrame(prices, columns=['timestamp', 'price'])
  39. df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
  40. return df
  41. except Exception as e:
  42. print(f"Error fetching historical data: {e}")
  43. return pd.DataFrame()
  44. def load_or_fetch_history():
  45. """Load history from CSV if exists, else fetch from API."""
  46. global price_df
  47. if os.path.exists(CSV_FILE):
  48. price_df = pd.read_csv(CSV_FILE, parse_dates=['timestamp'])
  49. print(f"Loaded {len(price_df)} historical points from CSV.")
  50. else:
  51. price_df = fetch_historical_data()
  52. if not price_df.empty:
  53. price_df.to_csv(CSV_FILE, index=False)
  54. print(f"Fetched and saved {len(price_df)} historical points.")
  55. # Trim to window size
  56. price_df = price_df.tail(HISTORY_WINDOW)
  57. def fetch_current_price():
  58. """Fetch current price from CoinGecko API."""
  59. try:
  60. response = requests.get(CURRENT_PRICE_URL)
  61. response.raise_for_status()
  62. data = response.json()
  63. price = data[CRYPTO][CURRENCY]
  64. timestamp = datetime.now()
  65. return timestamp, price
  66. except Exception as e:
  67. print(f"Error fetching current price: {e}")
  68. return None, None
  69. def engineer_features(df):
  70. """Engineer features for anomaly detection."""
  71. df = df.copy()
  72. df['pct_change'] = df['price'].pct_change() # Percentage change
  73. df['abs_diff'] = df['price'].diff() # Absolute difference
  74. df['rolling_mean_5'] = df['price'].rolling(window=5).mean() # Rolling mean
  75. df['rolling_std_5'] = df['price'].rolling(window=5).std() # Rolling std
  76. df['hour'] = df['timestamp'].dt.hour # Time of day
  77. # Fill NaNs with 0 or forward-fill for simplicity
  78. df.fillna(0, inplace=True)
  79. # Features to use (exclude timestamp and price for model input)
  80. features = ['pct_change', 'abs_diff', 'rolling_mean_5', 'rolling_std_5', 'hour']
  81. return df[features]
  82. def train_model():
  83. """Train or retrain Isolation Forest on historical features."""
  84. global model
  85. if len(price_df) < 10: # Need sufficient data
  86. print("Insufficient data to train model.")
  87. return
  88. features = engineer_features(price_df)
  89. model = IsolationForest(contamination=0.01, random_state=42) # Assume 1% anomalies
  90. model.fit(features)
  91. print("Model retrained successfully.")
  92. def detect_anomaly(timestamp, current_price):
  93. """Detect if current price is an anomaly using the model."""
  94. if model is None:
  95. return False, 0.0
  96. # Create a temporary DF with new point appended
  97. new_row = pd.DataFrame({'timestamp': [timestamp], 'price': [current_price]})
  98. temp_df = pd.concat([price_df, new_row], ignore_index=True)
  99. features = engineer_features(temp_df)
  100. # Predict on the latest point
  101. score = model.decision_function(features.tail(1))[0] # Score: higher = more normal
  102. is_anomaly = score < ANOMALY_THRESHOLD
  103. return is_anomaly, score
  104. def send_email_alert(timestamp, current_price, score):
  105. """Send email alert for anomaly."""
  106. subject = f"Anomaly Detected in {CRYPTO.upper()} Price!"
  107. body = f"""
  108. Alert Time: {timestamp}
  109. Current Price: ${current_price:.4f}
  110. Anomaly Score: {score:.2f} (Threshold: {ANOMALY_THRESHOLD})
  111. This indicates a sudden and sharp price fluctuation.
  112. """
  113. msg = MIMEMultipart()
  114. msg['From'] = EMAIL_FROM
  115. msg['To'] = EMAIL_TO
  116. msg['Subject'] = subject
  117. msg.attach(MIMEText(body, 'plain'))
  118. try:
  119. server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
  120. server.starttls()
  121. server.login(EMAIL_FROM, EMAIL_PASSWORD)
  122. server.sendmail(EMAIL_FROM, EMAIL_TO, msg.as_string())
  123. server.quit()
  124. print("Email alert sent successfully.")
  125. except Exception as e:
  126. print(f"Error sending email: {e}")
  127. def monitor():
  128. """Main monitoring function: Fetch price, check for anomaly, alert if needed."""
  129. global price_df
  130. timestamp, current_price = fetch_current_price()
  131. if current_price is None:
  132. return
  133. # Append new price to history
  134. new_row = pd.DataFrame({'timestamp': [timestamp], 'price': [current_price]})
  135. price_df = pd.concat([price_df, new_row], ignore_index=True)
  136. price_df = price_df.tail(HISTORY_WINDOW) # Keep window size
  137. price_df.to_csv(CSV_FILE, index=False) # Save updates
  138. is_anomaly, score = detect_anomaly(timestamp, current_price)
  139. print(f"{timestamp} - Current {CRYPTO.upper()} Price: ${current_price:.4f} | Anomaly Score: {score:.2f}")
  140. if is_anomaly:
  141. print(f"ANOMALY DETECTED! Score: {score:.2f}")
  142. send_email_alert(timestamp, current_price, score)
  143. def retrain_scheduler():
  144. """Scheduled task to retrain the model."""
  145. train_model()
  146. # Initialize
  147. load_or_fetch_history()
  148. train_model() # Initial training
  149. # Schedule tasks
  150. schedule.every(CHECK_INTERVAL_SECONDS).seconds.do(monitor)
  151. schedule.every(RETRAIN_INTERVAL_MINUTES).minutes.do(retrain_scheduler)
  152. # Run the monitoring loop
  153. print(f"Starting advanced {CRYPTO.upper()} price anomaly monitor with Isolation Forest...")
  154. while True:
  155. schedule.run_pending()
  156. time.sleep(1) # Avoid high CPU usage