Overall Statistics
Total Trades
2182
Average Win
6.11%
Average Loss
-0.75%
Compounding Annual Return
1662.453%
Drawdown
38.300%
Expectancy
0.425
Net Profit
38206.760%
Sharpe Ratio
3.233
Loss Rate
84%
Win Rate
16%
Profit-Loss Ratio
8.17
Alpha
3.389
Beta
0.05
Annual Standard Deviation
1.045
Annual Variance
1.092
Information Ratio
2.742
Tracking Error
1.31
Treynor Ratio
67.699
Total Fees
$24587517.55
using QuantConnect.Data;
using QuantConnect.Data.Custom;
using QuantConnect.Indicators;
using QuantConnect.Securities;
using System;
using System.Collections.Generic;
using QuantConnect.Data.Market;
using System.Linq;
using MathNet.Numerics.Statistics;
using QuantConnect.Data.Consolidators;

#if PETTER
using System.Windows.Media;
using LiveCharts.Wpf;
#endif

namespace QuantConnect.Algorithm.CSharp
{
    public partial class MirrorAlgorithm : QCAlgorithm
    {
        private enum Charting
        {
            Disabled,
            FullResolution,
            DailyEquityOnly,
            ProfitPerDelay,
        }

        private const Charting _charting = Charting.DailyEquityOnly;
        private static readonly bool _useStoploss = false;

        private const decimal _leverage = 1;
        private const decimal maxLeverage = 2;

        private static MirrorAlgorithm _instance;

        public override void Initialize()
        {
            SetCash(100000);

            SetStartDate(2016, 1, 4); //2017, 1, 4
            //SetEndDate(2016, 10, 1);

            try
            {
                ActualInitialization();
            }
            catch (Exception e)
            {
                ReportException(e, this);
            }
        }

        public static void ReportException(Exception e, QCAlgorithm algo)
        {
            algo.Error(algo.Time + ": " + e.Message + "\n" + e.StackTrace);
            algo.Log(algo.Time + ": " + e.Message + "\n" + e.StackTrace);
        }

#if PETTER
        private SignalView _signalView;
#endif

        private void ActualInitialization()
        {
            _instance = this;

            var res = Resolution.Minute;

            var first = AddEquity("OASM", res, leverage: maxLeverage);
            first.SlippageModel = new ConstantSlippageModel(0.75m / 100);
            AddTradable(first);

            Schedule.On(DateRules.EveryDay(), TimeRules.At(0, 0, 1), AtMidnight);

            //TODO: keeping this disabled unless we figure out it's a good idea
            //Schedule.On(DateRules.EveryDay(), TimeRules.Every(TimeSpan.FromSeconds(5)), CheckForSensitiveEvents);

            SetBenchmark(first.Symbol);

#if PETTER
            if (_charting != Charting.Disabled)
                _signalView = SignalView.ShowInNewThread(CreateSignalViewOptions());
#endif
        }

#if PETTER
        private SignalView.SetupOptions CreateSignalViewOptions()
        {
            var options = new SignalView.SetupOptions();

            options.AxisGenerator = CreateExtraAxes;

            return options;
        }

        private IEnumerable<Axis> CreateExtraAxes()
        {
            yield return new Axis()
            {
                MinValue = -210,
                MaxValue = 210,
                Sections = new SectionsCollection
                {
                    new AxisSection
                    {
                        Value = 0,
                        SectionWidth = 1,
                        Stroke = new SolidColorBrush(Color.FromRgb(248, 213, 72))
                    },
                    new AxisSection
                    {
                        Value = 100,
                        SectionWidth = 1,
                        Fill = new SolidColorBrush
                        {
                            Color = Color.FromRgb(0, 255, 0),
                            Opacity = .8
                        }
                    },
                    new AxisSection
                    {
                        Value = -100,
                        SectionWidth = 1,
                        Fill = new SolidColorBrush
                        {
                            Color = Color.FromRgb(255, 0, 0),
                            Opacity = .8
                        }
                    }
                }
            };
        }
#endif

        private void AtMidnight()
        {
#if PETTER
            if (_charting != Charting.Disabled && _charting != Charting.ProfitPerDelay)
            {
                _signalView.SetXLabel(Time.ToShortDateString());
                _signalView.PlotEquity((double)Portfolio.TotalPortfolioValue);
            }
#endif
        }

