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.
_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.
}

/// <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)
{
{
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;
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++;
}

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

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

if (peakiness > peakinessThres & !valleys.Contains(j))
{
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)

//return valleys;
return peaks;
}
}

//if(!valleys.Contains(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;
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++;
}

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

{
vB = histogram[i];
W++;
N += histogram[i];
i++;
}

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

if (peakiness > peakinessThres & !valleys.Contains(j))
{
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)

//return valleys;
return valleys;
}
}

//if(!valleys.Contains(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)
{
{
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)
{
}
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();
}
}

}