16 using MathNet.Numerics.Statistics;
20 using System.Collections.Generic;
32 private readonly
int _lookback;
34 private readonly
double _minimumCorrelation;
35 private Tuple<Symbol, Symbol> _bestPair;
45 : base(lookback, resolution, threshold)
48 _resolution = resolution;
49 _minimumCorrelation = minimumCorrelation;
61 var symbols =
Securities.Select(x => x.Symbol).ToArray();
63 var history = algorithm.
History(symbols, _lookback, _resolution);
65 var vectors = GetPriceVectors(history);
67 if (vectors.LongLength == 0)
69 algorithm.
Debug($
"PearsonCorrelationPairsTradingAlphaModel.OnSecuritiesChanged(): The requested historical data does not have series of prices with the same date/time. Please consider increasing the looback period. Current lookback: {_lookback}");
73 var pearsonMatrix = Correlation.PearsonMatrix(vectors).UpperTriangle();
75 var maxValue = pearsonMatrix.Enumerate().Where(x => Math.Abs(x) < 1).Max();
76 if (maxValue >= _minimumCorrelation)
78 var maxTuple = pearsonMatrix.Find(x => x == maxValue);
79 _bestPair = Tuple.Create(symbols[maxTuple.Item1], symbols[maxTuple.Item2]);
83 base.OnSecuritiesChanged(algorithm, changes);
95 return _bestPair !=
null && asset1 == _bestPair.Item1 && asset2 == _bestPair.Item2;
98 private double[][] GetPriceVectors(IEnumerable<Slice> slices)
100 var symbols =
Securities.Select(x => x.Symbol).ToArray();
101 var timeZones =
Securities.ToDictionary(x => x.Symbol, y => y.Exchange.TimeZone);
104 var isDailyAndMultipleTimeZone = _resolution ==
Resolution.Daily && timeZones.Values.Distinct().Count() > 1;
106 var bars =
new List<BaseData>();
108 if (isDailyAndMultipleTimeZone)
111 .GroupBy(x => x.Time.Date)
112 .Where(x => x.Sum(k => k.Count) == symbols.Length)
113 .SelectMany(x => x.SelectMany(y => y.Values)));
118 .Where(x => x.Count == symbols.Length)
119 .SelectMany(x => x.Values));
123 .GroupBy(x => x.Symbol)
126 var array = x.Select(b => Math.Log((
double)b.Price)).ToArray();
127 if (array.Length > 1)
129 for (var i = array.Length - 1; i > 0; i--)
131 array[i] = array[i] - array[i - 1];
138 return new double[0];