Class: BudaApi::AI::AnomalyDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/buda_api/ai/anomaly_detector.rb

Overview

AI-powered anomaly detection for trading patterns and market behavior

Constant Summary collapse

ANOMALY_TYPES =
{
  price_spike: {
    severity: :high,
    description: "Unusual price movement detected",
    threshold: 15.0  # 15% price change
  },
  volume_anomaly: {
    severity: :medium,
    description: "Abnormal trading volume",
    threshold: 3.0   # 3x average volume
  },
  spread_anomaly: {
    severity: :medium,
    description: "Unusual bid-ask spread",
    threshold: 2.0   # 2x normal spread
  },
  trading_pattern: {
    severity: :low,
    description: "Unusual trading pattern detected",
    threshold: 1.5   # 1.5x normal pattern deviation
  },
  market_correlation: {
    severity: :medium,
    description: "Abnormal market correlation",
    threshold: 0.7   # Correlation coefficient threshold
  },
  whale_activity: {
    severity: :high,
    description: "Large order activity detected",
    threshold: 10.0  # 10x average order size
  }
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(client, llm_provider: :openai) ⇒ AnomalyDetector

Returns a new instance of AnomalyDetector.



40
41
42
43
44
45
46
47
48
49
# File 'lib/buda_api/ai/anomaly_detector.rb', line 40

def initialize(client, llm_provider: :openai)
  @client = client
  @llm = RubyLLM.new(
    provider: llm_provider,
    system_prompt: build_anomaly_system_prompt
  )
  @historical_data = {}
  
  BudaApi::Logger.info("Anomaly Detector initialized")
end

Instance Method Details

#analyze_historical_anomalies(market_id, lookback_hours = 24) ⇒ Hash

Analyze historical data for patterns and anomalies

Parameters:

  • market_id (String)

    market to analyze

  • lookback_hours (Integer) (defaults to: 24)

    hours of history to analyze

Returns:

  • (Hash)

    historical anomaly analysis



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/buda_api/ai/anomaly_detector.rb', line 173

def analyze_historical_anomalies(market_id, lookback_hours = 24)
  BudaApi::Logger.info("Analyzing historical anomalies for #{market_id} (#{lookback_hours}h lookback)")
  
  begin
    # Get historical ticker data (simulated - Buda API might not provide full historical data)
    historical_data = fetch_historical_data(market_id, lookback_hours)
    
    if historical_data.empty?
      return {
        type: :historical_analysis,
        market_id: market_id,
        message: "Insufficient historical data for analysis",
        timestamp: Time.now
      }
    end
    
    # Detect various anomaly patterns
    anomalies = []
    
    # Price spike detection
    price_anomalies = detect_price_spikes(historical_data)
    anomalies.concat(price_anomalies)
    
    # Volume pattern analysis
    volume_anomalies = detect_volume_anomalies(historical_data)
    anomalies.concat(volume_anomalies)
    
    # Trend anomalies
    trend_anomalies = detect_trend_anomalies(historical_data)
    anomalies.concat(trend_anomalies)
    
    # Statistical analysis
    statistical_anomalies = detect_statistical_anomalies(historical_data)
    anomalies.concat(statistical_anomalies)
    
    {
      type: :historical_analysis,
      market_id: market_id,
      lookback_hours: lookback_hours,
      data_points: historical_data.length,
      anomalies_found: anomalies.length,
      anomalies: anomalies.sort_by { |a| a[:severity_score] }.reverse,
      summary: generate_historical_summary(anomalies),
      timestamp: Time.now
    }
    
  rescue => e
    error_msg = "Historical anomaly analysis failed: #{e.message}"
    BudaApi::Logger.error(error_msg)
    
    {
      type: :historical_analysis_error,
      error: error_msg,
      timestamp: Time.now
    }
  end
end

#detect_market_anomalies(options = {}) ⇒ Hash

Detect real-time anomalies across all markets

Parameters:

  • options (Hash) (defaults to: {})

    detection options

Options Hash (options):

  • :markets (Array<String>)

    specific markets to monitor

  • :anomaly_types (Array<Symbol>)

    types to detect

  • :include_ai_analysis (Boolean)

    include AI insights

Returns:

  • (Hash)

    anomaly detection results



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/buda_api/ai/anomaly_detector.rb', line 58

def detect_market_anomalies(options = {})
  markets = options[:markets] || BudaApi::Constants::Market::MAJOR
  anomaly_types = options[:anomaly_types] || ANOMALY_TYPES.keys
  include_ai = options[:include_ai_analysis] != false
  
  BudaApi::Logger.info("Detecting market anomalies across #{markets.length} markets")
  
  begin
    anomalies = []
    market_data = {}
    
    # Analyze each market
    markets.each do |market_id|
      market_analysis = analyze_market_for_anomalies(market_id, anomaly_types)
      market_data[market_id] = market_analysis[:data]
      
      if market_analysis[:anomalies].any?
        anomalies.concat(market_analysis[:anomalies])
      end
    end
    
    # Cross-market anomaly detection
    cross_market_anomalies = detect_cross_market_anomalies(market_data)
    anomalies.concat(cross_market_anomalies)
    
    # Sort by severity
    anomalies.sort_by! { |anomaly| anomaly[:severity_score] }.reverse!
    
    result = {
      type: :anomaly_detection,
      timestamp: Time.now,
      markets_analyzed: markets.length,
      anomalies_detected: anomalies.length,
      anomalies: anomalies,
      market_data: market_data,
      severity_summary: calculate_severity_summary(anomalies),
      recommendations: generate_anomaly_recommendations(anomalies)
    }
    
    # Add AI analysis if requested
    if include_ai && anomalies.any?
      result[:ai_analysis] = generate_ai_anomaly_analysis(result)
    end
    
    result
    
  rescue => e
    error_msg = "Anomaly detection failed: #{e.message}"
    BudaApi::Logger.error(error_msg)
    
    {
      type: :anomaly_detection_error,
      error: error_msg,
      timestamp: Time.now
    }
  end
end

#monitor_market_realtime(market_id, duration = 3600, &callback) ⇒ Hash

Monitor specific market for anomalies in real-time

Parameters:

  • market_id (String)

    market to monitor

  • duration (Integer) (defaults to: 3600)

    monitoring duration in seconds

  • callback (Proc)

    callback for real-time alerts

Returns:

  • (Hash)

    monitoring results



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/buda_api/ai/anomaly_detector.rb', line 122

def monitor_market_realtime(market_id, duration = 3600, &callback)
  BudaApi::Logger.info("Starting real-time monitoring of #{market_id} for #{duration} seconds")
  
  start_time = Time.now
  anomalies_detected = []
  monitoring_active = true
  
  # Background monitoring thread
  monitoring_thread = Thread.new do
    while monitoring_active && (Time.now - start_time) < duration
      begin
        anomalies = detect_single_market_anomalies(market_id)
        
        anomalies.each do |anomaly|
          anomalies_detected << anomaly
          callback&.call(anomaly)
          
          # Log significant anomalies
          if anomaly[:severity_score] >= 7.0
            BudaApi::Logger.warn("High severity anomaly detected in #{market_id}: #{anomaly[:type]}")
          end
        end
        
        # Check every 30 seconds
        sleep(30)
        
      rescue => e
        BudaApi::Logger.error("Real-time monitoring error: #{e.message}")
        sleep(60)  # Wait longer on error
      end
    end
  end
  
  # Return monitoring control object
  {
    type: :realtime_monitoring,
    market_id: market_id,
    start_time: start_time,
    duration: duration,
    thread: monitoring_thread,
    anomalies_detected: anomalies_detected,
    stop: -> { monitoring_active = false; monitoring_thread.join },
    status: -> { monitoring_active ? :active : :stopped }
  }
end

#setup_anomaly_alerts(alert_config = {}) ⇒ Hash

Set up automated alerts for specific anomaly types

Parameters:

  • alert_config (Hash) (defaults to: {})

    alert configuration

Returns:

  • (Hash)

    alert system status



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/buda_api/ai/anomaly_detector.rb', line 235

def setup_anomaly_alerts(alert_config = {})
  default_config = {
    markets: BudaApi::Constants::Market::MAJOR,
    anomaly_types: [:price_spike, :volume_anomaly, :whale_activity],
    severity_threshold: 6.0,
    notification_methods: [:log, :callback],
    check_interval: 60  # seconds
  }
  
  config = default_config.merge(alert_config)
  
  BudaApi::Logger.info("Setting up anomaly alerts with config: #{config}")
  
  {
    type: :alert_system,
    config: config,
    status: :configured,
    start_monitoring: -> { start_alert_monitoring(config) },
    timestamp: Time.now
  }
end