Overall Statistics
Total Trades
445
Average Win
0.04%
Average Loss
-0.03%
Compounding Annual Return
-64.362%
Drawdown
1.200%
Expectancy
-0.180
Net Profit
-0.967%
Sharpe Ratio
-11.449
Loss Rate
69%
Win Rate
31%
Profit-Loss Ratio
1.62
Alpha
-0.61
Beta
1.838
Annual Standard Deviation
0.053
Annual Variance
0.003
Information Ratio
-13.183
Tracking Error
0.046
Treynor Ratio
-0.332
Total Fees
$445.00
namespace QuantConnect 
{   
    class MultisymbolAlgorithm : QCAlgorithm
    {

        #region "Variables"

        private DateTime startTime = DateTime.Now;
        private DateTime _startDate = new DateTime(2015, 8, 11);
        private DateTime _endDate = new DateTime(2015, 8, 14);
        private decimal _portfolioAmount = 25000;

        /* +-------------------------------------------------+
         * |Algorithm Control Panel                          |
         * +-------------------------------------------------+*/
        private static int SMAPeriod = 22;            // Instantaneous Trend period.
        private static decimal Tolerance = 0.0001m;      // Trigger - Trend crossing tolerance.
        private static decimal RevertPCT = 1.0015m;     // Percentage tolerance before revert position.
        private static decimal maxLeverage = 1m;        // Maximum Leverage.
        private decimal leverageBuffer = 0.25m;         // Percentage of Leverage left unused.
        private int maxOperationQuantity = 500;         // Maximum shares per operation.
        private decimal RngFac = 0.35m;                 // Percentage of the bar range used to estimate limit prices.
        private bool noOvernight = true;                // Close all positions before market close.
        /* +-------------------------------------------------+*/

        string[] symbolarray = new string[] {"AAPL", "NFLX", "AMZN", "SPY"};
        List<Symbol> Symbols = new List<Symbol>();

        // Dictionary used to store the RSIStrategy object for each symbol.
        private Dictionary<string, MultiSymbolStrategy> Strategy = new Dictionary<string, MultiSymbolStrategy>();

        // Dictionary used to store the portfolio sharesize for each symbol.
        private Dictionary<string, decimal> ShareSize = new Dictionary<string, decimal>();

        private EquityExchange theMarket = new EquityExchange();



        #endregion

        public override void Initialize()
        {
            SetStartDate(_startDate);       //Set Start Date
            SetEndDate(_endDate);           //Set End Date
            SetCash(_portfolioAmount);      //Set Strategy Cash

            foreach (string t in symbolarray)
            {
                Symbols.Add(new Symbol(t));
            }

            foreach (string symbol in Symbols)
            {
                AddSecurity(SecurityType.Equity, symbol, Resolution.Minute);
                var priceIdentity = Identity(symbol, selector: Field.Close);

                Strategy.Add(symbol, new MultiSymbolStrategy(priceIdentity, SMAPeriod, Tolerance, RevertPCT));

                // Equally weighted portfolio.
                ShareSize.Add(symbol, (maxLeverage * (1 - leverageBuffer)) / Symbols.Count());
            }

        }

        public void OnData(TradeBars data)
        {
            bool isMarketAboutToClose = !theMarket.DateTimeIsOpen(Time.AddMinutes(10));
            OrderSignal actualOrder = OrderSignal.doNothing;

            
            foreach (string symbol in Symbols)
            {
                // Operate only if the market is open
                if (theMarket.DateTimeIsOpen(Time))
                {
                    // First check if there are some limit orders not filled yet.
                    if (Transactions.LastOrderId > 0)
                    {
                        CheckLimitOrderStatus(symbol);
                    }
                    // Check if the market is about to close and noOvernight is true.
                    if (noOvernight && isMarketAboutToClose)
                    {
                        actualOrder = ClosePositions(symbol);
                    }
                    else
                    {
                        // Now check if there is some signal and execute the strategy.
                        actualOrder = Strategy[symbol].ActualSignal;
                    }
                    ExecuteStrategy(symbol, actualOrder);
                }
            }
        }

        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            string symbol = orderEvent.Symbol;
            int portfolioPosition = Portfolio[symbol].Quantity;
            var actualTicket = Transactions.GetOrderTickets(t => t.OrderId == orderEvent.OrderId).Single();
            var actualOrder = Transactions.GetOrderById(orderEvent.OrderId);

