Overall Statistics
Total Trades
493
Average Win
1.52%
Average Loss
-1.14%
Compounding Annual Return
5.116%
Drawdown
25.000%
Expectancy
0.177
Net Profit
56.826%
Sharpe Ratio
0.438
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
1.33
Alpha
0.047
Beta
0.589
Annual Standard Deviation
0.133
Annual Variance
0.018
Information Ratio
0.289
Tracking Error
0.133
Treynor Ratio
0.099
Total Fees
$4408.91
namespace QuantConnect.Algorithm.CSharp
{
    /// <summary>
    /// Basic template algorithm simply initializes the date range and cash. This is a skeleton
    /// framework you can use for designing an algorithm.
    /// </summary>
    public class BasicTemplateAlgorithm : QCAlgorithm
    {
        private Symbol _spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
		SlopeIndicator _hislope;
		SlopeIndicator _loslope;
        /// <summary>
        /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
        /// </summary>
        public override void Initialize()
        {
            SetStartDate(2008, 10, 07);  //Set Start Date
            SetEndDate(2017, 10, 11);    //Set End Date
            SetCash(100000);             //Set Strategy Cash

            // Find more symbols here: http://quantconnect.com/data
            // Forex, CFD, Equities Resolutions: Tick, Second, Minute, Hour, Daily.
            // Futures Resolution: Tick, Second, Minute
            // Options Resolution: Minute Only.
            AddEquity("SPY", Resolution.Minute);
                        _hislope = new SlopeIndicator(_spy, 30, true, 1e-8);
                        _loslope = new SlopeIndicator(_spy, 30, false, 1e-8);
                         var consolidator = new TradeBarConsolidator(new TimeSpan(0, 15, 0));

                        RegisterIndicator(_spy, _hislope, consolidator, Field.High);
                        RegisterIndicator(_spy, _loslope, consolidator, Field.Low);
            // There are other assets with similar methods. See "Selecting Options" etc for more details.
            // AddFuture, AddForex, AddCfd, AddOption
        }

        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="data">Slice object keyed by symbol containing the stock data</param>
        public override void OnData(Slice data)
        {
        	if(!_hislope.IsReady)
        	{
        		return;
        	}
        	 var hiangle = Math.Atan((double)_hislope.Current.Value) * (180/Math.PI);
        	 var loangle = Math.Atan((double)_loslope.Current.Value) * (180/Math.PI);

            if (!Portfolio.Invested && ((hiangle<-10 && loangle>10) || loangle>20))
            {
                SetHoldings(_spy, 10);
                Debug(string.Format("Purchased Stock {0} {1}",hiangle,loangle));
            }
            else if (Portfolio.Invested && loangle<2)
            {
                Liquidate(_spy);
                Debug(string.Format("Liquidated Stock {0} {1}",hiangle,loangle));
            }
        }
    }
}                        
using System;
using System.Collections.Generic;


namespace QuantConnect
{
	public class HHLL
	{
        public static List<int> PeakinessTest(decimal[] histogram, double peakinessThres)
        {
            int j = 0;
            int length = histogram.Length;
            List<int> valleys = new List<int>();
            List<int> peaks = new List<int>();
            List<decimal> values = new List<decimal>();
            List<decimal> levels = new List<decimal>();
            //The start of the valley
            decimal vA = histogram[j];
            decimal P = vA;

            //The end of the valley
            decimal vB = 0;

            //The width of the valley, default width is 1
            int W = 1;

            //The sum of the pixels between vA and vB
            decimal N = 0;

            //The measure of the peaks peakiness
            double peakiness = 0.0;

            int peak = 0;
            bool l = false;
            decimal level = 0;
            try
            {
                level = histogram[0];
                while (j < length-1)
                {

                    l = false;
                    vA = histogram[j];
                    P = vA;
                    W = 1;
                    N = vA;


                    int i = j + 1;

                    //To find the peak
                    while (i < histogram.Length - 1 && P < histogram[i])
                    {
                        P = histogram[i];
                        W++;
                        N += histogram[i];
                        i++;
                        levels.Add(level);
                    }


                    //To find the border of the valley other side
                    peak = i - 1;
                    vB = histogram[i];
                    N += histogram[i];
                    i++;
                    W++;
                    levels.Add(level);
                    l = true;
                    while( i < histogram.Length - 1 && vB >= histogram[i])
                    {
                        vB = histogram[i];
                        W++;
                        N += histogram[i];
                        i++;
                        levels.Add(level);
                    }

                    //Calculate peakiness
                    peakiness = (1 - (double)((vA + vB) / ((decimal)2.0 * P))) * (1 - ((double)N / (double)(W * P)));

                    if (peakiness > peakinessThres & !valleys.Contains(j))
                    {
                        values.Add(histogram[j]);
                        peaks.Add(peak);                        
                        valleys.Add(j);
                        valleys.Add(i - 1);
                        level = histogram[j];
                    }


                    j = i - 1;
                }
            }
            catch (Exception e)
            {
                if (l)
                {
                    vB = histogram[length-1];

                    peakiness = (1 - (double)((vA + vB) / ((decimal)2.0 * P))) * (1 - ((double)N / (double)(W * P)));

                    if (peakiness > peakinessThres)
                        valleys.Add(length);

                    //peaks.Add(255);
                    //return valleys;
                    return peaks;
                }
            }

            //if(!valleys.Contains(255))
            //    valleys.Add(255);
//Console.WriteLine(string.Join(",", peaks.ToArray()));
        //    Console.WriteLine(string.Join(",", values.ToArray()));
        //    Console.WriteLine(string.Join(",", levels.ToArray()));

            //return valleys;
            return peaks;
        }
    


