/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.ComponentModel; using Newtonsoft.Json; using ProtoBuf; using QuantConnect.Orders.Fees; using QuantConnect.Orders.Serialization; using QuantConnect.Securities; namespace QuantConnect.Orders { /// /// Order Event - Messaging class signifying a change in an order state and record the change in the user's algorithm portfolio /// [ProtoContract(SkipConstructor = true)] public class OrderEvent { private decimal _fillPrice; private decimal _fillQuantity; private decimal _quantity; private decimal? _limitPrice; private decimal? _triggerPrice; private decimal? _stopPrice; private decimal? _trailingAmount; private bool? _trailingAsPercentage; /// /// Id of the order this event comes from. /// [ProtoMember(1)] public int OrderId { get; set; } /// /// The unique order event id for each order /// [ProtoMember(2)] public int Id { get; set; } /// /// Easy access to the order symbol associated with this event. /// [ProtoMember(3)] public Symbol Symbol { get; set; } /// /// The date and time of this event (UTC). /// [ProtoMember(4)] public DateTime UtcTime { get; set; } /// /// Status message of the order. /// [ProtoMember(5)] public OrderStatus Status { get; set; } /// /// The fee associated with the order /// [ProtoMember(6)] public OrderFee OrderFee { get; set; } /// /// Fill price information about the order /// [ProtoMember(7)] public decimal FillPrice { get { return _fillPrice; } set { _fillPrice = value.Normalize(); } } /// /// Currency for the fill price /// [ProtoMember(8)] public string FillPriceCurrency { get; set; } /// /// Number of shares of the order that was filled in this event. /// [ProtoMember(9)] public decimal FillQuantity { get { return _fillQuantity; } set { _fillQuantity = value.Normalize(); } } /// /// Public Property Absolute Getter of Quantity -Filled /// [JsonIgnore] public decimal AbsoluteFillQuantity => Math.Abs(FillQuantity); /// /// Order direction. /// [ProtoMember(10)] public OrderDirection Direction { get; set; } /// /// Any message from the exchange. /// [DefaultValue(""), JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] [ProtoMember(11)] public string Message { get; set; } /// /// True if the order event is an assignment /// [ProtoMember(12)] public bool IsAssignment { get; set; } /// /// The current stop price /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] [ProtoMember(13)] public decimal? StopPrice { get { return _stopPrice; } set { if (value.HasValue) { _stopPrice = value.Value.Normalize(); } } } /// /// The current trigger price /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] [ProtoMember(14)] public decimal? TriggerPrice { get { return _triggerPrice; } set { if (value.HasValue) { _triggerPrice = value.Value.Normalize(); } } } /// /// The current limit price /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] [ProtoMember(15)] public decimal? LimitPrice { get { return _limitPrice; } set { if (value.HasValue) { _limitPrice = value.Value.Normalize(); } } } /// /// The current order quantity /// [ProtoMember(16)] public decimal Quantity { get { return _quantity; } set { _quantity = value.Normalize(); } } /// /// True if the order event's option is In-The-Money (ITM) /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] [ProtoMember(17)] public bool IsInTheMoney { get; set; } /// /// The trailing stop amount /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] [ProtoMember(18)] public decimal? TrailingAmount { get { return _trailingAmount; } set { if (value.HasValue) { _trailingAmount = value.Value.Normalize(); } } } /// /// Whether the is a percentage or an absolute currency value /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] [ProtoMember(19)] public bool? TrailingAsPercentage { get { return _trailingAsPercentage; } set { if (value.HasValue) { _trailingAsPercentage = value.Value; } } } /// /// The order ticket associated to the order /// [JsonIgnore] public OrderTicket Ticket { get; set; } /// /// Order Event empty constructor required for json converter /// public OrderEvent() { } /// /// Order Event Constructor. /// /// Id of the parent order /// Asset Symbol /// Date/time of this event /// Status of the order /// The direction of the order this event belongs to /// Fill price information if applicable. /// Fill quantity /// The order fee /// Message from the exchange public OrderEvent(int orderId, Symbol symbol, DateTime utcTime, OrderStatus status, OrderDirection direction, decimal fillPrice, decimal fillQuantity, OrderFee orderFee, string message = "" ) { OrderId = orderId; Symbol = symbol; UtcTime = utcTime; Status = status; Direction = direction; FillPrice = fillPrice; FillPriceCurrency = string.Empty; FillQuantity = fillQuantity; OrderFee = orderFee; Message = message; IsAssignment = false; } /// /// Helper Constructor using Order to Initialize. /// /// Order for this order status /// Date/time of this event /// The order fee /// Message from exchange or QC. public OrderEvent(Order order, DateTime utcTime, OrderFee orderFee, string message = "") { OrderId = order.Id; Symbol = order.Symbol; Status = order.Status; Quantity = order.Quantity; Direction = order.Direction; //Initialize to zero, manually set fill quantity FillQuantity = 0; FillPrice = 0; FillPriceCurrency = order.PriceCurrency; UtcTime = utcTime; OrderFee = orderFee; Message = message; IsAssignment = false; } /// /// Returns a string that represents the current object. /// /// /// A string that represents the current object. /// /// 2 public override string ToString() { return Messages.OrderEvent.ToString(this); } /// /// Returns a short string that represents the current object. /// public string ShortToString() { return Messages.OrderEvent.ShortToString(this); } /// /// Returns a clone of the current object. /// /// The new clone object public OrderEvent Clone() { return (OrderEvent) MemberwiseClone(); } /// /// Creates a new instance based on the provided serialized order event /// public static OrderEvent FromSerialized(SerializedOrderEvent serializedOrderEvent) { var sid = SecurityIdentifier.Parse(serializedOrderEvent.Symbol); var symbol = new Symbol(sid, sid.Symbol); var orderFee = OrderFee.Zero; if (serializedOrderEvent.OrderFeeAmount.HasValue) { orderFee = new OrderFee(new CashAmount(serializedOrderEvent.OrderFeeAmount.Value, serializedOrderEvent.OrderFeeCurrency)); } var orderEvent = new OrderEvent(serializedOrderEvent.OrderId, symbol, DateTime.SpecifyKind(Time.UnixTimeStampToDateTime(serializedOrderEvent.Time), DateTimeKind.Utc), serializedOrderEvent.Status, serializedOrderEvent.Direction, serializedOrderEvent.FillPrice, serializedOrderEvent.FillQuantity, orderFee, serializedOrderEvent.Message) { IsAssignment = serializedOrderEvent.IsAssignment, IsInTheMoney = serializedOrderEvent.IsInTheMoney, LimitPrice = serializedOrderEvent.LimitPrice, StopPrice = serializedOrderEvent.StopPrice, FillPriceCurrency = serializedOrderEvent.FillPriceCurrency, Id = serializedOrderEvent.OrderEventId, Quantity = serializedOrderEvent.Quantity }; return orderEvent; } } }