Overall Statistics
Total Trades
69
Average Win
0.31%
Average Loss
-0.08%
Compounding Annual Return
71.214%
Drawdown
1.100%
Expectancy
0.119
Net Profit
1.434%
Sharpe Ratio
11.022
Probabilistic Sharpe Ratio
88.790%
Loss Rate
76%
Win Rate
24%
Profit-Loss Ratio
3.70
Alpha
0.537
Beta
-0.053
Annual Standard Deviation
0.047
Annual Variance
0.002
Information Ratio
0.773
Tracking Error
0.112
Treynor Ratio
-9.688
Total Fees
$269.46
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Parameters;
using QuantConnect.Brokerages;
using QuantConnect.Indicators;
using QuantConnect.Securities;

namespace QuantConnect.Algorithm.CSharp
{
    public enum VWAPState
    {
        Long,
        Short,
        Empty
    };

    public class VWAPAlgorithm : QCAlgorithm
    {
        private readonly string _ticker = "XOM";

        [Parameter("cash")]
        private readonly int _cash;

        private Resolution _resolution = Resolution.Minute;

        private AlphaModel _alphaModel;

        public override void Initialize()
        {
            Chart _plotter1 = new Chart("Chart 1", ChartType.Overlay);
            _plotter1.AddSeries(new Series("Price", SeriesType.Line, "$", Color.Green));
            _plotter1.AddSeries(new Series("VWAP", SeriesType.Line, "%", Color.Red));
            // _plotter1.AddSeries(new Series("MOMP", SeriesType.Line, "%", Color.Yellow));
            _plotter1.AddSeries(new Series("Long", SeriesType.Scatter, "", Color.Blue, ScatterMarkerSymbol.Square));
            _plotter1.AddSeries(new Series("Short", SeriesType.Scatter, "", Color.Pink, ScatterMarkerSymbol.Square));
            AddChart(_plotter1);

            //Chart _plotter2 = new Chart("Chart 2", ChartType.Overlay);
            //_plotter2.AddSeries(new Series("RSI", SeriesType.Line, "%", Color.Red));
            //AddChart(_plotter2);

            SetStartDate(2020, 1, 1);
            SetEndDate(2020, 1, 10);
            SetCash(_cash);

            SetUniverseSelection(
                new ManualUniverseSelectionModel(
                    QuantConnect.Symbol.Create(_ticker, SecurityType.Equity, Market.USA)
                )
            );

            UniverseSettings.Resolution = _resolution;
            UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;

            _alphaModel = new VWAPAlphaModel(_resolution);
            AddAlpha(_alphaModel);
            SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
            SetExecution(new ImmediateExecutionModel());
            SetRiskManagement(new LiquidatePositionOnDrawdawn());
            SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage);
        }
    }

    public class VWAPAlphaModel : AlphaModel
    {
        private Resolution _resolution;
        private Security _security;
        private IntradayVwap _vwap;
        private RelativeStrengthIndex _rsi;
        private MomentumPercent _momp;
        private RollingWindow<decimal> _priceRw = new RollingWindow<decimal>(2);
        private QCAlgorithm _algorithm;

        public VWAPAlphaModel(Resolution resolution)
        {
            _resolution = resolution;
        }

        public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
        {
            _algorithm = algorithm;
            _security = changes.AddedSecurities.First();

            _vwap = algorithm.VWAP(_security.Symbol);
            _rsi = algorithm.RSI(_security.Symbol, 14, MovingAverageType.Simple, _resolution);
            _momp = algorithm.MOMP(_security.Symbol, 14, _resolution);
        }

        public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
        {
            algorithm.Plot("Chart 1", "Price", _security.Price);
            algorithm.Plot("Chart 1", "VWAP", _vwap);
            algorithm.Plot("Chart 2", "MOMP", _momp * 100);
            algorithm.Plot("Chart 2", "RSI", _rsi);

            _priceRw.Add(_security.Price);

            if (!data.ContainsKey(_security.Symbol) || !_vwap.IsReady || !_priceRw.IsReady)
            {
                return Enumerable.Empty<Insight>();
            }

            if (State() != VWAPState.Long && _priceRw[0] > _vwap && _priceRw[1] <= _vwap)
            {
                return Insight.Group(Insight.Price(_security.Symbol, Expiry.EndOfDay, InsightDirection.Up));
            }

            if (State() != VWAPState.Short && _priceRw[0] < _vwap && _priceRw[1] >= _vwap)
            {
                return Insight.Group(Insight.Price(_security.Symbol, Expiry.EndOfDay, InsightDirection.Down));
            }

            return Enumerable.Empty<Insight>();
        }

        private VWAPState State()
        {
            decimal quantity = _algorithm.Portfolio[_security.Symbol].Quantity;

            if (quantity > 0)
            {
                return VWAPState.Long;
            }

            if (quantity < 0)
            {
                return VWAPState.Short;
            }

            return VWAPState.Empty;
        }
    }

    public class LiquidatePositionOnDrawdawn : RiskManagementModel
    {

        public LiquidatePositionOnDrawdawn()
        {
        }

        public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets)
        {
            foreach (var kvp in algorithm.Securities)
            {
                Security security = kvp.Value;

                if (security.Invested)
                {

                    // Liquidate holdings on end of trading session
                    if (algorithm.Time.Hour == 15 && algorithm.Time.Minute == 59)
                    {
                        yield return new PortfolioTarget(security.Symbol, 0);
                    }

                    // Liquidate holdings on drawdawn
                    //if (security.Holdings.Quantity == _previousQuantity)
                    //{

                    //}
                }

                //_previousQuantity = security.Holdings.Quantity;

                continue;
            }
        }
    }
}