| Overall Statistics |
|
Total Orders 73 Average Win 14.59% Average Loss -6.85% Compounding Annual Return 7.191% Drawdown 37.200% Expectancy 0.826 Start Equity 100000 End Equity 570416.44 Net Profit 470.416% Sharpe Ratio 0.262 Sortino Ratio 0.231 Probabilistic Sharpe Ratio 0.022% Loss Rate 42% Win Rate 58% Profit-Loss Ratio 2.13 Alpha 0.014 Beta 0.413 Annual Standard Deviation 0.14 Annual Variance 0.02 Information Ratio -0.112 Tracking Error 0.167 Treynor Ratio 0.089 Total Fees $744.84 Estimated Strategy Capacity $75000000.00 Lowest Capacity Asset QQQ RIWIV7K5Z9LX Portfolio Turnover 0.80% |
#region imports
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Drawing;
using QuantConnect;
using QuantConnect.Algorithm.Framework;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Portfolio.SignalExports;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Selection;
using QuantConnect.Api;
using QuantConnect.Parameters;
using QuantConnect.Benchmarks;
using QuantConnect.Brokerages;
using QuantConnect.Commands;
using QuantConnect.Configuration;
using QuantConnect.Util;
using QuantConnect.Interfaces;
using QuantConnect.Algorithm;
using QuantConnect.Indicators;
using QuantConnect.Data;
using QuantConnect.Data.Auxiliary;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Custom;
using QuantConnect.Data.Custom.IconicTypes;
using QuantConnect.DataSource;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.Market;
using QuantConnect.Data.Shortable;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Notifications;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.Fills;
using QuantConnect.Orders.OptionExercise;
using QuantConnect.Orders.Slippage;
using QuantConnect.Orders.TimeInForces;
using QuantConnect.Python;
using QuantConnect.Scheduling;
using QuantConnect.Securities;
using QuantConnect.Securities.Equity;
using QuantConnect.Securities.Future;
using QuantConnect.Securities.Option;
using QuantConnect.Securities.Positions;
using QuantConnect.Securities.Forex;
using QuantConnect.Securities.Crypto;
using QuantConnect.Securities.CryptoFuture;
using QuantConnect.Securities.IndexOption;
using QuantConnect.Securities.Interfaces;
using QuantConnect.Securities.Volatility;
using QuantConnect.Storage;
using QuantConnect.Statistics;
using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
using Calendar = QuantConnect.Data.Consolidators.Calendar;
#endregion
namespace QuantConnect.Algorithm.CSharp
{
public class VirtualLightBrownGalago : QCAlgorithm
{
// Add some class members
private Symbol _symbol;
private bool indicatorsReady = false;
private RateOfChange oneMonth, threeMonth, sixMonth, twelveMonth;
private Momentum dema50_returns;
private IDataConsolidator _consolidatorMonthly, _consolidatorDaily;
private ExponentialMovingAverage dema50, ema50;
private decimal fundx, stormGuard;
private List<decimal> eqtyCurveOneMonth, eqtyCurveThreeMonth, eqtyCurveSixMonth, eqtyCurveTwelveMonth;
private bool holdStockOneMonth = false, holdStockThreeMonth = false, holdStockSixMonth = false, holdStockTwelveMonth = false;
public override void Initialize()
{
SetStartDate(2000, 4, 30);
SetEndDate(2025, 5, 20);
SetCash(100000m);
eqtyCurveOneMonth = new List<decimal>();
eqtyCurveOneMonth.Add(100000m);
eqtyCurveThreeMonth = new List<decimal>();
eqtyCurveThreeMonth.Add(100000m);
eqtyCurveSixMonth = new List<decimal>();
eqtyCurveSixMonth.Add(100000m);
eqtyCurveTwelveMonth = new List<decimal>();
eqtyCurveTwelveMonth.Add(100000m);
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Adjusted;
// In Initialize, subscribe to a security, create the consolidator, and register it for automatic updates
_symbol = AddEquity("QQQ", Resolution.Minute).Symbol;
SetBenchmark(_symbol);
oneMonth = new RateOfChange(1);
threeMonth = new RateOfChange(3);
sixMonth = new RateOfChange(6);
twelveMonth = new RateOfChange(12);
dema50_returns = new Momentum(21);
ema50 = IndicatorExtensions.Of(new ExponentialMovingAverage(21,0.02m), dema50_returns);
dema50 = IndicatorExtensions.Of(new ExponentialMovingAverage(21,0.02m), ema50);
_consolidatorMonthly = Consolidate(_symbol, Calendar.Monthly, ConsolidationHandler);
_consolidatorDaily = Consolidate(_symbol, TimeSpan.FromDays(1), DailyConsolidationHandler);
// Feed in 100 trading days worth of data before the start date
SetWarmUp(252+18, Resolution.Daily);
}
// Notify yourself when the algorithm is ready to begin trading.
public override void OnWarmupFinished()
{
Log("Algorithm Ready");
}
// Define the consolidation handler
void DailyConsolidationHandler(TradeBar consolidatedBar)
{
dema50_returns.Update(consolidatedBar);
ema50.Update(dema50_returns.Current);
dema50.Update(ema50.Current);
}
// Define the consolidation handler
void ConsolidationHandler(TradeBar consolidatedBar)
{
Plot("MonthlyBars", "SPYMonthly", consolidatedBar);
oneMonth.Update(consolidatedBar);
threeMonth.Update(consolidatedBar);
sixMonth.Update(consolidatedBar);
twelveMonth.Update(consolidatedBar);
if (oneMonth.IsReady) {
Plot("ROCR", "oneMonth", oneMonth.Current.Value);
}
if (threeMonth.IsReady) {
Plot("ROCR", "threeMonth", threeMonth.Current.Value);
}
if (sixMonth.IsReady) {
Plot("ROCR", "sixMonth", sixMonth.Current.Value);
}
if (twelveMonth.IsReady) {
Plot("ROCR", "twelveMonth", twelveMonth.Current.Value);
}
if (oneMonth.IsReady && threeMonth.IsReady && sixMonth.IsReady && twelveMonth.IsReady) {
indicatorsReady = true;
if (!IsWarmingUp) {
if (holdStockOneMonth) {
eqtyCurveOneMonth.Add(eqtyCurveOneMonth.Last()*consolidatedBar.Close/consolidatedBar.Open);
} else {
eqtyCurveOneMonth.Add(eqtyCurveOneMonth.Last());
}
Plot("Strategy eqts","1monthEquityCurve",eqtyCurveOneMonth.Last());
holdStockOneMonth = oneMonth.Current.Value > 0;
if (holdStockThreeMonth) {
eqtyCurveThreeMonth.Add(eqtyCurveThreeMonth.Last()*consolidatedBar.Close/consolidatedBar.Open);
} else {
eqtyCurveThreeMonth.Add(eqtyCurveThreeMonth.Last());
}
Plot("Strategy eqts","3monthEquityCurve",eqtyCurveThreeMonth.Last());
holdStockThreeMonth = threeMonth.Current.Value > 0;
if (holdStockSixMonth) {
eqtyCurveSixMonth.Add(eqtyCurveSixMonth.Last()*consolidatedBar.Close/consolidatedBar.Open);
} else {
eqtyCurveSixMonth.Add(eqtyCurveSixMonth.Last());
}
Plot("Strategy eqt2","6monthEquityCurve",eqtyCurveSixMonth.Last());
holdStockSixMonth = sixMonth.Current.Value > 0;
if (holdStockTwelveMonth) {
eqtyCurveTwelveMonth.Add(eqtyCurveTwelveMonth.Last()*consolidatedBar.Close/consolidatedBar.Open);
} else {
eqtyCurveTwelveMonth.Add(eqtyCurveTwelveMonth.Last());
}
Plot("Strategy eqts2","12monthEquityCurve",eqtyCurveTwelveMonth.Last());
holdStockTwelveMonth = twelveMonth.Current.Value > 0;
int lookback_for_optim = 2;
decimal delta1month = eqtyCurveOneMonth.Last()/eqtyCurveOneMonth[eqtyCurveOneMonth.Count - lookback_for_optim]-1;
decimal delta3month = eqtyCurveThreeMonth.Last()/eqtyCurveThreeMonth[eqtyCurveThreeMonth.Count - lookback_for_optim]-1;
decimal delta6month = eqtyCurveSixMonth.Last()/eqtyCurveSixMonth[eqtyCurveSixMonth.Count - lookback_for_optim]-1;
decimal delta12month = eqtyCurveTwelveMonth.Last()/eqtyCurveTwelveMonth[eqtyCurveTwelveMonth.Count - lookback_for_optim]-1;
decimal maxCurveBetween12And6 = decimal.Max(delta12month,delta6month);
decimal maxCurveBetween1And3 = decimal.Max(delta1month,delta3month);
decimal maxCurveBetween1and12 = decimal.Max(maxCurveBetween12And6,maxCurveBetween1And3);
decimal w1=0m,w3=0m,w6=0m,w12=0m;
if (maxCurveBetween1and12 == delta12month)
w12=1m;
else if (maxCurveBetween1and12 == delta6month)
w6=1m;
else if (maxCurveBetween1and12 == delta3month)
w3=1m;
else if (maxCurveBetween1and12 == delta1month)
w1=1m;
fundx = w1*oneMonth.Current.Value+w3*threeMonth.Current.Value+w6*sixMonth.Current.Value+w12*twelveMonth.Current.Value;
Plot("Timers", "fundx", fundx);
}
}
if (dema50.IsReady) {
stormGuard = dema50.Current.Value;
Plot("Timers", "stormGuard", dema50.Current.Value);
}
if (oneMonth.IsReady && threeMonth.IsReady && sixMonth.IsReady && twelveMonth.IsReady && dema50.IsReady) {
int fundx_timer = 0;
if (fundx > 0) fundx_timer = 1;
int stormGuard_timer = 0;
if (stormGuard > 0) stormGuard_timer = 1;
Plot("Signals", "fundx_timer", fundx_timer);
Plot("Signals", "stormGuard_timer", stormGuard_timer);
}
}
/// 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 (!indicatorsReady) return;
if (fundx > 0) {
if (!Portfolio.Invested )
{
SetHoldings(_symbol, 1m);
}
} else {
if (Portfolio.Invested)
Liquidate();
}
}
}
}