That search is worth years of study to find a satisfying conclusion. I know nothing of ML, ideally, these type of problems are better served using Clustering.
Why ML? Because in other scenarios, such as, using Std. Dev. or Percentile of MA difference to determine narrow region(s) a threshold needs to be used. Now, using same threshold everywhere is futile. So, optimization is required anyways to ascertain an underlying's wiggle factor.
Instead of using ML, here is a simple application using Stochastics.
/*
_____________________________________________________________________________________________
|This code is for AmiBroker Formula Language (AFL) learning (non-commercial) purposes only. |
|Please do not copy this code (or any other version of it) and paste it over on other forums |
|or anywhere else on the Internet or in any other form without the AmiBroker Forum owner's |
|consent (https://forum.amibroker.com/). |
_____________________________________________________________________________________________|
*/
_SECTION_BEGIN( "Detecting MA Proximity using Stochastics" );
SetChartBkColor( ColorRGB( 2, 18, 30 ) );
price = C;
Plot( price, "Price", colorDefault, styleCandle );
maTypeCh = ParamList( "Choose MA Type", "SMA|EMA|Wilders", 0 );
maPerList = "10,20,50,100"; // comma-separated list of MA periods
maMxRGBColorSet = MxFromString( StrFormat( // a matrix storing RGB for each MA in maPerList
"{
{188, 229, 251},
{108, 197, 246},
{28, 166, 242},
{10, 116, 174}
}"
) );
maxMA = minMA = 0;
numOfMAs = StrCount( maPerList, "," );
for( i = 0; ( maPer = StrExtract( maPerList, i ) ) != ""; ++i ) {
maPer = StrToNum( maPer );
switch( maTypeCh ) {
case "SMA":
movingAvg = MA( price, maPer );
break;
case "EMA":
movingAvg = EMA( price, maPer );
break;
case "Wilders":
movingAvg = Wilders( price, maPer );
break;
}
maxMA = IIf( movingAvg > maxMA, movingAvg, maxMA );
minMA = IIf( movingAvg < minMA, movingAvg, minMA );
maColor = ColorRGB(
maMxRGBColorSet[ i ][ 0 ],
maMxRGBColorSet[ i ][ 1 ],
maMxRGBColorSet[ i ][ 2 ]
);
Plot( movingAvg, maTypeCh + "(" + maPer + ")", maColor, styleNoLabel | styleNoRescale );
}
maRng = maxMA - minMA;
stochMaRngPer = Param( "Set Stochastic Period", 100, 20, 100, 1 );
stochMaRng = 100 * ( ( maRng - LLV( maRng, stochMaRngPer ) ) / ( ( HHV( maRng, stochMaRngPer ) ) - LLV( maRng, stochMaRngPer ) + 1e-12 ) );
// Plot( stochMaRng, "stochMaRng", colorDarkYellow, styleThick | styleOwnScale );
converging = stochMaRng < Ref( stochMaRng, -1 ) AND Ref( stochMaRng, -1 ) > Ref( stochMaRng, -2 );
// diverging = stochMaRng > Ref( stochMaRng, -1 ) AND Ref( stochMaRng, -1 ) < Ref( stochMaRng, -2 );
// confluence = ExRem( converging, diverging );
PlotShapes( converging * shapeSmallSquare, colorGold, 0, Status( "axisMinY" ), 0 );
_SECTION_END();
Whatever method is used, such analysis would always remain subjective.