            switch (orderEvent.Status)
            {
                case OrderStatus.Submitted:
                    Strategy[symbol].Position = StockState.orderSent;
                    Log("New order submitted: " + actualOrder.ToString());
                    break;

                case OrderStatus.PartiallyFilled:
                    Log("Order partially filled: " + actualOrder.ToString());
                    Log("Canceling order");
                    actualTicket.Cancel();
                    //do { }
                    //while (actualTicket.GetMostRecentOrderResponse().IsSuccess);
                    goto case OrderStatus.Filled;

                case OrderStatus.Filled:
                    if (portfolioPosition > 0) Strategy[symbol].Position = StockState.longPosition;
                    else if (portfolioPosition < 0) Strategy[symbol].Position = StockState.shortPosition;
                    else Strategy[symbol].Position = StockState.noInvested;

                    Strategy[symbol].EntryPrice = actualTicket.AverageFillPrice;

                    Log("Order filled: " + actualOrder.ToString());
                    break;

                case OrderStatus.Canceled:
                    Log("Order successfully canceled: " + actualOrder.ToString());
                    break;

                default:
                    break;
            }
        }

        /// <summary>
        /// Checks if the limits order are filled, and updates the ITrenStrategy object and the
        /// LastOrderSent dictionary.
        /// If the limit order aren't filled, then cancels the order and send a market order.
        /// </summary>
        /// <param name="symbol">The symbol.</param>
        /// <param name="lastOrder">The last order.</param>
        private void CheckLimitOrderStatus(string symbol)
        {
            // Pick the submitted limit tickets for the symbol.
            var actualSubmittedTicket = Transactions.GetOrderTickets(t => t.Symbol == symbol
                                                              && t.OrderType == OrderType.Limit
                                                              && t.Status == OrderStatus.Submitted);
            // If there is none, return.
            if (actualSubmittedTicket.Count() == 0) return;
            // if there is more than one, stop the algorithm, something is wrong.
            else if (actualSubmittedTicket.Count() != 1) throw new ApplicationException("More than one submitted limit order");

            Log("||| Cancel Limit order and send a market order");
            // Now, define the ticket to handle the actual OrderTicket.
            var actualTicket = actualSubmittedTicket.Single();
            // Retrieve the operation quantity. 
            int shares = actualTicket.Quantity;
            // Cancel the order.
            actualTicket.Cancel();
            // Send a market order.
            MarketOrder(symbol, shares);
        }
        private OrderSignal ClosePositions(string symbol)
        {
            OrderSignal actualOrder;
            if (Strategy[symbol].Position == StockState.longPosition) actualOrder = OrderSignal.closeLong;
            else if (Strategy[symbol].Position == StockState.shortPosition) actualOrder = OrderSignal.closeShort;
            else actualOrder = OrderSignal.doNothing;
            return actualOrder;
        }
        /// <summary>
        /// Executes the ITrend strategy orders.
        /// </summary>
        /// <param name="symbol">The symbol to be traded.</param>
        /// <param name="actualOrder">The actual order to be execute.</param>
        /// <param name="data">The actual TradeBar data.</param>
        private void ExecuteStrategy(string symbol, OrderSignal actualOrder)
        {
            // Define the operation size.
            int shares = PositionShares(symbol, actualOrder);

            switch (actualOrder)
            {
                case OrderSignal.goLong:
                case OrderSignal.goShort:
                case OrderSignal.goLongLimit:
                case OrderSignal.goShortLimit:
                    Log("===> Entry to Market");
                    decimal limitPrice;
                    var barPrices = Securities[symbol];

                    // Define the limit price.
                    if (actualOrder == OrderSignal.goLong ||
                        actualOrder == OrderSignal.goLongLimit)
                    {
                        limitPrice = Math.Max(barPrices.Low,
                                    (barPrices.Close - (barPrices.High - barPrices.Low) * RngFac));
                    }
                    else
                    {
                        limitPrice = Math.Min(barPrices.High,
                                    (barPrices.Close + (barPrices.High - barPrices.Low) * RngFac));
                    }
                    // Send the order.
                    LimitOrder(symbol, shares, limitPrice);
                    break;

                case OrderSignal.closeLong:
                case OrderSignal.closeShort:
                    Log("<=== Closing Position");
                    // Send the order.
                    MarketOrder(symbol, shares);
                    break;

                case OrderSignal.revertToLong:
                case OrderSignal.revertToShort:
                    Log("<===> Reverting Position");
                    // Send the order.
                    MarketOrder(symbol, shares);
                    break;

                default: break;
            }
        }
        /// <summary>
        /// Estimate number of shares, given a kind of operation.
        /// </summary>
        /// <param name="symbol">The symbol to operate.</param>
        /// <param name="order">The kind of order.</param>
        /// <returns>The signed number of shares given the operation.</returns>
        public int PositionShares(string symbol, OrderSignal order)
        {
            int quantity;
            int operationQuantity;

            switch (order)
            {
                case OrderSignal.goLong:
                case OrderSignal.goLongLimit:
                    operationQuantity = CalculateOrderQuantity(symbol, ShareSize[symbol]);
                    quantity = Math.Min(maxOperationQuantity, operationQuantity);
                    break;

                case OrderSignal.goShort:
                case OrderSignal.goShortLimit:
                    operationQuantity = CalculateOrderQuantity(symbol, -ShareSize[symbol]);
                    quantity = Math.Max(-maxOperationQuantity, operationQuantity);
                    break;

                case OrderSignal.closeLong:
                case OrderSignal.closeShort:
                    quantity = -Portfolio[symbol].Quantity;
                    break;

                case OrderSignal.revertToLong:
                case OrderSignal.revertToShort:
                    quantity = -2 * Portfolio[symbol].Quantity;
                    break;

                default:
                    quantity = 0;
                    break;
            }
            return quantity;
        }
    }

}
namespace QuantConnect {
    class MultiSymbolStrategy : BaseStrategy
    {
        #region Fields

