17 using System.Collections.Generic;
18 using System.Diagnostics;
20 using System.Threading;
32 private readonly
object _orderEventsLock =
new object();
33 private readonly
object _updateRequestsLock =
new object();
34 private readonly
object _cancelRequestLock =
new object();
40 private decimal _quantityFilled;
41 private decimal _averageFillPrice;
43 private readonly
int _orderId;
44 private readonly List<OrderEvent> _orderEvents;
46 private readonly ManualResetEvent _orderStatusClosedEvent;
47 private readonly List<UpdateOrderRequest> _updateRequests;
48 private readonly ManualResetEvent _orderSetEvent;
58 get {
return _orderId; }
68 if (_orderStatusOverride.HasValue)
return _orderStatusOverride.Value;
78 get {
return _submitRequest.
Symbol; }
86 get {
return _submitRequest.SecurityType; }
103 get {
return _averageFillPrice; }
112 get {
return _quantityFilled; }
128 get {
return _submitRequest.OrderType; }
136 get {
return _order ==
null ? _submitRequest.
Tag : _order.
Tag; }
144 get {
return _submitRequest; }
155 lock (_updateRequestsLock)
157 return _updateRequests.ToList();
170 lock (_cancelRequestLock)
172 return _cancelRequest;
184 lock (_orderEventsLock)
186 return _orderEvents.ToList();
196 get {
return _orderStatusClosedEvent; }
216 _submitRequest = submitRequest;
217 _orderId = submitRequest.
OrderId;
218 _transactionManager = transactionManager;
220 _orderEvents =
new List<OrderEvent>();
221 _updateRequests =
new List<UpdateOrderRequest>();
222 _orderStatusClosedEvent =
new ManualResetEvent(
false);
223 _orderSetEvent =
new ManualResetEvent(
false);
235 return Get<decimal>(field);
247 object fieldValue =
null;
252 if (_submitRequest.OrderType ==
OrderType.ComboLimit)
254 fieldValue = AccessOrder<ComboLimitOrder, decimal>(
this, field, o => o.GroupOrderManager.LimitPrice, r => r.LimitPrice);
256 else if (_submitRequest.OrderType ==
OrderType.ComboLegLimit)
258 fieldValue = AccessOrder<ComboLegLimitOrder, decimal>(
this, field, o => o.LimitPrice, r => r.LimitPrice);
260 else if (_submitRequest.OrderType ==
OrderType.Limit)
262 fieldValue = AccessOrder<LimitOrder, decimal>(
this, field, o => o.LimitPrice, r => r.LimitPrice);
264 else if (_submitRequest.OrderType ==
OrderType.StopLimit)
266 fieldValue = AccessOrder<StopLimitOrder, decimal>(
this, field, o => o.LimitPrice, r => r.LimitPrice);
268 else if (_submitRequest.OrderType ==
OrderType.LimitIfTouched)
270 fieldValue = AccessOrder<LimitIfTouchedOrder, decimal>(
this, field, o => o.LimitPrice, r => r.LimitPrice);
275 if (_submitRequest.OrderType ==
OrderType.StopLimit)
277 fieldValue = AccessOrder<StopLimitOrder, decimal>(
this, field, o => o.StopPrice, r => r.StopPrice);
279 else if (_submitRequest.OrderType ==
OrderType.StopMarket)
281 fieldValue = AccessOrder<StopMarketOrder, decimal>(
this, field, o => o.StopPrice, r => r.StopPrice);
283 else if (_submitRequest.OrderType ==
OrderType.TrailingStop)
285 fieldValue = AccessOrder<TrailingStopOrder, decimal>(
this, field, o => o.StopPrice, r => r.StopPrice);
290 fieldValue = AccessOrder<LimitIfTouchedOrder, decimal>(
this, field, o => o.TriggerPrice, r => r.TriggerPrice);
294 fieldValue = AccessOrder<TrailingStopOrder, decimal>(
this, field, o => o.TrailingAmount, r => r.TrailingAmount);
298 fieldValue = AccessOrder<TrailingStopOrder, bool>(
this, field, o => o.TrailingAsPercentage, r => r.TrailingAsPercentage);
302 throw new ArgumentOutOfRangeException(nameof(field), field,
null);
305 if (fieldValue ==
null)
310 return (T)fieldValue;
322 return ticket.UpdateRequests.Last().Response;
431 lock (_cancelRequestLock)
442 var ticket = _transactionManager.ProcessRequest(request);
443 return ticket.CancelRequest.Response;
461 lock (_cancelRequestLock)
463 if (_cancelRequest !=
null)
465 return _cancelRequest;
469 var lastUpdate = _updateRequests.LastOrDefault();
470 if (lastUpdate !=
null)
481 internal void AddOrderEvent(
OrderEvent orderEvent)
483 lock (_orderEventsLock)
485 _orderEvents.Add(orderEvent);
495 var quantityWeightedFillPrice = _orderEvents.Where(x => x.Status.IsFill())
496 .Aggregate(0m, (d, x) => d + x.AbsoluteFillQuantity * x.FillPrice);
497 _averageFillPrice = quantityWeightedFillPrice / Math.Abs(_quantityFilled);
499 _order.
Price = _averageFillPrice;
512 _averageFillPrice = _order.
Price;
519 if (orderEvent.
Status.IsClosed())
521 _orderStatusClosedEvent.Set();
529 internal void SetOrder(Order order)
531 if (_order !=
null && _order.
Id != order.Id)
533 throw new ArgumentException(
"Order id mismatch");
538 _orderSetEvent.Set();
545 internal void AddUpdateRequest(UpdateOrderRequest request)
547 if (request.OrderId !=
OrderId)
549 throw new ArgumentException(
"Received UpdateOrderRequest for incorrect order id.");
552 lock (_updateRequestsLock)
554 _updateRequests.Add(request);
566 internal bool TrySetCancelRequest(CancelOrderRequest request)
568 if (request.OrderId !=
OrderId)
570 throw new ArgumentException(
"Received CancelOrderRequest for incorrect order id.");
573 lock (_cancelRequestLock)
581 _cancelRequest = request;
594 submit.SetOrderId(request.
OrderId);
595 var ticket =
new OrderTicket(transactionManager, submit);
597 ticket.TrySetCancelRequest(request);
609 submit.SetOrderId(request.
OrderId);
610 var ticket =
new OrderTicket(transactionManager, submit);
612 ticket.AddUpdateRequest(request);
638 private int ResponseCount()
643 lock (_cancelRequestLock)
651 private int RequestCount()
653 var count = 1 + _updateRequests.Count;
655 lock (_cancelRequestLock)
657 count += _cancelRequest ==
null ? 0 : 1;
671 if (response !=
null && response.IsError)
678 private static P AccessOrder<T, P>(
OrderTicket ticket,
OrderField field, Func<T, P> orderSelector, Func<SubmitOrderRequest, P> requestSelector)
681 var order = ticket._order;
684 return requestSelector(ticket._submitRequest);
686 var typedOrder = order as T;
687 if (typedOrder !=
null)
689 return orderSelector(typedOrder);
691 throw new ArgumentException(Invariant($
"Unable to access property {field} on order of type {order.Type}"));