Overall Statistics
Total Trades
5088
Average Win
0.17%
Average Loss
-0.33%
Compounding Annual Return
114.443%
Drawdown
6.300%
Expectancy
0.095
Net Profit
118.059%
Sharpe Ratio
3.675
Loss Rate
28%
Win Rate
72%
Profit-Loss Ratio
0.53
Alpha
1.32
Beta
-41.643
Annual Standard Deviation
0.174
Annual Variance
0.03
Information Ratio
3.58
Tracking Error
0.174
Treynor Ratio
-0.015
Total Fees
$19158.71
using QuantConnect.Data.Market;
using QuantConnect.Orders;
using QuantConnect.Orders.Fills;
using QuantConnect.Securities;
using System;
using System.Linq;

namespace QuantConnect.Algorithm.CSharp
{
    public sealed class ImmediateOptimisticStopFillModel : ImmediateFillModel
    {
        /// <summary>
        /// Default limit order fill model in the base security class.
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="StopMarketFill(Security, StopMarketOrder)"/>
        /// <seealso cref="MarketFill(Security, MarketOrder)"/>
        public override OrderEvent LimitFill(Security asset, LimitOrder order)
        {
            //Initialise;
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled) return fill;

            //Get the range of prices in the last bar:
            var prices = GetPrices(asset, order.Direction);

            //-> Valid Live/Model Order: 
            switch (order.Direction)
            {
                case OrderDirection.Buy:
                    //Buy limit seeks lowest price
                    if (prices.Low < order.LimitPrice)
                    {
                        //Set order fill:
                        fill.Status = OrderStatus.Filled;
                        // fill at the worse price this bar or the limit price, this allows far out of the money limits
                        // to be executed properly
                        fill.FillPrice = order.LimitPrice;
                    }
                    break;
                case OrderDirection.Sell:
                    //Sell limit seeks highest price possible
                    if (prices.High > order.LimitPrice)
                    {
                        fill.Status = OrderStatus.Filled;
                        // fill at the worse price this bar or the limit price, this allows far out of the money limits
                        // to be executed properly
                        fill.FillPrice = order.LimitPrice;
                    }
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }

        /// <summary>
        /// Default stop fill model implementation in base class security. (Stop Market Order Type)
        /// </summary>
        /// <param name="asset">Security asset we're filling</param>
        /// <param name="order">Order packet to model</param>
        /// <returns>Order fill information detailing the average price and quantity filled.</returns>
        /// <seealso cref="MarketFill(Security, MarketOrder)"/>
        /// <seealso cref="SecurityTransactionModel.LimitFill"/>
        public override OrderEvent StopMarketFill(Security asset, StopMarketOrder order)
        {
            //Default order event to return.
            var utcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
            var fill = new OrderEvent(order, utcTime, 0);

            // make sure the exchange is open before filling
            if (!IsExchangeOpen(asset)) return fill;

            //If its cancelled don't need anymore checks:
            if (order.Status == OrderStatus.Canceled) return fill;

            //Get the range of prices in the last bar:
            var prices = GetPrices(asset, order.Direction);

            //Calculate the model slippage: e.g. 0.01c
            var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);

            //Check if the Stop Order was filled: opposite to a limit order
            switch (order.Direction)
            {
                case OrderDirection.Sell:
                    //-> 1.1 Sell Stop: If Price below setpoint, Sell:
                    if (prices.Low < order.StopPrice)
                    {
                        fill.Status = OrderStatus.Filled;
                        fill.FillPrice = order.StopPrice - slip;
                    }
                    break;

                case OrderDirection.Buy:
                    //-> 1.2 Buy Stop: If Price Above Setpoint, Buy:
                    if (prices.High > order.StopPrice)
                    {
                        fill.Status = OrderStatus.Filled;
                        fill.FillPrice = order.StopPrice + slip;
                    }
                    break;
            }

            // assume the order completely filled
            if (fill.Status == OrderStatus.Filled)
            {
                fill.FillQuantity = order.Quantity;
                fill.OrderFee = asset.FeeModel.GetOrderFee(asset, order);
            }

            return fill;
        }

