30 private readonly decimal _fastLimit;
35 private readonly decimal _slowLimit;
40 private readonly decimal _rad2Deg = 180m / (4m * (decimal)Math.Atan(1.0));
54 private decimal _prevPeriod;
55 private decimal _prevInPhase2;
56 private decimal _prevQuadrature2;
57 private decimal _prevReal;
58 private decimal _prevImaginary;
59 private decimal _prevSmoothPeriod;
60 private decimal _prevPhase;
61 private decimal _prevMama;
77 _fastLimit = fastLimit;
78 _slowLimit = slowLimit;
86 _prevQuadrature2 = 0m;
89 _prevSmoothPeriod = 0m;
102 : this($
"MAMA", fastLimit, slowLimit)
126 var price = (input.
High + input.
Low) / 2;
127 _priceHistory.Add(price);
129 if (!_priceHistory.IsReady)
135 var (mama, fama) = ComputeMamaAndFama();
148 private (decimal, decimal) ComputeMamaAndFama()
150 const decimal smallCoefficient = 0.0962m;
151 const decimal largeCoefficient = 0.5769m;
153 var adjustedPeriod = 0.075m * _prevPeriod + 0.54m;
156 var smooth = (4 * _priceHistory[0] + 3 * _priceHistory[1] + 2 * _priceHistory[2] + _priceHistory[3]) / 10;
159 var detrender = (smallCoefficient * smooth + largeCoefficient * _smoothHistory[1] - largeCoefficient * _smoothHistory[3] - smallCoefficient * _smoothHistory[5]) * adjustedPeriod;
162 var quadrature1 = (smallCoefficient * detrender + largeCoefficient * _detrendHistory[1] - largeCoefficient * _detrendHistory[3] - smallCoefficient * _detrendHistory[5]) * adjustedPeriod;
163 var inPhase1 = _detrendHistory[2];
166 var adjustedInPhase = (smallCoefficient * inPhase1 + largeCoefficient * _inPhaseHistory[1] - largeCoefficient * _inPhaseHistory[3] - smallCoefficient * _inPhaseHistory[5]) * adjustedPeriod;
167 var adjustedQuadrature = (smallCoefficient * quadrature1 + largeCoefficient * _quadratureHistory[1] - largeCoefficient * _quadratureHistory[3] - smallCoefficient * _quadratureHistory[5]) * adjustedPeriod;
168 var inPhase2 = inPhase1 - adjustedQuadrature;
169 var quadrature2 = quadrature1 + adjustedInPhase;
172 inPhase2 = 0.2m * inPhase2 + 0.8m * _prevInPhase2;
173 quadrature2 = 0.2m * quadrature2 + 0.8m * _prevQuadrature2;
176 var alpha = ComputeAlpha(inPhase1, quadrature1, inPhase2, quadrature2);
179 var mama = alpha * _priceHistory[0] + (1m - alpha) * _prevMama;
180 var fama = 0.5m * alpha * mama + (1m - 0.5m * alpha) *
Fama.Current.Value;
183 _smoothHistory.Add(smooth);
184 _detrendHistory.Add(detrender);
185 _inPhaseHistory.Add(inPhase1);
186 _quadratureHistory.Add(quadrature1);
191 private decimal ComputeAlpha(decimal inPhase1, decimal quadrature1, decimal inPhase2, decimal quadrature2)
193 var real = inPhase2 * _prevInPhase2 + quadrature2 * _prevQuadrature2;
194 var imaginary = inPhase2 * _prevQuadrature2 - quadrature2 * _prevInPhase2;
195 real = 0.2m * real + 0.8m * _prevReal;
196 imaginary = 0.2m * imaginary + 0.8m * _prevImaginary;
200 if (imaginary != 0 && real != 0)
202 var angleInDegrees = (decimal)Math.Atan((
double)(imaginary / real)) * _rad2Deg;
203 period = (angleInDegrees > 0) ? 360m / angleInDegrees : 0m;
207 if (period > 1.5m * _prevPeriod)
209 period = 1.5m * _prevPeriod;
211 if (period < 0.67m * _prevPeriod)
213 period = 0.67m * _prevPeriod;
225 period = 0.2m * period + 0.8m * _prevPeriod;
226 var smoothPeriod = 0.33m * period + 0.67m * _prevSmoothPeriod;
232 phase = (decimal)Math.Atan((
double)(quadrature1 / inPhase1)) * _rad2Deg;
236 var deltaPhase = _prevPhase - phase;
243 var alpha = _fastLimit / deltaPhase;
244 if (alpha < _slowLimit)
250 _prevInPhase2 = inPhase2;
251 _prevQuadrature2 = quadrature2;
253 _prevImaginary = imaginary;
254 _prevPeriod = period;
255 _prevSmoothPeriod = smoothPeriod;
266 _priceHistory.Reset();
267 _smoothHistory.Reset();
268 _detrendHistory.Reset();
269 _inPhaseHistory.Reset();
270 _quadratureHistory.Reset();
273 _prevQuadrature2 = 0m;
276 _prevSmoothPeriod = 0m;