Overall Statistics |
Total Trades 15 Average Win 80.25% Average Loss -7.30% Compounding Annual Return 149.942% Drawdown 82.400% Expectancy 1.998 Net Profit 149.942% Sharpe Ratio 4.454 Probabilistic Sharpe Ratio 64.335% Loss Rate 75% Win Rate 25% Profit-Loss Ratio 10.99 Alpha 4.29 Beta 10.8 Annual Standard Deviation 1.569 Annual Variance 2.461 Information Ratio 4.539 Tracking Error 1.484 Treynor Ratio 0.647 Total Fees $333.00 |
using QuantConnect.Securities.Future; using QuantConnect.Data.Market; namespace QuantConnect.Algorithm.CSharp { public class BuyAndHoldFuturesTemplate : QCAlgorithm { private Future _future; private FuturesContract _activeContract; private bool _isInitializedForFutures = false; private int _DaysBeforeExpiryToRollover = 1; public override void Initialize() { SetStartDate(2019, 1, 1); SetEndDate(2020, 1, 1); SetCash(100000); _future = AddFuture(Futures.Indices.SP500EMini, Resolution.Minute); _future.SetFilter(0, 600); // optional, helps reduce margin calls Settings.FreePortfolioValuePercentage = 0.3m; } override public void OnData(Slice slice) { // for QC API reasons, futures are best initialized in the OnData method if (!_isInitializedForFutures) { InitializeForFutures(slice); return; } // indicator (alpha) generating logic goes here // ... } private void InitializeForFutures(Slice slice) { SetActiveContractAndScheduleRollover(slice); SetHoldings(_activeContract.Symbol, 1); Log($"New contract purchased: {_activeContract.Symbol.Value}"); _isInitializedForFutures = true; } #region FUTURES ROLLOVER OVERHEAD private void SetActiveContractAndScheduleRollover(Slice slice) { if (slice.FutureChains.Count != 1) { Log($"ERROR - No contracts in var {nameof(slice.FutureChains)}"); return; } var esMiniChain = slice.FutureChains.First(); var recentContracts = esMiniChain.Value .Where(x => (x.Expiry - Time.Date).TotalDays > _DaysBeforeExpiryToRollover) .OrderBy(x => (x.Expiry - Time.Date).TotalDays) .ToList(); if (recentContracts.Count == 0) { _activeContract = null; Log($"ERROR - No contracts in var {nameof(recentContracts)}, no active contract assigned, no scheduled rollover. Liquidating portfolio."); Liquidate(); Log($"Portfolio liquidated."); return; } Log($"list of sorted recent contracts: {string.Join(", ", recentContracts.Select(x => x.Symbol.Value).ToList())}"); var frontContract = recentContracts.First(); _activeContract = frontContract; Log($"New active contract set to {_activeContract.Symbol.Value}"); ScheduleRollover(slice); } private void ScheduleRollover(Slice slice) { // hack to pass Slice to Rollover callback, see https://social.msdn.microsoft.com/Forums/en-US/fd7dcd64-5ec3-4951-81ab-2ca4f7dc06b2/ Action rolloverCallback = () => { Rollover(slice); }; Log($"Contract {_activeContract.Symbol.Value} has rollover scheduled for: {_activeContract.Expiry.AddDays(-1 * _DaysBeforeExpiryToRollover).ToShortDateString()}"); Schedule.On(DateRules.On(_activeContract.Expiry.AddDays(-1 * _DaysBeforeExpiryToRollover)), TimeRules.AfterMarketOpen(_activeContract.Symbol), rolloverCallback); } private void Rollover(Slice slice) { SetActiveContractAndScheduleRollover(slice); if (Portfolio.Invested) { Liquidate(); Log($"Portfolio liquidated."); SetHoldings(_activeContract.Symbol, 1); Log($"New contract purchased: {_activeContract.Symbol.Value}"); } } #endregion } }