Overall Statistics |
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio NaN Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha NaN Beta NaN Annual Standard Deviation 0 Annual Variance 0 Information Ratio NaN Tracking Error NaN Treynor Ratio NaN Total Fees $0.00 |
namespace QuantConnect { using System; using System.Linq; using QuantConnect.Data.Market; using QuantConnect.Indicators; using QuantConnect.Orders; using QuantConnect.Securities; using QuantConnect.Util; /* * QuantConnect University: Full Basic Template: * * The underlying QCAlgorithm class is full of helper methods which enable you to use QuantConnect. * We have explained some of these here, but the full algorithm can be found at: * https://github.com/QuantConnect/QCAlgorithm/blob/master/QuantConnect.Algorithm/QCAlgorithm.cs */ public class InstantaneousTrendAlgorithm : QCAlgorithm { private DateTime _startDate = new DateTime(2015, 8, 19); private DateTime _endDate = new DateTime(2015, 8, 25); private decimal _portfolioAmount = 22000; private string symbol = "AAPL"; private int barcount = 0; private RollingWindow<IndicatorDataPoint> Price; private InstantaneousTrend trend; private RollingWindow<IndicatorDataPoint> trendHistory; private RollingWindow<IndicatorDataPoint> trendTrigger; // Strategy private InstantTrendStrategy iTrendStrategy; private bool shouldSellOutAtEod = true; private int orderId = 0; private int tradesize; //Initialize the data and resolution you require for your strategy: public override void Initialize() { //Initialize dates SetStartDate(_startDate); SetEndDate(_endDate); SetCash(_portfolioAmount); //Add as many securities as you like. All the data will be passed into the event handler: AddSecurity(SecurityType.Equity, symbol, Resolution.Minute); // Indicators Price = new RollingWindow<IndicatorDataPoint>(14); // The price history // ITrend trend = new InstantaneousTrend(7); trendHistory = new RollingWindow<IndicatorDataPoint>(14); trendTrigger = new RollingWindow<IndicatorDataPoint>(14); // The ITrendStrategy iTrendStrategy = new InstantTrendStrategy(symbol, 14, this); iTrendStrategy.ShouldSellOutAtEod = shouldSellOutAtEod; } //Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol. public void OnData(TradeBars data) { barcount++; // Add the history for the bar var time = data.Time; Price.Add(idp(time, (data[symbol].Close + data[symbol].Open) / 2)); // Update the indicators trend.Update(idp(time, Price[0].Value)); trendHistory.Add(idp(time, trend.Current.Value)); //add last iteration value for the cycle trendTrigger.Add(idp(time, trend.Current.Value)); if (barcount == 1) { tradesize = (int)(Portfolio.Cash / Convert.ToInt32(Price[0].Value + 1)); } // iTrendStrategy starts on bar 3 because it uses trendHistory[0] - trendHistory[3] if (barcount < 7 && barcount > 2) { trendHistory[0].Value = (Price[0].Value + 2 * Price[1].Value + Price[2].Value) / 4; } if (barcount > 2) { trendTrigger[0].Value = 2 * trendHistory[0].Value - trendHistory[2].Value; } Strategy(data); if (data.Time.Hour == 16) { trend.Reset(); trendHistory.Reset(); trendTrigger.Reset(); barcount = 0; Plot("Strategy Equity", "Portfolio", Portfolio.TotalPortfolioValue); } } /// <summary> /// Run the strategy associated with this algorithm /// </summary> /// <param name="data">TradeBars - the data received by the OnData event</param> private void Strategy(TradeBars data) { string comment = string.Empty; #region "Strategy Execution" if (SellOutEndOfDay(data)) { iTrendStrategy.Barcount = barcount; // for debugging // if there were limit order tickets to cancel, wait a bar to execute the strategy if (!CanceledUnfilledLimitOrder()) comment = iTrendStrategy.ExecuteStrategy(data, tradesize, trend.Current, trendTrigger[0]); } #endregion } /// <summary> /// If the order did not fill within one bar, cancel it and assume the market moved away from the limit order /// </summary> private bool CanceledUnfilledLimitOrder() { #region "Unfilled Limit Orders" bool retval = false; var tickets = Transactions.GetOrderTickets(t => !t.Status.IsClosed()); if (tickets != null && tickets.Any()) { foreach (var ticket in tickets) { ticket.Cancel(); retval = true; } } #endregion return retval; } /// <summary> /// Handle order events /// </summary> /// <param name="orderEvent">the order event</param> public override void OnOrderEvent(OrderEvent orderEvent) { base.OnOrderEvent(orderEvent); ProcessOrderEvent(orderEvent); } /// <summary> /// Local processing of the order event /// </summary> /// <param name="orderEvent">OrderEvent - the order event</param> private void ProcessOrderEvent(OrderEvent orderEvent) { orderId = orderEvent.OrderId; var tickets = Transactions.GetOrderTickets(t => t.OrderId == orderId); if (tickets.Any()) { foreach (OrderTicket ticket in tickets) { var status = ticket.Status; if (ticket.Status == OrderStatus.Canceled) { iTrendStrategy.orderFilled = false; } if (ticket.Status == OrderStatus.Filled) { iTrendStrategy.orderFilled = true; if (Portfolio[orderEvent.Symbol].Invested) { iTrendStrategy.nEntryPrice = orderEvent.FillPrice; } } } } } public bool SellOutEndOfDay(TradeBars data) { if (shouldSellOutAtEod) { if (data.Time.Hour == 15 && data.Time.Minute > 49 || data.Time.Hour == 16) { if (Portfolio[symbol].IsLong) { Sell(symbol, Portfolio[symbol].AbsoluteQuantity); } if (Portfolio[symbol].IsShort) { Buy(symbol, Portfolio[symbol].AbsoluteQuantity); } return false; } } return true; } /// <summary> /// Convenience function which creates an IndicatorDataPoint /// </summary> /// <param name="time">DateTime - the bar time for the IndicatorDataPoint</param> /// <param name="value">decimal - the value for the IndicatorDataPoint</param> /// <returns>a new IndicatorDataPoint</returns> /// <remarks>I use this function to shorten the a Add call from /// new IndicatorDataPoint(data.Time, value) /// Less typing.</remarks> private IndicatorDataPoint idp(DateTime time, decimal value) { return new IndicatorDataPoint(time, value); } } }
namespace QuantConnect { using System; /// <summary> /// InstanteaousTrend Indicator /// </summary> public class InstantaneousTrend : WindowIndicator<IndicatorDataPoint> { // the alpha for the formula private readonly decimal a = 0.5m; private readonly int _period; private readonly RollingWindow<IndicatorDataPoint> _trend; private readonly RollingWindow<IndicatorDataPoint> _price; private int barcount; /// <summary> /// /// </summary> /// <param name="name"></param> /// <param name="period"></param> public InstantaneousTrend(string name, int period) : base(name, period) { // InstantaneousTrend history _trend = new RollingWindow<IndicatorDataPoint>(period); _price = new RollingWindow<IndicatorDataPoint>(period); _period = period; barcount = 0; } /// <summary> /// Default constructor /// </summary> /// <param name="period">int - the number of periods in the indicator warmup</param> public InstantaneousTrend(int period) : this("CCy" + period, period) { } /// <summary> /// Gets a flag indicating when this indicator is ready and fully initialized /// </summary> public override bool IsReady { get { return _trend.IsReady; } } /// <summary> /// Calculates the next value for the ITrend /// </summary> /// <param name="window">the window for this indicator</param> /// <param name="input">the latest price to input into the trend</param> /// <returns>the computed value</returns> protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input) { // for convenience var time = input.Time; _price.Add(input); if (barcount < _period) { _trend.Add(input); } else { // Calc the low pass filter _trend value and add it to the _trend var lfp = (a - ((a / 2) * (a / 2))) * input.Value + ((a * a) / 2) * _price[1].Value - (a - (3 * (a * a) / 4)) * _price[2].Value + 2 * (1 - a) * _trend[0].Value - ((1 - a) * (1 - a)) * _trend[1].Value; _trend.Add(idp(time, lfp)); } barcount++; return _trend[0].Value; } /// <summary> /// Factory function which creates an IndicatorDataPoint /// </summary> /// <param name="time">DateTime - the bar time for the IndicatorDataPoint</param> /// <param name="value">decimal - the value for the IndicatorDataPoint</param> /// <returns>a new IndicatorDataPoint</returns> /// <remarks>I use this function to shorten the a Add call from /// new IndicatorDataPoint(data.Time, value) /// Less typing.</remarks> private IndicatorDataPoint idp(DateTime time, decimal value) { return new IndicatorDataPoint(time, value); } } }
namespace QuantConnect { using System; using QuantConnect.Data.Market; using QuantConnect.Indicators; using QuantConnect.Orders; /// <summary> /// From Ehlers Cybernetics page 27 on Trading the trend /// </summary> public class InstantTrendStrategy { /// <summary> /// The entry price for the latest trade /// </summary> public decimal nEntryPrice { get; set; } public int Barcount { get; set; } private bool bReverseTrade = false; private string _symbol { get; set; } private decimal RevPct = 1.0025m; private decimal RngFac = .35m; private decimal nLimitPrice = 0; private int nStatus = 0; private int xOver = 0; private RollingWindow<IndicatorDataPoint> trendHistory; /// <summary> /// Flag to determine if the algo should go flat overnight. /// </summary> public bool ShouldSellOutAtEod; /// <summary> /// the Algorithm being run. /// </summary> public QCAlgorithm _algorithm; /// <summary> /// The flag as to whether the order has been filled. /// </summary> public Boolean orderFilled { get; set; } /// <summary> /// Constructor initializes the symbol and period of the RollingWindow /// </summary> /// <param name="symbol">string - ticker symbol</param> /// <param name="period">int - the period of the Trend History Rolling Window</param> /// <param name="algorithm"></param> public InstantTrendStrategy(string symbol, int period, QCAlgorithm algorithm) { _symbol = symbol; trendHistory = new RollingWindow<IndicatorDataPoint>(period); _algorithm = algorithm; orderFilled = true; } /// <summary> /// Executes the Instant Trend strategy /// </summary> /// <param name="data">TradeBars - the current OnData</param> /// <param name="tradesize"></param> /// <param name="trendCurrent">IndicatorDataPoint - the current trend value trend</param> /// <param name="triggerCurrent">IndicatorDataPoint - the current trigger</param> public string ExecuteStrategy(TradeBars data, int tradesize, IndicatorDataPoint trendCurrent, IndicatorDataPoint triggerCurrent) { OrderTicket ticket; string comment = string.Empty; trendHistory.Add(trendCurrent); nStatus = 0; if (_algorithm.Portfolio[_symbol].IsLong) nStatus = 1; if (_algorithm.Portfolio[_symbol].IsShort) nStatus = -1; if (!trendHistory.IsReady) { return "Trend Not Ready"; } if (!SellOutEndOfDay(data)) { #region "Strategy Execution" bReverseTrade = false; try { var nTrig = 2 * trendHistory[0].Value - trendHistory[2].Value; if (nStatus == 1 && nTrig < (nEntryPrice / RevPct)){ comment = string.Format("Long Reverse to short. Close < {0} / {1}", nEntryPrice, RevPct); ticket = ReverseToShort(); orderFilled = ticket.OrderId > 0; bReverseTrade = true; } else { if (nStatus == -1 && nTrig > (nEntryPrice * RevPct)) { comment = string.Format("Short Reverse to Long. Close > {0} * {1}", nEntryPrice, RevPct); ticket = ReverseToLong(); orderFilled = ticket.OrderId > 0; bReverseTrade = true; } } if (!bReverseTrade) { if (nTrig > trendHistory[0].Value) { if (xOver == -1 && nStatus != 1) { if (!orderFilled) { ticket = _algorithm.Buy(_symbol, tradesize); comment = string.Format("Enter Long after cancel trig xover price up"); } else { nLimitPrice = Math.Max(data[_symbol].Low, (data[_symbol].Close - (data[_symbol].High - data[_symbol].Low) * RngFac)); ticket = _algorithm.LimitOrder(_symbol, tradesize, nLimitPrice, "Long Limit"); comment = string.Format("Enter Long Limit trig xover price up", nLimitPrice); } } if (comment.Length == 0) comment = "Trigger over Trend"; xOver = 1; } else { if (nTrig < trendHistory[0].Value) { if (xOver == 1 && nStatus != -1) { if (!orderFilled) { ticket = _algorithm.Sell(_symbol, tradesize); comment = string.Format("Enter Short after cancel trig xunder price down"); } else { nLimitPrice = Math.Min(data[_symbol].High, (data[_symbol].Close + (data[_symbol].High - data[_symbol].Low) * RngFac)); ticket = _algorithm.LimitOrder(_symbol, -tradesize, nLimitPrice, "Short Limit"); comment = string.Format("Enter Short Limit at {0} trig xover price down", nLimitPrice); } } if (comment.Length == 0) comment = "Trigger under trend"; xOver = -1; } } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.StackTrace); } #endregion } return comment; } private OrderTicket ReverseToLong() { nLimitPrice = 0; nStatus = 1; return _algorithm.Buy(_symbol, _algorithm.Portfolio[_symbol].Quantity * 2); } private OrderTicket ReverseToShort() { nLimitPrice = 0; nStatus = -1; return _algorithm.Sell(_symbol, _algorithm.Portfolio[_symbol].Quantity * 2); } private bool SellOutEndOfDay(TradeBars data) { if (ShouldSellOutAtEod) { if (data.Time.Hour == 15 && data.Time.Minute > 55 || data.Time.Hour == 16) { if (_algorithm.Portfolio[_symbol].IsLong) { _algorithm.Sell(_symbol, _algorithm.Portfolio[_symbol].AbsoluteQuantity); } if (_algorithm.Portfolio[_symbol].IsShort) { _algorithm.Buy(_symbol, _algorithm.Portfolio[_symbol].AbsoluteQuantity); } return true; } } return false; } } }