        private decimal _tolerance;
        private decimal _revertPCT;
        private RevertPositionCheck _checkRevertPosition;

        #region made public for debug

        public bool TriggerCrossOverITrend = false;
        public bool TriggerCrossUnderITrend = false;
        public bool ExitFromLong = false;
        public bool ExitFromShort = false;

        Indicator _price;
        public SimpleMovingAverage sma;
        public Momentum SMAMomentum;
        public RollingWindow<decimal> MomentumWindow;

        #endregion made public for debug


        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ITrendStrategy"/> class.
        /// </summary>
        /// <param name="period">The period of the Instantaneous trend.</param>
        public MultiSymbolStrategy(Indicator price, int period, decimal tolerance = 0.001m, decimal revetPct = 1.0015m,
            RevertPositionCheck checkRevertPosition = RevertPositionCheck.vsTrigger)
        {
            _price = price;
            sma = new SimpleMovingAverage(period).Of(price);
            SMAMomentum = new Momentum(2).Of(sma);
            MomentumWindow = new RollingWindow<decimal>(2);

            Position = StockState.noInvested;
            EntryPrice = null;
            ActualSignal = OrderSignal.doNothing;

            _tolerance = tolerance;
            _revertPCT = revetPct;
            _checkRevertPosition = checkRevertPosition;

            

            SMAMomentum.Updated += (object sender, IndicatorDataPoint updated) =>
            {
                if (SMAMomentum.IsReady) MomentumWindow.Add(SMAMomentum.Current.Value);
                if (MomentumWindow.IsReady) CheckSignal();
            };
        }


        #endregion Constructors
        #region Methods

