Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions project-templates/csharp/equity-dollar-cost-averaging/Main.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#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
public class VooWeeklyDcaAlgorithm : QCAlgorithm
{
private const decimal _dollarAmount = 5000m;

private Equity _voo;

public override void Initialize()
{
SetStartDate(2022, 1, 1);
SetEndDate(2024, 12, 31);
SetCash(200000);

Settings.SeedInitialPrices = true;

_voo = AddEquity("VOO", Resolution.Minute);

Schedule.On(
DateRules.WeekStart(_voo.Symbol),
TimeRules.AfterMarketOpen(_voo.Symbol, 1),
BuyVoo);

}

public override void OnWarmupFinished()
{
BuyVoo();
}

public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status == OrderStatus.Filled)
{
Plot("Fills", "VOO", orderEvent.FillPrice * orderEvent.FillQuantity);
}
}

private void BuyVoo()
{
if (Portfolio.Cash < _dollarAmount)
{
return;
}

var holdingsValue = _voo.Holdings.HoldingsValue;
var targetFraction = (holdingsValue + _dollarAmount) / Portfolio.TotalPortfolioValue;
var quantity = CalculateOrderQuantity(_voo.Symbol, targetFraction);

if (quantity > 0)
{
MarketOrder(_voo.Symbol, quantity);
}
}
}
107 changes: 107 additions & 0 deletions project-templates/csharp/equity-dual-momentum-asset-class/Main.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#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
public class DualMomentumAlgorithm : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2022, 1, 1);
SetEndDate(2024, 12, 31);
SetCash(100000);
Settings.SeedInitialPrices = true;
Settings.AutomaticIndicatorWarmUp = true;

var tickers = new[] { "SPY", "EFA", "AGG" };
foreach (var ticker in tickers)
{
dynamic equity = AddEquity(ticker, Resolution.Minute);
equity.Rocp = ROCP(equity.Symbol, 252, Resolution.Daily);
}

Schedule.On(DateRules.MonthStart("SPY"), TimeRules.BeforeMarketOpen("SPY", 5), Rebalance);
}

public override void OnWarmupFinished()
{
Rebalance();
}

private void Rebalance()
{
var returns = new Dictionary<Symbol, decimal>();
foreach (dynamic security in Securities.Values)
{
if (!security.Rocp.IsReady)
{
continue;
}
returns[security.Symbol] = security.Rocp.Current.Value;
}
if (returns.Count == 0)
{
return;
}

var winner = returns.OrderByDescending(kvp => kvp.Value).First().Key;
SetHoldings(new List<PortfolioTarget> { new PortfolioTarget(winner, 1m) }, true);
}
}
105 changes: 105 additions & 0 deletions project-templates/csharp/equity-permanent-portfolio/Main.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#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
public class PermanentPortfolioAlgorithm : QCAlgorithm
{
private readonly List<PortfolioTarget> _targets = new();
private const decimal _weight = 0.25m;
private const decimal _driftThreshold = 0.03m;

public override void Initialize()
{
SetStartDate(2022, 1, 1);
SetEndDate(2024, 12, 31);
SetCash(100000);
Settings.SeedInitialPrices = true;

foreach (var ticker in new[] { "SPY", "TLT", "GLD", "SHY" })
{
var symbol = AddEquity(ticker, Resolution.Minute).Symbol;
_targets.Add(new PortfolioTarget(symbol, _weight));
}

Schedule.On(
DateRules.YearStart("SPY", 2),
TimeRules.AfterMarketOpen("SPY", 5),
Rebalance);
}

public override void OnWarmupFinished()
{
SetHoldings(_targets, liquidateExistingHoldings: true);
}

private void Rebalance()
{
foreach (var target in _targets)
{
var currentWeight = Portfolio[target.Symbol].HoldingsValue / Portfolio.TotalHoldingsValue;
if (Math.Abs(currentWeight - _weight) > _driftThreshold)
{
SetHoldings(_targets, liquidateExistingHoldings: true);
return;
}
}
}
}
24 changes: 24 additions & 0 deletions project-templates/csharp/templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,30 @@
"spec": "Asset: IWM. Minute resolution. 2022-01-01 to 2024-12-31, $100k. WilliamsPercentR(14). Long when %R < -80; exit when %R > -20. Demonstrates: Williams %R indicator, oversold reversion logic, plotting against -80/-20 reference lines. Edge case: hold cap of 5 trading days.",
"tags": ["Equity", "indicators", "williams-r", "oscillator"],
"reference_template": "equities-static-universe"
},
{
"folder": "equity-permanent-portfolio",
"name": "Equity Permanent Portfolio",
"description": "Holds 25% each of SPY, TLT, GLD, and SHY with annual rebalance — Browne's Permanent Portfolio.",
"spec": "Assets: SPY, TLT, GLD, SHY. Minute. 2022-01-01 to 2024-12-31, $100k. Equal-weight 25% on first bar; annual rebalance every January 2nd. Demonstrates: 4-asset allocation, annual scheduled event, scheduled-event rule chaining. Edge case: skip rebalance if drift < 3% from target.",
"tags": ["Equity", "permanent-portfolio", "asset-allocation", "scheduled-event"],
"reference_template": "equities-static-universe"
},
{
"folder": "equity-dual-momentum-asset-class",
"name": "Equity Dual Momentum",
"description": "Implements Antonacci dual momentum across SPY, EFA, and AGG: pick the top 12-month return, fall back to AGG if absolute momentum is negative.",
"spec": "Assets: SPY, EFA, AGG. Minute resolution. 2022-01-01 to 2024-12-31, $100k. Monthly: compute 12-month return for each; pick the highest; if highest <= AGG return then hold AGG; else hold winner 100%. Demonstrates: history-based momentum, monthly schedule, conditional hold. Edge case: rebalance only on first trading day of month.",
"tags": ["Equity", "dual-momentum", "asset-allocation", "history"],
"reference_template": "history-and-etf-universe"
},
{
"folder": "equity-dollar-cost-averaging",
"name": "Equity Dollar Cost Averaging",
"description": "Buys $5,000 worth of VOO every Monday morning regardless of price, accumulating shares over the backtest.",
"spec": "Asset: VOO. Minute. 2022-01-01 to 2024-12-31, $200k starting cash. Schedule: every Monday after market open buy VOO with $5,000 of cash via market_order using calculate_order_quantity. Demonstrates: weekly schedule, fixed-dollar buys, calculate_order_quantity, no liquidation. Edge case: skip if insufficient cash; never sell.",
"tags": ["Equity", "dca", "scheduled-event", "buy-and-hold"],
"reference_template": "equities-static-universe"
}
]
}
Loading