17 using System.Collections.Generic;
37 private int _numOfAssets;
38 private double[] _weightVector;
39 private decimal _reversionThreshold;
40 private int _windowSize;
42 private Dictionary<Symbol, MeanReversionSymbolData> _symbolData =
new();
55 decimal reversionThreshold = 1,
58 : this(rebalancingDateRules.ToFunc(), portfolioBias, reversionThreshold, windowSize, resolution)
72 decimal reversionThreshold = 1,
75 : this(rebalanceResolution.ToTimeSpan(), portfolioBias, reversionThreshold, windowSize, resolution)
89 decimal reversionThreshold = 1,
92 : this(dt => dt.Add(timeSpan), portfolioBias, reversionThreshold, windowSize, resolution)
109 decimal reversionThreshold = 1,
112 : this((Func<DateTime, DateTime?>)null, portfolioBias, reversionThreshold, windowSize, resolution)
129 decimal reversionThreshold = 1,
132 : this(rebalancingFunc != null ? (Func<DateTime, DateTime?>)(timeUtc => rebalancingFunc(timeUtc)) : null,
133 portfolioBias, reversionThreshold, windowSize, resolution)
149 decimal reversionThreshold = 1,
152 : base(rebalancingFunc)
156 throw new ArgumentException(
"Long position must be allowed in MeanReversionPortfolioConstructionModel.");
159 _reversionThreshold = reversionThreshold;
160 _resolution = resolution;
161 _windowSize = windowSize;
171 var targets =
new Dictionary<Insight, double>();
174 if (activeInsights.IsNullOrEmpty() ||
175 !activeInsights.All(x => _symbolData[x.Symbol].IsReady()))
180 var numOfAssets = activeInsights.Count;
181 if (_numOfAssets != numOfAssets)
183 _numOfAssets = numOfAssets;
185 _weightVector = Enumerable.Repeat((
double) 1/_numOfAssets, _numOfAssets).ToArray();
194 var nextPrediction = priceRelatives.Average();
195 var assetsMeanDev = priceRelatives.Select(x => x - nextPrediction).ToArray();
196 var secondNorm = Math.Pow(assetsMeanDev.Euclidean(), 2);
199 if (secondNorm == 0d)
205 stepSize = (_weightVector.InnerProduct(priceRelatives) - (double)_reversionThreshold) / secondNorm;
206 stepSize = Math.Max(0d, stepSize);
211 var nextPortfolio = _weightVector.Select((x, i) => x - assetsMeanDev[i] * stepSize);
215 _weightVector = normalizedPortfolioWeightVector;
218 for (
int i = 0; i < _numOfAssets; i++)
220 targets.Add(activeInsights[i], normalizedPortfolioWeightVector[i]);
233 var numOfInsights = activeInsights.Count;
236 var nextPriceRelatives =
new double[numOfInsights];
238 for (
int i = 0; i < numOfInsights; i++)
240 var insight = activeInsights[i];
241 var symbolData = _symbolData[insight.Symbol];
243 nextPriceRelatives[i] = insight.Magnitude !=
null ?
244 1 + (double)insight.Magnitude * (
int)insight.Direction:
245 (double)symbolData.Identity.Current.Value / (
double)symbolData.Sma.Current.Value;
248 return nextPriceRelatives;
258 base.OnSecuritiesChanged(algorithm, changes);
261 foreach (var removed
in changes.RemovedSecurities)
263 _symbolData.Remove(removed.Symbol, out var symbolData);
268 var symbols = changes.AddedSecurities.Select(x => x.Symbol);
270 foreach(var symbol
in symbols)
272 if (!_symbolData.ContainsKey(symbol))
274 _symbolData.Add(symbol,
new MeanReversionSymbolData(algorithm, symbol, _windowSize, _resolution));
284 public static IEnumerable<double>
CumulativeSum(IEnumerable<double> sequence)
287 foreach(var item
in sequence)
308 throw new ArgumentException(
"Total must be > 0 for Euclidean Projection onto the Simplex.");
312 var mu = vector.OrderByDescending(x => x).ToArray();
315 var rho = Enumerable.Range(0, vector.Count()).Where(i => mu[i] > (sv[i] - total) / (i+1)).Last();
316 var theta = (sv[rho] - total) / (rho + 1);
317 var w = vector.Select(x => Math.Max(x - theta, 0d)).ToArray();
321 private class MeanReversionSymbolData
331 Sma = algo.
SMA(symbol, windowSize, resolution);
344 public bool IsReady()