The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
using System;
using System.Collections;
using System.Collections.Generic;
using QuantConnect.Orders;
using QuantConnect.Indicators;
namespace QuantConnect
{
///
/// Method used to trailing the stop loss price.
///
public enum TrailingMethod
{
FixedPercentage,
StandardDeviationStop,
// More comming soon!
}
///
/// Stop Market Order Type Definition
///
public class TrailingStopOrder
{
///
/// The fixed percentage to determine the trailing stop price.
///
private decimal _stopPricePercentage;
///
/// The window lookback to estimate the standar deviations stop prices
///
private int _windowLookback;
///
/// The StopMarket order to be used.
///
private StopMarketOrder _stopOrder;
///
/// The series history used to estimate the
///
private RollingWindow _seriesHistory;
///
/// Stop price for this stop market order.
///
public decimal StopPrice;
///
/// Signal showing the "StopLimitOrder" has been converted into a Limit Order
///
public bool StopTriggered = false;
///
/// Is the stop price allowed to move backwards?
///
public bool AllowStopPriceRetreat;
///
/// The trailing method used to determine the stop price.
///
public TrailingMethod trailingMethod;
///
/// Gets or sets the stop price percentage, adjusting if is needed.
///
///
/// The stop price percentage.
///
public decimal StopPricePercentage
{
get { return _stopPricePercentage; }
set
{
if (_stopOrder.Direction == OrderDirection.Buy && value > 1m) _stopPricePercentage = value - 1m;
if (_stopOrder.Direction == OrderDirection.Sell && value < 1m) _stopPricePercentage = value + 1m;
}
}
///
/// Maximum value of the order at is the stop limit price
///
public override decimal Value
{
get { return _stopOrder.Quantity * StopPrice; }
}
///
/// Initializes a new instance of the class.
///
/// The stop order.
private TrailingStopOrder(StopMarketOrder stopOrder);
///
/// Fixeds the trailing stop order.
///
/// Symbol asset we're seeking to trade
/// Quantity of the asset we're seeking to trade
/// The actual symbol's price.
/// The price fixed percentage used to estiamte the stop price.
/// Time the order was placed
/// A trailing stop order
public TrailingStopOrder FixedTrailingStopOrder(string symbol, int quantity, decimal price, decimal pricePercentage, DateTime time)
{
StopPricePercentage = pricePercentage;
trailingMethod = TrailingMethod.FixedPercentage;
StopPrice = price * _stopPricePercentage;
_stopOrder = new StopMarketOrder(symbol, quantity, StopPrice, time);
return new TrailingStopOrder(_stopOrder);
}
public TrailingStopOrder SDTrailingStopOrder(string symbol, int quantity, List series, int lookBackWindow, DateTime time)
{
_windowLookback = lookBackWindow;
_seriesHistory = new RollingWindow(_windowLookback);
foreach (decimal seriesValue in series)
{
_seriesHistory.Add(seriesValue);
}
decimal SDBand = EstimateSDBand(_seriesHistory);
StopPrice = (quantity > 0) ? series[series.Count] - SDBand : series[series.Count] + SDBand;
_stopOrder = new StopMarketOrder(symbol, quantity, StopPrice, time);
return new TrailingStopOrder(_stopOrder);
}
///
///
///
/// The last price.
///
private void ActualizeStopPrice(decimal lastPrice)
{
decimal newStopPrice;
bool priceChanged = false;
switch (trailingMethod)
{
case TrailingMethod.StandardDeviationStop:
_seriesHistory.Add(lastPrice);
decimal SDBand = EstimateSDBand(_seriesHistory);
decimal direction = (_stopOrder.Direction == OrderDirection.Buy) ? new decimal(-1) : new decimal(1);
StopPrice = lastPrice + SDBand * direction;
priceChanged = true;
break;
case TrailingMethod.FixedPercentage:
newStopPrice = lastPrice * _stopPricePercentage;
if ((_stopOrder.Direction == OrderDirection.Buy && newStopPrice > StopPrice) ||
(_stopOrder.Direction == OrderDirection.Sell && newStopPrice < StopPrice))
{
StopPrice = newStopPrice;
priceChanged = true;
}
break;
}
if (priceChanged) ActualizeOrder(StopPrice);
}
private decimal EstimateSDBand(RollingWindow _seriesHistory)
{
throw new NotImplementedException();
}
private void ActualizeOrder(decimal StopPrice)
{
_stopOrder.StopPrice = StopPrice;
}
}
}
consolidator.DataConsolidated += (sender, consolidated) =>
{
// do something with our 'consolidated' data, such as update stop prices
};
2013-01-02 09:31:00 01/02/2013 09:31:00 - Market - Submitted:: OrderID: 1 Symbol: IBM Status: Submitted
2013-01-02 09:31:00 01/02/2013 09:31:00 - Market - Filled:: OrderID: 1 Symbol: IBM Status: Filled Quantity: 136 FillPrice: 183.377433816
2013-01-02 09:31:00 01/02/2013 09:31:00 - StopMarket - Submitted:: OrderID: 2 Symbol: IBM Status: Submitted
2013-01-02 09:31:00 01/02/2013 09:31:00 - StopMarket - Filled:: OrderID: 2 Symbol: IBM Status: Filled Quantity: 136 FillPrice: 183.377433816
Transactions.AddOrder(order.StopOrder)
in the wrappers methods?StopOrder = null;
StopOrder = new ... ;
. This makes sure you no longer reference the old object and it can be disposed by garbage collector if possible. However, orders will not be disposed because they are stored by transaction manager. And that's ok. I think you have a 10000 order limit at the moment, and I believe eventually we'll have an ability to clear the cache on demand....write a FuncStopOrder type which accepts a function! Then people could create their own functions to decide the stop price.
This doesn't seem to work any more. Are there any updates with this? Been integrated into core perhaps?
@Levi; Now orders are disconnected from order tickets. The algorithm "requests" and order, and you get a ticket for the request which you can cancel or update directly. This didn't affect 99% of people but you're right it does break this algorithm.
We split it up because the transactions handler who processes the orders and the algorithm are on different threads. If you were to modify the order directly it can cause cross threading issues and kill an algorithm.
As such; the actual order isn't really used in the same sense anymore. Its a system of order tickets and order requests. You can submit a create-request, update-request and cancel-request. The order is tracked with its ticket.
You could tweak this to get it working I think? Theres no reason why you can't have a order ticket being updated to implement the trailing stop. See here for how to do it.
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
@Levi,
@Jared already gave you a great answer. Just in case, here is a strategy with an implementation of a trailing stop loss; however I'm not sure that strategy still works.
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can
continue your Boot Camp training progress from the terminal. We
hope to see you in the community soon!