using System;
using System.Collections.Generic;
namespace NT8.Core.OMS
{
#region Enumerations
///
/// Order side enumeration
///
public enum OrderSide
{
Buy = 1,
Sell = -1
}
///
/// Order type enumeration
///
public enum OrderType
{
Market,
Limit,
StopMarket,
StopLimit
}
///
/// Order state enumeration for the OMS state machine
///
public enum OrderState
{
Pending, // Order request created, waiting for risk approval
Submitted, // Sent to broker, waiting for acceptance
Accepted, // Broker accepted the order
Working, // Order is live in the market
PartiallyFilled, // Order partially filled
Filled, // Order completely filled
Cancelled, // Order cancelled by user or system
Rejected, // Order rejected by broker or system
Expired // Order expired
}
///
/// Time in force enumeration
///
public enum TimeInForce
{
Day,
Gtc, // Good Till Cancelled
Ioc, // Immediate Or Cancel
Fok // Fill Or Kill
}
#endregion
#region Core Order Models
///
/// Order request parameters
///
public class OrderRequest
{
///
/// Trading symbol
///
public string Symbol { get; set; }
///
/// Order side
///
public OrderSide Side { get; set; }
///
/// Order type
///
public OrderType Type { get; set; }
///
/// Order quantity
///
public int Quantity { get; set; }
///
/// Limit price (if applicable)
///
public decimal? LimitPrice { get; set; }
///
/// Stop price (if applicable)
///
public decimal? StopPrice { get; set; }
///
/// Time in force
///
public TimeInForce TimeInForce { get; set; }
///
/// Unique identifier for this order request
///
public string ClientOrderId { get; set; }
///
/// Timestamp when order was created
///
public DateTime CreatedTime { get; set; }
///
/// Constructor for OrderRequest
///
public OrderRequest()
{
CreatedTime = DateTime.UtcNow;
}
}
///
/// Order submission result
///
public class OrderResult
{
///
/// Whether the order submission was successful
///
public bool Success { get; set; }
///
/// Order ID if successful
///
public string OrderId { get; set; }
///
/// Message describing the result
///
public string Message { get; set; }
///
/// Original order request
///
public OrderRequest Request { get; set; }
///
/// Constructor for OrderResult
///
public OrderResult(bool success, string orderId, string message, OrderRequest request)
{
Success = success;
OrderId = orderId;
Message = message;
Request = request;
}
}
///
/// Current order status with full state information
///
public class OrderStatus
{
///
/// Internal order ID assigned by the OMS
///
public string OrderId { get; set; }
///
/// Client-provided order ID
///
public string ClientOrderId { get; set; }
///
/// Trading symbol
///
public string Symbol { get; set; }
///
/// Order side
///
public OrderSide Side { get; set; }
///
/// Order type
///
public OrderType Type { get; set; }
///
/// Original order quantity
///
public int Quantity { get; set; }
///
/// Filled quantity
///
public int FilledQuantity { get; set; }
///
/// Remaining quantity
///
public int RemainingQuantity { get { return Quantity - FilledQuantity; } }
///
/// Limit price (if applicable)
///
public decimal? LimitPrice { get; set; }
///
/// Stop price (if applicable)
///
public decimal? StopPrice { get; set; }
///
/// Current order state
///
public OrderState State { get; set; }
///
/// Order creation time
///
public DateTime CreatedTime { get; set; }
///
/// Order fill time (if filled)
///
public DateTime? FilledTime { get; set; }
///
/// Order fills
///
public List Fills { get; set; }
///
/// Average fill price
///
public decimal AverageFillPrice { get; set; }
///
/// Total value of filled shares
///
public decimal FillValue { get; set; }
///
/// Constructor for OrderStatus
///
public OrderStatus()
{
Fills = new List();
CreatedTime = DateTime.UtcNow;
}
}
///
/// Represents a single fill event for an order
///
public class OrderFill
{
///
/// Fill ID from the broker
///
public string FillId { get; set; }
///
/// Order ID this fill belongs to
///
public string OrderId { get; set; }
///
/// Quantity filled in this transaction
///
public int FillQuantity { get; set; }
///
/// Price at which the fill occurred
///
public decimal FillPrice { get; set; }
///
/// Timestamp of the fill
///
public DateTime FillTime { get; set; }
///
/// Commission paid for this fill
///
public decimal Commission { get; set; }
///
/// Constructor for OrderFill
///
public OrderFill()
{
FillTime = DateTime.UtcNow;
}
}
///
/// Order modification parameters
///
public class OrderModification
{
///
/// Order ID to modify
///
public string OrderId { get; set; }
///
/// New quantity (if changing)
///
public int? NewQuantity { get; set; }
///
/// New limit price (if changing)
///
public decimal? NewLimitPrice { get; set; }
///
/// New stop price (if changing)
///
public decimal? NewStopPrice { get; set; }
///
/// New time in force (if changing)
///
public TimeInForce? NewTimeInForce { get; set; }
///
/// Constructor for OrderModification
///
public OrderModification(string orderId)
{
OrderId = orderId;
}
}
///
/// Order cancellation request
///
public class OrderCancellation
{
///
/// Order ID to cancel
///
public string OrderId { get; set; }
///
/// Reason for cancellation
///
public string Reason { get; set; }
///
/// Constructor for OrderCancellation
///
public OrderCancellation(string orderId, string reason)
{
OrderId = orderId;
Reason = reason;
}
}
#endregion
#region Phase 2 - Partial Fill Models
///
/// Detailed information about a partial fill event
///
public class PartialFillInfo
{
///
/// Order ID this partial fill belongs to
///
public string OrderId { get; set; }
///
/// Quantity filled in this event
///
public int FilledQuantity { get; set; }
///
/// Remaining quantity after this fill
///
public int RemainingQuantity { get; set; }
///
/// Total quantity of the original order
///
public int TotalQuantity { get; set; }
///
/// Fill price for this partial fill
///
public decimal FillPrice { get; set; }
///
/// Average fill price across all fills so far
///
public decimal AverageFillPrice { get; set; }
///
/// Timestamp of this partial fill
///
public DateTime FillTime { get; set; }
///
/// Fill percentage (0-100)
///
public double FillPercentage { get; set; }
///
/// Whether this completes the order
///
public bool IsComplete { get; set; }
///
/// Constructor for PartialFillInfo
///
public PartialFillInfo(
string orderId,
int filledQuantity,
int remainingQuantity,
int totalQuantity,
decimal fillPrice,
decimal averageFillPrice,
DateTime fillTime)
{
if (string.IsNullOrEmpty(orderId))
throw new ArgumentNullException("orderId");
if (filledQuantity <= 0)
throw new ArgumentException("FilledQuantity must be positive", "filledQuantity");
if (totalQuantity <= 0)
throw new ArgumentException("TotalQuantity must be positive", "totalQuantity");
OrderId = orderId;
FilledQuantity = filledQuantity;
RemainingQuantity = remainingQuantity;
TotalQuantity = totalQuantity;
FillPrice = fillPrice;
AverageFillPrice = averageFillPrice;
FillTime = fillTime;
FillPercentage = ((double)(totalQuantity - remainingQuantity) / (double)totalQuantity) * 100.0;
IsComplete = remainingQuantity == 0;
}
}
///
/// Strategy for handling partial fills
///
public enum PartialFillStrategy
{
///
/// Allow partial fills and wait for complete fill
///
AllowAndWait,
///
/// Cancel remaining quantity after first partial fill
///
CancelRemaining,
///
/// Accept any partial fill as complete
///
AcceptPartial,
///
/// Reject the order if not filled immediately (FOK-like)
///
AllOrNone
}
///
/// Configuration for partial fill handling
///
public class PartialFillConfig
{
///
/// Strategy to use for partial fills
///
public PartialFillStrategy Strategy { get; set; }
///
/// Minimum fill percentage to accept (0-100)
///
public double MinimumFillPercentage { get; set; }
///
/// Maximum time to wait for complete fill (seconds)
///
public int MaxWaitTimeSeconds { get; set; }
///
/// Whether to retry remaining quantity with new order
///
public bool RetryRemaining { get; set; }
///
/// Constructor for PartialFillConfig
///
public PartialFillConfig(
PartialFillStrategy strategy,
double minimumFillPercentage,
int maxWaitTimeSeconds,
bool retryRemaining)
{
Strategy = strategy;
MinimumFillPercentage = minimumFillPercentage;
MaxWaitTimeSeconds = maxWaitTimeSeconds;
RetryRemaining = retryRemaining;
}
///
/// Default configuration - allow partial fills and wait
///
public static PartialFillConfig Default
{
get
{
return new PartialFillConfig(
PartialFillStrategy.AllowAndWait,
0.0, // Accept any fill percentage
300, // Wait up to 5 minutes
false // Don't auto-retry
);
}
}
}
///
/// Result of handling a partial fill
///
public class PartialFillResult
{
///
/// Order ID
///
public string OrderId { get; set; }
///
/// Action taken
///
public PartialFillAction Action { get; set; }
///
/// Reason for the action
///
public string Reason { get; set; }
///
/// Whether the order is now complete
///
public bool IsComplete { get; set; }
///
/// New order ID if retry was attempted
///
public string RetryOrderId { get; set; }
///
/// Constructor for PartialFillResult
///
public PartialFillResult(
string orderId,
PartialFillAction action,
string reason,
bool isComplete,
string retryOrderId)
{
OrderId = orderId;
Action = action;
Reason = reason;
IsComplete = isComplete;
RetryOrderId = retryOrderId;
}
}
///
/// Action taken when handling partial fill
///
public enum PartialFillAction
{
///
/// Continue waiting for complete fill
///
Wait,
///
/// Cancel remaining quantity
///
CancelRemaining,
///
/// Accept partial fill as complete
///
AcceptPartial,
///
/// Retry remaining quantity with new order
///
RetryRemaining,
///
/// No action needed (order complete)
///
None
}
#endregion
#region Phase 3 - Advanced Order Types
///
/// Limit order request with specific price
///
public class LimitOrderRequest : OrderRequest
{
///
/// Limit price for the order
///
public new decimal LimitPrice { get; set; }
///
/// Constructor for LimitOrderRequest
///
/// Trading symbol
/// Order side (Buy/Sell)
/// Order quantity
/// Limit price
/// Time in force
public LimitOrderRequest(string symbol, OrderSide side, int quantity, decimal limitPrice, TimeInForce tif)
{
if (string.IsNullOrEmpty(symbol))
throw new ArgumentNullException("symbol");
if (quantity <= 0)
throw new ArgumentException("Quantity must be positive", "quantity");
if (limitPrice <= 0)
throw new ArgumentException("LimitPrice must be positive", "limitPrice");
Symbol = symbol;
Side = side;
Quantity = quantity;
LimitPrice = limitPrice;
TimeInForce = tif;
Type = OrderType.Limit;
ClientOrderId = Guid.NewGuid().ToString();
CreatedTime = DateTime.UtcNow;
}
}
///
/// Stop order request (stop market order)
///
public class StopOrderRequest : OrderRequest
{
///
/// Stop price that triggers the order
///
public new decimal StopPrice { get; set; }
///
/// Constructor for StopOrderRequest
///
/// Trading symbol
/// Order side (Buy/Sell)
/// Order quantity
/// Stop price
/// Time in force
public StopOrderRequest(string symbol, OrderSide side, int quantity, decimal stopPrice, TimeInForce tif)
{
if (string.IsNullOrEmpty(symbol))
throw new ArgumentNullException("symbol");
if (quantity <= 0)
throw new ArgumentException("Quantity must be positive", "quantity");
if (stopPrice <= 0)
throw new ArgumentException("StopPrice must be positive", "stopPrice");
Symbol = symbol;
Side = side;
Quantity = quantity;
StopPrice = stopPrice;
TimeInForce = tif;
Type = OrderType.StopMarket;
ClientOrderId = Guid.NewGuid().ToString();
CreatedTime = DateTime.UtcNow;
}
}
///
/// Stop-limit order request
///
public class StopLimitOrderRequest : OrderRequest
{
///
/// Stop price that triggers the order
///
public new decimal StopPrice { get; set; }
///
/// Limit price for the triggered order
///
public new decimal LimitPrice { get; set; }
///
/// Constructor for StopLimitOrderRequest
///
/// Trading symbol
/// Order side (Buy/Sell)
/// Order quantity
/// Stop price
/// Limit price
/// Time in force
public StopLimitOrderRequest(string symbol, OrderSide side, int quantity, decimal stopPrice, decimal limitPrice, TimeInForce tif)
{
if (string.IsNullOrEmpty(symbol))
throw new ArgumentNullException("symbol");
if (quantity <= 0)
throw new ArgumentException("Quantity must be positive", "quantity");
if (stopPrice <= 0)
throw new ArgumentException("StopPrice must be positive", "stopPrice");
if (limitPrice <= 0)
throw new ArgumentException("LimitPrice must be positive", "limitPrice");
Symbol = symbol;
Side = side;
Quantity = quantity;
StopPrice = stopPrice;
LimitPrice = limitPrice;
TimeInForce = tif;
Type = OrderType.StopLimit;
ClientOrderId = Guid.NewGuid().ToString();
CreatedTime = DateTime.UtcNow;
}
}
///
/// Market-if-touched order request
///
public class MITOrderRequest : OrderRequest
{
///
/// Trigger price for the MIT order
///
public decimal TriggerPrice { get; set; }
///
/// Constructor for MITOrderRequest
///
/// Trading symbol
/// Order side (Buy/Sell)
/// Order quantity
/// Trigger price
/// Time in force
public MITOrderRequest(string symbol, OrderSide side, int quantity, decimal triggerPrice, TimeInForce tif)
{
if (string.IsNullOrEmpty(symbol))
throw new ArgumentNullException("symbol");
if (quantity <= 0)
throw new ArgumentException("Quantity must be positive", "quantity");
if (triggerPrice <= 0)
throw new ArgumentException("TriggerPrice must be positive", "triggerPrice");
Symbol = symbol;
Side = side;
Quantity = quantity;
TriggerPrice = triggerPrice;
TimeInForce = tif;
Type = OrderType.Market; // MIT orders become market orders when triggered
ClientOrderId = Guid.NewGuid().ToString();
CreatedTime = DateTime.UtcNow;
}
}
///
/// Trailing stop configuration
///
public class TrailingStopConfig
{
///
/// Trailing amount in ticks
///
public int TrailingTicks { get; set; }
///
/// Trailing amount as percentage of current price
///
public decimal? TrailingPercent { get; set; }
///
/// Whether to trail by ATR or fixed amount
///
public bool UseAtrTrail { get; set; }
///
/// ATR multiplier for dynamic trailing
///
public decimal AtrMultiplier { get; set; }
///
/// Constructor for TrailingStopConfig
///
/// Trailing amount in ticks
/// Whether to use ATR-based trailing
/// ATR multiplier if using ATR trail
public TrailingStopConfig(int trailingTicks, bool useAtrTrail = false, decimal atrMultiplier = 2m)
{
if (trailingTicks <= 0)
throw new ArgumentException("TrailingTicks must be positive", "trailingTicks");
if (atrMultiplier <= 0)
throw new ArgumentException("AtrMultiplier must be positive", "atrMultiplier");
TrailingTicks = trailingTicks;
UseAtrTrail = useAtrTrail;
AtrMultiplier = atrMultiplier;
}
///
/// Constructor for percentage-based trailing stop
///
/// Trailing percentage
public TrailingStopConfig(decimal trailingPercent)
{
if (trailingPercent <= 0 || trailingPercent >= 100)
throw new ArgumentException("TrailingPercent must be between 0 and 100", "trailingPercent");
TrailingPercent = trailingPercent;
}
}
///
/// Parameters for different order types
///
public class OrderTypeParameters
{
///
/// For limit orders - the limit price
///
public decimal? LimitPrice { get; set; }
///
/// For stop orders - the stop price
///
public decimal? StopPrice { get; set; }
///
/// For trailing stops - the trailing configuration
///
public TrailingStopConfig TrailingConfig { get; set; }
///
/// For iceberg orders - the displayed quantity
///
public int? DisplayQty { get; set; }
///
/// For algo orders - additional parameters
///
public Dictionary AdditionalParams { get; set; }
///
/// Constructor for OrderTypeParameters
///
public OrderTypeParameters()
{
AdditionalParams = new Dictionary();
}
}
#endregion
}