        /// <summary>
        /// Get the minimum and maximum price for this security in the last bar:
        /// </summary>
        /// <param name="asset">Security asset we're checking</param>
        /// <param name="direction">The order direction, decides whether to pick bid or ask</param>
        private Prices GetPrices(Security asset, OrderDirection direction)
        {
            var low = asset.Low;
            var high = asset.High;
            var open = asset.Open;
            var close = asset.Close;
            var current = asset.Price;

            if (direction == OrderDirection.Hold)
            {
                return new Prices(current, open, high, low, close);
            }

            // Only fill with data types we are subscribed to
            var subscriptionTypes = asset.Subscriptions.Select(x => x.Type).ToList();

            // Tick
            var tick = asset.Cache.GetData<Tick>();
            if (subscriptionTypes.Contains(typeof(Tick)) && tick != null)
            {
                var price = direction == OrderDirection.Sell ? tick.BidPrice : tick.AskPrice;
                if (price != 0m)
                {
                    return new Prices(price, 0, 0, 0, 0);
                }

                // If the ask/bid spreads are not available for ticks, try the price
                price = tick.Price;
                if (price != 0m)
                {
                    return new Prices(price, 0, 0, 0, 0);
                }
            }

            // Quote
            var quoteBar = asset.Cache.GetData<QuoteBar>();
            if (subscriptionTypes.Contains(typeof(QuoteBar)) && quoteBar != null)
            {
                var bar = direction == OrderDirection.Sell ? quoteBar.Bid : quoteBar.Ask;
                if (bar != null)
                {
                    return new Prices(bar);
                }
            }

            // Trade
            var tradeBar = asset.Cache.GetData<TradeBar>();
            if (subscriptionTypes.Contains(typeof(TradeBar)) && tradeBar != null)
            {
                return new Prices(tradeBar);
            }

            return new Prices(current, open, high, low, close);
        }

        /// <summary>
        /// Determines if the exchange is open using the current time of the asset
        /// </summary>
        private static bool IsExchangeOpen(Security asset)
        {
            if (!asset.Exchange.DateTimeIsOpen(asset.LocalTime))
            {
                // if we're not open at the current time exactly, check the bar size, this handle large sized bars (hours/days)
                var currentBar = asset.GetLastData();
                if (asset.LocalTime.Date != currentBar.EndTime.Date || !asset.Exchange.IsOpenDuringBar(currentBar.Time, currentBar.EndTime, false))
                {
                    return false;
                }
            }
            return true;
        }

        private class Prices
        {
            public readonly decimal Current;
            public readonly decimal Open;
            public readonly decimal High;
            public readonly decimal Low;
            public readonly decimal Close;

            public Prices(IBar bar)
                : this(bar.Close, bar.Open, bar.High, bar.Low, bar.Close)
            {
            }

            public Prices(decimal current, decimal open, decimal high, decimal low, decimal close)
            {
                Current = current;
                Open = open == 0 ? current : open;
                High = high == 0 ? current : high;
                Low = low == 0 ? current : low;
                Close = close == 0 ? current : close;
            }
        }
    }
}
using QuantConnect.Securities;
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Orders;
using QuantConnect.Orders.Fills;
using QuantConnect.Orders.Slippage;

namespace QuantConnect.Algorithm.CSharp
{
    public partial class GapReversalAlgorithm : QCAlgorithm
    {
        private const decimal _minGapSize = 0.25m / 100;
        private const Resolution _resolution = Resolution.Minute;
        private const decimal _leverage = 4;
        private const decimal _maxAllocations = 3;
        private const decimal _maxLongShortImbalance = 100000; //1
        private const decimal _allocationSize = 0.25m;
        private const int _universeSize = 100;
        private const decimal _simSlippage = 0;//0.063m / 100;

        private readonly Dictionary<Symbol, Tradable> _tradables = new Dictionary<Symbol, Tradable>();
        private SlippageMeasurement _slippageMeasurement;
        private IFillModel _fillModel;
        private ISlippageModel _slippageModel;

        private decimal _allocationsToday;
        private decimal _longShortBalanceToday;

        private static GapReversalAlgorithm _instance;

        public override void Initialize()
        {
            SetCash(100000);
            SetStartDate(2017, 1, 1);
            //SetEndDate(2017, 1, 1);

            _instance = this;
            _slippageMeasurement = new SlippageMeasurement(this, 50);
            _fillModel = new ImmediateOptimisticStopFillModel();

            var slippageModel = new OrderTypeDependentSlippageModel(new ConstantSlippageModel(0));
            slippageModel.MarketOrderSlippage = new ConstantSlippageModel(_simSlippage);
            slippageModel.MarketOnCloseOrderSlippage = new ConstantSlippageModel(_simSlippage);
            slippageModel.MarketOnOpenOrderSlippage = new ConstantSlippageModel(_simSlippage);
            slippageModel.StopMarketOrderSlippage = new ConstantSlippageModel(_simSlippage);
            _slippageModel = slippageModel;

            if (LiveMode)
                _createUniverse = false;

            var someSecurity = AddEquity("SPY", _resolution, leverage: _leverage);

            Schedule.On(DateRules.EveryDay(someSecurity.Symbol), TimeRules.BeforeMarketClose(someSecurity.Symbol, 10), ClosePositions);
            Schedule.On(DateRules.EveryDay(someSecurity.Symbol), TimeRules.AfterMarketOpen(someSecurity.Symbol, -1), PrepareForNewDay);

            if (LiveMode)
            {
                Schedule.On(DateRules.EveryDay(someSecurity.Symbol), TimeRules.Every(TimeSpan.FromMinutes(1)), PrintSlippage);
            }

            SetUpUniverse();
        }

        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
            foreach (var change in changes.RemovedSecurities)
            {
                _tradables.Remove(change.Symbol);
            }

