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