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