Skip to content

Commit

Permalink
Refactor variables and update method parameters
Browse files Browse the repository at this point in the history
- Renamed variables for better clarity.
- Updated method to use 'IBaseDataBar' instead of 'TradeBar'
- Used 'MAMA({fastLimit}, {slowLimit}) instead of just 'MAMA'
  • Loading branch information
JosueNina committed Nov 27, 2024
1 parent c6f00c7 commit 2e0a201
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 44 deletions.
4 changes: 2 additions & 2 deletions Algorithm/QCAlgorithm.Indicators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1292,9 +1292,9 @@ public MeanAbsoluteDeviation MAD(Symbol symbol, int period, Resolution? resoluti
/// <param name="selector">Optional function to select a value from the BaseData. Defaults to casting the input to a TradeBar.</param>
/// <returns>The Mesa Adaptive Moving Average (MAMA) indicator for the requested symbol with the specified limits.</returns>
[DocumentationAttribute(Indicators)]
public MesaAdaptiveMovingAverage MAMA(Symbol symbol, decimal fastLimit = 0.5m, decimal slowLimit = 0.05m, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
public MesaAdaptiveMovingAverage MAMA(Symbol symbol, decimal fastLimit = 0.5m, decimal slowLimit = 0.05m, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"MAMA", resolution);
var name = CreateIndicatorName(symbol, $"MAMA({fastLimit},{slowLimit})", resolution);
var mesaAdaptiveMovingAverage = new MesaAdaptiveMovingAverage(name, fastLimit, slowLimit);
InitializeIndicator(mesaAdaptiveMovingAverage, resolution, selector, symbol);
return mesaAdaptiveMovingAverage;
Expand Down
79 changes: 37 additions & 42 deletions Indicators/MesaAdaptiveMovingAverage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ public class MesaAdaptiveMovingAverage : BarIndicator, IIndicatorWarmUpPeriodPro
/// Variables holding previous calculation values for use in subsequent iterations.
/// </summary>
private decimal _prevPeriod;
private decimal _prevI2;
private decimal _prevQ2;
private decimal _prevRe;
private decimal _prevIm;
private decimal _prevInPhase2;
private decimal _prevQuadrature2;
private decimal _prevReal;
private decimal _prevImaginary;
private decimal _prevSmoothPeriod;
private decimal _prevPhase;
private decimal _prevMama;
Expand All @@ -82,10 +82,10 @@ public MesaAdaptiveMovingAverage(string name, decimal fastLimit = 0.5m, decimal
_inPhaseHistory = new RollingWindow<decimal>(6);
_quadratureHistory = new RollingWindow<decimal>(6);
_prevPeriod = 0m;
_prevI2 = 0m;
_prevQ2 = 0m;
_prevRe = 0m;
_prevIm = 0m;
_prevInPhase2 = 0m;
_prevQuadrature2 = 0m;
_prevReal = 0m;
_prevImaginary = 0m;
_prevSmoothPeriod = 0m;
_prevPhase = 0m;
_prevMama = 0m;
Expand Down Expand Up @@ -147,35 +147,30 @@ protected override decimal ComputeNextValue(IBaseDataBar input)

private (decimal, decimal) ComputeMamaAndFama()
{
// Small Coefficient
const decimal sC = 0.0962m;
// Large Coefficient
const decimal lC = 0.5769m;

var adjustedPeriod = 0.075m * _prevPeriod + 0.54m;

// Compute the smoothed price value using a weighted average of the most recent prices.
var smooth = (4 * _priceHistory[0] + 3 * _priceHistory[1] + 2 * _priceHistory[2] + _priceHistory[3]) / 10;

// Detrend the smoothed price to remove market noise, applying coefficients and adjusted period.
var detrender = (sC * smooth + lC * _smoothHistory[1] - lC * _smoothHistory[3] - sC * _smoothHistory[5]) * adjustedPeriod;
var detrender = (0.0962m * smooth + 0.5769m * _smoothHistory[1] - 0.5769m * _smoothHistory[3] - 0.0962m * _smoothHistory[5]) * adjustedPeriod;

// Compute the InPhase (I1) and Quadrature (Q1) components for the adaptive moving average.
var q1 = (sC * detrender + lC * _detrendHistory[1] - lC * _detrendHistory[3] - sC * _detrendHistory[5]) * adjustedPeriod;
var i1 = _detrendHistory[2];
var quadrature1 = (0.0962m * detrender + 0.5769m * _detrendHistory[1] - 0.5769m * _detrendHistory[3] - 0.0962m * _detrendHistory[5]) * adjustedPeriod;
var inPhase1 = _detrendHistory[2];

// Advance the phase of I1 and Q1 by 90 degrees
var ji = (sC * i1 + lC * _inPhaseHistory[1] - lC * _inPhaseHistory[3] - sC * _inPhaseHistory[5]) * adjustedPeriod;
var jq = (sC * q1 + lC * _quadratureHistory[1] - lC * _quadratureHistory[3] - sC * _quadratureHistory[5]) * adjustedPeriod;
var i2 = i1 - jq;
var q2 = q1 + ji;
var adjustedInPhase = (0.0962m * inPhase1 + 0.5769m * _inPhaseHistory[1] - 0.5769m * _inPhaseHistory[3] - 0.0962m * _inPhaseHistory[5]) * adjustedPeriod;
var adjustedQuadrature = (0.0962m * quadrature1 + 0.5769m * _quadratureHistory[1] - 0.5769m * _quadratureHistory[3] - 0.0962m * _quadratureHistory[5]) * adjustedPeriod;
var inPhase2 = inPhase1 - adjustedQuadrature;
var quadrature2 = quadrature1 + adjustedInPhase;

// Smooth the I2 and Q2 components before applying the discriminator
i2 = 0.2m * i2 + 0.8m * _prevI2;
q2 = 0.2m * q2 + 0.8m * _prevQ2;
inPhase2 = 0.2m * inPhase2 + 0.8m * _prevInPhase2;
quadrature2 = 0.2m * quadrature2 + 0.8m * _prevQuadrature2;

// Get alpha
var alpha = ComputeAlpha(i1, q1, i2, q2);
var alpha = ComputeAlpha(inPhase1, quadrature1, inPhase2, quadrature2);

// Calculate the MAMA and FAMA
var mama = alpha * _priceHistory[0] + (1m - alpha) * _prevMama;
Expand All @@ -184,24 +179,24 @@ protected override decimal ComputeNextValue(IBaseDataBar input)
// Update rolling history
_smoothHistory.Add(smooth);
_detrendHistory.Add(detrender);
_inPhaseHistory.Add(i1);
_quadratureHistory.Add(q1);
_inPhaseHistory.Add(inPhase1);
_quadratureHistory.Add(quadrature1);

return (mama, fama);
}

private decimal ComputeAlpha(decimal i1, decimal q1, decimal i2, decimal q2)
private decimal ComputeAlpha(decimal inPhase1, decimal quadrature1, decimal inPhase2, decimal quadrature2)
{
var re = i2 * _prevI2 + q2 * _prevQ2;
var im = i2 * _prevQ2 - q2 * _prevI2;
re = 0.2m * re + 0.8m * _prevRe;
im = 0.2m * im + 0.8m * _prevIm;
var real = inPhase2 * _prevInPhase2 + quadrature2 * _prevQuadrature2;
var imaginary = inPhase2 * _prevQuadrature2 - quadrature2 * _prevInPhase2;
real = 0.2m * real + 0.8m * _prevReal;
imaginary = 0.2m * imaginary + 0.8m * _prevImaginary;

// Calculate the period
var period = 0m;
if (im != 0 && re != 0)
if (imaginary != 0 && real != 0)
{
var angleInDegrees = (decimal)Math.Atan((double)(im / re)) * _rad2Deg;
var angleInDegrees = (decimal)Math.Atan((double)(imaginary / real)) * _rad2Deg;
period = (angleInDegrees > 0) ? 360m / angleInDegrees : 0m;
}

Expand Down Expand Up @@ -229,9 +224,9 @@ private decimal ComputeAlpha(decimal i1, decimal q1, decimal i2, decimal q2)

// Calculate the phase
var phase = 0m;
if (i1 != 0)
if (inPhase1 != 0)
{
phase = (decimal)Math.Atan((double)(q1 / i1)) * _rad2Deg;
phase = (decimal)Math.Atan((double)(quadrature1 / inPhase1)) * _rad2Deg;
}

// Calculate the delta phase
Expand All @@ -249,10 +244,10 @@ private decimal ComputeAlpha(decimal i1, decimal q1, decimal i2, decimal q2)
}

// Update previous values
_prevI2 = i2;
_prevQ2 = q2;
_prevRe = re;
_prevIm = im;
_prevInPhase2 = inPhase2;
_prevQuadrature2 = quadrature2;
_prevReal = real;
_prevImaginary = imaginary;
_prevPeriod = period;
_prevSmoothPeriod = smoothPeriod;
_prevPhase = phase;
Expand All @@ -271,10 +266,10 @@ public override void Reset()
_inPhaseHistory.Reset();
_quadratureHistory.Reset();
_prevPeriod = 0m;
_prevI2 = 0m;
_prevQ2 = 0m;
_prevRe = 0m;
_prevIm = 0m;
_prevInPhase2 = 0m;
_prevQuadrature2 = 0m;
_prevReal = 0m;
_prevImaginary = 0m;
_prevSmoothPeriod = 0m;
_prevPhase = 0m;
_prevMama = 0m;
Expand Down

0 comments on commit 2e0a201

Please sign in to comment.