            foreach (var change in changes.AddedSecurities)
            {
                if (!_tradables.ContainsKey(change.Symbol))
                {
                    var tradable = new Tradable(change);
                    _tradables[change.Symbol] = tradable;
                }
            }
        }

        public override void OnEndOfAlgorithm()
        {
            _slippageMeasurement.Process();
            Log(_slippageMeasurement.ToString());
        }

        public override void OnEndOfDay()
        {
            if (LiveMode)
            {
                _slippageMeasurement.Process();
                Log(_slippageMeasurement.ToString());
            }
        }

        private void PrintSlippage()
        {
            _slippageMeasurement.Process();

            SetRuntimeStatistic("Slippage %", _slippageMeasurement.GetMeanSlippage().ToString("P3"));
            SetRuntimeStatistic("Slippage SD", _slippageMeasurement.GetStandardDeviationOfSlippage().ToString("P3"));
        }

        public override void OnData(Slice slice)
        {
            foreach (var bar in slice.Bars)
            {
                Tradable tradable;
                if (_tradables.TryGetValue(bar.Key, out tradable))
                {
                    tradable.OnData(bar.Value, false);
                }
            }

            _slippageMeasurement.Process();
        }

        public override void OnOrderEvent(OrderEvent orderEvent)
        {
            Tradable tradable;
            if (_tradables.TryGetValue(orderEvent.Symbol, out tradable))
            {
                tradable.OnOrderEventAsync(orderEvent);
            }
        }

        private void PrepareForNewDay()
        {
            _allocationsToday = 0;
            _longShortBalanceToday = 0;
        }

        private decimal RequestAllocationToday(int dir)
        {
            if (_allocationsToday >= _maxAllocations)
                return 0;

            if (Math.Abs(_longShortBalanceToday + dir) > _maxLongShortImbalance)
                return 0;

            _longShortBalanceToday += dir;
            _allocationsToday += _allocationSize;
            if (LiveMode)
            {
                _instance.SetRuntimeStatistic("Alloc", _allocationsToday);
                _instance.SetRuntimeStatistic("Bal", _longShortBalanceToday);
            }
                
            return _allocationSize;
        }

        private void ClosePositions()
        {
            foreach (var tradable in _tradables.Values)
                tradable.ExitBeforeClose();

            Liquidate();
        }

        private class Tradable
        {
            public readonly Security Security;

            public Symbol Symbol { get { return Security.Symbol; } }

            private readonly RollingWindow<Gap> _gaps = new RollingWindow<Gap>(2);
            private readonly StandardDeviationOverflowSafe _std = new StandardDeviationOverflowSafe(60 * 7 * 2);

            private decimal _allocation;
            private bool _hasPosition;
            private bool _canEnter = false;

            private sealed class Gap
            {
                public readonly decimal Open;
                public readonly decimal PrevClose;
                public decimal Change
                {
                    get { return Open / PrevClose - 1; }
                }

                public Gap(decimal open, decimal close)
                {
                    Open = open;
                    PrevClose = close;
                }
            }

            public Tradable(Security sec)
            {
                Security = sec;

                sec.FillModel = _instance._fillModel;
                sec.SlippageModel = _instance._slippageModel;

                foreach (var bar in _instance.History(Symbol, TimeSpan.FromDays(5), _resolution))
                {
                    OnData(bar, true);
                }
            }

            public Tradable(string ticker)
                : this(_instance.AddEquity(ticker, _resolution, leverage: _leverage))
            {

            }

