| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 |
/*
* 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 MathNet.Numerics.Statistics;
namespace QuantConnect.Algorithm.CSharp
{
public class HurstExample : QCAlgorithm
{
HurstExponent hurst1;
HurstExponent hurst2;
HurstExponent hurst3;
TradeBarConsolidator con2 = new TradeBarConsolidator(TimeSpan.FromDays(20));
RelativeStrengthIndex rsi1;
RelativeStrengthIndex rsi2;
AverageDirectionalIndex adx;
Dictionary<string, HurstExponent.HurstExponentResult> result = new Dictionary<string, HurstExponent.HurstExponentResult>
{
{ "SPY", HurstExponent.HurstExponentResult.None },
{ "SH", HurstExponent.HurstExponentResult.None },
{ "UCO", HurstExponent.HurstExponentResult.None },
};
decimal volumeSum;
public override void Initialize()
{
SetStartDate(2001, 1, 1); //Set Start Date
SetEndDate(2017, 1, 1); //Set End Date
SetCash(100000);
AddEquity("SPY", Resolution.Daily, Market.USA);
AddEquity("SH", Resolution.Daily, Market.USA);
AddEquity("UCO", Resolution.Daily, Market.USA);
adx = ADX("SPY", 180, Resolution.Daily);
rsi1 = RSI("SPY", 7, MovingAverageType.Exponential, Resolution.Daily);
rsi2 = RSI("SH", 7, MovingAverageType.Exponential, Resolution.Daily);
int period = 1000;
hurst1 = new HurstExponent(period);
hurst2 = new HurstExponent("", 100,10);
hurst3 = new HurstExponent(period);
con2.DataConsolidated += Con_DataConsolidated;
}
private void Con_DataConsolidated(object sender, Data.Market.TradeBar e)
{
hurst2.Update(ToPoint(e));
}
public override void OnData(Slice data)
{
if (data.Bars.ContainsKey("UCO"))
{
var bar = new TradeBar(data.Bars["UCO"]);
volumeSum += data.Bars["UCO"].Volume;
bar.Value = volumeSum;
con2.Update(bar);
}
if (data.Bars.ContainsKey("SPY"))
{
hurst1.Update(ToPoint(data.Bars["SPY"]));
}
if (data.Bars.ContainsKey("SH") && rsi1.IsReady && rsi2.IsReady)
{
var reverting = rsi1.Current - rsi2.Current;
data.Bars["SH"].Value = reverting;
hurst3.Update(ToPoint(data.Bars["SH"]));
}
if (hurst1.IsReady)
{
Output(hurst1, "SPY");
}
if (hurst2.IsReady)
{
Output(hurst2, "UCO");
}
if (hurst3.IsReady)
{
Output(hurst3, "SH");
}
}
private IndicatorDataPoint ToPoint(TradeBar bar)
{
return new IndicatorDataPoint(bar.Symbol, bar.Time, bar.Value);
}
private void Output(HurstExponent hurst, string symbol)
{
if (result[symbol] != hurst.CurrentResult())
{
Debug(string.Format("{0} {1} {2} {3}", this.Time, symbol, hurst.Current.Value.ToString("0.0000"), hurst.CurrentResult().ToString()));
Plot(symbol.ToString() + ": " + hurst.CurrentResult().ToString(), hurst.Current.Value);
result[symbol] = hurst.CurrentResult();
}
}
}
public class HurstExponent : IndicatorBase<IndicatorDataPoint>
{
int _period;
int _lagVector;
int[] lag;
FixedSizeHashQueue<double> p;
decimal _hurst;
public enum HurstExponentResult
{
GeometricBrownianMotion,
MeanReversion,
Trend,
StrongTrend,
None
}
public HurstExponent(int period)
: this(string.Format("Hurst({0})", period), period)
{
}
public HurstExponent(string name, int period, int lagVector = 100)
: base(name)
{
if (period <= lagVector)
{
throw new ArgumentException("The period must be greater than lag vector.");
}
_period = period;
_lagVector = lagVector;
lag = new int[lagVector - 2];
for (int i = 2; i < lagVector; i++)
{
lag[i - 2] = i;
}
p = new FixedSizeHashQueue<double>(period);
}
public override bool IsReady
{
get
{
return p.Count() >= _period;
}
}
public HurstExponentResult CurrentResult()
{
if (_hurst > 0.4m && _hurst < 0.6m)
{
return HurstExponentResult.GeometricBrownianMotion;
}
else if (_hurst > -0.1m && _hurst < 0.1m)
{
return HurstExponentResult.MeanReversion;
}
else if (_hurst > 0.9m)
{
return HurstExponentResult.StrongTrend;
}
else if (_hurst > 0.6m)
{
return HurstExponentResult.Trend;
}
return HurstExponentResult.None;
}
protected override decimal ComputeNextValue(IndicatorDataPoint input)
{
p.Add((double)input.Price);
this.Current.Symbol = input.Symbol;
if (!this.IsReady) { return 0; }
var tau = new List<double>();
foreach (var item in lag)
{
var start = p.Skip(item).ToArray();
var end = p.Take(p.Count() - item).ToArray();
var pp = new double[start.Length];
for (int ii = 0; ii < start.Count(); ii++)
{
pp[ii] = start[ii] - end[ii];
}
tau.Add(Math.Sqrt(pp.PopulationStandardDeviation()));
}
var x = lag.Select(l => Math.Log(l)).ToArray();
var y = tau.Select(t => Math.Log(t)).ToArray();
var fit = MathNet.Numerics.Fit.Polynomial(x, y, 1);
if (double.IsNaN(fit[1]) || double.IsInfinity(fit[1]))
{
return -10m;
}
_hurst = (decimal)(fit[1] * 2.0);
return _hurst;
}
}
}