   public static List<int> ValleysTest(decimal[] histogram, double peakinessThres)
    {
        int j = 0;
        int length = histogram.Length;
        List<int> valleys = new List<int>();
        List<int> peaks = new List<int>();
        List<decimal> values = new List<decimal>();
        List<decimal> levels = new List<decimal>();
        //The start of the valley
        decimal vA = histogram[j];
        decimal P = vA;

        //The end of the valley
        decimal vB = 0;

        //The width of the valley, default width is 1
        int W = 1;

        //The sum of the pixels between vA and vB
        decimal N = 0;

        //The measure of the peaks peakiness
        double peakiness = 0.0;

        int peak = 0;
        bool l = false;
        decimal level = 0;
        try
        {
            level = histogram[0];
            while (j < length -1)
            {

                l = false;
                vA = histogram[j];
                P = vA;
                W = 1;
                N = vA;


                int i = j + 1;

                //To find the peak
                    while (i < histogram.Length - 1 && P < histogram[i])
                {
                    P = histogram[i];
                    W++;
                    N += histogram[i];
                    i++;
                    levels.Add(level);
                }


                //To find the border of the valley other side
                peak = i - 1;
                vB = histogram[i];
                N += histogram[i];
                i++;
                W++;
                levels.Add(level);
                l = true;
                while (i < histogram.Length - 1 && vB >= histogram[i])

                {
                    vB = histogram[i];
                    W++;
                    N += histogram[i];
                    i++;
                    levels.Add(level);
                }

                //Calculate peakiness
                peakiness = (1 - (double)((vA + vB) / ((decimal)2.0 * P))) * (1 - ((double)N / (double)(W * P)));

                if (peakiness > peakinessThres & !valleys.Contains(j))
                {
                    values.Add(histogram[j]);
                    peaks.Add(peak);
                    valleys.Add(j);
                    valleys.Add(i - 1);
                    level = histogram[j];
                }


                j = i - 1;
            }
        }
        catch (Exception e)
        {
            if (l)
            {
                vB = histogram[length-1];

                peakiness = (1 - (double)((vA + vB) / ((decimal)2.0 * P))) * (1 - ((double)N / (double)(W * P)));

                if (peakiness > peakinessThres)
                    valleys.Add(length);

                //peaks.Add(255);
                //return valleys;
                return valleys;
            }
        }

        //if(!valleys.Contains(255))
        //    valleys.Add(255);
       // Console.WriteLine(string.Join(",", peaks.ToArray()));
       // Console.WriteLine(string.Join(",", values.ToArray()));
       // Console.WriteLine(string.Join(",", levels.ToArray()));

        //return valleys;
        return valleys;
    }
}
}                        
/*
 * 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 System;
using System.Collections.Generic;
using System.Linq;
using MathNet.Numerics;
using MathNet.Numerics.LinearAlgebra;

namespace QuantConnect.Indicators
{

    public class SlopeIndicator : Indicator
    {

        private RollingWindow<decimal> highs;
        private bool _peaks;
        private double _peakinessThres;
        public SlopeIndicator(string name, int period, bool peaks, double peakinessThres = 1e-8)
            : base(name)
        {
            highs = new RollingWindow<decimal>(period);
            _peaks = peaks;
            _peakinessThres = peakinessThres;

        }
        /// <summary>
        /// Computes the average value
        /// </summary>
        /// <param name="input">The data for the calculation</param>
        /// <returns>The average value</returns>
        protected override decimal ComputeNextValue(IndicatorDataPoint input)
        {
            highs.Add(input.Value);
            if(!IsReady)
            {
                return 0;
            }
            decimal[] h = highs.ToArray();
            Array.Reverse(h);

            List<int> peakindexes = _peaks?HHLL.PeakinessTest(h,_peakinessThres):HHLL.ValleysTest(h, _peakinessThres);
            List<double> peakvalues = new List<double>();
            foreach(int index in peakindexes)
            {
                peakvalues.Add((double)h[index]);
            }
            if(peakvalues.Count<2)
            {
                return 0;
            }
            double[] t = Vector<double>.Build.Dense(peakvalues.Count, i => i + 1).ToArray();
            var slope = Fit.Line(x: t, y: peakvalues.ToArray());

            return (decimal)slope.Item2;

        }


        /// <summary>
        /// Returns whether the indicator will return valid results
        /// </summary>
        public override bool IsReady
        {
            get { return highs.IsReady; }
        }

        /// <summary>
        /// Resets the average to its initial state
        /// </summary>
        public override void Reset()
        {
            highs.Reset();
            base.Reset();
        }
    }

}