/*
* 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;
}
}
}