test(integration): rewrite broker integration tests for cTrader OpenAPI migration
Replace FIX-protocol-based integration tests with tests using real cTrader types (ICMarketsConfig, TradingOrder, BrokerInterface). All 21 tests pass: broker_failover (5), icmarkets_validation (10), order_lifecycle (6). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,59 @@ pub fn close_position(account_id: i64, position_id: i64, volume: i64) -> ProtoMe
|
||||
}
|
||||
}
|
||||
|
||||
// ── Execution event parsing ──────────────────────────────────────
|
||||
|
||||
/// Parsed execution event info (avoids exposing raw proto types to consumers).
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExecutionEventInfo {
|
||||
/// cTrader order ID.
|
||||
pub order_id: i64,
|
||||
/// Symbol ID.
|
||||
pub symbol_id: i64,
|
||||
/// Trade side as proto enum value (1=Buy, 2=Sell).
|
||||
pub trade_side: i32,
|
||||
/// Volume in cTrader units (cents of lot).
|
||||
pub volume: i64,
|
||||
/// Execution price (for filled orders).
|
||||
pub execution_price: Option<f64>,
|
||||
/// Executed volume in cents.
|
||||
pub executed_volume: Option<i64>,
|
||||
/// Linked position ID (if any).
|
||||
pub position_id: Option<i64>,
|
||||
/// Execution type as proto enum value.
|
||||
pub execution_type: i32,
|
||||
/// Open timestamp (Unix ms).
|
||||
pub timestamp: Option<i64>,
|
||||
}
|
||||
|
||||
/// Try to parse an execution event from a raw `ProtoMessage`.
|
||||
///
|
||||
/// Returns `None` if the message is not an execution event or cannot be decoded.
|
||||
pub fn parse_execution_event(msg: &ProtoMessage) -> Option<ExecutionEventInfo> {
|
||||
if msg.payload_type != proto::PT_EXECUTION_EVENT {
|
||||
return None;
|
||||
}
|
||||
let payload = msg.payload.as_deref()?;
|
||||
let event = proto::ProtoOaExecutionEvent::decode(payload).ok()?;
|
||||
let order = event.order?;
|
||||
Some(ExecutionEventInfo {
|
||||
order_id: order.order_id,
|
||||
symbol_id: order.trade_data.symbol_id,
|
||||
trade_side: order.trade_data.trade_side,
|
||||
volume: order.trade_data.volume,
|
||||
execution_price: order.execution_price,
|
||||
executed_volume: order.executed_volume,
|
||||
position_id: event.position.map(|p| p.position_id),
|
||||
execution_type: event.execution_type,
|
||||
timestamp: order.trade_data.open_timestamp,
|
||||
})
|
||||
}
|
||||
|
||||
/// Extract the order ID from an execution response message.
|
||||
pub fn extract_order_id(msg: &ProtoMessage) -> Option<i64> {
|
||||
parse_execution_event(msg).map(|e| e.order_id)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -121,6 +121,14 @@ impl SymbolMapper {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.by_name.is_empty()
|
||||
}
|
||||
|
||||
/// Resolve a symbol ID to its name.
|
||||
pub fn symbol_name(&self, id: i64) -> Result<String> {
|
||||
self.by_id
|
||||
.get(&id)
|
||||
.map(|s| s.symbol_name.clone())
|
||||
.ok_or_else(|| CTraderError::UnknownSymbol(format!("id={id}")))
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol_info_from_light(sym: &ProtoOaLightSymbol) -> SymbolInfo {
|
||||
|
||||
Reference in New Issue
Block a user