| 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
}
}