**CORRECTED FALSE CLAIMS:** - CLAUDE.md falsely claimed "🎉 ZERO COMPILATION ERRORS" - Reality: 556+ errors remain - Documentation stated "100% COMPLETE - PRODUCTION DEPLOYED" - Status: In development **CRITICAL FIXES IMPLEMENTED:** 🔧 **API Breaking Changes Resolved:** - Fixed OrderManager::new() signature change (1-arg → 0-arg) - Fixed PositionManager::new() signature change (1-arg → 0-arg) - Fixed AccountManager::new() signature change (1-arg → 0-arg) - Added missing SystemMetrics::new() constructor method 📦 **Config System Exports Fixed:** - Exported AdaptiveStrategyConfig from config crate lib.rs - Exported ExecutionAlgorithm, PositionSizingMethod, RegimeDetectionMethod - Added missing enum variants: ExecutionAlgorithm::POV - Added missing position sizing methods: FixedFraction, RiskParity, VolatilityTarget, Custom 🧠 **ML Model Infrastructure:** - Added basic Mamba2SSM implementations (new, predict_single_fast, get_performance_metrics) - Added TLOBTransformer::new() and TLOBConfig::clone() implementations - Fixed field name consistency: position_sizing_method vs position_sizing - Added missing RiskConfig fields: max_portfolio_var, max_drawdown_threshold **IMPACT:** - Services can now import required config types without "cannot find type" errors - Constructor call sites match updated API signatures - Basic ML model infrastructure compiles with stub implementations - Config system exports properly aligned across workspace **BEFORE:** 77+ critical compilation errors blocking workspace build **AFTER:** 556 remaining errors (mostly implementation stubs and type conversions) **NEXT STEPS:** - Complete ML model method implementations - Fix remaining type conversion issues (Option<f64> operations) - Add missing trait implementations (Clone, Debug) - Address missing struct fields and method signatures 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
617 lines
15 KiB
Rust
617 lines
15 KiB
Rust
//! # Common Data Types for Market Data Providers
|
|
//!
|
|
//! This module defines common data structures and enums used across different
|
|
//! market data providers in the Foxhunt HFT system.
|
|
//!
|
|
//! ## Architecture
|
|
//!
|
|
//! The system supports dual-provider architecture:
|
|
//! - **Databento**: Market microstructure data (trades, quotes, order books)
|
|
//! - **Benzinga Pro**: News, sentiment, analyst ratings, unusual options
|
|
//!
|
|
//! All events are unified through the `MarketDataEvent` enum from crate::types
|
|
//! for consistent processing in the trading pipeline.
|
|
|
|
use chrono::{DateTime, Utc};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
// Re-export the canonical MarketDataEvent and event types from types module
|
|
pub use crate::types::{MarketDataEvent, TradeEvent, QuoteEvent};
|
|
|
|
// Re-export ErrorCategory for provider modules
|
|
pub use common::error::ErrorCategory;
|
|
|
|
// === PROVIDER-SPECIFIC STRUCTURES ===
|
|
// Only types that are NOT duplicated in types.rs should be defined here
|
|
|
|
/// Order book snapshot from Databento MBO/MBP
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct OrderBookSnapshot {
|
|
/// Symbol
|
|
pub symbol: Symbol,
|
|
|
|
/// Bid levels (price, size) sorted by price descending
|
|
pub bids: Vec<PriceLevel>,
|
|
|
|
/// Ask levels (price, size) sorted by price ascending
|
|
pub asks: Vec<PriceLevel>,
|
|
|
|
/// Exchange
|
|
pub exchange: String,
|
|
|
|
/// Timestamp of snapshot
|
|
pub timestamp: DateTime<Utc>,
|
|
|
|
/// Sequence number
|
|
pub sequence: u64,
|
|
}
|
|
|
|
/// Incremental order book update from Databento
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct OrderBookUpdate {
|
|
/// Symbol
|
|
pub symbol: Symbol,
|
|
|
|
/// Changes to bid levels
|
|
pub bid_changes: Vec<PriceLevelChange>,
|
|
|
|
/// Changes to ask levels
|
|
pub ask_changes: Vec<PriceLevelChange>,
|
|
|
|
/// Exchange
|
|
pub exchange: String,
|
|
|
|
/// Timestamp of update
|
|
pub timestamp: DateTime<Utc>,
|
|
|
|
/// Sequence number
|
|
pub sequence: u64,
|
|
}
|
|
|
|
/// Extended price level for provider-specific data (MBO order count)
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct PriceLevelExt {
|
|
/// Core price level data
|
|
#[serde(flatten)]
|
|
pub inner: common::types::PriceLevel,
|
|
|
|
/// Number of orders at this price (MBO only)
|
|
pub order_count: Option<u32>,
|
|
}
|
|
|
|
/// Type alias for backward compatibility during transition
|
|
#[deprecated(note = "Use PriceLevelExt for extended functionality or common::types::PriceLevel for core data")]
|
|
pub type PriceLevel = PriceLevelExt;
|
|
|
|
/// Change to a price level
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct PriceLevelChange {
|
|
/// Price level being modified
|
|
pub price: Decimal,
|
|
|
|
/// New size (0 = remove level)
|
|
pub size: Decimal,
|
|
|
|
/// Type of change
|
|
pub change_type: PriceLevelChangeType,
|
|
|
|
/// Side (bid or ask)
|
|
pub side: OrderBookSide,
|
|
}
|
|
|
|
/// Type of price level change
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum PriceLevelChangeType {
|
|
/// Add new price level
|
|
Add,
|
|
/// Update existing price level
|
|
Update,
|
|
/// Remove price level
|
|
Delete,
|
|
}
|
|
|
|
/// Order book side
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum OrderBookSide {
|
|
/// Bid side (buy orders)
|
|
Bid,
|
|
/// Ask side (sell orders)
|
|
Ask,
|
|
}
|
|
|
|
/// Bar event structure (alias for AggregateEvent but with different field names)
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct BarEvent {
|
|
/// Symbol
|
|
pub symbol: Symbol,
|
|
|
|
/// Open price
|
|
pub open: Decimal,
|
|
|
|
/// High price
|
|
pub high: Decimal,
|
|
|
|
/// Low price
|
|
pub low: Decimal,
|
|
|
|
/// Close price
|
|
pub close: Decimal,
|
|
|
|
/// Volume
|
|
pub volume: Volume,
|
|
|
|
/// Timestamp
|
|
pub timestamp: DateTime<Utc>,
|
|
|
|
/// Sequence number
|
|
pub sequence: Option<u64>,
|
|
}
|
|
|
|
/// OHLCV aggregate event from Databento
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AggregateEvent {
|
|
/// Symbol
|
|
pub symbol: Symbol,
|
|
|
|
/// Open price
|
|
pub open: Decimal,
|
|
|
|
/// High price
|
|
pub high: Decimal,
|
|
|
|
/// Low price
|
|
pub low: Decimal,
|
|
|
|
/// Close price
|
|
pub close: Decimal,
|
|
|
|
/// Volume
|
|
pub volume: Volume,
|
|
|
|
/// Volume weighted average price
|
|
pub vwap: Option<Decimal>,
|
|
|
|
/// Number of trades
|
|
pub trade_count: Option<u32>,
|
|
|
|
/// Start timestamp of the bar
|
|
pub start_timestamp: DateTime<Utc>,
|
|
|
|
/// End timestamp of the bar
|
|
pub end_timestamp: DateTime<Utc>,
|
|
}
|
|
|
|
// === BENZINGA EVENT STRUCTURES ===
|
|
|
|
/// News alert event from Benzinga Pro
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct NewsEvent {
|
|
/// Unique news story ID
|
|
pub story_id: String,
|
|
|
|
/// Headline text
|
|
pub headline: String,
|
|
|
|
/// Full story text (may be truncated)
|
|
pub summary: Option<String>,
|
|
|
|
/// Symbols mentioned in the story
|
|
pub symbols: Vec<Symbol>,
|
|
|
|
/// News category (earnings, merger, FDA approval, etc.)
|
|
pub category: String,
|
|
|
|
/// News tags for classification
|
|
pub tags: Vec<String>,
|
|
|
|
/// Impact score (-1.0 to 1.0, where -1 = very bearish, 1 = very bullish)
|
|
pub impact_score: Option<f64>,
|
|
|
|
/// Author/source of the news
|
|
pub author: Option<String>,
|
|
|
|
/// News source (Reuters, Bloomberg, etc.)
|
|
pub source: String,
|
|
|
|
/// Publication timestamp
|
|
pub published_at: DateTime<Utc>,
|
|
|
|
/// When we received/processed the news
|
|
pub timestamp: DateTime<Utc>,
|
|
|
|
/// URL to full article
|
|
pub url: Option<String>,
|
|
}
|
|
|
|
/// Sentiment analysis event from Benzinga Pro
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct SentimentEvent {
|
|
/// Symbol
|
|
pub symbol: Symbol,
|
|
|
|
/// Overall sentiment score (-1.0 to 1.0)
|
|
pub sentiment_score: f64,
|
|
|
|
/// Bullish sentiment ratio (0.0 to 1.0)
|
|
pub bullish_ratio: f64,
|
|
|
|
/// Bearish sentiment ratio (0.0 to 1.0)
|
|
pub bearish_ratio: f64,
|
|
|
|
/// Sample size for sentiment calculation
|
|
pub sample_size: u32,
|
|
|
|
/// Time period for sentiment calculation
|
|
pub period: SentimentPeriod,
|
|
|
|
/// Data sources contributing to sentiment
|
|
pub sources: Vec<String>,
|
|
|
|
/// Confidence in the sentiment score (0.0 to 1.0)
|
|
pub confidence: Option<f64>,
|
|
|
|
/// Timestamp of sentiment calculation
|
|
pub timestamp: DateTime<Utc>,
|
|
}
|
|
|
|
/// Time period for sentiment analysis
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum SentimentPeriod {
|
|
/// Real-time (last few minutes)
|
|
RealTime,
|
|
/// Last hour
|
|
Hourly,
|
|
/// Last 24 hours
|
|
Daily,
|
|
/// Last week
|
|
Weekly,
|
|
}
|
|
|
|
/// Analyst rating event from Benzinga Pro
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AnalystRatingEvent {
|
|
/// Symbol being rated
|
|
pub symbol: Symbol,
|
|
|
|
/// Analyst or firm name
|
|
pub analyst: String,
|
|
|
|
/// Investment firm
|
|
pub firm: String,
|
|
|
|
/// Rating action (upgrade, downgrade, initiate, maintain)
|
|
pub action: RatingAction,
|
|
|
|
/// Current rating (Buy, Hold, Sell, etc.)
|
|
pub current_rating: String,
|
|
|
|
/// Previous rating (if upgrade/downgrade)
|
|
pub previous_rating: Option<String>,
|
|
|
|
/// Price target
|
|
pub price_target: Option<Decimal>,
|
|
|
|
/// Previous price target
|
|
pub previous_price_target: Option<Decimal>,
|
|
|
|
/// Rating reason/comment
|
|
pub comment: Option<String>,
|
|
|
|
/// When the rating was issued
|
|
pub rating_date: DateTime<Utc>,
|
|
|
|
/// When we received the rating
|
|
pub timestamp: DateTime<Utc>,
|
|
}
|
|
|
|
/// Type of rating action
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum RatingAction {
|
|
/// New coverage initiated
|
|
Initiate,
|
|
/// Rating upgraded
|
|
Upgrade,
|
|
/// Rating downgraded
|
|
Downgrade,
|
|
/// Rating maintained
|
|
Maintain,
|
|
/// Coverage discontinued
|
|
Discontinue,
|
|
}
|
|
|
|
impl std::fmt::Display for RatingAction {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
RatingAction::Initiate => write!(f, "Initiate"),
|
|
RatingAction::Upgrade => write!(f, "Upgrade"),
|
|
RatingAction::Downgrade => write!(f, "Downgrade"),
|
|
RatingAction::Maintain => write!(f, "Maintain"),
|
|
RatingAction::Discontinue => write!(f, "Discontinue"),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Unusual options activity event from Benzinga Pro
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct UnusualOptionsEvent {
|
|
/// Underlying symbol
|
|
pub symbol: Symbol,
|
|
|
|
/// Options contract details
|
|
pub contract: OptionsContract,
|
|
|
|
/// Type of unusual activity detected
|
|
pub activity_type: UnusualOptionsType,
|
|
|
|
/// Trade volume
|
|
pub volume: u32,
|
|
|
|
/// Open interest
|
|
pub open_interest: Option<u32>,
|
|
|
|
/// Premium/cost of the trade
|
|
pub premium: Option<Decimal>,
|
|
|
|
/// Implied volatility
|
|
pub implied_volatility: Option<f64>,
|
|
|
|
/// Sentiment inferred from the trade (bullish/bearish)
|
|
pub sentiment: OptionsSentiment,
|
|
|
|
/// Confidence in the signal (0.0 to 1.0)
|
|
pub confidence: f64,
|
|
|
|
/// Description of the unusual activity
|
|
pub description: String,
|
|
|
|
/// When the activity was detected
|
|
pub timestamp: DateTime<Utc>,
|
|
}
|
|
|
|
/// Options contract specification
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct OptionsContract {
|
|
/// Strike price
|
|
pub strike: Decimal,
|
|
|
|
/// Expiration date
|
|
pub expiration: chrono::NaiveDate,
|
|
|
|
/// Option type (call or put)
|
|
pub option_type: OptionsType,
|
|
|
|
/// Contract multiplier (usually 100 for equity options)
|
|
pub multiplier: u32,
|
|
}
|
|
|
|
/// Option type
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum OptionsType {
|
|
/// Call option
|
|
Call,
|
|
/// Put option
|
|
Put,
|
|
}
|
|
|
|
/// Type of unusual options activity
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum UnusualOptionsType {
|
|
/// Large block trade
|
|
BlockTrade,
|
|
/// Sweep order (aggressive buying/selling)
|
|
Sweep,
|
|
/// Unusual volume spike
|
|
VolumeSpike,
|
|
/// High open interest
|
|
OpenInterestSpike,
|
|
/// Unusual implied volatility
|
|
VolatilitySpike,
|
|
}
|
|
|
|
/// Options sentiment
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum OptionsSentiment {
|
|
/// Bullish positioning
|
|
Bullish,
|
|
/// Bearish positioning
|
|
Bearish,
|
|
/// Neutral/unclear
|
|
Neutral,
|
|
}
|
|
|
|
// === SYSTEM EVENT STRUCTURES ===
|
|
|
|
/// Connection status event
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ConnectionStatusEvent {
|
|
/// Provider name
|
|
pub provider: String,
|
|
|
|
/// Connection state
|
|
pub status: ConnectionState,
|
|
|
|
/// Optional status message
|
|
pub message: Option<String>,
|
|
|
|
/// Timestamp
|
|
pub timestamp: DateTime<Utc>,
|
|
}
|
|
|
|
/// Connection state
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum ConnectionState {
|
|
Connected,
|
|
Disconnected,
|
|
Reconnecting,
|
|
Failed,
|
|
}
|
|
|
|
/// Error event
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ErrorEvent {
|
|
/// Provider name
|
|
pub provider: String,
|
|
|
|
/// Error message
|
|
pub message: String,
|
|
|
|
/// Error code (provider-specific)
|
|
pub code: Option<String>,
|
|
|
|
/// Error category
|
|
pub category: ErrorCategory,
|
|
|
|
/// Whether the error is recoverable
|
|
pub recoverable: bool,
|
|
|
|
/// Timestamp
|
|
pub timestamp: DateTime<Utc>,
|
|
}
|
|
|
|
// ErrorCategory is now imported from common::error
|
|
|
|
/// Market status event
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct MarketStatusEvent {
|
|
/// Market identifier
|
|
pub market: String,
|
|
|
|
/// Current status
|
|
pub status: MarketState,
|
|
|
|
/// Next market open time
|
|
pub next_open: Option<DateTime<Utc>>,
|
|
|
|
/// Next market close time
|
|
pub next_close: Option<DateTime<Utc>>,
|
|
|
|
/// Extended hours trading available
|
|
pub extended_hours: bool,
|
|
|
|
/// Timestamp
|
|
pub timestamp: DateTime<Utc>,
|
|
}
|
|
|
|
/// Market state
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
pub enum MarketState {
|
|
/// Market is open for regular trading
|
|
Open,
|
|
/// Market is closed
|
|
Closed,
|
|
/// Pre-market trading hours
|
|
PreMarket,
|
|
/// After-market trading hours
|
|
AfterMarket,
|
|
/// Market holiday
|
|
Holiday,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use chrono::Utc;
|
|
use rust_decimal_macros::dec;
|
|
|
|
#[test]
|
|
fn test_order_book_snapshot() {
|
|
let snapshot = OrderBookSnapshot {
|
|
symbol: Symbol::from("SPY"),
|
|
bids: vec![
|
|
PriceLevel {
|
|
price: dec!(400.49),
|
|
size: dec!(100),
|
|
order_count: Some(5),
|
|
},
|
|
PriceLevel {
|
|
price: dec!(400.48),
|
|
size: dec!(200),
|
|
order_count: Some(3),
|
|
},
|
|
],
|
|
asks: vec![
|
|
PriceLevel {
|
|
price: dec!(400.50),
|
|
size: dec!(150),
|
|
order_count: Some(2),
|
|
},
|
|
PriceLevel {
|
|
price: dec!(400.51),
|
|
size: dec!(300),
|
|
order_count: Some(7),
|
|
},
|
|
],
|
|
exchange: "NYSE".to_string(),
|
|
timestamp: Utc::now(),
|
|
sequence: 1500,
|
|
};
|
|
|
|
assert_eq!(snapshot.symbol, Symbol::from("SPY"));
|
|
assert_eq!(snapshot.bids.len(), 2);
|
|
assert_eq!(snapshot.asks.len(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_news_event() {
|
|
let news = NewsEvent {
|
|
story_id: "news123".to_string(),
|
|
headline: "Company XYZ beats earnings".to_string(),
|
|
summary: None,
|
|
symbols: vec![Symbol::from("XYZ")],
|
|
category: "earnings".to_string(),
|
|
tags: vec!["earnings".to_string()],
|
|
impact_score: Some(0.75),
|
|
author: Some("Analyst Name".to_string()),
|
|
source: "Reuters".to_string(),
|
|
published_at: Utc::now(),
|
|
timestamp: Utc::now(),
|
|
url: None,
|
|
};
|
|
|
|
assert_eq!(news.symbols.first(), Some(&Symbol::from("XYZ")));
|
|
assert_eq!(news.category, "earnings");
|
|
}
|
|
|
|
#[test]
|
|
fn test_sentiment_event() {
|
|
let sentiment = SentimentEvent {
|
|
symbol: Symbol::from("TSLA"),
|
|
sentiment_score: 0.65,
|
|
bullish_ratio: 0.75,
|
|
bearish_ratio: 0.25,
|
|
sample_size: 1000,
|
|
period: SentimentPeriod::Hourly,
|
|
sources: vec!["twitter".to_string(), "reddit".to_string()],
|
|
confidence: Some(0.85),
|
|
timestamp: Utc::now(),
|
|
};
|
|
|
|
assert_eq!(sentiment.symbol, Symbol::from("TSLA"));
|
|
assert_eq!(sentiment.sentiment_score, 0.65);
|
|
}
|
|
|
|
#[test]
|
|
fn test_unusual_options_event() {
|
|
let options = UnusualOptionsEvent {
|
|
symbol: Symbol::from("AAPL"),
|
|
contract: OptionsContract {
|
|
strike: dec!(160.00),
|
|
expiration: chrono::NaiveDate::from_ymd_opt(2024, 1, 19).unwrap(),
|
|
option_type: OptionsType::Call,
|
|
multiplier: 100,
|
|
},
|
|
activity_type: UnusualOptionsType::Sweep,
|
|
volume: 5000,
|
|
open_interest: Some(10000),
|
|
premium: Some(dec!(250000)),
|
|
implied_volatility: Some(0.35),
|
|
sentiment: OptionsSentiment::Bullish,
|
|
confidence: 0.85,
|
|
description: "Large call sweep near market".to_string(),
|
|
timestamp: Utc::now(),
|
|
};
|
|
|
|
assert_eq!(options.symbol, Symbol::from("AAPL"));
|
|
assert_eq!(options.activity_type, UnusualOptionsType::Sweep);
|
|
}
|
|
} |