1413 lines
50 KiB
Markdown
1413 lines
50 KiB
Markdown
# Iceberg Order Algorithm Implementation Design
|
|
|
|
## Overview
|
|
|
|
This document details the implementation of the Iceberg order algorithm in the Order Management System (OMS), which executes large orders by only displaying a small portion of the total order size at any given time to minimize market impact and reduce information leakage.
|
|
|
|
## Iceberg Algorithm Fundamentals
|
|
|
|
### Algorithm Description
|
|
The Iceberg algorithm hides large order sizes by only displaying a small, visible portion of the total order quantity. As each displayed portion is filled, a new portion is revealed until the entire order is executed. This approach minimizes market impact by preventing other market participants from seeing the true size of the order.
|
|
|
|
### Key Characteristics
|
|
1. **Size Concealment**: Hides large order sizes from the market
|
|
2. **Sequential Execution**: Executes orders in small, visible portions
|
|
3. **Market Impact Reduction**: Reduces information leakage and adverse price movements
|
|
4. **Continuous Replenishment**: Automatically replenishes visible quantity as portions are filled
|
|
|
|
## Iceberg Parameters
|
|
|
|
### Core Parameters
|
|
```csharp
|
|
/// <summary>
|
|
/// Parameters for Iceberg algorithm execution
|
|
/// </summary>
|
|
public record IcebergParameters
|
|
{
|
|
/// <summary>
|
|
/// Trading symbol
|
|
/// </summary>
|
|
public string Symbol { get; set; }
|
|
|
|
/// <summary>
|
|
/// Order side (Buy/Sell)
|
|
/// </summary>
|
|
public OrderSide Side { get; set; }
|
|
|
|
/// <summary>
|
|
/// Total quantity to execute
|
|
/// </summary>
|
|
public int TotalQuantity { get; set; }
|
|
|
|
/// <summary>
|
|
/// Visible quantity (displayed to market)
|
|
/// </summary>
|
|
public int VisibleQuantity { get; set; }
|
|
|
|
/// <summary>
|
|
/// Optional limit price for limit orders
|
|
/// </summary>
|
|
public decimal? LimitPrice { get; set; }
|
|
|
|
/// <summary>
|
|
/// Time in force for orders
|
|
/// </summary>
|
|
public TimeInForce TimeInForce { get; set; } = TimeInForce.Day;
|
|
|
|
/// <summary>
|
|
/// Whether to automatically replenish visible quantity
|
|
/// </summary>
|
|
public bool AutoReplenish { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Minimum visible quantity (to avoid very small orders)
|
|
/// </summary>
|
|
public int MinVisibleQuantity { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// Maximum visible quantity (to control individual order impact)
|
|
/// </summary>
|
|
public int? MaxVisibleQuantity { get; set; }
|
|
|
|
/// <summary>
|
|
/// Delay between order placements (in milliseconds)
|
|
/// </summary>
|
|
public int PlacementDelayMs { get; set; } = 1000;
|
|
|
|
/// <summary>
|
|
/// Whether to cancel remaining visible quantity at end
|
|
/// </summary>
|
|
public bool CancelAtEnd { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Aggressiveness factor (0.0 to 1.0) - higher values place orders more aggressively
|
|
/// </summary>
|
|
public double Aggressiveness { get; set; } = 0.5;
|
|
|
|
/// <summary>
|
|
/// Whether to adjust visible quantity based on market conditions
|
|
/// </summary>
|
|
public bool AdaptiveVisibility { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Custom metadata for the algorithm
|
|
/// </summary>
|
|
public Dictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>();
|
|
}
|
|
```
|
|
|
|
### Iceberg Configuration
|
|
```csharp
|
|
/// <summary>
|
|
/// Configuration for Iceberg algorithm behavior
|
|
/// </summary>
|
|
public record IcebergConfig
|
|
{
|
|
/// <summary>
|
|
/// Default visible quantity as percentage of total quantity
|
|
/// </summary>
|
|
public double DefaultVisiblePercentage { get; set; } = 0.1; // 10%
|
|
|
|
/// <summary>
|
|
/// Default placement delay (in milliseconds)
|
|
/// </summary>
|
|
public int DefaultPlacementDelayMs { get; set; } = 1000;
|
|
|
|
/// <summary>
|
|
/// Whether to enable adaptive visibility based on market conditions
|
|
/// </summary>
|
|
public bool EnableAdaptiveVisibility { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Maximum visible quantity as percentage of total quantity
|
|
/// </summary>
|
|
public double MaxVisiblePercentage { get; set; } = 0.25; // 25%
|
|
|
|
/// <summary>
|
|
/// Minimum visible quantity as percentage of total quantity
|
|
/// </summary>
|
|
public double MinVisiblePercentage { get; set; } = 0.01; // 1%
|
|
|
|
/// <summary>
|
|
/// Whether to prioritize execution speed over impact reduction
|
|
/// </summary>
|
|
public bool PrioritizeSpeed { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Retry count for failed order placements
|
|
/// </summary>
|
|
public int MaxRetries { get; set; } = 3;
|
|
|
|
/// <summary>
|
|
/// Delay between retries (in milliseconds)
|
|
/// </summary>
|
|
public int RetryDelayMs { get; set; } = 5000;
|
|
|
|
/// <summary>
|
|
/// Whether to use market depth analysis for visibility adjustment
|
|
/// </summary>
|
|
public bool EnableMarketDepthAnalysis { get; set; } = false;
|
|
|
|
/// <summary>
|
|
/// Whether to log detailed execution information
|
|
/// </summary>
|
|
public bool EnableDetailedLogging { get; set; } = false;
|
|
|
|
public static IcebergConfig Default => new IcebergConfig();
|
|
}
|
|
```
|
|
|
|
## Iceberg Execution Models
|
|
|
|
### Iceberg Execution State
|
|
```csharp
|
|
/// <summary>
|
|
/// State of an Iceberg execution
|
|
/// </summary>
|
|
public record IcebergExecutionState
|
|
{
|
|
/// <summary>
|
|
/// Unique identifier for this Iceberg execution
|
|
/// </summary>
|
|
public string ExecutionId { get; set; } = Guid.NewGuid().ToString();
|
|
|
|
/// <summary>
|
|
/// Parameters used for this execution
|
|
/// </summary>
|
|
public IcebergParameters Parameters { get; set; }
|
|
|
|
/// <summary>
|
|
/// Current execution status
|
|
/// </summary>
|
|
public IcebergExecutionStatus Status { get; set; } = IcebergExecutionStatus.Pending;
|
|
|
|
/// <summary>
|
|
/// Total quantity to execute
|
|
/// </summary>
|
|
public int TotalQuantity { get; set; }
|
|
|
|
/// <summary>
|
|
/// Quantity already executed
|
|
/// </summary>
|
|
public int ExecutedQuantity { get; set; }
|
|
|
|
/// <summary>
|
|
/// Remaining quantity to execute
|
|
/// </summary>
|
|
public int RemainingQuantity => TotalQuantity - ExecutedQuantity;
|
|
|
|
/// <summary>
|
|
/// Currently visible quantity
|
|
/// </summary>
|
|
public int VisibleQuantity { get; set; }
|
|
|
|
/// <summary>
|
|
/// Currently displayed order (if any)
|
|
/// </summary>
|
|
public IcebergOrder DisplayedOrder { get; set; }
|
|
|
|
/// <summary>
|
|
/// All orders placed during execution
|
|
/// </summary>
|
|
public List<IcebergOrder> Orders { get; set; } = new List<IcebergOrder>();
|
|
|
|
/// <summary>
|
|
/// Completed orders
|
|
/// </summary>
|
|
public List<IcebergOrder> CompletedOrders { get; set; } = new List<IcebergOrder>();
|
|
|
|
/// <summary>
|
|
/// Failed orders
|
|
/// </summary>
|
|
public List<IcebergOrder> FailedOrders { get; set; } = new List<IcebergOrder>();
|
|
|
|
/// <summary>
|
|
/// Start time of execution
|
|
/// </summary>
|
|
public DateTime? StartTime { get; set; }
|
|
|
|
/// <summary>
|
|
/// End time of execution
|
|
/// </summary>
|
|
public DateTime? EndTime { get; set; }
|
|
|
|
/// <summary>
|
|
/// When this execution was created
|
|
/// </summary>
|
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
|
|
/// <summary>
|
|
/// When this execution was last updated
|
|
/// </summary>
|
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
|
|
|
/// <summary>
|
|
/// Error information if execution failed
|
|
/// </summary>
|
|
public string ErrorMessage { get; set; }
|
|
|
|
/// <summary>
|
|
/// Performance metrics for this execution
|
|
/// </summary>
|
|
public IcebergPerformanceMetrics PerformanceMetrics { get; set; } = new IcebergPerformanceMetrics();
|
|
}
|
|
```
|
|
|
|
### Iceberg Order
|
|
```csharp
|
|
/// <summary>
|
|
/// Represents a single order placed as part of Iceberg execution
|
|
/// </summary>
|
|
public record IcebergOrder
|
|
{
|
|
/// <summary>
|
|
/// Unique identifier for this order
|
|
/// </summary>
|
|
public string OrderId { get; set; }
|
|
|
|
/// <summary>
|
|
/// Reference to parent Iceberg execution
|
|
/// </summary>
|
|
public string ExecutionId { get; set; }
|
|
|
|
/// <summary>
|
|
/// Order number within execution (1-based)
|
|
/// </summary>
|
|
public int OrderNumber { get; set; }
|
|
|
|
/// <summary>
|
|
/// Scheduled placement time
|
|
/// </summary>
|
|
public DateTime ScheduledTime { get; set; }
|
|
|
|
/// <summary>
|
|
/// Actual placement time
|
|
/// </summary>
|
|
public DateTime? ActualTime { get; set; }
|
|
|
|
/// <summary>
|
|
/// Quantity for this order
|
|
/// </summary>
|
|
public int Quantity { get; set; }
|
|
|
|
/// <summary>
|
|
/// Status of this order
|
|
/// </summary>
|
|
public IcebergOrderStatus Status { get; set; } = IcebergOrderStatus.Pending;
|
|
|
|
/// <summary>
|
|
/// Order details
|
|
/// </summary>
|
|
public OrderRequest OrderDetails { get; set; }
|
|
|
|
/// <summary>
|
|
/// Fills for this order
|
|
/// </summary>
|
|
public List<OrderFill> Fills { get; set; } = new List<OrderFill>();
|
|
|
|
/// <summary>
|
|
/// Total filled quantity
|
|
/// </summary>
|
|
public int FilledQuantity => Fills?.Sum(f => f.Quantity) ?? 0;
|
|
|
|
/// <summary>
|
|
/// Average fill price
|
|
/// </summary>
|
|
public decimal AverageFillPrice => Fills?.Any() == true ?
|
|
Fills.Sum(f => f.Quantity * f.FillPrice) / FilledQuantity : 0;
|
|
|
|
/// <summary>
|
|
/// Total commission for this order
|
|
/// </summary>
|
|
public decimal TotalCommission => Fills?.Sum(f => f.Commission) ?? 0;
|
|
|
|
/// <summary>
|
|
/// Error information if order failed
|
|
/// </summary>
|
|
public string ErrorMessage { get; set; }
|
|
|
|
/// <summary>
|
|
/// Retry count for this order
|
|
/// </summary>
|
|
public int RetryCount { get; set; }
|
|
|
|
/// <summary>
|
|
/// Whether this order was cancelled
|
|
/// </summary>
|
|
public bool WasCancelled { get; set; }
|
|
|
|
/// <summary>
|
|
/// When this order was created
|
|
/// </summary>
|
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
|
|
/// <summary>
|
|
/// When this order was last updated
|
|
/// </summary>
|
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
|
}
|
|
```
|
|
|
|
### Iceberg Performance Metrics
|
|
```csharp
|
|
/// <summary>
|
|
/// Performance metrics for Iceberg execution
|
|
/// </summary>
|
|
public record IcebergPerformanceMetrics
|
|
{
|
|
/// <summary>
|
|
/// Total execution time
|
|
/// </summary>
|
|
public TimeSpan TotalExecutionTime { get; set; }
|
|
|
|
/// <summary>
|
|
/// Average fill price
|
|
/// </summary>
|
|
public decimal AverageFillPrice { get; set; }
|
|
|
|
/// <summary>
|
|
/// Slippage (percentage)
|
|
/// </summary>
|
|
public decimal Slippage { get; set; }
|
|
|
|
/// <summary>
|
|
/// Implementation shortfall (percentage)
|
|
/// </summary>
|
|
public decimal ImplementationShortfall { get; set; }
|
|
|
|
/// <summary>
|
|
/// Number of order placements
|
|
/// </summary>
|
|
public int TotalOrders { get; set; }
|
|
|
|
/// <summary>
|
|
/// Number of successful orders
|
|
/// </summary>
|
|
public int SuccessfulOrders { get; set; }
|
|
|
|
/// <summary>
|
|
/// Number of failed orders
|
|
/// </summary>
|
|
public int FailedOrders { get; set; }
|
|
|
|
/// <summary>
|
|
/// Number of cancelled orders
|
|
/// </summary>
|
|
public int CancelledOrders { get; set; }
|
|
|
|
/// <summary>
|
|
/// Average visible quantity as percentage of total
|
|
/// </summary>
|
|
public decimal AverageVisibility { get; set; }
|
|
|
|
/// <summary>
|
|
/// Total commission paid
|
|
/// </summary>
|
|
public decimal TotalCommission { get; set; }
|
|
|
|
/// <summary>
|
|
/// When metrics were last updated
|
|
/// </summary>
|
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
|
}
|
|
```
|
|
|
|
### Enums
|
|
```csharp
|
|
/// <summary>
|
|
/// Status of Iceberg execution
|
|
/// </summary>
|
|
public enum IcebergExecutionStatus
|
|
{
|
|
Pending,
|
|
Running,
|
|
Completed,
|
|
Cancelled,
|
|
Failed
|
|
}
|
|
|
|
/// <summary>
|
|
/// Status of Iceberg order
|
|
/// </summary>
|
|
public enum IcebergOrderStatus
|
|
{
|
|
Pending,
|
|
Scheduled,
|
|
Submitted,
|
|
PartiallyFilled,
|
|
Filled,
|
|
Cancelled,
|
|
Failed
|
|
}
|
|
```
|
|
|
|
## Iceberg Algorithm Implementation
|
|
|
|
### Iceberg Executor
|
|
```csharp
|
|
/// <summary>
|
|
/// Executes Iceberg algorithms
|
|
/// </summary>
|
|
public class IcebergExecutor
|
|
{
|
|
private readonly ILogger<IcebergExecutor> _logger;
|
|
private readonly IOrderManager _orderManager;
|
|
private readonly IMarketDataProvider _marketDataProvider;
|
|
private readonly IcebergConfig _config;
|
|
private readonly Dictionary<string, IcebergExecutionState> _executions;
|
|
private readonly Dictionary<string, CancellationTokenSource> _executionCancellations;
|
|
private readonly object _lock = new object();
|
|
|
|
public IcebergExecutor(
|
|
ILogger<IcebergExecutor> logger,
|
|
IOrderManager orderManager,
|
|
IMarketDataProvider marketDataProvider,
|
|
IcebergConfig config = null)
|
|
{
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
_orderManager = orderManager ?? throw new ArgumentNullException(nameof(orderManager));
|
|
_marketDataProvider = marketDataProvider ?? throw new ArgumentNullException(nameof(marketDataProvider));
|
|
_config = config ?? IcebergConfig.Default;
|
|
_executions = new Dictionary<string, IcebergExecutionState>();
|
|
_executionCancellations = new Dictionary<string, CancellationTokenSource>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute an Iceberg order
|
|
/// </summary>
|
|
public async Task<IcebergExecutionState> ExecuteIcebergAsync(IcebergParameters parameters, StrategyContext context)
|
|
{
|
|
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
|
if (context == null) throw new ArgumentNullException(nameof(context));
|
|
|
|
// Validate parameters
|
|
ValidateParameters(parameters);
|
|
|
|
// Create execution state
|
|
var executionState = CreateExecutionState(parameters);
|
|
|
|
lock (_lock)
|
|
{
|
|
_executions[executionState.ExecutionId] = executionState;
|
|
}
|
|
|
|
_logger.LogInformation("Starting Iceberg execution {ExecutionId} for {Symbol} {Side} {Quantity} (visible: {VisibleQuantity})",
|
|
executionState.ExecutionId, parameters.Symbol, parameters.Side, parameters.TotalQuantity, parameters.VisibleQuantity);
|
|
|
|
try
|
|
{
|
|
// Start execution
|
|
await StartExecutionAsync(executionState, context);
|
|
|
|
return executionState;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error starting Iceberg execution {ExecutionId}", executionState.ExecutionId);
|
|
|
|
executionState.Status = IcebergExecutionStatus.Failed;
|
|
executionState.ErrorMessage = ex.Message;
|
|
executionState.UpdatedAt = DateTime.UtcNow;
|
|
|
|
throw;
|
|
}
|
|
|
|
private void ValidateParameters(IcebergParameters parameters)
|
|
{
|
|
if (string.IsNullOrEmpty(parameters.Symbol))
|
|
throw new ArgumentException("Symbol is required", nameof(parameters));
|
|
|
|
if (parameters.TotalQuantity <= 0)
|
|
throw new ArgumentException("Total quantity must be positive", nameof(parameters));
|
|
|
|
if (parameters.VisibleQuantity <= 0)
|
|
throw new ArgumentException("Visible quantity must be positive", nameof(parameters));
|
|
|
|
if (parameters.VisibleQuantity > parameters.TotalQuantity)
|
|
throw new ArgumentException("Visible quantity cannot exceed total quantity", nameof(parameters));
|
|
|
|
if (parameters.PlacementDelayMs < 0)
|
|
throw new ArgumentException("Placement delay must be non-negative", nameof(parameters));
|
|
}
|
|
|
|
private IcebergExecutionState CreateExecutionState(IcebergParameters parameters)
|
|
{
|
|
var executionState = new IcebergExecutionState
|
|
{
|
|
Parameters = parameters,
|
|
TotalQuantity = parameters.TotalQuantity,
|
|
VisibleQuantity = parameters.VisibleQuantity,
|
|
StartTime = DateTime.UtcNow
|
|
};
|
|
|
|
return executionState;
|
|
}
|
|
|
|
private async Task StartExecutionAsync(IcebergExecutionState executionState, StrategyContext context)
|
|
{
|
|
executionState.Status = IcebergExecutionStatus.Running;
|
|
executionState.StartTime = DateTime.UtcNow;
|
|
executionState.UpdatedAt = DateTime.UtcNow;
|
|
|
|
// Create cancellation token for this execution
|
|
var cancellationTokenSource = new CancellationTokenSource();
|
|
lock (_lock)
|
|
{
|
|
_executionCancellations[executionState.ExecutionId] = cancellationTokenSource;
|
|
}
|
|
|
|
// Start execution loop
|
|
_ = ExecuteIcebergLoopAsync(executionState, context, cancellationTokenSource.Token);
|
|
|
|
_logger.LogInformation("Iceberg execution {ExecutionId} started", executionState.ExecutionId);
|
|
}
|
|
|
|
private async Task ExecuteIcebergLoopAsync(IcebergExecutionState executionState, StrategyContext context, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
while (executionState.RemainingQuantity > 0 && !cancellationToken.IsCancellationRequested)
|
|
{
|
|
// Check if we should place a new order
|
|
if (executionState.DisplayedOrder == null ||
|
|
executionState.DisplayedOrder.Status == IcebergOrderStatus.Filled ||
|
|
executionState.DisplayedOrder.Status == IcebergOrderStatus.Cancelled ||
|
|
executionState.DisplayedOrder.Status == IcebergOrderStatus.Failed)
|
|
{
|
|
// Place new order
|
|
await PlaceNextOrderAsync(executionState, context);
|
|
}
|
|
else if (executionState.DisplayedOrder.Status == IcebergOrderStatus.Submitted ||
|
|
executionState.DisplayedOrder.Status == IcebergOrderStatus.PartiallyFilled)
|
|
{
|
|
// Monitor existing order
|
|
await MonitorOrderAsync(executionState, context);
|
|
}
|
|
|
|
// Wait before next iteration
|
|
await Task.Delay(executionState.Parameters.PlacementDelayMs, cancellationToken);
|
|
}
|
|
|
|
// Complete execution
|
|
await CompleteExecutionAsync(executionState);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// Execution was cancelled
|
|
_logger.LogInformation("Iceberg execution {ExecutionId} was cancelled", executionState.ExecutionId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error in Iceberg execution loop {ExecutionId}", executionState.ExecutionId);
|
|
executionState.Status = IcebergExecutionStatus.Failed;
|
|
executionState.ErrorMessage = ex.Message;
|
|
executionState.UpdatedAt = DateTime.UtcNow;
|
|
}
|
|
}
|
|
|
|
private async Task PlaceNextOrderAsync(IcebergExecutionState executionState, StrategyContext context)
|
|
{
|
|
// Calculate order size
|
|
var orderSize = Math.Min(executionState.VisibleQuantity, executionState.RemainingQuantity);
|
|
if (orderSize <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Adjust visible quantity if adaptive
|
|
if (executionState.Parameters.AdaptiveVisibility)
|
|
{
|
|
orderSize = await AdjustVisibleQuantityAsync(executionState, orderSize);
|
|
}
|
|
|
|
var orderNumber = executionState.Orders.Count + 1;
|
|
|
|
var order = new IcebergOrder
|
|
{
|
|
ExecutionId = executionState.ExecutionId,
|
|
OrderNumber = orderNumber,
|
|
ScheduledTime = DateTime.UtcNow,
|
|
Quantity = orderSize,
|
|
OrderDetails = new OrderRequest(
|
|
Symbol: executionState.Parameters.Symbol,
|
|
Side: executionState.Parameters.Side,
|
|
Type: executionState.Parameters.LimitPrice.HasValue ? OrderType.Limit : OrderType.Market,
|
|
Quantity: orderSize,
|
|
LimitPrice: executionState.Parameters.LimitPrice,
|
|
StopPrice: null,
|
|
TimeInForce: executionState.Parameters.TimeInForce,
|
|
Algorithm: null,
|
|
AlgorithmParameters: new Dictionary<string, object>()
|
|
)
|
|
};
|
|
|
|
executionState.Orders.Add(order);
|
|
executionState.DisplayedOrder = order;
|
|
|
|
try
|
|
{
|
|
order.Status = IcebergOrderStatus.Submitted;
|
|
order.ActualTime = DateTime.UtcNow;
|
|
order.UpdatedAt = DateTime.UtcNow;
|
|
|
|
_logger.LogInformation("Placing Iceberg order {OrderNumber} for {Quantity} (remaining: {Remaining})",
|
|
orderNumber, orderSize, executionState.RemainingQuantity);
|
|
|
|
// Submit order
|
|
var orderResult = await _orderManager.SubmitOrderAsync(order.OrderDetails, context);
|
|
|
|
if (orderResult.Success)
|
|
{
|
|
order.OrderId = orderResult.OrderId;
|
|
order.Status = IcebergOrderStatus.Submitted;
|
|
order.UpdatedAt = DateTime.UtcNow;
|
|
|
|
_logger.LogInformation("Iceberg order {OrderNumber} submitted: {OrderId}",
|
|
orderNumber, orderResult.OrderId);
|
|
}
|
|
else
|
|
{
|
|
order.Status = IcebergOrderStatus.Failed;
|
|
order.ErrorMessage = orderResult.Message;
|
|
order.UpdatedAt = DateTime.UtcNow;
|
|
|
|
_logger.LogWarning("Iceberg order {OrderNumber} failed: {ErrorMessage}",
|
|
orderNumber, orderResult.Message);
|
|
|
|
// Handle retry if configured
|
|
if (order.RetryCount < _config.MaxRetries)
|
|
{
|
|
order.RetryCount++;
|
|
_logger.LogInformation("Retrying Iceberg order {OrderNumber} (attempt {RetryCount})",
|
|
orderNumber, order.RetryCount);
|
|
|
|
await Task.Delay(_config.RetryDelayMs);
|
|
await PlaceNextOrderAsync(executionState, context);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error placing Iceberg order {OrderNumber}", orderNumber);
|
|
|
|
order.Status = IcebergOrderStatus.Failed;
|
|
order.ErrorMessage = ex.Message;
|
|
order.UpdatedAt = DateTime.UtcNow;
|
|
}
|
|
|
|
UpdateExecutionState(executionState, order);
|
|
}
|
|
|
|
private async Task<int> AdjustVisibleQuantityAsync(IcebergExecutionState executionState, int currentVisibleQuantity)
|
|
{
|
|
if (!_config.EnableAdaptiveVisibility)
|
|
return currentVisibleQuantity;
|
|
|
|
// Get market depth information
|
|
var marketDepth = await GetMarketDepthAsync(executionState.Parameters.Symbol);
|
|
if (marketDepth == null)
|
|
return currentVisibleQuantity;
|
|
|
|
// Adjust based on market depth
|
|
var adjustedQuantity = currentVisibleQuantity;
|
|
|
|
// If there's good liquidity at our price level, we can be more aggressive
|
|
if (executionState.Parameters.Side == OrderSide.Buy)
|
|
{
|
|
var askDepth = marketDepth.Asks.FirstOrDefault()?.Size ?? 0;
|
|
if (askDepth > currentVisibleQuantity * 5) // 5x our size available
|
|
{
|
|
adjustedQuantity = Math.Min(currentVisibleQuantity * 2, executionState.VisibleQuantity);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var bidDepth = marketDepth.Bids.FirstOrDefault()?.Size ?? 0;
|
|
if (bidDepth > currentVisibleQuantity * 5) // 5x our size available
|
|
{
|
|
adjustedQuantity = Math.Min(currentVisibleQuantity * 2, executionState.VisibleQuantity);
|
|
}
|
|
}
|
|
|
|
// Ensure we don't exceed configured limits
|
|
var maxVisible = executionState.Parameters.MaxVisibleQuantity ??
|
|
(int)(executionState.TotalQuantity * _config.MaxVisiblePercentage);
|
|
var minVisible = Math.Max(executionState.Parameters.MinVisibleQuantity,
|
|
(int)(executionState.TotalQuantity * _config.MinVisiblePercentage));
|
|
|
|
if (adjustedQuantity > maxVisible)
|
|
adjustedQuantity = maxVisible;
|
|
|
|
if (adjustedQuantity < minVisible)
|
|
adjustedQuantity = minVisible;
|
|
|
|
return adjustedQuantity;
|
|
}
|
|
|
|
private async Task<MarketDepth> GetMarketDepthAsync(string symbol)
|
|
{
|
|
// In a real implementation, this would get real-time market depth data
|
|
// For now, we'll return null to indicate no adjustment
|
|
return null;
|
|
}
|
|
|
|
private async Task MonitorOrderAsync(IcebergExecutionState executionState, StrategyContext context)
|
|
{
|
|
if (executionState.DisplayedOrder == null)
|
|
return;
|
|
|
|
// In a real implementation, we would monitor the order status
|
|
// For now, we'll simulate order completion
|
|
var random = new Random();
|
|
if (random.NextDouble() < 0.3) // 30% chance of order completion each cycle
|
|
{
|
|
// Simulate order fill
|
|
executionState.DisplayedOrder.Status = IcebergOrderStatus.Filled;
|
|
executionState.DisplayedOrder.Fills.Add(new OrderFill
|
|
{
|
|
OrderId = executionState.DisplayedOrder.OrderId,
|
|
Symbol = executionState.Parameters.Symbol,
|
|
Quantity = executionState.DisplayedOrder.Quantity,
|
|
FillPrice = executionState.Parameters.LimitPrice ?? 100, // Simulated price
|
|
FillTime = DateTime.UtcNow,
|
|
Commission = executionState.DisplayedOrder.Quantity * 0.5m, // Simulated commission
|
|
ExecutionId = Guid.NewGuid().ToString()
|
|
});
|
|
|
|
executionState.DisplayedOrder.UpdatedAt = DateTime.UtcNow;
|
|
UpdateExecutionState(executionState, executionState.DisplayedOrder);
|
|
}
|
|
}
|
|
|
|
private void UpdateExecutionState(IcebergExecutionState executionState, IcebergOrder order)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
// Update executed quantity
|
|
executionState.ExecutedQuantity = executionState.Orders
|
|
.Where(o => o.Status == IcebergOrderStatus.Filled)
|
|
.Sum(o => o.FilledQuantity);
|
|
|
|
// Move order to appropriate list
|
|
if (order.Status == IcebergOrderStatus.Filled)
|
|
{
|
|
executionState.CompletedOrders.Add(order);
|
|
executionState.DisplayedOrder = null; // Clear displayed order
|
|
}
|
|
else if (order.Status == IcebergOrderStatus.Failed)
|
|
{
|
|
executionState.FailedOrders.Add(order);
|
|
}
|
|
|
|
// Update execution metrics
|
|
UpdatePerformanceMetrics(executionState);
|
|
|
|
// Check if execution is complete
|
|
if (executionState.RemainingQuantity <= 0)
|
|
{
|
|
_ = CompleteExecutionAsync(executionState);
|
|
}
|
|
|
|
executionState.UpdatedAt = DateTime.UtcNow;
|
|
}
|
|
}
|
|
|
|
private void UpdatePerformanceMetrics(IcebergExecutionState executionState)
|
|
{
|
|
var metrics = new IcebergPerformanceMetrics();
|
|
|
|
// Calculate basic metrics
|
|
var allOrders = executionState.Orders;
|
|
if (allOrders.Any())
|
|
{
|
|
metrics.TotalOrders = allOrders.Count;
|
|
metrics.SuccessfulOrders = executionState.CompletedOrders.Count;
|
|
metrics.FailedOrders = executionState.FailedOrders.Count;
|
|
metrics.TotalCommission = allOrders.Sum(o => o.TotalCommission);
|
|
|
|
// Calculate average visibility
|
|
if (executionState.TotalQuantity > 0)
|
|
{
|
|
metrics.AverageVisibility = (decimal)(executionState.VisibleQuantity / (double)executionState.TotalQuantity);
|
|
}
|
|
|
|
// Calculate average fill price
|
|
var totalValue = allOrders.Where(o => o.Status == IcebergOrderStatus.Filled)
|
|
.Sum(o => o.FilledQuantity * (double)o.AverageFillPrice);
|
|
var totalQuantity = allOrders.Where(o => o.Status == IcebergOrderStatus.Filled)
|
|
.Sum(o => o.FilledQuantity);
|
|
|
|
if (totalQuantity > 0)
|
|
{
|
|
metrics.AverageFillPrice = (decimal)(totalValue / totalQuantity);
|
|
}
|
|
}
|
|
|
|
executionState.PerformanceMetrics = metrics;
|
|
}
|
|
|
|
private async Task CompleteExecutionAsync(IcebergExecutionState executionState)
|
|
{
|
|
if (executionState.RemainingQuantity <= 0)
|
|
{
|
|
executionState.Status = IcebergExecutionStatus.Completed;
|
|
_logger.LogInformation("Iceberg execution {ExecutionId} completed successfully", executionState.ExecutionId);
|
|
}
|
|
else
|
|
{
|
|
executionState.Status = IcebergExecutionStatus.Failed;
|
|
_logger.LogWarning("Iceberg execution {ExecutionId} completed with remaining quantity", executionState.ExecutionId);
|
|
}
|
|
|
|
executionState.EndTime = DateTime.UtcNow;
|
|
executionState.UpdatedAt = DateTime.UtcNow;
|
|
|
|
// Cancel any remaining displayed order if configured
|
|
if (executionState.Parameters.CancelAtEnd && executionState.DisplayedOrder != null)
|
|
{
|
|
await CancelDisplayedOrderAsync(executionState);
|
|
}
|
|
|
|
// Clean up cancellation token
|
|
lock (_lock)
|
|
{
|
|
if (_executionCancellations.ContainsKey(executionState.ExecutionId))
|
|
{
|
|
_executionCancellations[executionState.ExecutionId].Dispose();
|
|
_executionCancellations.Remove(executionState.ExecutionId);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task CancelDisplayedOrderAsync(IcebergExecutionState executionState)
|
|
{
|
|
if (executionState.DisplayedOrder?.OrderId != null)
|
|
{
|
|
try
|
|
{
|
|
await _orderManager.CancelOrderAsync(executionState.DisplayedOrder.OrderId);
|
|
executionState.DisplayedOrder.Status = IcebergOrderStatus.Cancelled;
|
|
executionState.DisplayedOrder.WasCancelled = true;
|
|
executionState.DisplayedOrder.UpdatedAt = DateTime.UtcNow;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error cancelling displayed Iceberg order {OrderId}",
|
|
executionState.DisplayedOrder.OrderId);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cancel an Iceberg execution
|
|
/// </summary>
|
|
public async Task<bool> CancelExecutionAsync(string executionId)
|
|
{
|
|
if (string.IsNullOrEmpty(executionId)) throw new ArgumentException("Execution ID required", nameof(executionId));
|
|
|
|
IcebergExecutionState executionState;
|
|
CancellationTokenSource cancellationTokenSource;
|
|
|
|
lock (_lock)
|
|
{
|
|
if (!_executions.ContainsKey(executionId))
|
|
return false;
|
|
|
|
executionState = _executions[executionId];
|
|
|
|
if (!_executionCancellations.ContainsKey(executionId))
|
|
return false;
|
|
|
|
cancellationTokenSource = _executionCancellations[executionId];
|
|
}
|
|
|
|
if (executionState.Status != IcebergExecutionStatus.Running)
|
|
return false;
|
|
|
|
try
|
|
{
|
|
// Cancel the execution loop
|
|
cancellationTokenSource.Cancel();
|
|
|
|
// Cancel any displayed order
|
|
await CancelDisplayedOrderAsync(executionState);
|
|
|
|
// Update execution state
|
|
executionState.Status = IcebergExecutionStatus.Cancelled;
|
|
executionState.EndTime = DateTime.UtcNow;
|
|
executionState.UpdatedAt = DateTime.UtcNow;
|
|
|
|
_logger.LogInformation("Iceberg execution {ExecutionId} cancelled", executionId);
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error cancelling Iceberg execution {ExecutionId}", executionId);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get execution state
|
|
/// </summary>
|
|
public IcebergExecutionState GetExecutionState(string executionId)
|
|
{
|
|
if (string.IsNullOrEmpty(executionId)) return null;
|
|
|
|
lock (_lock)
|
|
{
|
|
return _executions.ContainsKey(executionId) ?
|
|
new IcebergExecutionState(_executions[executionId]) : null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get all execution states
|
|
/// </summary>
|
|
public List<IcebergExecutionState> GetAllExecutionStates()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _executions.Values.Select(e => new IcebergExecutionState(e)).ToList();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Integration with OrderManager
|
|
|
|
### Iceberg Integration in OrderManager
|
|
```csharp
|
|
public partial class OrderManager : IOrderManager
|
|
{
|
|
private readonly IcebergExecutor _icebergExecutor;
|
|
|
|
// Enhanced constructor with Iceberg executor
|
|
public OrderManager(
|
|
IRiskManager riskManager,
|
|
IPositionSizer positionSizer,
|
|
ILogger<OrderManager> logger,
|
|
RoutingConfigurationManager configManager,
|
|
RoutingMetricsCollector metricsCollector,
|
|
TwapExecutor twapExecutor,
|
|
VwapExecutor vwapExecutor,
|
|
IcebergExecutor icebergExecutor) : base(riskManager, positionSizer, logger, configManager, metricsCollector, twapExecutor, vwapExecutor)
|
|
{
|
|
_icebergExecutor = icebergExecutor ?? throw new ArgumentNullException(nameof(icebergExecutor));
|
|
_venueManager = new VenueManager(logger);
|
|
_omsToVenueOrderIdMap = new Dictionary<string, string>();
|
|
_venueToOmsOrderIdMap = new Dictionary<string, string>();
|
|
|
|
// Initialize with configurations
|
|
InitializeWithConfigurationsAsync().Wait();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute an Iceberg order
|
|
/// </summary>
|
|
public async Task<OrderResult> ExecuteIcebergAsync(IcebergParameters parameters, StrategyContext context)
|
|
{
|
|
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
|
if (context == null) throw new ArgumentNullException(nameof(context));
|
|
|
|
try
|
|
{
|
|
_logger.LogInformation("Executing Iceberg order for {Symbol} {Side} {Quantity} (visible: {VisibleQuantity})",
|
|
parameters.Symbol, parameters.Side, parameters.TotalQuantity, parameters.VisibleQuantity);
|
|
|
|
// Validate through risk management
|
|
var riskDecision = await ValidateIcebergOrderAsync(parameters, context);
|
|
if (!riskDecision.Allow)
|
|
{
|
|
_logger.LogWarning("Iceberg order rejected by risk management: {Reason}", riskDecision.RejectReason);
|
|
return new OrderResult(false, null, $"Risk validation failed: {riskDecision.RejectReason}", null);
|
|
}
|
|
|
|
// Execute Iceberg
|
|
var executionState = await _icebergExecutor.ExecuteIcebergAsync(parameters, context);
|
|
|
|
// Create order result
|
|
var orderResult = new OrderResult(
|
|
Success: executionState.Status == IcebergExecutionStatus.Completed,
|
|
OrderId: executionState.ExecutionId,
|
|
Message: executionState.Status == IcebergExecutionStatus.Completed ?
|
|
"Iceberg execution completed successfully" :
|
|
$"Iceberg execution failed: {executionState.ErrorMessage}",
|
|
Status: ConvertToOrderStatus(executionState)
|
|
);
|
|
|
|
_logger.LogInformation("Iceberg order execution {Result}: {Message}",
|
|
orderResult.Success ? "succeeded" : "failed", orderResult.Message);
|
|
|
|
return orderResult;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error executing Iceberg order for {Symbol}", parameters.Symbol);
|
|
return new OrderResult(false, null, $"Error executing Iceberg order: {ex.Message}", null);
|
|
}
|
|
}
|
|
|
|
private async Task<RiskDecision> ValidateIcebergOrderAsync(IcebergParameters parameters, StrategyContext context)
|
|
{
|
|
// Convert Iceberg parameters to strategy intent for risk validation
|
|
var intent = new StrategyIntent(
|
|
Symbol: parameters.Symbol,
|
|
Side: ConvertOrderSide(parameters.Side),
|
|
EntryType: parameters.LimitPrice.HasValue ? OrderType.Limit : OrderType.Market,
|
|
LimitPrice: (double?)parameters.LimitPrice,
|
|
StopTicks: 10, // Placeholder - would calculate based on stop price
|
|
TargetTicks: null,
|
|
Confidence: 1.0,
|
|
Reason: "Iceberg Algorithm Order",
|
|
Metadata: parameters.Metadata
|
|
);
|
|
|
|
// Get risk configuration
|
|
var config = new RiskConfig(1000, 200, 10, true); // Placeholder - would get from configuration
|
|
|
|
return _riskManager.ValidateOrder(intent, context, config);
|
|
}
|
|
|
|
private OrderStatus ConvertToOrderStatus(IcebergExecutionState executionState)
|
|
{
|
|
if (executionState == null) return null;
|
|
|
|
var state = executionState.Status switch
|
|
{
|
|
IcebergExecutionStatus.Pending => OrderState.New,
|
|
IcebergExecutionStatus.Running => OrderState.Accepted,
|
|
IcebergExecutionStatus.Completed => OrderState.Filled,
|
|
IcebergExecutionStatus.Cancelled => OrderState.Cancelled,
|
|
IcebergExecutionStatus.Failed => OrderState.Rejected,
|
|
_ => OrderState.Unknown
|
|
};
|
|
|
|
// Combine all fills from completed orders
|
|
var allFills = executionState.Orders.SelectMany(o => o.Fills).ToList();
|
|
|
|
return new OrderStatus(
|
|
OrderId: executionState.ExecutionId,
|
|
Symbol: executionState.Parameters.Symbol,
|
|
Side: executionState.Parameters.Side,
|
|
Type: executionState.Parameters.LimitPrice.HasValue ? OrderType.Limit : OrderType.Market,
|
|
Quantity: executionState.TotalQuantity,
|
|
FilledQuantity: executionState.ExecutedQuantity,
|
|
LimitPrice: executionState.Parameters.LimitPrice,
|
|
StopPrice: null,
|
|
State: state,
|
|
CreatedTime: executionState.CreatedAt,
|
|
FilledTime: executionState.EndTime,
|
|
Fills: allFills
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cancel an Iceberg execution
|
|
/// </summary>
|
|
public async Task<bool> CancelIcebergAsync(string executionId)
|
|
{
|
|
if (string.IsNullOrEmpty(executionId)) throw new ArgumentException("Execution ID required", nameof(executionId));
|
|
|
|
return await _icebergExecutor.CancelExecutionAsync(executionId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get Iceberg execution state
|
|
/// </summary>
|
|
public IcebergExecutionState GetIcebergExecutionState(string executionId)
|
|
{
|
|
if (string.IsNullOrEmpty(executionId)) return null;
|
|
|
|
return _icebergExecutor.GetExecutionState(executionId);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Iceberg Configuration Management
|
|
|
|
### Iceberg Configuration Integration
|
|
```csharp
|
|
public partial class RoutingConfigurationManager
|
|
{
|
|
/// <summary>
|
|
/// Get Iceberg configuration
|
|
/// </summary>
|
|
public async Task<IcebergConfig> GetIcebergConfigAsync()
|
|
{
|
|
var config = await GetConfigurationAsync<IcebergConfig>("iceberg-config");
|
|
return config ?? IcebergConfig.Default;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update Iceberg configuration
|
|
/// </summary>
|
|
public async Task UpdateIcebergConfigAsync(IcebergConfig config)
|
|
{
|
|
if (config == null) throw new ArgumentNullException(nameof(config));
|
|
|
|
config.Id = "iceberg-config";
|
|
config.Name = "Iceberg Configuration";
|
|
config.Description = "Configuration for Iceberg algorithm behavior";
|
|
|
|
await UpdateConfigurationAsync(config);
|
|
_logger.LogInformation("Iceberg configuration updated");
|
|
}
|
|
}
|
|
```
|
|
|
|
## Testing Considerations
|
|
|
|
### Unit Tests for Iceberg Algorithm
|
|
1. **Order Size Calculation**: Test calculation of order sizes based on visible quantity
|
|
2. **Parameter Validation**: Test validation of Iceberg parameters
|
|
3. **Order Placement**: Test placement of individual orders
|
|
4. **Order Monitoring**: Test monitoring of order status and fills
|
|
5. **Error Handling**: Test handling of execution errors and retries
|
|
6. **Cancellation**: Test cancellation of Iceberg executions
|
|
7. **Metrics Collection**: Test collection of performance metrics
|
|
8. **Visibility Adjustment**: Test adjustment of visible quantity based on market conditions
|
|
|
|
### Integration Tests
|
|
1. **End-to-End Execution**: Test complete Iceberg execution from start to finish
|
|
2. **Order Manager Integration**: Test integration with OrderManager
|
|
3. **Risk Management Integration**: Test risk validation for Iceberg orders
|
|
4. **Market Data Integration**: Test integration with market data providers
|
|
5. **Performance Testing**: Test performance with large order sizes
|
|
6. **Concurrent Executions**: Test multiple concurrent Iceberg executions
|
|
|
|
## Performance Considerations
|
|
|
|
### Memory Management
|
|
```csharp
|
|
/// <summary>
|
|
/// Manages memory usage for Iceberg executions
|
|
/// </summary>
|
|
public class IcebergMemoryManager
|
|
{
|
|
private readonly int _maxExecutions;
|
|
private readonly TimeSpan _executionRetentionTime;
|
|
private readonly Dictionary<string, DateTime> _executionAccessTimes;
|
|
private readonly object _lock = new object();
|
|
|
|
public IcebergMemoryManager(int maxExecutions = 1000, TimeSpan retentionTime = default)
|
|
{
|
|
_maxExecutions = maxExecutions;
|
|
_executionRetentionTime = retentionTime == default ?
|
|
TimeSpan.FromHours(24) : retentionTime;
|
|
_executionAccessTimes = new Dictionary<string, DateTime>();
|
|
}
|
|
|
|
public void RecordExecutionAccess(string executionId)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_executionAccessTimes[executionId] = DateTime.UtcNow;
|
|
}
|
|
}
|
|
|
|
public List<string> GetExpiredExecutions()
|
|
{
|
|
var cutoffTime = DateTime.UtcNow.Subtract(_executionRetentionTime);
|
|
|
|
lock (_lock)
|
|
{
|
|
return _executionAccessTimes
|
|
.Where(kvp => kvp.Value < cutoffTime)
|
|
.Select(kvp => kvp.Key)
|
|
.ToList();
|
|
}
|
|
}
|
|
|
|
public bool IsMemoryPressureHigh(int currentExecutionCount)
|
|
{
|
|
return currentExecutionCount > (_maxExecutions * 0.8); // 80% threshold
|
|
}
|
|
}
|
|
```
|
|
|
|
### Adaptive Iceberg
|
|
```csharp
|
|
/// <summary>
|
|
/// Adaptive Iceberg that adjusts based on market conditions
|
|
/// </summary>
|
|
public class AdaptiveIcebergExecutor : IcebergExecutor
|
|
{
|
|
private readonly IMarketAnalyzer _marketAnalyzer;
|
|
|
|
public AdaptiveIcebergExecutor(
|
|
ILogger<IcebergExecutor> logger,
|
|
IOrderManager orderManager,
|
|
IMarketDataProvider marketDataProvider,
|
|
IMarketAnalyzer marketAnalyzer,
|
|
IcebergConfig config = null) : base(logger, orderManager, marketDataProvider, config)
|
|
{
|
|
_marketAnalyzer = marketAnalyzer ?? throw new ArgumentNullException(nameof(marketAnalyzer));
|
|
}
|
|
|
|
protected override async Task<int> AdjustVisibleQuantityAsync(IcebergExecutionState executionState, int currentVisibleQuantity)
|
|
{
|
|
if (!_config.EnableAdaptiveVisibility || _marketAnalyzer == null)
|
|
return await base.AdjustVisibleQuantityAsync(executionState, currentVisibleQuantity);
|
|
|
|
try
|
|
{
|
|
var marketConditions = await _marketAnalyzer.AnalyzeMarketConditionsAsync(
|
|
executionState.Parameters.Symbol);
|
|
|
|
var adjustedQuantity = currentVisibleQuantity;
|
|
|
|
// Adjust based on market volatility
|
|
if (marketConditions.Volatility > 0.02m) // High volatility (2%+)
|
|
{
|
|
// Reduce visibility in volatile markets
|
|
adjustedQuantity = (int)(currentVisibleQuantity * 0.7);
|
|
}
|
|
else if (marketConditions.Volatility < 0.005m) // Low volatility (<0.5%)
|
|
{
|
|
// Increase visibility in stable markets
|
|
adjustedQuantity = (int)(currentVisibleQuantity * 1.3);
|
|
}
|
|
|
|
// Adjust based on liquidity
|
|
if (marketConditions.Liquidity < 0.3) // Low liquidity
|
|
{
|
|
// Reduce visibility in illiquid markets
|
|
adjustedQuantity = Math.Min(adjustedQuantity, (int)(currentVisibleQuantity * 0.5));
|
|
}
|
|
|
|
// Ensure we don't exceed configured limits
|
|
var maxVisible = executionState.Parameters.MaxVisibleQuantity ??
|
|
(int)(executionState.TotalQuantity * _config.MaxVisiblePercentage);
|
|
var minVisible = Math.Max(executionState.Parameters.MinVisibleQuantity,
|
|
(int)(executionState.TotalQuantity * _config.MinVisiblePercentage));
|
|
|
|
if (adjustedQuantity > maxVisible)
|
|
adjustedQuantity = maxVisible;
|
|
|
|
if (adjustedQuantity < minVisible)
|
|
adjustedQuantity = minVisible;
|
|
|
|
return adjustedQuantity;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error adjusting visible quantity for {Symbol}", executionState.Parameters.Symbol);
|
|
return await base.AdjustVisibleQuantityAsync(executionState, currentVisibleQuantity);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Interface for market analysis
|
|
/// </summary>
|
|
public interface IMarketAnalyzer
|
|
{
|
|
/// <summary>
|
|
/// Analyze current market conditions for a symbol
|
|
/// </summary>
|
|
Task<MarketConditions> AnalyzeMarketConditionsAsync(string symbol);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Market conditions analysis result
|
|
/// </summary>
|
|
public record MarketConditions
|
|
{
|
|
public string Symbol { get; set; }
|
|
public decimal Volatility { get; set; } // 0.0 to 1.0
|
|
public decimal Liquidity { get; set; } // 0.0 to 1.0
|
|
public MarketTrend Trend { get; set; }
|
|
public decimal Spread { get; set; }
|
|
public DateTime AnalysisTime { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Market trend enumeration
|
|
/// </summary>
|
|
public enum MarketTrend
|
|
{
|
|
Up,
|
|
Down,
|
|
Sideways
|
|
}
|
|
```
|
|
|
|
## Monitoring and Alerting
|
|
|
|
### Iceberg Metrics Export
|
|
```csharp
|
|
/// <summary>
|
|
/// Exports Iceberg metrics for monitoring
|
|
/// </summary>
|
|
public class IcebergMetricsExporter
|
|
{
|
|
private readonly IcebergExecutor _icebergExecutor;
|
|
|
|
public IcebergMetricsExporter(IcebergExecutor icebergExecutor)
|
|
{
|
|
_icebergExecutor = icebergExecutor ?? throw new ArgumentNullException(nameof(icebergExecutor));
|
|
}
|
|
|
|
public string ExportToPrometheus()
|
|
{
|
|
var executions = _icebergExecutor.GetAllExecutionStates();
|
|
var sb = new StringBuilder();
|
|
|
|
// Overall Iceberg metrics
|
|
var activeExecutions = executions.Count(e => e.Status == IcebergExecutionStatus.Running);
|
|
var completedExecutions = executions.Count(e => e.Status == IcebergExecutionStatus.Completed);
|
|
var failedExecutions = executions.Count(e => e.Status == IcebergExecutionStatus.Failed);
|
|
|
|
sb.AppendLine($"# HELP iceberg_active_executions Number of active Iceberg executions");
|
|
sb.AppendLine($"# TYPE iceberg_active_executions gauge");
|
|
sb.AppendLine($"iceberg_active_executions {activeExecutions}");
|
|
|
|
sb.AppendLine($"# HELP iceberg_completed_executions Total number of completed Iceberg executions");
|
|
sb.AppendLine($"# TYPE iceberg_completed_executions counter");
|
|
sb.AppendLine($"iceberg_completed_executions {completedExecutions}");
|
|
|
|
sb.AppendLine($"# HELP iceberg_failed_executions Total number of failed Iceberg executions");
|
|
sb.AppendLine($"# TYPE iceberg_failed_executions counter");
|
|
sb.AppendLine($"iceberg_failed_executions {failedExecutions}");
|
|
|
|
// Performance metrics for completed executions
|
|
var completed = executions.Where(e => e.Status == IcebergExecutionStatus.Completed).ToList();
|
|
if (completed.Any())
|
|
{
|
|
var avgSlippage = completed.Average(e => (double)e.PerformanceMetrics.Slippage);
|
|
var avgCommission = (double)completed.Average(e => e.PerformanceMetrics.TotalCommission);
|
|
var avgVisibility = completed.Average(e => (double)e.PerformanceMetrics.AverageVisibility);
|
|
|
|
sb.AppendLine($"# HELP iceberg_average_slippage Average slippage for completed executions");
|
|
sb.AppendLine($"# TYPE iceberg_average_slippage gauge");
|
|
sb.AppendLine($"iceberg_average_slippage {avgSlippage:F4}");
|
|
|
|
sb.AppendLine($"# HELP iceberg_average_commission Average commission for completed executions");
|
|
sb.AppendLine($"# TYPE iceberg_average_commission gauge");
|
|
sb.AppendLine($"iceberg_average_commission {avgCommission:F2}");
|
|
|
|
sb.AppendLine($"# HELP iceberg_average_visibility Average visibility for completed executions");
|
|
sb.AppendLine($"# TYPE iceberg_average_visibility gauge");
|
|
sb.AppendLine($"iceberg_average_visibility {avgVisibility:F4}");
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
```
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Machine Learning Optimization**: Use ML to optimize Iceberg parameters based on historical performance
|
|
2. **Real-time Market Adaptation**: Adjust Iceberg execution based on real-time market conditions
|
|
3. **Cross-Venue Iceberg**: Execute Iceberg orders across multiple venues simultaneously
|
|
4. **Iceberg Analytics**: Advanced analytics and reporting on Iceberg performance
|
|
5. **Iceberg Strategy Builder**: Visual tools for building and testing Iceberg strategies
|
|
6. **Iceberg Benchmarking**: Compare Iceberg performance against other execution algorithms
|
|
7. **Iceberg Risk Controls**: Enhanced risk controls specific to algorithmic execution
|
|
8. **Iceberg Compliance**: Ensure Iceberg execution complies with regulatory requirements
|
|
9. **Smart Iceberg**: Iceberg orders that adapt visibility based on fill patterns
|
|
10. **Iceberg with TWAP/VWAP**: Hybrid algorithms combining Iceberg with other strategies
|