            private decimal _lastClose;
            private DateTime _lastBar;
            private bool _anyBar;
            public void OnData(TradeBar bar, bool warmup)
            {
                if (!_anyBar)
                {
                    _anyBar = true;
                }
                if (bar.Time.Day != _lastBar.Day || _lastBar == DateTime.MinValue)
                {
                    _lastBar = bar.Time;
                    OnNewDay(bar, warmup);
                }

                _std.Update(_instance.Time, bar.Close);

                bool gapClosed = false;
                int dir = -Math.Sign(_gaps[0].Change);
                if (dir > 0)
                {
                    if (bar.Close >= _gaps[0].PrevClose)
                    {
                        gapClosed = true;
                    }
                }
                else if (dir < 0)
                {
                    if (bar.Close <= _gaps[0].PrevClose)
                    {
                        gapClosed = true;
                    }
                }

                /*if (_hasPosition)
                {
                    if (gapClosed)
                    {
                        _hasPosition = false;
                        _instance.Liquidate(Symbol);
                        //TODO: relinquish allocation?
                    }
                }
                else*/
                if (!_hasPosition && _canEnter)
                {
                    if (gapClosed)
                        _canEnter = false;

                    if (_canEnter && _allocation == 0)
                    {
                        _canEnter = false;

                        TryEnter(dir, bar.Close);
                    }
                }

                _lastClose = bar.Close;
            }

            private decimal _targetLevel;
            private decimal _stopLevel;
            private OrderTicket _entryTicket;
            private OrderTicket _stopTicket;
            private OrderTicket _exitTicket;

            private void TryEnter(int dir, decimal price)
            {
                decimal proposedStop = price - dir * _std * 3;
                if (!(proposedStop >= price * 0.75m && proposedStop <= price / 0.75m))
                    return; //also catches NaN

                _allocation = _instance.RequestAllocationToday(dir);
                if (_allocation <= 0)
                    return;

                _hasPosition = true;
                _targetLevel = _gaps[0].PrevClose;
                _stopLevel = proposedStop;

                //_instance.SetHoldings(Symbol, dir * _allocation);

                var qty = _instance.CalculateOrderQuantity(Symbol, dir * _allocation);
                if (qty == 0)
                    return;

                //decimal limitPrice = price * (1 - dir * _minGapSize);

                if (_instance.LiveMode)
                    _instance.Log("Enter: " + qty + " " + Symbol.ToString() + " at " + _targetLevel + " stopped at " + _stopLevel);
                _entryTicket = _instance.MarketOrder(Symbol, qty, true, "Entry");
                _instance._slippageMeasurement.NewOrder(_entryTicket);
            }

            public void OnOrderEventAsync(OrderEvent ev)
            {
                if (ev.Status == OrderStatus.Filled)
                {
                    if (_entryTicket != null && ev.OrderId == _entryTicket.OrderId)
                    {
                        var qty = -ev.FillQuantity;

                        _exitTicket = _instance.LimitOrder(Symbol, qty, _targetLevel, "Exit");
                        _instance._slippageMeasurement.NewOrder(_exitTicket);
                        _stopTicket = _instance.StopMarketOrder(Symbol, qty, _stopLevel, "Stop");
                        _instance._slippageMeasurement.NewOrder(_stopTicket);
                    }
                    else if (_exitTicket != null && ev.OrderId == _exitTicket.OrderId)
                    {
                        if (_stopTicket != null)
                            _stopTicket.Cancel();
                    }
                    else if (_stopTicket != null && ev.OrderId == _stopTicket.OrderId)
                    {
                        if (_exitTicket != null)
                            _exitTicket.Cancel();
                    }
                }

                _instance._slippageMeasurement.OnOrderEventAsync(ev);
            }

            private void OnNewDay(TradeBar bar, bool warmup)
            {
                if (_lastClose == 0)
                    _lastClose = bar.Open;

                _gaps.Add(new Gap(bar.Open, _lastClose));

                if (_gaps.IsReady && !warmup)
                {
                    //hardcoded rule now for testing
                    var change1 = _gaps[0].Change;
                    var change2 = _gaps[1].Change;
                    _canEnter = Math.Sign(change1) == Math.Sign(change2);
                    if (_canEnter)
                    {
                        _canEnter = Math.Abs(change1 + change2) > 2 * _minGapSize &&
                            Math.Abs(change1) > _minGapSize && Math.Abs(change2) > _minGapSize;
                    }
                }
            }

            public void ExitBeforeClose()
            {
                try
                {
                    if (_hasPosition)
                    {
                        //_instance.Liquidate(Symbol);
                    }
                }
                finally
                {
                    _canEnter = false;
                    _hasPosition = false;
                    _allocation = 0;
                    _entryTicket = null;
                    _stopTicket = null;
                    _exitTicket = null;
                }
            }
        }
    }
}
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

using QuantConnect.Indicators;
using System;

