/* * 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 Newtonsoft.Json; using QuantConnect.Interfaces; namespace QuantConnect.Orders { /// /// Trailing Stop Order Type Definition /// public class TrailingStopOrder : StopMarketOrder { /// /// Trailing amount for this trailing stop order /// [JsonProperty(PropertyName = "trailingAmount")] public decimal TrailingAmount { get; internal set; } /// /// Determines whether the is a percentage or an absolute currency value /// [JsonProperty(PropertyName = "trailingAsPercentage")] public bool TrailingAsPercentage { get; internal set; } /// /// StopLimit Order Type /// public override OrderType Type { get { return OrderType.TrailingStop; } } /// /// Default constructor for JSON Deserialization: /// public TrailingStopOrder() { } /// /// New Trailing Stop Market Order constructor /// /// Symbol asset being traded /// Quantity of the asset to be traded /// Initial stop price at which the order should be triggered /// The trailing amount to be used to update the stop price /// Whether the is a percentage or an absolute currency value /// Time the order was placed /// User defined data tag for this order /// The properties for this order public TrailingStopOrder(Symbol symbol, decimal quantity, decimal stopPrice, decimal trailingAmount, bool trailingAsPercentage, DateTime time, string tag = "", IOrderProperties properties = null) : base(symbol, quantity, stopPrice, time, tag, properties) { TrailingAmount = trailingAmount; TrailingAsPercentage = trailingAsPercentage; } /// /// New Trailing Stop Market Order constructor. /// It creates a new Trailing Stop Market Order with an initial stop price calculated by subtracting (for a sell) or adding (for a buy) the /// trailing amount to the current market price. /// /// Symbol asset being traded /// Quantity of the asset to be traded /// The trailing amount to be used to update the stop price /// Whether the is a percentage or an absolute currency value /// Time the order was placed /// User defined data tag for this order /// The properties for this order public TrailingStopOrder(Symbol symbol, decimal quantity, decimal trailingAmount, bool trailingAsPercentage, DateTime time, string tag = "", IOrderProperties properties = null) : this(symbol, quantity, 0, trailingAmount, trailingAsPercentage, time, tag, properties) { } /// /// Gets the default tag for this order /// /// The default tag public override string GetDefaultTag() { return Messages.TrailingStopOrder.Tag(this); } /// /// Modifies the state of this order to match the update request /// /// The request to update this order object public override void ApplyUpdateOrderRequest(UpdateOrderRequest request) { base.ApplyUpdateOrderRequest(request); if (request.TrailingAmount.HasValue) { TrailingAmount = request.TrailingAmount.Value; } } /// /// Returns a string that represents the current object. /// /// /// A string that represents the current object. /// /// 2 public override string ToString() { return Messages.TrailingStopOrder.ToString(this); } /// /// Creates a deep-copy clone of this order /// /// A copy of this order public override Order Clone() { var order = new TrailingStopOrder { StopPrice = StopPrice, TrailingAmount = TrailingAmount, TrailingAsPercentage = TrailingAsPercentage }; CopyTo(order); return order; } /// /// Tries to update the stop price for a trailing stop order given the current market price /// /// The current market price /// The current trailing stop order stop price /// The trailing amount to be used to update the stop price /// Whether the is a percentage or an absolute currency value /// The order direction /// The updated stop price /// /// Whether the stop price was updated. /// This only happens when the distance between the current stop price and the current market price is greater than the trailing amount, /// which will happen when the market price raises/falls for sell/buy orders respectively. /// public static bool TryUpdateStopPrice(decimal currentMarketPrice, decimal currentStopPrice, decimal trailingAmount, bool trailingAsPercentage, OrderDirection direction, out decimal updatedStopPrice) { updatedStopPrice = 0m; var distanceToMarketPrice = direction == OrderDirection.Sell ? currentMarketPrice - currentStopPrice : currentStopPrice - currentMarketPrice; var stopReference = trailingAsPercentage ? currentMarketPrice * trailingAmount : trailingAmount; if (distanceToMarketPrice <= stopReference) { return false; } updatedStopPrice = CalculateStopPrice(currentMarketPrice, trailingAmount, trailingAsPercentage, direction); return true; } /// /// Calculates the stop price for a trailing stop order given the current market price /// /// The current market price /// The trailing amount to be used to update the stop price /// Whether the is a percentage or an absolute currency value /// The order direction /// The stop price for the order given the current market price public static decimal CalculateStopPrice(decimal currentMarketPrice, decimal trailingAmount, bool trailingAsPercentage, OrderDirection direction) { if (trailingAsPercentage) { return direction == OrderDirection.Buy ? currentMarketPrice * (1 + trailingAmount) : currentMarketPrice * (1 - trailingAmount); } return direction == OrderDirection.Buy ? currentMarketPrice + trailingAmount : currentMarketPrice - trailingAmount; } } }