        /// <summary>
        /// Checks If the strategy throws a operation signal.
        /// </summary>
        /// <returns>An OrderSignal with the proper actualSignal to operate.</returns>
        public override void CheckSignal()
        {
            TriggerCrossOverITrend = MomentumWindow[1] < 0 &&
                                     MomentumWindow[0] > 0 &&
                                     Math.Abs(MomentumWindow[0] - MomentumWindow[1]) >= _tolerance;

            TriggerCrossUnderITrend = MomentumWindow[1] > 0 &&
                                      MomentumWindow[0] < 0 &&
                                      Math.Abs(MomentumWindow[0] - MomentumWindow[1]) >= _tolerance;

            if (_checkRevertPosition == RevertPositionCheck.vsTrigger)
            {
                ExitFromLong = (EntryPrice != null) ? sma + SMAMomentum < EntryPrice / _revertPCT : false;
                ExitFromShort = (EntryPrice != null) ? sma + SMAMomentum > EntryPrice * _revertPCT : false;
            }
            else if (_checkRevertPosition == RevertPositionCheck.vsClosePrice)
            {
                ExitFromLong = (EntryPrice != null) ? _price < EntryPrice / _revertPCT : false;
                ExitFromShort = (EntryPrice != null) ? _price > EntryPrice * _revertPCT : false;
            }

            OrderSignal actualSignal;

            switch (Position)
            {
                case StockState.noInvested:
                    if (TriggerCrossOverITrend) actualSignal = OrderSignal.goLongLimit;
                    else if (TriggerCrossUnderITrend) actualSignal = OrderSignal.goShortLimit;
                    else actualSignal = OrderSignal.doNothing;
                    break;

                case StockState.longPosition:
                    if (TriggerCrossUnderITrend) actualSignal = OrderSignal.closeLong;
                    else if (ExitFromLong) actualSignal = OrderSignal.revertToShort;
                    else actualSignal = OrderSignal.doNothing;
                    break;

                case StockState.shortPosition:
                    if (TriggerCrossOverITrend) actualSignal = OrderSignal.closeShort;
                    else if (ExitFromShort) actualSignal = OrderSignal.revertToLong;
                    else actualSignal = OrderSignal.doNothing;
                    break;

                default: actualSignal = OrderSignal.doNothing;
                    break;
            }
            ActualSignal = actualSignal;
        }

        public void Reset()
        {
            // Not resetting the ITrend increases returns
            sma.Reset();
            SMAMomentum.Reset();
            MomentumWindow.Reset();
        }

        #endregion Methods
 
    }

}
namespace QuantConnect {

    public interface IStrategy
    {      
        /// <summary>
        /// Checks the for signals.
        /// </summary>
        /// <returns></returns>
        void CheckSignal();
    }

    public abstract class BaseStrategy : IStrategy
    {
        /// <summary>
        /// Indicates what is the actual investing status for the strategy.
        /// </summary>
        public StockState Position;

        /// <summary>
        /// In case the strategy has an position taken, this is the entry price. Null otherwise.
        /// </summary>
        public Nullable<decimal> EntryPrice;

        /// <summary>
        /// The actual signal.
        /// </summary>
        public OrderSignal ActualSignal;

        /// <summary>
        /// Checks the for signals.
        /// </summary>
        public abstract void CheckSignal();
    }
}
namespace QuantConnect {

    public enum StockState
    {
        shortPosition,  // The Portfolio has short position in this bar.
        longPosition,   // The Portfolio has long position in this bar.
        noInvested,     // The Portfolio hasn't any position in this bar.
        orderSent       // An order has been sent in this same bar, skip analysis.
    };

    public enum OrderSignal
    {
        goShort, goLong,                // Entry to the market orders.
        goShortLimit, goLongLimit,      // Entry with limit order.
        closeShort, closeLong,          // Exit from the market orders.
        revertToShort, revertToLong,    // Reverse a position when in the wrong side of the trade.
        doNothing
    };

    public enum RevertPositionCheck
    {
        vsTrigger,
        vsClosePrice,
    }

    public enum PositionInventoryMethod
    {
        Lifo, Fifo
    }

}