namespace QuantConnect.Algorithm.CSharp
{
    /// <summary>
    /// This indicator computes the n-period population standard deviation.
    /// </summary>
    public class StandardDeviationOverflowSafe : Variance
    {
        /// <summary>
        /// Initializes a new instance of the StandardDeviation class with the specified period.
        /// 
        /// Evaluates the standard deviation of samples in the lookback period. 
        /// On a dataset of size N will use an N normalizer and would thus be biased if applied to a subset.
        /// </summary>
        /// <param name="period">The sample size of the standard deviation</param>
        public StandardDeviationOverflowSafe(int period)
            : this("STD" + period, period)
        {
        }

        /// <summary>
        /// Initializes a new instance of the StandardDeviation class with the specified name and period.
        /// 
        /// Evaluates the standard deviation of samples in the lookback period. 
        /// On a dataset of size N will use an N normalizer and would thus be biased if applied to a subset.
        /// </summary>
        /// <param name="name">The name of this indicator</param>
        /// <param name="period">The sample size of the standard deviation</param>
        public StandardDeviationOverflowSafe(string name, int period)
            : base(name, period)
        {
        }

        /// <summary>
        /// Gets a flag indicating when this indicator is ready and fully initialized
        /// </summary>
        public override bool IsReady
        {
            get { return Samples >= Period; }
        }

        /// <summary>
        /// Computes the next value of this indicator from the given state
        /// </summary>
        /// <param name="input">The input given to the indicator</param>
        /// <param name="window">The window for the input history</param>
        /// <returns>A new value for this indicator</returns>
        protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input)
        {
            double val = Math.Sqrt((double)base.ComputeNextValue(window, input));
            return (decimal)val.Clamp(_min, _max);
        }

        private static readonly double _max = (double)decimal.MaxValue * 0.01;
        private static readonly double _min = (double)decimal.MinValue * 0.01;
    }
}
using System;
using System.Collections.Generic;
using System.Reflection;

namespace QuantConnect.Algorithm.CSharp
{
    public static class Xtend
    {
        public static FieldInfo GetPrivateField(Type type, string name)
        {
            return type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance);
        }

        public static FieldInfo GetPrivateField<MyType>(this MyType dummy, string name)
        {
            return GetPrivateField(typeof(MyType), name);
        }

        public static object GetPrivateFieldValue(Type type, object instance, string name)
        {
            var fieldInfo = GetPrivateField(type, name);
            if (fieldInfo == null)
                throw new InvalidOperationException("Unable to find field with name " + name);
            return fieldInfo.GetValue(instance);
        }

        public static object GetPrivateFieldValue<MyType>(this MyType instance, string name)
        {
            return GetPrivateFieldValue(typeof(MyType), instance, name);
        }

        public static T Clamp<T>(this T val, T min, T max) where T : IComparable
        {
            XMath.Clamp(ref val, min, max);
            return val;
        }

