| Overall Statistics |
|
Total Trades 39 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 $39.00 Estimated Strategy Capacity $3000000.00 Lowest Capacity Asset AMZN R735QTJ8XC9X |
namespace QuantConnect.Indicators {
using System.Numerics;
public class FourierSeries {
private readonly int _period;
private readonly decimal _frequency;
private readonly int _depth;
private decimal _leading;
private decimal _value;
public int WarmUpPeriod { get; }
public bool IsReady => CosineCoefficients.Count() == _depth && SineCoefficients.Count() == _depth;
public decimal Value => _value;
public decimal LeadingCoefficient => _leading;
public List<decimal> CosineCoefficients { get; }
public List<decimal> SineCoefficients { get; }
public void Reset()
{
CosineCoefficients.Clear();
SineCoefficients.Clear();
}
public FourierSeries(string name, int period, decimal frequency = 2 * (decimal)Math.PI, int depth = 5)
{
_period = period;
_frequency = frequency;
_depth = depth;
WarmUpPeriod = period;
CosineCoefficients = new List<decimal>();
SineCoefficients = new List<decimal>();
}
public void Update(decimal value, decimal intercept, decimal slope)
{
Console.WriteLine($"Updated");
// calculate coefficients
if(_leading == 0)
_leading = ((slope * _frequency) + intercept);
//_leading = 0;
// clear coefficients
CosineCoefficients.Clear();
SineCoefficients.Clear();
for(int i = 1; i <= _depth; i++)
{
decimal a_n = (2 * slope * _frequency) / (decimal)(Math.Pow(i, 2) * Math.Pow(Math.PI, 2)) * ((decimal)Math.Pow(-1, i) - 1);
CosineCoefficients.Add(a_n);
SineCoefficients.Add(0.0m);
/*
decimal sin_n = (decimal)((Math.Sin(i * Math.PI) - Math.Sin(-i * Math.PI)) / (Math.PI * i));
decimal cos_n = (decimal)((Math.Cos(i * Math.PI) - Math.Cos(-i * Math.PI)) / (Math.PI * i));
decimal a_n = ((intercept - value) * sin_n) + (slope * (z / _frequency) * (decimal)Math.Sin((double)z)) - (slope * cos_n);
CosineCoefficients.Add(a_n);
decimal b_n = ((intercept - value) * cos_n) + (slope * (-z / _frequency) * (decimal)Math.Cos((double)z)) - (slope * sin_n);
SineCoefficients.Add(b_n);
*/
}
_value = CalculateFunction(value);
}
public decimal CalculateFunction(decimal value, int iterations) {
decimal result = value;
for(int i = 0; i <= iterations; i++)
result = CalculateFunction(result);
return result;
}
public decimal CalculateFunction(decimal value) {
var function = LeadingCoefficient;
for(int i = 0; i < _depth; i++) {
function += (CosineCoefficients[i] * (decimal)Math.Cos((double)((i + 1) * (decimal)Math.PI * value / _frequency))) / (i + 1);
function += (SineCoefficients[i] * (decimal)Math.Sin((double)((i + 1) * (decimal)Math.PI * value / _frequency))) / (i + 1);
}
return function;
}
}
}/*
* 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();
}
}
}/*
This program was developed by Quantify and is property of the client
Usage and marketing of this program is permitted.
Quantify Developer(s): Conor Flynn
Date Created:
Client:
Client ID:
If you find a bug or an inconsistantcy please contact your assigned developer.
Contact: cflynn@quantify-co.com
To request a new copy of your program please contact support:
Contact: support@quantify-co.com
Note: Client ID is required for client verification upon requesting a new copy
*/
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
);
}
}
// 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 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;
if(!sd.IsReady) {
sd.Fourier.Update(sd.Close[0], sd.LeastSquares.Intercept, sd.LeastSquares.Slope);
return;
}
if(enablePlotting) {
Plot("FS", "P", bar.Close);
Plot("FS", "F", sd.Fourier.CalculateFunction(0));
Plot("FS", "F1", ForwardEuler(sd.Fourier.CalculateFunction, sd.Close[1], 0, 1, 100).Last() / 2);
Plot("FS", "F2", ForwardEuler(sd.Fourier.CalculateFunction, sd.Close[1], 0, 3, 100).Last() / 4);
Plot("FS", "F3", ForwardEuler(sd.Fourier.CalculateFunction, sd.Close[1], 0, 5, 100).Last() / 6);
Plot("LS", "I", sd.LeastSquares.Intercept);
Plot("LS", "S", sd.LeastSquares.Slope);
Plot("FSC", "A1+3/2", (sd.Fourier.CosineCoefficients[0] + sd.Fourier.CosineCoefficients[2]) / 2);
Plot("FSS", "B1", sd.Fourier.SineCoefficients[0]);
Plot("FSS", "B2", sd.Fourier.SineCoefficients[1]);
}
decimal coeff = (sd.Fourier.CosineCoefficients[0] + sd.Fourier.CosineCoefficients[2]) / 2;
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, 2 * (decimal)Math.PI, 100);
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);
}
}
}
}