Overall Statistics |
Total Trades 1 Average Win 0% Average Loss 0% Compounding Annual Return 53.090% Drawdown 4.100% Expectancy 0 Net Profit 23.802% Sharpe Ratio 3.216 Probabilistic Sharpe Ratio 89.225% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0.442 Beta -0.008 Annual Standard Deviation 0.136 Annual Variance 0.019 Information Ratio -0.018 Tracking Error 0.194 Treynor Ratio -52.729 Total Fees $1.48 Estimated Strategy Capacity $1100000000.00 |
using QuantConnect.Data.Market; using System; namespace QuantConnect.Algorithm.CSharp { public class CasualSkyBlueJaguar : QCAlgorithm { private PercentageVolumeOscillator pvo; private Symbol symbol; public override void Initialize() { SetStartDate(2020, 10, 26); //Set Start Date SetCash(100000); //Set Strategy Cash symbol = AddEquity("SPY", Resolution.Daily).Symbol; var fastMovingAveragePeriods = 10; var slowMovingAveragePeriods = 15; pvo = new PercentageVolumeOscillator( $"{nameof(PercentageVolumeOscillator)}({symbol},{fastMovingAveragePeriods},{slowMovingAveragePeriods})", fastMovingAveragePeriods, slowMovingAveragePeriods); RegisterIndicator(symbol, pvo, Resolution.Daily); } /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// Slice object keyed by symbol containing the stock data public override void OnData(Slice data) { if (!Portfolio.Invested) { SetHoldings("SPY", 1); Debug("Purchased Stock"); } // To update the indicator manually... (need to remove `RegisterIndicator`) //Plot("Update", "IsReady", Convert.ToInt32(p.Update(data[s]))); Plot("PercentageVolumeOscillator", "Value", pvo.Current.Value); } } } namespace QuantConnect.Indicators { /// <summary> /// This indicator computes the Percentage Volume Ocillator (PVO) /// PVO = ([Fast moving average of volume] - [Slow moving average of volume]) / [Slow moving average of volume] /// </summary> public class PercentageVolumeOscillator : TradeBarIndicator, IIndicatorWarmUpPeriodProvider { private readonly SimpleMovingAverage _slowMovingAverageVolume; private readonly SimpleMovingAverage _fastMovingAverageVolume; /// <summary> /// Creates a new PercentageVolumeOscillator indicator using the specified periods /// </summary> public PercentageVolumeOscillator( string name, int fastMovingAveragePeriods = 5, int slowMovingAveragePeriods = 20) // Try 14 and 28 for Resolution.Daily and longer intervals : base(name) { _slowMovingAverageVolume = new SimpleMovingAverage($"{name}_SlowMovingAverageVolume", slowMovingAveragePeriods); _fastMovingAverageVolume = new SimpleMovingAverage($"{name}_FastMovingAverageVolume", fastMovingAveragePeriods); } /// <summary> /// Creates a new PercentageVolumeOscillator indicator using the specified periods /// </summary> public PercentageVolumeOscillator(int fastMovingAveragePeriods, int slowMovingAveragePeriods) : this($"{nameof(PercentageVolumeOscillator)}({fastMovingAveragePeriods},{slowMovingAveragePeriods})", fastMovingAveragePeriods, slowMovingAveragePeriods) { } /// <summary> /// Gets a flag indicating when this indicator is ready and fully initialized /// </summary> public override bool IsReady => _slowMovingAverageVolume.IsReady && _fastMovingAverageVolume.IsReady; /// <summary> /// Resets this indicator to its initial state /// </summary> public override void Reset() { _slowMovingAverageVolume.Reset(); _fastMovingAverageVolume.Reset(); base.Reset(); } /// <summary> /// Required period, in data points, for the indicator to be ready and fully initialized. /// </summary> public int WarmUpPeriod => _slowMovingAverageVolume.WarmUpPeriod; /// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(TradeBar input) { _slowMovingAverageVolume.Update(input.Time, input.Volume); _fastMovingAverageVolume.Update(input.Time, input.Volume); if (_slowMovingAverageVolume == 0) return 0; // To avoid a divide-by-zero error var difference = (_fastMovingAverageVolume - _slowMovingAverageVolume); var percentageChange = difference / _slowMovingAverageVolume * 100; return percentageChange; } } }