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 Probabilistic 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 Estimated Strategy Capacity $0 Lowest Capacity Asset |
namespace QuantConnect.Indicators { using System.Numerics; public class FourierSeries { private readonly int _period; private readonly double _frequency; private readonly int _depth; private double _leading; private double _value; private GuassianQuadrature _gauss; public int WarmUpPeriod { get; } public bool IsReady => CosineCoefficients.Count() == _depth && SineCoefficients.Count() == _depth; public double Value => _value; public double LeadingCoefficient => _leading; public List<double> CosineCoefficients { get; } public List<double> SineCoefficients { get; } public void Reset() { CosineCoefficients.Clear(); SineCoefficients.Clear(); } public FourierSeries(string name, int period, int n = 5, double frequency = 2 * (double)Math.PI, int depth = 5) { _period = period; _frequency = frequency; _depth = depth; _gauss = new GuassianQuadrature(n); WarmUpPeriod = period; CosineCoefficients = new List<double>(); SineCoefficients = new List<double>(); } private static Func<double, double> _func; private static int _n = 0; public double AlphaIntegralFunction(double t) { return _func(t) * Math.Cos(_n * t); } public double BetaIntegralFunction(double t) { return _func(t) * Math.Sin(_n * t); } public void Update(double value, Func<double, double> f) { // update temp variables _func = f; // calculate coefficients _leading = (1.0 / _frequency) * _gauss.Solve(f, 0, _frequency); // clear coefficients CosineCoefficients.Clear(); SineCoefficients.Clear(); for(int i = 1; i <= _depth; i++) { _n = i; double a_n = (2.0 / _frequency) * _gauss.Solve(AlphaIntegralFunction, 0, _frequency); CosineCoefficients.Add(a_n); double b_n = (2.0 / _frequency) * _gauss.Solve(BetaIntegralFunction, 0, _frequency); SineCoefficients.Add(b_n); } _value = CalculateFunction(value); } public double CalculateFunction(double value, int iterations) { double result = value; for(int i = 0; i <= iterations; i++) result = CalculateFunction(result); return result; } public double CalculateFunction(double value) { var function = LeadingCoefficient; for(int i = 0; i < _depth; i++) { function += (CosineCoefficients[i] * (double)Math.Cos((double)((i + 1) * (double)Math.PI * value / _frequency))) / (i + 1); function += (SineCoefficients[i] * (double)Math.Sin((double)((i + 1) * (double)Math.PI * value / _frequency))) / (i + 1); } return function; } } }
namespace QuantConnect.Indicators { public class GuassianQuadrature { private readonly int N; private readonly double[] _roots; private readonly double[] _weights; private readonly double[,] _coefficients; public GuassianQuadrature(int N) { this.N = N; this._roots = new double[N]; this._weights = new double[N]; this._coefficients = new double[N + 1, N + 1]; GenerateCoefficients(); GenerateRoots(); } private void GenerateCoefficients() { _coefficients[0, 0] = _coefficients[1, 1] = 1; for (int n = 2; n <= N; n++) { _coefficients[n, 0] = -(n - 1) * _coefficients[n - 2, 0] / n; for (int i = 1; i <= n; i++) { _coefficients[n, i] = ((2 * n - 1) * _coefficients[n - 1, i - 1] - (n - 1) * _coefficients[n - 2, i]) / n; } } } private double Evaluate(int n, double x) { double s = _coefficients[n, n]; for (int i = n; i > 0; i--) s = s * x + _coefficients[n, i - 1]; return s; } private double Differentiate(int n, double x) { return n * (x * Evaluate(n, x) - Evaluate(n - 1, x)) / (x * x - 1); } private void GenerateRoots() { double x, x1; for (int i = 1; i <= N; i++) { x = Math.Cos(Math.PI * (i - 0.25) / (N + 0.5)); do { x1 = x; x -= Evaluate(N, x) / Differentiate(N, x); } while (x != x1); _roots[i - 1] = x; x1 = Differentiate(N, x); _weights[i - 1] = 2 / ((1 - x * x) * x1 * x1); } } public double Solve(Func<Double, Double> f, double a, double b) { double c1 = (b - a) / 2, c2 = (b + a) / 2, sum = 0; for (int i = 0; i < N; i++) sum += _weights[i] * f(c1 * _roots[i] + c2); return c1 * sum; } } }
/* * 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.Linq; using MathNet.Numerics; using MathNet.Numerics.LinearAlgebra; namespace QuantConnect.Indicators { /// <summary> /// The Least Squares Moving Average (LSMA) first calculates a least squares regression line /// over the preceding time periods, and then projects it forward to the current period. In /// essence, it calculates what the value would be if the regression line continued. /// Source: https://rtmath.net/helpFinAnalysis/html/b3fab79c-f4b2-40fb-8709-fdba43cdb363.htm /// </summary> public class LeastSquaresMovingAverage : WindowIndicator<IndicatorDataPoint>, IIndicatorWarmUpPeriodProvider { /// <summary> /// Array representing the time. /// </summary> private readonly double[] _t; /// <summary> /// The point where the regression line crosses the y-axis (price-axis) /// </summary> public IndicatorBase<IndicatorDataPoint> Intercept { get; } /// <summary> /// The regression line slope /// </summary> public IndicatorBase<IndicatorDataPoint> Slope { get; } /// <summary> /// Required period, in data points, for the indicator to be ready and fully initialized. /// </summary> public int WarmUpPeriod => Period; /// <summary> /// Initializes a new instance of the <see cref="LeastSquaresMovingAverage"/> class. /// </summary> /// <param name="name">The name of this indicator</param> /// <param name="period">The number of data points to hold in the window</param> public LeastSquaresMovingAverage(string name, int period) : base(name, period) { _t = Vector<double>.Build.Dense(period, i => i + 1).ToArray(); Intercept = new Identity(name + "_Intercept"); Slope = new Identity(name + "_Slope"); } /// <summary> /// Initializes a new instance of the <see cref="LeastSquaresMovingAverage"/> class. /// </summary> /// <param name="period">The number of data points to hold in the window.</param> public LeastSquaresMovingAverage(int period) : this($"LSMA({period})", period) { } /// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="window"></param> /// <param name="input">The input given to the indicator</param> /// <returns> /// A new value for this indicator /// </returns> protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input) { // Until the window is ready, the indicator returns the input value. if (window.Samples <= window.Size) return input.Value; // Sort the window by time, convert the observations to double and transform it to an array var series = window .OrderBy(i => i.Time) .Select(i => Convert.ToDouble(i.Value)) .ToArray(); // Fit OLS var ols = Fit.Line(x: _t, y: series); Intercept.Update(input.Time, (decimal)ols.Item1); Slope.Update(input.Time, (decimal)ols.Item2); // Calculate the fitted value corresponding to the input return Intercept.Current.Value + Slope.Current.Value * Period; } /// <summary> /// Resets this indicator and all sub-indicators (Intercept, Slope) /// </summary> public override void Reset() { Intercept.Reset(); Slope.Reset(); base.Reset(); } } }
namespace QuantConnect.Algorithm.CSharp { using System; using System.Numerics; public class ClientAlgorithm : QCAlgorithm { // BACKTESTING PARAMETERS // ================================================================================================================= // general settings: // set starting cash private int _startingCash = 100000; // backtesting start date time: // date setting variables private int _startYear = 2022; private int _startMonth = 1; private int _startDay = 3; // backtesting end date time: // determines whether there is a specified end date // if false it will go to the current date (if 'true' it will go to the specified date) private bool _enableEndDate = true; // date setting variables private int _endYear = 2022; private int _endMonth = 1; private int _endDay = 3; // enable plotting private bool enablePlotting = true; // universe settings: // universe selection type // determines whether securities are selected by QC's universe function // or manually by the user // manual = false; QC universe = true private readonly bool _universeSelectionType = false; // number of securities for the universe selection to select private readonly int _stockCount = 5; // use default values for universe private readonly bool _useDefaultSymbolBase = false; // stock list for equities // list of equities you want in the universe // used in manual selection of universe // set selectionType = false for activation private readonly SymbolBase[] _universeList = new SymbolBase[]{ new SymbolBase( "AMZN", // symbol ticker Resolution.Minute, // data resolution 1, // data resolution consolidation rate 1.0m // portfolio allocation percentage ) }; // default symbol base settings // used if using QC universe selection or a base is not detected for // an added security private readonly SymbolBase _defaultSymbolBase = new SymbolBase( "<BASE>", // do not modify // parameters to modify: Resolution.Minute, // data resolution 1, // data resolution consolidation rate 1.0m // portfolio allocation percentage ); // position settings: // percent of portfolio to use for trading // must be below 1 private readonly decimal _portfolioAllocation = 1m; // ================================================================================================================= // contains all SymbolBase definitions private Dictionary<string, SymbolBase> _symbolBases = new Dictionary<string, SymbolBase>(); // creates new universe variable setting private Dictionary<Symbol, SymbolData> _universe = new Dictionary<Symbol, SymbolData>(); // security changes variable private SecurityChanges _securityChanges = SecurityChanges.None; // define offset universe to avoid first candle private bool offsetUniverse = true; public override void Initialize() { // set start date SetStartDate(_startYear, _startMonth, _startDay); // set end date if(_enableEndDate) SetEndDate(_endYear, _endMonth, _endDay); // set starting cash SetCash(_startingCash); // add default symbol base _symbolBases.Add("<BASE>", _defaultSymbolBase); // initialize universe if(!_universeSelectionType) { foreach(SymbolBase sb in _universeList) { _symbolBases.Add(sb.Symbol, sb); AddEquity(sb.Symbol, sb.SymbolResolution); } } else { UniverseSettings.Resolution = _defaultSymbolBase.SymbolResolution; AddUniverse(CoarseFilterFunction, FineFilterFunction ); } } public double f(double x) { return Math.Exp(x); } // filter based on CoarseFundamental public IEnumerable<Symbol> CoarseFilterFunction(IEnumerable<CoarseFundamental> coarse) { // returns the highest DollarVolume stocks // returns "totalNumberOfStocks" amount of stocks return (from stock in coarse where !stock.HasFundamentalData orderby stock.DollarVolume descending select stock.Symbol).Take(_stockCount); return Universe.Unchanged; } // filters out all symbols not contained in the NASDAQ exchange public IEnumerable<Symbol> FineFilterFunction(IEnumerable<FineFundamental> fine) { return (from stock in fine select stock.Symbol).Take(_stockCount); } private static double[] _coefficients = null; public double Regression(double t) { if(_coefficients == null) return 0.0; double sum = 0; for(int i = 0; i < _coefficients.Count(); i++) sum += Math.Pow(t, i) * _coefficients[i]; return sum; } private decimal time = 0; public void OnDataConsolidated(object sender, TradeBar bar) { SymbolData sd = _universe[bar.Symbol]; sd.Close.Add(bar.Close); if(!sd.Close.IsReady) return; _coefficients = new double[] {(double)sd.LeastSquares.Intercept.Current.Value, (double)sd.LeastSquares.Slope.Current.Value}; if(time % 5 == 0) sd.Fourier.Update((double)sd.Close[0], Regression); if(!sd.IsReady) { return; } if(enablePlotting) { Plot("FS", "P", bar.Close); Plot("FS", "F0", sd.Fourier.CalculateFunction(0)); Plot("FS", "F1", sd.Fourier.CalculateFunction(1)); Plot("LS", "I", sd.LeastSquares.Intercept); Plot("LS", "S", sd.LeastSquares.Slope); Plot("FSC", "A0", sd.Fourier.LeadingCoefficient); Plot("FSC", "A1", sd.Fourier.CosineCoefficients[0]); Plot("FSC", "B1", sd.Fourier.SineCoefficients[0]); //Plot("FSS", "B1", sd.Fourier.SineCoefficients[0]); //Plot("FSS", "B2", sd.Fourier.SineCoefficients[1]); } /*if(coeff < -3 && !Portfolio[sd.Symbol].Invested) SetHoldings(sd.Symbol, 1); else if(coeff > 3) Liquidate(sd.Symbol); sd.Fourier.Update(sd.Close[0], sd.LeastSquares.Intercept, sd.LeastSquares.Slope);*/ } public decimal[] ForwardEuler(Func<decimal, decimal> f, decimal ya, int a, int b, int n) { decimal dt = (b - a * 1.0m) / n; decimal[] y = new decimal[n + 1]; decimal[] t = new decimal[n + 1]; y[0] = ya; t[0] = 0; for(int i = 1; i < n + 1; i++) { t[i] = t[i - 1] + dt; y[i] = y[i - 1] + (dt * f(t[i])); } return y; } // OnSecuritiesChanged runs when the universe updates current securities public override void OnSecuritiesChanged(SecurityChanges changes) { _securityChanges = changes; // remove stocks from list that get removed from universe foreach (var security in _securityChanges.RemovedSecurities) { if(Securities[security.Symbol].Invested) { Log($"{Time}->Portfolio: Liquidated security {security.Symbol} on universe exit"); Liquidate(security.Symbol); } _universe.Remove(security.Symbol); Log($"{Time}->Universe: Removed security {security.Symbol} from universe"); } // add new securities to universe list foreach(var security in _securityChanges.AddedSecurities) { // creare new SymbolData object SymbolData sd; // if no base exists for symbol use default if(!_symbolBases.ContainsKey(security.Symbol) || _useDefaultSymbolBase) sd = new SymbolData(this, security.Symbol, _symbolBases["<BASE>"]); // otherwise use defined base else sd = new SymbolData(this, security.Symbol, _symbolBases[security.Symbol]); // initialize consolidator and store if needed TickConsolidator tickConsolidator = null; TradeBarConsolidator barConsolidator = null; if(sd.SymbolBase.SymbolResolution == Resolution.Tick) { var consolidator = sd.GetTickConsolidator(); if(consolidator != null) { consolidator.DataConsolidated += OnDataConsolidated; SubscriptionManager.AddConsolidator(sd.Symbol, consolidator); tickConsolidator = consolidator; } } else { var consolidator = sd.GetConsolidator(); if(consolidator != null) { consolidator.DataConsolidated += OnDataConsolidated; SubscriptionManager.AddConsolidator(sd.Symbol, consolidator); barConsolidator = consolidator; } } // initialize indicators: sd.Fourier = new FourierSeries(sd.Symbol, 15, 5, 2 * Math.PI, 2); sd.LeastSquares = new LeastSquaresMovingAverage(sd.Symbol, 2); // register indicators if(tickConsolidator != null) { RegisterIndicator(sd.Symbol, sd.LeastSquares, tickConsolidator); } else { RegisterIndicator(sd.Symbol, sd.LeastSquares, barConsolidator); } // load historical data var historical = History(sd.Symbol, sd.LeastSquares.WarmUpPeriod, sd.SymbolBase.SymbolResolution); foreach(var bar in historical) { sd.LeastSquares.Update(bar.Time, bar.Close); } // add SymbolData to universe _universe.Add(security.Symbol, sd); Log($"{Time}->Universe: Added security {security.Symbol} to universe"); } } public class SymbolBase { public readonly string Symbol; public readonly Resolution SymbolResolution; public readonly int SymbolConsolidationRate; public readonly decimal PortfolioAllocation; public SymbolBase(string symbol = "<BASE>", Resolution symbolResolution = Resolution.Minute, int symbolConsolidationRate = 1, decimal portfolioAllocation = 1.0m) { Symbol = symbol; SymbolResolution = symbolResolution; SymbolConsolidationRate = symbolConsolidationRate; PortfolioAllocation = portfolioAllocation; } } // default class containing all symbol information public class SymbolData { // Variables: // algorithm public readonly ClientAlgorithm Algorithm; // symbol public readonly string Symbol; // symbol base public readonly SymbolBase SymbolBase; // is ready public bool IsReady => Close.IsReady && Fourier.IsReady && LeastSquares.IsReady; // previous close public RollingWindow<decimal> Close = new RollingWindow<decimal>(10); // fourier series public FourierSeries Fourier; // least squares SMA public LeastSquaresMovingAverage LeastSquares; public SymbolData(ClientAlgorithm algorithm, Symbol symbol, SymbolBase symbolBase) { Algorithm = algorithm; Symbol = symbol; SymbolBase = symbolBase; } public TradeBarConsolidator GetConsolidator() { TimeSpan timeSpan; switch(SymbolBase.SymbolResolution) { case Resolution.Second: timeSpan = TimeSpan.FromSeconds(SymbolBase.SymbolConsolidationRate); break; case Resolution.Minute: timeSpan = TimeSpan.FromMinutes(SymbolBase.SymbolConsolidationRate); break; case Resolution.Hour: timeSpan = TimeSpan.FromHours(SymbolBase.SymbolConsolidationRate); break; case Resolution.Daily: timeSpan = TimeSpan.FromDays(SymbolBase.SymbolConsolidationRate); break; default: return null; } return new TradeBarConsolidator(timeSpan); } public TickConsolidator GetTickConsolidator() { return new TickConsolidator(SymbolBase.SymbolConsolidationRate); } } } }