Overall Statistics |
Total Trades 2 Average Win 2.01% Average Loss -1.18% Compounding Annual Return 99.557% Drawdown 1.400% Expectancy 0.355 Net Profit 0.812% Sharpe Ratio 8.409 Loss Rate 50% Win Rate 50% Profit-Loss Ratio 1.71 Alpha -0.052 Beta 0.991 Annual Standard Deviation 0.049 Annual Variance 0.002 Information Ratio -2.542 Tracking Error 0.022 Treynor Ratio 0.413 Total Fees $4.00 |
namespace QuantConnect { public partial class TestingTrailingOrders : QCAlgorithm { string symbol = "IBM"; RollingWindow<IndicatorDataPoint> priceWindow; TrailingStopOrder trailingOrder; public override void Initialize() { SetStartDate(2013, 1, 14); SetEndDate(2013, 1, 18); SetCash(25000); AddSecurity(SecurityType.Equity, symbol, Resolution.Minute); priceWindow = new RollingWindow<IndicatorDataPoint>(20); } public void OnData(TradeBars data) { priceWindow.Add(new IndicatorDataPoint(Time, data[symbol].Price)); if (!Portfolio.HoldStock) { int quantity = (int)Math.Floor(Portfolio.Cash / data[symbol].Close); Order(symbol, quantity); trailingOrder = FixedTrailingStopOrder(symbol, 0.99m); } if (priceWindow.IsReady) { // trailingOrder = SDTrailingStopOrder(symbol, priceWindow); } } public override void OnOrderEvent(OrderEvent fill) { var order = Transactions.GetOrderById(fill.OrderId); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(Time + " - " + order.Type + " - " + fill.Status + ":: " + fill); Console.ResetColor(); } } }
namespace QuantConnect { /// <summary> /// Method used to trailing the stop loss price. /// </summary> public enum TrailingMethod { FixedPercentage, StandardDeviationStop, // not fully implemented yet // WIP } /// <summary> /// Stop Market Order Type Definition /// </summary> public class TrailingStopOrder { #region Fields and properties /// Algorithm reference for updating orders and logging /// </summary> private readonly QCAlgorithm _algorithm; /// <summary> /// The symbol which this order will track. /// </summary> private string _symbol; /// <summary> /// The fixed percentage to determine the trailing stop price. /// </summary> private decimal _stopPricePercentage; /// <summary> /// The window look-back to estimate the standard deviations stop prices. /// </summary> private int _lookBackWindow; /// <summary> /// The mthod to estimate the standard deviation. /// </summary> private StandardDeviation _sd; /// <summary> /// The StopMarketOrder object to be used. /// </summary> public StopMarketOrder StopOrder; /// <summary> /// Stop price for this stop market order. /// </summary> public decimal StopPrice; /// <summary> /// Is the stop price allowed to move backwards? /// </summary> public bool AllowStopPriceRetreat; /// <summary> /// The trailing method used to determine the stop price. /// </summary> public TrailingMethod trailingMethod; /// <summary> /// Maximum value of the order at is the stop limit price /// </summary> public decimal Value { get { return StopOrder.Quantity * StopOrder.StopPrice; } } #endregion #region Constructor and destructor /// <summary> /// Initializes a new instance of the <see cref="TrailingStopOrder"/> class. /// </summary> /// <param name="algorithm">The actual QCAlgorithm instance.</param> /// <param name="symbol">The symbol we are looking to trade.</param> /// <param name="pricePercentage">The fixed price percentage of the actual price. Should be less than 1 for long position and greater than 1 for short positions.</param> public TrailingStopOrder(QCAlgorithm algorithm, string symbol, decimal pricePercentage) { _algorithm = algorithm; _symbol = symbol; _stopPricePercentage = pricePercentage; trailingMethod = TrailingMethod.FixedPercentage; StopPrice = _algorithm.Portfolio[_symbol].Price * _stopPricePercentage; // the quantity is the negative of the actual positions. int quantity = - _algorithm.Portfolio[_symbol].Quantity; StopOrder = new StopMarketOrder(symbol, quantity, StopPrice, _algorithm.Time); RegisterTrailingOrder(_symbol); } /// <summary> /// Initializes a new instance of the <see cref="TrailingStopOrder"/> class. /// </summary> /// <param name="algorithm">The actual QCAlgorithm instance.</param> /// <param name="symbol">The symbol we are looking to trade.</param> /// <param name="series">A rolling windows with the previous prices to estimate the standar deviation. /// This constructor assumes the RollingWindows observations as the windows lenght to estimate the standar deviation.</param> public TrailingStopOrder(QCAlgorithm algorithm, string symbol, RollingWindow<IndicatorDataPoint> series, bool allowStopPriceRetreat = false) { _algorithm = algorithm; _symbol = symbol; _lookBackWindow = series.Count; trailingMethod = TrailingMethod.StandardDeviationStop; int quantity = -_algorithm.Portfolio[_symbol].Quantity; int direction = (quantity < 0) ? (-1) : (1); InitializeSDBand(_symbol, series, _lookBackWindow); StopPrice = _algorithm.Portfolio[_symbol].Price + _sd * direction; StopOrder = new StopMarketOrder(symbol, quantity, StopPrice, _algorithm.Time); RegisterTrailingOrder(_symbol); } #endregion #region Methods /// <summary> /// Registers the trailing order to receive automatic prices updates. /// </summary> /// <param name="symbol">Symbol asset prices to be updated.</param> private void RegisterTrailingOrder(string symbol) { var consolidator = new IdentityDataConsolidator<TradeBar>(); _algorithm.SubscriptionManager.AddConsolidator(symbol, consolidator); consolidator.DataConsolidated += (sender, consolidated) => { this.ActualizeStopPrice(consolidated.Price); }; } /// <summary> /// Check the order status and dispose the object if is filled. /// If not, estimates the new stop price and update the order if needed. /// </summary> /// <param name="lastPrice">The last price observation.</param> public void ActualizeStopPrice(decimal lastPrice) { decimal newStopPrice; bool stopPriceChanged = false; // If the order is filled, return. if (StopOrder.Status == OrderStatus.Filled) return; switch (trailingMethod) { case TrailingMethod.FixedPercentage: newStopPrice = lastPrice * _stopPricePercentage; stopPriceChanged = CheckNewStopPrice(newStopPrice, stopPriceChanged); break; case TrailingMethod.StandardDeviationStop: int direction = (StopOrder.Direction == OrderDirection.Sell) ? (-1) : (1); newStopPrice = lastPrice + _sd * direction; if (AllowStopPriceRetreat) { StopPrice = newStopPrice; stopPriceChanged = true; } else { stopPriceChanged = CheckNewStopPrice(newStopPrice, stopPriceChanged); } break; } if (stopPriceChanged) ActualizeOrder(StopPrice); } /// <summary> /// Checks the new stop price, and actualize the stop price if correspond. /// </summary> /// <param name="newStopPrice">The new stop price.</param> /// <param name="stopPriceChanged">if set to <c>true</c> [stop price changed].</param> /// <returns></returns> private bool CheckNewStopPrice(decimal newStopPrice, bool stopPriceChanged) { if ((StopOrder.Direction == OrderDirection.Sell && newStopPrice > StopPrice) || (StopOrder.Direction == OrderDirection.Buy && newStopPrice < StopPrice)) { StopPrice = newStopPrice; stopPriceChanged = true; } return stopPriceChanged; } /// <summary> /// Actualizes the order. /// </summary> /// <param name="StopPrice">The updated stop price.</param> private void ActualizeOrder(decimal StopPrice) { StopOrder.StopPrice = StopPrice; // update the order by sending to transaction manager _algorithm.Transactions.UpdateOrder(StopOrder); } /// <summary> /// Initializes the standard deviation indicator used to estimate the trailing stop price. /// </summary> /// <param name="symbol">The symbol.</param> /// <param name="series">The series.</param> /// <param name="lookBackWindow">The look back window.</param> private void InitializeSDBand(string symbol, RollingWindow<IndicatorDataPoint> series, int lookBackWindow) { // Alternative 1: string name = string.Format("SD({0}, {1})", symbol, lookBackWindow.ToString()); _sd = new StandardDeviation(name, lookBackWindow); // Alternative 2: _sd = _algorithm.STD(symbol, lookBackWindow); foreach (IndicatorDataPoint obs in series) { // Here is where I'm stuck. Error: "This is a forward only indicator" _sd.Update(obs); } } #endregion } }
namespace QuantConnect { public partial class TestingTrailingOrders : QCAlgorithm { #region Wrapper methods /// <summary> /// Instantiate a stop trailing order with stop price estiamted as a price fixed percentage. /// </summary> /// <param name="symbol">Symbol asset we're seeking to trade.</param> /// <param name="pricePercentage">The price fixed percentage used to estiamte the stop price.</param> /// <returns>A fixed percentage trailing stop order</returns> public TrailingStopOrder FixedTrailingStopOrder(string symbol, decimal pricePercentage) { var order = new TrailingStopOrder(this, symbol, pricePercentage); Transactions.AddOrder(order.StopOrder); return order; } /// <summary> /// Instantiate a stop trailing order with stop price estiamted as price +/- a standar deviation. /// </summary> /// <param name="symbol">Symbol asset we're seeking to trade.</param> /// <param name="series">Historical prices used to estimate the standar deviation.</param> /// <param name="lookBackWindow">The look back window used to estimate the standar deviation.</param> /// <returns></returns> public TrailingStopOrder SDTrailingStopOrder(string symbol, RollingWindow<IndicatorDataPoint> series) { var order = new TrailingStopOrder(this, symbol, series); Transactions.AddOrder(order.StopOrder); return order; } #endregion } }