| Overall Statistics |
|
Total Trades 3 Average Win 0% Average Loss -1.82% Compounding Annual Return -5.356% Drawdown 33.800% Expectancy -1 Net Profit -5.351% Sharpe Ratio 0.019 Loss Rate 100% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.382 Beta 1.364 Annual Standard Deviation 0.346 Annual Variance 0.12 Information Ratio -0.886 Tracking Error 0.314 Treynor Ratio 0.005 Total Fees $5.10 |
namespace QuantConnect
{
public partial class TestingTrailingOrders : QCAlgorithm
{
string symbol = "IBM";
TrailingStopOrder trailingOrder;
public override void Initialize()
{
SetStartDate(2013, 1, 1);
SetEndDate(2013, 12, 31);
SetCash(25000);
AddSecurity(SecurityType.Equity, symbol, Resolution.Minute);
}
public void OnData(TradeBars data)
{
if (!Portfolio.HoldStock)
{
int quantity = (int)Math.Floor(Portfolio.Cash / data[symbol].Close);
Order(symbol, quantity);
trailingOrder = FixedTrailingStopOrder(symbol, quantity, data[symbol].Price, 0.95m, Time);
}
trailingOrder.ActualizeStopPrice(data[symbol].Price);
if(trailingOrder.StopOrder != null && trailingOrder.StopOrder.Status == OrderStatus.Update)
{
Log(String.Format("Updating {0}", trailingOrder.StopOrder));
Transactions.UpdateOrder(trailingOrder.StopOrder);
}
}
public override void OnOrderEvent(OrderEvent fill)
{
var order = Transactions.GetOrderById(fill.OrderId);
Console.WriteLine(Time + " - " + order.Type + " - " + fill.Status + ":: " + fill);
}
}
}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 // :QCAlgorithm we don't need another algorithm if you need access to the Log function, pass in the algortihm instance
// or for debug you can use Console.WriteLine, or for errors you can use Console.Error.WriteLine
{
#region Fields and properties
/// <summary>
/// Algoritm 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 lookback to estimate the standar deviations stop prices.
/// </summary>
private int _windowLookback;
/// <summary>
/// The StopMarketOrder object to be used.
/// </summary>
public StopMarketOrder StopOrder;
/// <summary>
/// The series history used to estimate the standar deviations stop prices.
/// </summary>
private RollingWindow<decimal> _seriesHistory;
/// <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; // not implemented yet
/// <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="stopOrder">The stop order.</param>
public TrailingStopOrder(QCAlgorithm algorithm, string symbol, int quantity, decimal price, decimal pricePercentage, DateTime time)
{
_symbol = symbol;
_algorithm = algorithm;
_stopPricePercentage = CheckPercentage(quantity, pricePercentage);
trailingMethod = TrailingMethod.FixedPercentage;
StopPrice = price * _stopPricePercentage;
StopOrder = new StopMarketOrder(symbol, quantity, StopPrice, time);
RegisterTrailingOrder(_symbol);
algorithm.Log("Trailing Stop Order ID " + StopOrder.Id + " set for " + _symbol + " at stop price " + StopOrder.StopPrice);
}
public TrailingStopOrder(QCAlgorithm algorithm, string symbol, int quantity, List<decimal> series, int lookBackWindow, DateTime time)
{
_symbol = symbol;
_algorithm = algorithm;
_windowLookback = lookBackWindow;
_seriesHistory = new RollingWindow<decimal>(_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);
RegisterTrailingOrder(_symbol);
}
#endregion
#region Methods
/// <summary>
/// Registers the trailing order to recieve automatic prices updates.
/// </summary>
/// <param name="symbol">Symbol asset prices to be updated.</param>
private void RegisterTrailingOrder(string symbol)
{
// create and register the consolidator for updates
var consolidator = new IdentityDataConsolidator<TradeBar>();
_algorithm.SubscriptionManager.AddConsolidator(symbol, consolidator);
consolidator.DataConsolidated += (sender, consolidated) =>
{
// if we always change the stop every single time to the close value
// then it will always execute immediately!!
this.ActualizeOrder(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 priceChanged = false;
// If the order is filled, dispose the instance.
if (StopOrder.Status == OrderStatus.Filled)
{
//this.Dispose();
return;
}
switch (trailingMethod)
{
case TrailingMethod.FixedPercentage:
newStopPrice = lastPrice * _stopPricePercentage;
if ((StopOrder.Direction == OrderDirection.Buy && newStopPrice > StopPrice) ||
(StopOrder.Direction == OrderDirection.Sell && newStopPrice < StopPrice))
{
StopPrice = newStopPrice;
priceChanged = true;
}
break;
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;
}
if (priceChanged) ActualizeOrder(StopPrice);
}
/// <summary>
/// Actualizes the order.
/// </summary>
/// <param name="StopPrice">The updated stop price.</param>
private void ActualizeOrder(decimal StopPrice)
{
decimal newPrice;
if (StopOrder.Direction == OrderDirection.Buy)
{
// when buying we want the lowest price
newPrice = Math.Min(StopOrder.StopPrice, StopPrice);
}
else
{
// when selling we want the highest price
newPrice = Math.Max(StopOrder.StopPrice, StopPrice);
}
StopOrder.StopPrice = StopPrice;
// update the order by sending to transaction manager
_algorithm.Transactions.UpdateOrder(StopOrder);
_algorithm.Log("Trailing Stop Order ID " + StopOrder.Id + " for " + _symbol + " update stop price to " + StopOrder.StopPrice);
}
/// <summary>
/// Gets or sets the stop price percentage, adjusting the value if needed.
/// </summary>
/// <value>
/// The stop price percentage.
/// </value>
private decimal CheckPercentage(int quantity, decimal pricePercentage)
{
if (quantity > 0 && pricePercentage > 1m) return pricePercentage - 1m;
else if (quantity < 0 && pricePercentage < 1m) return pricePercentage + 1m;
else return pricePercentage;
}
/// <summary>
/// Estimates the standar deviation of the historical prices.
/// </summary>
/// <param name="seriesHistory">The price series history.</param>
/// <returns></returns>
/// <exception cref="System.NotImplementedException"></exception>
private decimal EstimateSDBand(RollingWindow<decimal> seriesHistory)
{
throw new NotImplementedException();
}
#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="quantity">Quantity of the asset we're seeking to trade.</param>
/// <param name="price">The actual symbol's price.</param>
/// <param name="pricePercentage">The price fixed percentage used to estiamte the stop price.</param>
/// <param name="time">Time the order was placed.</param>
/// <returns>A trailing stop order</returns>
public TrailingStopOrder FixedTrailingStopOrder(string symbol, int quantity, decimal price, decimal pricePercentage, DateTime time)
{
var order = new TrailingStopOrder(this, symbol, quantity, price, pricePercentage, time);
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="quantity">Quantity of the 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>
/// <param name="time">Time the order was placed.</param>
/// <returns></returns>
public TrailingStopOrder SDTrailingStopOrder(string symbol, int quantity, List<decimal> series, int lookBackWindow, DateTime time)
{
var order = new TrailingStopOrder(this, symbol, quantity, series, lookBackWindow, time);
Transactions.AddOrder(order.StopOrder);
return order;
}
#endregion
}
}