        public override void OnEndOfAlgorithm()
        {

#if PETTER
            if (_signalView != null)
                _signalView.JoinThread();
#endif
        }

        private void CheckForSensitiveEvents()
        {
            /*_sensitiveEvents.Update();

            if (_sensitiveEvents.InSensitiveZone && _components[0].Exchange.ExchangeOpen && _components[0].HoldStock)
            {
                ClosePosition();
            }*/
        }

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

        private void AddTradable(Security sec)
        {
            _tradables[sec.Symbol] = new Tradable(sec);
        }

        private readonly Dictionary<Symbol, Tradable> _tradables = new Dictionary<Symbol, Tradable>();

        private sealed class Tradable
        {
            private readonly Security _security;

            private readonly RollingWindow<double> _priceWindow = new RollingWindow<double>(2000);

            private readonly VirtualEquity _equity;
            private bool _stopped;
            private decimal _peakEquity;
            private decimal _floorStopEquity;

            public Tradable(Security sec)
            {
                _security = sec;

                _equity = new VirtualEquity(sec)
                {
                    Slippage = 0,
                    TradeFeeFraction = 0,
                };
            }

            public void OnData(TradeBar bar)
            {
                _peakEquity = Math.Max(_peakEquity, _equity.GetEquity());
                if (_stopped)
                {
                    _floorStopEquity = Math.Min(_floorStopEquity, _equity.GetEquity());

                    if (_equity.GetEquity() >= _floorStopEquity * 1.05m)
                        _stopped = false;
                }

                _priceWindow.Add((double)bar.Close);

                FindMirrors();

                if (_useStoploss && _equity.GetEquity() < 0.95m * _peakEquity)
                {
                    _stopped = true;
                    _floorStopEquity = _equity.GetEquity();
                    _instance.Liquidate(_security.Symbol);
                }  
            }

            private double GetPrice(int i)
            {
                if (i < _priceWindow.Count)
                    return  _priceWindow[i];

                return _priceWindow[_priceWindow.Count - 1];
            }

