| 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();
}
}
}