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