            private void FindMirrors()
            {
                double estimate = 0;
                int maxWidth = 10;

                for (int width = 2; width <= maxWidth; ++width)
                {
                    double squaredErrorSum = 0;
                    double min = double.MaxValue;
                    double max = -double.MaxValue;

                    for (int i = 0; i < width; ++i)
                    {
                        double target = GetPrice(i);
                        double source = GetPrice(i + width);

                        min = Math.Min(target, min);
                        min = Math.Min(source, min);
                        max = Math.Max(target, max);
                        max = Math.Max(source, max);

                        double error = target - source;
                        squaredErrorSum += error * error;
                    }

                    double changeSince = GetPrice(0) / GetPrice(width) - 1;
                    double dissimilarity = Math.Sqrt(squaredErrorSum / width) / (max - min + double.Epsilon);
                    double sigmoid = 1 / (1 + Math.Exp(1 / dissimilarity));

                    estimate += changeSince * 2 * (sigmoid - 0.5);
                }

                estimate /= (maxWidth - 1);

                if (Math.Abs(estimate) > 0.02)
                {
                    _instance.SetHoldings(_security.Symbol, Math.Sign(estimate) * _leverage);
                }
            }
        }
    }
}
/*
 * 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;

namespace QuantConnect.Algorithm.CSharp
{
    public sealed class VirtualEquity
    {
        public interface ISecurity
        {
            decimal GetPrice();
            Security GetSecurityIfSupportedOtherwiseThrow();
        }

        private class SecurityAdapter : ISecurity
        {
            private readonly Security _sec;

            public SecurityAdapter(Security sec)
            {
                _sec = sec;
            }

            public decimal GetPrice()
            {
                return _sec.Price;
            }

            public Security GetSecurityIfSupportedOtherwiseThrow()
            {
                return _sec;
            }
        }

        public decimal TradeFeeFraction { get; set; }

        private readonly ISecurity _security;

        private decimal _entryFee;
        private decimal _entryPrice;
        private decimal _position;
        private decimal _equityBase = 1;

        public VirtualEquity(ISecurity sec)
        {
            _security = sec;
            TradeFeeFraction = 0.005m;
        }

        public VirtualEquity(Security sec) : this(new SecurityAdapter(sec))
        {

        }

        public decimal Slippage
        {
            get; set;
        }

        public decimal Position
        {
            get { return _position; }
            set { SetPosition(value); }
        }

        public Security Security { get { return _security.GetSecurityIfSupportedOtherwiseThrow(); } }

        public decimal GetEquity()
        {
            if (_position == 0)
                return _equityBase;
            return Math.Max(0, _equityBase * (1 + _position * (_security.GetPrice() / _entryPrice - 1) - Slippage - _entryFee - GetTradeFee()));
        }

        public decimal GetReturn()
        {
            return GetEquity() - 1;
        }

        private decimal GetTradeFee()
        {
            if (_security.GetPrice() == 0)
                return TradeFeeFraction;
            return Math.Min(TradeFeeFraction, TradeFeeFraction / _security.GetPrice());
        }

        public void SetPosition(decimal weight)
        {
            var old = _equityBase;
            _equityBase = GetEquity();

            _position = weight;
            _entryPrice = _security.GetPrice();
            _entryFee = GetTradeFee();
        }

        public void ResetEquity(bool keepPosition = true)
        {
            var oldPos = _position;
            SetPosition(0);
            _equityBase = 1;
            if (oldPos != 0 && keepPosition)
            {
                _equityBase += Slippage;
                SetPosition(oldPos);
            }
        }
    }
}
using System;
using System.Collections.Generic;

//found and copied from random site on Internetz
namespace QuantConnect.Algorithm.CSharp
{
    public sealed class PriorityQueue<T> where T : IComparable<T>
    {
        private readonly List<T> _data = new List<T>();

        public PriorityQueue()
        {
            _data = new List<T>();
        }

        public void Enqueue(T item)
        {
            _data.Add(item);
            int ci = _data.Count - 1; // child index; start at end
            while (ci > 0)
            {
                int pi = (ci - 1) / 2; // parent index
                if (_data[ci].CompareTo(_data[pi]) >= 0) break; // child item is larger than (or equal) parent so we're done
                T tmp = _data[ci]; _data[ci] = _data[pi]; _data[pi] = tmp;
                ci = pi;
            }
        }

        public T Dequeue()
        {
            // assumes pq is not empty; up to calling code
            int li = _data.Count - 1; // last index (before removal)
            T frontItem = _data[0];   // fetch the front
            _data[0] = _data[li];
            _data.RemoveAt(li);

            --li; // last index (after removal)
            int pi = 0; // parent index. start at front of pq
            while (true)
            {
                int ci = pi * 2 + 1; // left child index of parent
                if (ci > li) break;  // no children so done
                int rc = ci + 1;     // right child
                if (rc <= li && _data[rc].CompareTo(_data[ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead
                    ci = rc;
                if (_data[pi].CompareTo(_data[ci]) <= 0) break; // parent is smaller than (or equal to) smallest child so done
                T tmp = _data[pi]; _data[pi] = _data[ci]; _data[ci] = tmp; // swap parent and child
                pi = ci;
            }
            return frontItem;
        }

        public T Peek()
        {
            T frontItem = _data[0];
            return frontItem;
        }

        public int Count
        {
            get { return _data.Count; }
        }

        public override string ToString()
        {
            string s = "";
            for (int i = 0; i < _data.Count; ++i)
                s += _data[i].ToString() + " ";
            s += "count = " + _data.Count;
            return s;
        }

        internal bool IsConsistent()
        {
            // is the heap property true for all data?
            if (_data.Count == 0) return true;
            int li = _data.Count - 1; // last index
            for (int pi = 0; pi < _data.Count; ++pi) // each parent index
            {
                int lci = 2 * pi + 1; // left child index
                int rci = 2 * pi + 2; // right child index

                if (lci <= li && _data[pi].CompareTo(_data[lci]) > 0) return false; // if lc exists and it's greater than parent then bad.
                if (rci <= li && _data[pi].CompareTo(_data[rci]) > 0) return false; // check the right child too.
            }
            return true; // passed all checks
        }
    }
}