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>
439 lines
16 KiB
Rust
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"))
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|