Files
foxhunt/crates/data/src/brokers/mod.rs
jgrusewski 9c3d741a08 refactor: restructure repo — crates/, bin/, testing/ layout
Move 17 library crates into crates/, CLI binary into bin/fxt,
consolidate 10 test crates into testing/, split config crate
from deployment config files.

Root directory reduced from 38+ to ~17 directories.
All Cargo.toml paths and build.rs proto refs updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:56:00 +01:00

439 lines
16 KiB
Rust

//! # Broker Integration Module
//!
//! High-performance broker integration for trading and market data connectivity.
//! Provides adapters and clients for connecting to various trading platforms
//! using their native protocols including FIX, REST APIs, and WebSocket connections.
//!
//! ## Architecture
//!
//! The broker integration follows a modular design with standardized interfaces:
//!
//! ```text
//! ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
//! │ Application │────│ Broker Factory │────│ Protocol Layer │
//! │ Trading Logic │ │ & Adapters │ │ (FIX/REST/WS) │
//! └─────────────────┘ └─────────────────┘ └─────────────────┘
//! │ │ │
//! ▼ ▼ ▼
//! ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
//! │ Order Flow │ │ Data Adapter │ │ Connection │
//! │ Management │ │ Layer │ │ Management │
//! └─────────────────┘ └─────────────────┘ └─────────────────┘
//! ```
//!
//! ## Supported Brokers
//!
//! ### Interactive Brokers (TWS API)
//! - **Protocol**: TWS API over TCP socket
//! - **Features**: Real-time data, order management, account info
//! - **Markets**: Global equities, futures, forex, options
//! - **Latency**: Medium (~10-50ms)
//!
//! ### ICMarkets (FIX 4.4)
//! - **Protocol**: Financial Information eXchange (FIX) 4.4
//! - **Features**: High-frequency trading, ECN access
//! - **Markets**: Forex, CFDs, commodities
//! - **Latency**: Low (~1-5ms)
//!
//! ### Future Integrations
//! - **Alpaca**: Commission-free equity trading
//! - **TD Ameritrade**: Retail trading platform
//! - **IBKR Pro**: Enhanced Interactive Brokers
//!
//! ## Design Patterns
//!
//! ### Adapter Pattern
//! Each broker has a specific adapter that translates between the broker's
//! native protocol and our standardized internal interfaces.
//!
//! ### Factory Pattern
//! The `BrokerFactory` creates appropriate client instances based on
//! configuration, enabling runtime broker selection.
//!
//! ### Strategy Pattern
//! Different connection strategies (persistent, reconnecting, etc.) can be
//! plugged in based on requirements.
//!
//! ## Usage Examples
//!
//! ```rust
//! use data::brokers::{BrokerFactory, BrokerType, InteractiveBrokersAdapter, IBConfig};
//!
//! // Direct adapter usage
//! let ib_config = IBConfig {
//! host: "127.0.0.1".to_string(),
//! port: 7497,
//! client_id: 1,
//! // ... other config
//! };
//! let mut ib_adapter = InteractiveBrokersAdapter::new(ib_config);
//! ib_adapter.connect().await?;
//!
//! // Factory-based creation (future)
//! // let client = BrokerFactory::create_client(
//! // BrokerType::InteractiveBrokers,
//! // serde_json::to_value(ib_config)?
//! // ).await?;
//! ```
//!
//! ## Configuration
//!
//! Broker configurations are managed through the central config system:
//!
//! ```toml
//! [data.interactive_brokers]
//! host = "127.0.0.1"
//! port = 7497
//! client_id = 1
//! timeout_seconds = 30
//!
//! [data.icmarkets]
//! host = "fix-demo.icmarkets.com"
//! port = 9880
//! username = "${ICMARKETS_USERNAME}"
//! password = "${ICMARKETS_PASSWORD}"
//! ```
//!
//! ## Error Handling
//!
//! All broker operations return `Result<T, DataError>` for consistent error
//! handling across different broker implementations.
//!
//! ## Performance Considerations
//!
//! - **Connection Pooling**: Reuse connections where possible
//! - **Async Operations**: All I/O is non-blocking
//! - **Batching**: Group related operations to reduce latency
//! - **Circuit Breakers**: Automatic failover and recovery
//!
//! ## Architecture Note
//!
//! Core trading clients have been moved to the `core` module for the monolithic
//! architecture. This module now focuses on data-specific broker adapters and
//! connection management.
pub mod common;
pub mod interactive_brokers;
// Re-export commonly used types for convenient access
// Note: Using direct imports from common crate instead of broker-specific types
/// Re-export Interactive Brokers adapter and configuration
pub use interactive_brokers::{IBConfig, InteractiveBrokersAdapter};
/// Re-export common broker client trait
pub use common::BrokerClient;
// Create alias for BrokerAdapter (used in examples)
// TODO: Re-enable when BrokerClient trait is implemented
// /// Type alias for boxed broker client trait objects
// ///
// /// Provides a convenient way to work with different broker implementations
// /// through a common interface without knowing the specific type at compile time.
// pub type BrokerAdapter = Box<dyn BrokerClient>;
/// Enumeration of supported broker types and their protocols.
///
/// Each variant represents a different broker platform with its own
/// connectivity requirements, protocols, and capabilities.
///
/// # Protocol Details
///
/// - **ICMarkets**: `FIX` 4.4 protocol for institutional-grade trading
/// - **InteractiveBrokers**: TWS API for retail and professional trading
/// - **Alpaca**: REST API for commission-free equity trading
/// - **Mock**: In-memory broker simulation for testing
///
/// # Selection Criteria
///
/// Choose broker based on:
/// - **Latency Requirements**: ICMarkets for HFT, others for regular trading
/// - **Market Access**: Geographic and asset class coverage
/// - **Cost Structure**: Commission rates and minimum account sizes
/// - **API Capabilities**: Order types, data feeds, and functionality
///
/// # Examples
///
/// ```rust
/// use data::brokers::BrokerType;
///
/// // Select broker based on trading style
/// let hft_broker = BrokerType::ICMarkets; // High-frequency trading
/// let retail_broker = BrokerType::InteractiveBrokers; // Retail trading
/// let test_broker = BrokerType::Mock; // Development/testing
/// ```
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum BrokerType {
/// ICMarkets `FIX` 4.4 protocol integration
///
/// Professional ECN broker with direct market access via `FIX` protocol.
/// Optimized for high-frequency trading with sub-millisecond latency.
/// Supports forex, CFDs, and commodities trading.
ICMarkets,
/// Interactive Brokers TWS API integration
///
/// Comprehensive trading platform with global market access.
/// Uses proprietary TWS API for orders, data, and account management.
/// Supports equities, options, futures, forex, and bonds.
InteractiveBrokers,
/// Alpaca REST API integration (future)
///
/// Commission-free stock trading platform with modern REST API.
/// Designed for algorithmic trading with paper trading support.
/// US equities and crypto trading.
Alpaca,
/// Mock broker for testing and simulation
///
/// In-memory broker simulator for development and backtesting.
/// Provides realistic order fills and market data simulation
/// without real money or external connections.
Mock,
}
/// Factory for creating broker client instances.
///
/// Provides a centralized way to instantiate broker clients based on
/// configuration and broker type. Handles the complexity of different
/// broker initialization requirements and provides a uniform interface.
///
/// # Design Benefits
///
/// - **Abstraction**: Hide broker-specific initialization details
/// - **Configuration**: Centralized config-driven client creation
/// - **Extensibility**: Easy addition of new broker types
/// - **Testing**: Simplified mock broker injection
///
/// # Future Implementation
///
/// The factory will support dynamic broker client creation once the
/// `BrokerClient` trait is fully implemented across all broker types.
///
/// # Examples
///
/// ```rust
/// use data::brokers::{BrokerFactory, BrokerType};
/// use serde_json::json;
///
/// // Future usage (when trait is implemented)
/// // let config = json!({
/// // "host": "127.0.0.1",
/// // "port": 7497,
/// // "client_id": 1
/// // });
/// //
/// // let client = BrokerFactory::create_client(
/// // BrokerType::InteractiveBrokers,
/// // config
/// // ).await?;
/// ```
pub struct BrokerFactory;
impl BrokerFactory {
/// Validate broker configuration for the specified broker type.
///
/// Checks that the provided configuration contains all required fields
/// for the specified broker type before attempting to create a client.
///
/// # Parameters
///
/// * `broker_type` - The type of broker to validate configuration for
/// * `config` - JSON configuration object to validate
///
/// # Returns
///
/// `Ok(())` if configuration is valid, `Err(String)` with details if invalid.
///
/// # Examples
///
/// ```rust
/// use data::brokers::{BrokerFactory, BrokerType};
/// use serde_json::json;
///
/// let config = json!({
/// "host": "127.0.0.1",
/// "port": 7497,
/// "client_id": 1
/// });
///
/// let result = BrokerFactory::validate_config(
/// &BrokerType::InteractiveBrokers,
/// &config
/// );
/// assert!(result.is_ok());
/// ```
pub fn validate_config(
broker_type: &BrokerType,
config: &serde_json::Value,
) -> Result<(), String> {
match broker_type {
BrokerType::ICMarkets => {
let required_fields = ["host", "port", "username", "password"];
for field in &required_fields {
if config.get(field).is_none() {
return Err(format!("Missing required field '{}' for ICMarkets", field));
}
}
Ok(())
},
BrokerType::InteractiveBrokers => {
let required_fields = ["host", "port", "client_id"];
for field in &required_fields {
if config.get(field).is_none() {
return Err(format!(
"Missing required field '{}' for Interactive Brokers",
field
));
}
}
Ok(())
},
BrokerType::Alpaca => {
let required_fields = ["api_key", "secret_key", "base_url"];
for field in &required_fields {
if config.get(field).is_none() {
return Err(format!("Missing required field '{}' for Alpaca", field));
}
}
Ok(())
},
BrokerType::Mock => {
// Mock broker requires minimal configuration
Ok(())
},
}
}
/// Get the default configuration template for a broker type.
///
/// Returns a JSON template with all required and optional fields
/// for the specified broker type, with example or default values.
///
/// # Parameters
///
/// * `broker_type` - The broker type to get template for
///
/// # Returns
///
/// JSON object with configuration template.
///
/// # Examples
///
/// ```rust
/// use data::brokers::{BrokerFactory, BrokerType};
///
/// let template = BrokerFactory::get_config_template(&BrokerType::InteractiveBrokers);
/// println!("IB Config Template: {}", serde_json::to_string_pretty(&template).unwrap());
/// ```
pub fn get_config_template(broker_type: &BrokerType) -> serde_json::Value {
match broker_type {
BrokerType::ICMarkets => serde_json::json!({
"host": "fix-demo.icmarkets.com",
"port": 9880,
"username": "${ICMARKETS_USERNAME}",
"password": "${ICMARKETS_PASSWORD}",
"sender_comp_id": "CLIENT",
"target_comp_id": "ICMARKETS",
"heartbeat_interval": 30,
"timeout_seconds": 30
}),
BrokerType::InteractiveBrokers => serde_json::json!({
"host": "127.0.0.1",
"port": 7497,
"client_id": 1,
"account_id": "DU123456",
"timeout_seconds": 30,
"heartbeat_interval": 30,
"max_reconnect_attempts": 5,
"request_timeout": 30
}),
BrokerType::Alpaca => serde_json::json!({
"api_key": "${ALPACA_API_KEY}",
"secret_key": "${ALPACA_SECRET_KEY}",
"base_url": "https://paper-api.alpaca.markets",
"data_url": "https://data.alpaca.markets",
"timeout_seconds": 30
}),
BrokerType::Mock => serde_json::json!({
"initial_balance": 100000.0,
"latency_ms": 10,
"fill_rate": 0.99
}),
}
}
// TODO: Uncomment when BrokerClient trait is restored
/*
/// Create a broker client based on configuration.
///
/// Instantiates the appropriate broker client implementation based on
/// the broker type and configuration provided. Validates configuration
/// before attempting to create the client.
///
/// # Parameters
///
/// * `broker_type` - Type of broker client to create
/// * `config` - JSON configuration object with broker-specific settings
///
/// # Returns
///
/// Boxed broker client implementing the `BrokerClient` trait.
///
/// # Errors
///
/// Returns `DataError` if:
/// - Configuration is invalid or missing required fields
/// - Broker type is not yet implemented
/// - Client initialization fails
///
/// # Examples
///
/// ```rust
/// use data::brokers::{BrokerFactory, BrokerType};
/// use serde_json::json;
///
/// let config = json!({
/// "host": "127.0.0.1",
/// "port": 7497,
/// "client_id": 1
/// });
///
/// let client = BrokerFactory::create_client(
/// BrokerType::InteractiveBrokers,
/// config
/// ).await?;
/// ```
pub async fn create_client(
broker_type: BrokerType,
config: serde_json::Value
) -> crate::Result<Box<dyn BrokerClient>> {
// Validate configuration first
Self::validate_config(&broker_type, &config)
.map_err(|e| crate::DataError::configuration(&e))?;
match broker_type {
BrokerType::ICMarkets => {
let icmarkets_config: ICMarketsConfig = serde_json::from_value(config)
.map_err(|e| crate::DataError::configuration(&format!("Invalid ICMarkets config: {}", e)))?;
let client = ICMarketsClient::new(icmarkets_config);
Ok(Box::new(client))
}
BrokerType::InteractiveBrokers => {
let ib_config: IBConfig = serde_json::from_value(config)
.map_err(|e| crate::DataError::configuration(&format!("Invalid IB config: {}", e)))?;
let client = InteractiveBrokersAdapter::new(ib_config);
Ok(Box::new(client))
}
BrokerType::Alpaca => {
Err(crate::DataError::configuration("Alpaca broker not yet implemented"))
}
BrokerType::Mock => {
Err(crate::DataError::configuration("Mock broker not yet implemented"))
}
}
}
*/
}