        public static void Shuffle<T>(this IList<T> list, Random rng)
        {
            int n = list.Count;
            while (n > 1)
            {
                n--;
                int k = rng.Next(n + 1);
                T value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }

        public static int Argmax(this IList<int> list)
        {
            int maxIndex = list.Count - 1;
            var max = list[maxIndex];
            for (int index = list.Count - 2; index >= 0; --index)
            {
                var x = list[index];
                if (x > max)
                {
                    maxIndex = index;
                    max = x;
                }
            }

            return maxIndex;
        }

        public static int Argmin(this IList<int> list)
        {
            int minIndex = list.Count - 1;
            var min = list[minIndex];
            for (int index = list.Count - 2; index >= 0; --index)
            {
                var x = list[index];
                if (x < min)
                {
                    minIndex = index;
                    min = x;
                }
            }

            return minIndex;
        }

        public static int Argmax(this IList<double> list)
        {
            int maxIndex = list.Count - 1;
            var max = list[maxIndex];
            for (int index = list.Count - 2; index >= 0; --index)
            {
                var x = list[index];
                if (x > max)
                {
                    maxIndex = index;
                    max = x;
                }
            }

            return maxIndex;
        }

        public static int Argmin(this IList<double> list)
        {
            int minIndex = list.Count - 1;
            var min = list[minIndex];
            for (int index = list.Count - 2; index >= 0; --index)
            {
                var x = list[index];
                if (x < min)
                {
                    minIndex = index;
                    min = x;
                }
            }

            return minIndex;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QuantConnect.Algorithm.CSharp
{
    public static class XMath
    {
        public static bool IsPowerOfTwo(ulong x)
        {
            return (x & (x - 1)) == 0;
        }

        public static int Log2(int v)
        {
            int r = 0xFFFF - v >> 31 & 0x10;
            v >>= r;
            int shift = 0xFF - v >> 31 & 0x8;
            v >>= shift;
            r |= shift;
            shift = 0xF - v >> 31 & 0x4;
            v >>= shift;
            r |= shift;
            shift = 0x3 - v >> 31 & 0x2;
            v >>= shift;
            r |= shift;
            r |= (v >> 1);
            return r;
        }

        public static void Clamp<T>(ref T val, T min, T max) where T : IComparable
        {
            if (min.CompareTo(val) > 0)
                val = min;
            else if (max.CompareTo(val) < 0)
                val = max;
        }
    }
}
using MathNet.Numerics.Statistics;
using QuantConnect.Indicators;
using QuantConnect.Orders;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace QuantConnect.Algorithm.CSharp
{
    sealed class SlippageMeasurement
    {
        private const int _numOrderTypes = 7;

        private readonly QCAlgorithm _algo;
        
        private sealed class OrderInfo
        {
            public OrderType Type;
            public int Dir;
            public decimal PriceAtIssue;
            public decimal VolumeFilled;
            public decimal DollarVolumeFilled;

            public decimal AverageFillPrice
            {
                get
                {
                    return DollarVolumeFilled / VolumeFilled;
                }
            }

            public decimal SlippageInPrice
            {
                get
                {
                    return -Dir * (AverageFillPrice - PriceAtIssue);
                }
            }

            public decimal SlippageAsFraction
            {
                get { return SlippageInPrice / PriceAtIssue; }
            }
        }

        private readonly ConcurrentDictionary<int, OrderInfo> _orders = new ConcurrentDictionary<int, OrderInfo>();
        private readonly ConcurrentQueue<OrderEvent> _orderEvents = new ConcurrentQueue<OrderEvent>();

        private readonly RollingWindow<OrderInfo>[] _statWindow;

        public SlippageMeasurement(QCAlgorithm algo, int windowSize)
        {
            _algo = algo;

            _statWindow = new RollingWindow<OrderInfo>[(_numOrderTypes + 1) * 3 + 1]; //(orderType + anyOrderType) * (direction + anyDirection) + any

            for (int i = 0; i < _statWindow.Length; ++i)
            {
                _statWindow[i] = new RollingWindow<OrderInfo>(windowSize);
            }
        }

        private RollingWindow<OrderInfo> GetStatWindow(int orderType = -1, int dir = 0)
        {
            if (orderType < -1)
                throw new ArgumentException("orderType");

            if (orderType < 0 && dir < 0)
                return _statWindow[0];

            return _statWindow[1 + (1 + orderType) * 3 + (1 + dir)];
        }

        public void NewOrder(Order order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            decimal priceAtIssue = _algo.Securities[order.Symbol].Price;
            if (order is StopMarketOrder)
                priceAtIssue = ((StopMarketOrder)order).StopPrice;
            else if (order is StopLimitOrder)
                priceAtIssue = ((StopLimitOrder)order).LimitPrice;
            else if (order is LimitOrder)
                priceAtIssue = ((LimitOrder)order).LimitPrice;

            NewOrder(order.Id, order.Direction == OrderDirection.Buy? 1 : -1, priceAtIssue, order.Type);
        }

        public void NewOrder(OrderTicket order)
        {
            if (order == null)
                throw new ArgumentNullException("order");

            decimal priceAtIssue = _algo.Securities[order.Symbol].Price;
            if (order.OrderType == OrderType.StopMarket)
            {
                priceAtIssue = order.SubmitRequest.StopPrice;
            }
            else if (order.OrderType == OrderType.Limit || order.OrderType == OrderType.StopLimit)
            {
                priceAtIssue = order.SubmitRequest.LimitPrice;
            }

            NewOrder(order.OrderId, Math.Sign(order.Quantity), priceAtIssue, order.OrderType);
        }

        public void NewOrder(int orderId, int direction, decimal priceAtIssue, OrderType type)
        {
            if ((int)type >= _numOrderTypes)
                throw new ArgumentException("Order type " + type.ToString() + " has too high enum value", "type");

            _orders[orderId] = new OrderInfo()
            {
                Type = type,
                Dir = direction,
                PriceAtIssue = priceAtIssue,
            };
        }

        private void OnFill(int orderId, decimal quantity, decimal actualPrice)
        {
            OrderInfo orderInfo;
            if (_orders.TryGetValue(orderId, out orderInfo))
            {
                orderInfo.VolumeFilled += quantity;
                orderInfo.DollarVolumeFilled += quantity * actualPrice;
            }
        }

        private void OnOrderClosed(int orderId)
        {
            OrderInfo orderInfo;
            if (_orders.TryRemove(orderId, out orderInfo))
            {
                if (orderInfo.VolumeFilled > 0)
                {
                    RecordOrder(orderInfo);
                }
            }
        }

        public void OnOrderEventAsync(OrderEvent ev)
        {
            _orderEvents.Enqueue(ev);
        }

        public void Process()
        {
            OrderEvent ev;
            while (_orderEvents.TryDequeue(out ev))
            {
                if (ev.Status == OrderStatus.PartiallyFilled || ev.Status == OrderStatus.Filled)
                {
                    OnFill(ev.OrderId, ev.AbsoluteFillQuantity, ev.FillPrice);
                }

                if (ev.Status.IsClosed())
                {
                    OnOrderClosed(ev.OrderId);
                }
            }
        }

        private void RecordOrder(OrderInfo orderInfo)
        {
            GetStatWindow().Add(orderInfo);
            GetStatWindow((int)orderInfo.Type).Add(orderInfo);
            GetStatWindow(-1, orderInfo.Dir).Add(orderInfo);
            GetStatWindow((int)orderInfo.Type, orderInfo.Dir).Add(orderInfo);
        }

        public override string ToString()
        {
            var builder = new StringBuilder();

            builder.AppendLine("Slippage % Mean VW Std:");
            PrintStatLine("All", builder, GetStatWindow());
            PrintStatLine("Buy", builder, GetStatWindow(-1, 1));
            PrintStatLine("Sell", builder, GetStatWindow(-1, -1));

            for (int i = 0; i < _numOrderTypes; ++i)
            {
                var type = (OrderType)i;
                PrintStatLine(type.ToString(), builder, GetStatWindow(i));
            }

            for (int i = 0; i < _numOrderTypes; ++i)
            {
                var type = (OrderType)i;
                for (int dir = -1; dir < 1; ++dir)
                {
                    if (dir == 0)
                        dir = 1;

                    PrintStatLine(type.ToString() + (dir == 1? " Buy" : " Sell"), builder, GetStatWindow(i, dir));
                }
            }

            return builder.ToString();
        }

        private static double GetMean(IEnumerable<OrderInfo> window)
        {
            return window.Select(x => (double)x.SlippageAsFraction).Average();
        }

        private static double GetVolumeWeighted(IEnumerable<OrderInfo> window)
        {
            double totalDollarVolume = window.Sum(x => (double)x.DollarVolumeFilled);
            double volumeWeighted = totalDollarVolume > 0 ? window.Select(x => (double)x.SlippageAsFraction * (double)x.DollarVolumeFilled).Sum() / totalDollarVolume : 0;
            return volumeWeighted;
        }

        private static double GetStandardDeviation(IEnumerable<OrderInfo> window)
        {
            return window.Select(x => (double)x.SlippageAsFraction).StandardDeviation();
        }

        private static void PrintStatLine(string caption, StringBuilder builder, IEnumerable<OrderInfo> window)
        {
            if (!window.Any())
                return;

            builder.Append(caption);
            builder.Append(": ");
            builder.Append(GetMean(window).ToString("P3"));
            builder.Append(" ");
            builder.Append(GetVolumeWeighted(window).ToString("P3"));
            builder.Append(" ");
            builder.Append(GetStandardDeviation(window).ToString("P3"));
            builder.AppendLine();
        }

        public double GetMeanSlippage()
        {
            return GetMean(GetStatWindow());
        }

        public double GetVolumeWeightedSlippage()
        {
            return GetVolumeWeighted(GetStatWindow());
        }

        public double GetStandardDeviationOfSlippage()
        {
            return GetStandardDeviation(GetStatWindow());
        }
    }
}
using QuantConnect.Orders.Slippage;
using System;
using QuantConnect.Orders;
using QuantConnect.Securities;

namespace QuantConnect.Algorithm.CSharp
{
    class OrderTypeDependentSlippageModel : ISlippageModel
    {
        public ISlippageModel LimitOrderSlippage { get; set; }
        public ISlippageModel MarketOrderSlippage { get; set; }
        public ISlippageModel MarketOnCloseOrderSlippage { get; set; }
        public ISlippageModel MarketOnOpenOrderSlippage { get; set; }
        public ISlippageModel StopLimitOrderSlippage { get; set; }
        public ISlippageModel StopMarketOrderSlippage { get; set; }

        public OrderTypeDependentSlippageModel(ISlippageModel defaultModel)
        {
            LimitOrderSlippage = defaultModel;
            MarketOrderSlippage = defaultModel;
            MarketOnCloseOrderSlippage = defaultModel;
            MarketOnOpenOrderSlippage = defaultModel;
            StopLimitOrderSlippage = defaultModel;
            StopMarketOrderSlippage = defaultModel;
        }

        public void SetMarketSlippageModel(ISlippageModel model)
        {
            MarketOrderSlippage = model;
            MarketOnCloseOrderSlippage = model;
            MarketOnOpenOrderSlippage = model;
            StopMarketOrderSlippage = model;
        }

        public void SetLimitSlippageModel(ISlippageModel model)
        {
            LimitOrderSlippage = model;
            StopLimitOrderSlippage = model;
        }

        public decimal GetSlippageApproximation(Security asset, Order order)
        {
            switch (order.Type)
            {
                case OrderType.Limit:
                    return LimitOrderSlippage.GetSlippageApproximation(asset, order);
                case OrderType.Market:
                    return MarketOrderSlippage.GetSlippageApproximation(asset, order);
                case OrderType.MarketOnClose:
                    return MarketOnCloseOrderSlippage.GetSlippageApproximation(asset, order);
                case OrderType.MarketOnOpen:
                    return MarketOnOpenOrderSlippage.GetSlippageApproximation(asset, order);
                case OrderType.StopLimit:
                    return StopLimitOrderSlippage.GetSlippageApproximation(asset, order);
                case OrderType.StopMarket:
                    return StopMarketOrderSlippage.GetSlippageApproximation(asset, order);
                default:
                    throw new NotImplementedException("Slippage specialization not implemented for order type " + order.Type.ToString());
            }
        }
    }
}
using QuantConnect.Securities;
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using MathNet.Numerics.Statistics;

namespace QuantConnect.Algorithm.CSharp
{
    public partial class GapReversalAlgorithm : QCAlgorithm
    {
        //if false, load from external list file even during backtest
        private bool _createUniverse = true;
        private const int _universeWindow = 120;

        private readonly Dictionary<Symbol, UniverseData> _universeData = new Dictionary<QuantConnect.Symbol, UniverseData>();

        private void SetUpUniverse()
        {
            UniverseSettings.MinimumTimeInUniverse = TimeSpan.FromDays(1);
            UniverseSettings.Leverage = _leverage;
            UniverseSettings.Resolution = _resolution;

            if (_createUniverse)
                AddUniverse(CoarseUniverseSelection);
            else
                throw new Exception("Unimplemented");
        }

        private IEnumerable<Symbol> CoarseUniverseSelection(IEnumerable<CoarseFundamental> coarse)
        {
            var eligible = coarse
                .Where(x => x.HasFundamentalData);

            //the eligible tickers are the ones we analyze
            foreach (var fundamental in eligible)
            {
                UniverseData data;
                if (!_universeData.TryGetValue(fundamental.Symbol, out data))
                {
                    data = new UniverseData(fundamental.Symbol);
                    _universeData[fundamental.Symbol] = data;
                }

                data.AnalyzeCoarse(fundamental);
            }
               
            var finalFilter = eligible.Select(x => _universeData[x.Symbol])
                .Where(x => x.LastPrice > 30 && x.LastPrice < 200) //due to IB fee structure
                .Where(x => x.AverageDollarVolume > 100000)
                .OrderByDescending(x => x.Rank)
                .Select(x => x.Symbol);

            Debug("Max coarse universe size " + finalFilter.Count());

            return finalFilter.Take(_universeSize);
        }

        private class UniverseData
        {
            public Symbol Symbol { get; private set; }
            public double Rank { get; private set; }
            public decimal LastPrice { get; private set; }
            public SimpleMovingAverage AverageDollarVolume { get; private set; }

            private readonly RollingWindow<double> _prices;

            public UniverseData(Symbol sym)
            {
                Symbol = sym;

                AverageDollarVolume = new SimpleMovingAverage(_universeWindow);

                _prices = new RollingWindow<double>(_universeWindow + 1);
            }

            public void AnalyzeCoarse(CoarseFundamental coarse)
            {
                LastPrice = coarse.Price;
                AverageDollarVolume.Update(_instance.Time, coarse.DollarVolume);
                _prices.Add((double)coarse.Price);

                var spearman = _prices.Count > 2? Correlation.Spearman(_prices.Take(_prices.Count - 1), _prices.Skip(1)) : 0;

                Rank = -spearman;
            }
        }
    }
}