| Overall Statistics |
|
Total Trades 910 Average Win 0.42% Average Loss -0.33% Compounding Annual Return 20.970% Drawdown 39.400% Expectancy 1.096 Net Profit 1116.155% Sharpe Ratio 0.869 Probabilistic Sharpe Ratio 20.349% Loss Rate 8% Win Rate 92% Profit-Loss Ratio 1.28 Alpha 0.024 Beta 1.198 Annual Standard Deviation 0.184 Annual Variance 0.034 Information Ratio 0.845 Tracking Error 0.055 Treynor Ratio 0.134 Total Fees $954.47 Estimated Strategy Capacity $320000.00 Lowest Capacity Asset DBP TP2MIF0KNIAT |
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Common.Logging.Factory;
using QuantConnect.Data;
using QuantConnect.Indicators;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Util;
namespace QuantConnect.Algorithm.CSharp {
public class AllWeather : QCAlgorithm {
private Strat[] _strategies;
public override void Initialize() {
SetStartDate(2009, 1, 1);
SetCash(100000);
var weightings = new (string Sector, Weighting Target)[] {
("Industrial", new("SPY", 0.35m)),
("Metals", new("DBP", 0.10m)),
("Crypto", new("GBTC", 0.35m)),
("China", new("GXC", 0.06m)),
("Tech", new("XLK", 0.16m)),
("Energy", new("XLE", 0.09m)),
("Finance", new("XLF", 0.08m)),
("Health", new("XLV", 0.07m)),
("Fixed", new("TLT", 0.15m))
};
var coreInvestor = new LongFixedRatio(weightings.Select(x => x.Target), leverage: 3.3m);
Schedule.On(DateRules.MonthStart(), TimeRules.At(10, 00), coreInvestor.ScheduleRebalance);
_strategies = new[] { coreInvestor };
foreach (var inv in _strategies) {
foreach (var sym in inv.Symbols) {
var equity = AddEquity(sym, Resolution.Daily);
equity.SetDataNormalizationMode(DataNormalizationMode.Raw);
}
}
}
public override void OnData(Slice data) {
Plot("Values", "Margin Remaining", Portfolio.MarginRemaining / Portfolio.TotalPortfolioValue);
Plot("Values", "Margin Used", Portfolio.TotalMarginUsed / Portfolio.TotalPortfolioValue);
foreach (var inv in _strategies) {
inv.OnData(this, data);
}
}
}
internal interface Strat {
public decimal Leverage { get; }
public IEnumerable<Symbol> Symbols { get; }
public void OnData(QCAlgorithm algo, Slice slice);
}
internal class LongFixedRatio : Strat {
private readonly Weighting[] _weightings;
private bool _shouldRebalance = true;
public decimal Leverage { get; }
public IEnumerable<Symbol> Symbols => _weightings.Select(x => x.Symbol);
public LongFixedRatio(IEnumerable<Weighting> weightings, decimal leverage) {
_weightings = weightings.ToArray();
Leverage = leverage;
}
public void ScheduleRebalance() {
_shouldRebalance = true;
}
public void OnData(QCAlgorithm algo, Slice slice) {
if (_shouldRebalance) {
var P = algo.Portfolio;
var validWeightings = _weightings.Where(w => slice.Bars.ContainsKey(w.Symbol)).ToArray();
var totalWeight = validWeightings.Select(w => w.Weight).Sum();
var realizedWeightings = validWeightings.Select(x => x with { Weight = x.Weight / totalWeight });
var totalMargin = 2 * P.TotalMarginUsed + P.MarginRemaining;
foreach (var wt in realizedWeightings) {
var close = slice.Bars[wt.Symbol].Close;
int goalQty = (int)Math.Truncate(0.9m * totalMargin * wt.Weight / close);
var currentQty = (int)P[wt.Symbol].Quantity;
int toBuyQty = goalQty - currentQty;
algo.Plot("Space", wt.Symbol, (P.MarginRemaining - toBuyQty * close) / P.TotalPortfolioValue);
algo.LimitOrder(wt.Symbol, toBuyQty, close);
}
_shouldRebalance = false;
}
}
}
record Weighting(Symbol Symbol, decimal Weight) {
public Weighting(string symbol, decimal weight) :
this(Symbol.Create(symbol, SecurityType.Equity, Market.USA), weight) { }
}
}