little gift. Code uses REMAP function. It looks for a similar pattern in the past data. Best to play around with it first with EOD data because of speed. If you use it with intraday data set it to "Trigger Mode" in the Param window and then press the "Calculation Trigger" because else it is too slow. Trigger mode only calculates it 1 time when you push the calculation trigger. You can "Lock Pattern In Place" so you can scroll back to see which patterns fitted the best. If the code crashes the pattern is probably locked and you do reset all or clear all. I added 4 different patterns. Pattern 3 uses Bollinger bands which looks promising. I also made an intraday version to forecast intraday futures. Possibly will post that later. I added 2 methods of normalization, see "Normalization Mode". Forecast still pretty unreliable so code is just for educational purposes I was just playing around with the REMAP function.
So best to use EOD data first and play with it, see also the Parameter window. Hope you like it.
Chart shows ES EOD data with 1 one the best fits visible in the chart. It is the 3rd best fit it found in default mode.
SetBarsRequired( sbrAll, sbrAll );
per = Param( "Pattern Number of Bars", 10, 1, 50, 1 );
npred = Param( "Number of Bars to Predict", 10, 1, 50, 1 );
nfits = Param( "Number of Fits", 3, 1, 50, 1 );
calculationMode = ParamList( "Calculation Mode", "Continuous Mode|Trigger Mode", 0 ); // continuous gets real time updates
calculationTrigger = ParamTrigger( "Calculation Trigger", "Press Here" ); // works when calculation mode is in Trigger Mode
patternType = ParamList( "Pattern Type", "Pattern 1|Pattern 2|Pattern 3|Pattern 4", 0 );
displayType = ParamList( "Display Type", "Show Average Fit Plus Forcasts|Show Average Fit Standard Deviation Cone", 1 );
normalizationmode = ParamList( "Normalization mode", "Percentage|0 to 1", 1 );
showbarnumbering = ParamToggle( "Show Bar Numbering", "Not Show|Show", 1 );
ft = ParamList( "Font Type", "Tahoma|Arial Black|Verdana|Courier New|Times New Roman|Open Sans|Segoe UI|DejaVu Sans", 1 );
sz = Param( "Font Size", 10, 8, 50, 1 );
lockToggle = ParamToggle( "Lock Pattern in Place", "Off|On", 0 );
clearAll = ParamTrigger( "Clear All", "Clear All" );
sintest = ParamToggle( "SIN TEST", "Not Show|Show", 0 );
if( clearAll )
{
StaticVarRemove( "*" );
lockToggle = 0;
}
// initialisations
bi = BarIndex();
distance = 1e12;
patternText = "";
hper = lper = Null;
bestFitsStorageArray = 0;
idx0 = ss = shift = 0;
topcone = botcone = Null;
yymin = Status( "axisminy" );
yymax = Status( "axismaxy" );
// Pattern arrays
patO = cpatO = 0;
patH = cpatH = 0;
patL = cpatL = 0;
patC = cpatC = 0;
patBBOT = cpatBBOT = 0;
patBTOP = cpatBTOP = 0;
patMA1 = cpatMA1 = 0;
patMA2 = cpatMA2 = 0;
patMA3 = cpatMA3 = 0;
bbot = btop = Null;
ma1 = ma2 = ma3 = Null;
// lock pattern in place
if( lockToggle == 0 )
{
idx0 = Nz( SelectedValue( BarIndex() ) );
StaticVarSet( "idx0", idx0 );
}
if( lockToggle == 1 )
{
idx0 = Nz( StaticVarGet( "idx0" ) );
}
////////////////////////////////////////////////////
// For testing purposes
pi = 3.14159265359;
function sinfunc( wavelength, phase )
{
sinusFunctionArray = 2 * sin( 2 * pi * Cum( 1 ) / wavelength + phase )
+ 1 * sin( 2 * pi * Cum( 1 ) / ( trunc( wavelength / 2 ) ) + phase / 2 )
+ 0.5 * sin( 2 * pi * Cum( 1 ) / ( trunc( wavelength / 4 ) ) + phase / 4 )
+ 1 * sin( 2 * pi * Cum( 1 ) / ( trunc( wavelength * 50 ) ) + phase / 8 );
//+ 0.75 * mtRandomA( seed = 1 );
return sinusFunctionArray;
}
if( sintest )
{
O = H = L = C = sinfunc( 30, pi );
}
////////////////////////////////////////////////////
if( patternType == "Pattern 1" )
{
patternText = "1 variable C";
hper = HHV( C, per );
lper = LLV( C, per );
}
if( patternType == "Pattern 2" )
{
patternText = "4 variables O, H, L, C";
hper = HHV( H, per );
lper = LLV( L, per );
}
if( patternType == "Pattern 3" )
{
patternText = "3 variables, btop, bbot, and C";
btop = BBandTop( C, 20, 2 );
bbot = BBandBot( C, 20, 2 );
hper = Max( HHV( C, per ), Max( HHV( btop, per ), HHV( bbot, per ) ) );
lper = Min( LLV( C, per ), Min( LLV( btop, per ), LLV( bbot, per ) ) );
}
if( patternType == "Pattern 4" )
{
patternText = "4 variables, ma1, ma2, ma3 and C";
ma1 = MA( C, 20 );
ma2 = MA( C, 50 );
ma3 = MA( C, 200 );
hper = Max( HHV( C, per ), Max( HHV( ma1, per ), Max( HHV( ma2, per ), HHV( ma3, per ) ) ) );
lper = Min( LLV( C, per ), Min( LLV( ma1, per ), Min( LLV( ma2, per ), LLV( ma3, per ) ) ) );
}
function patternDefinition1()
{
for( z = 0; z < per; z++ )
{
x = idx0 - per + z + 1;
if( normalizationmode == "0 to 1" )
{
patC[z] = Remap( C[x], lper[idx0], hper[idx0], 0, 1 );
}
if( normalizationmode == "Percentage" )
{
patC[z] = Remap( C[x], lper[idx0], hper[idx0], 0, SafeDivide( hper[idx0] - lper[idx0], lper[idx0] ) * 100 );
}
if( showbarnumbering )
PlotTextSetFont( "" + z, ft, sz, x, yymin, colorBlack, colorWhite, 0 );
}
for( i = 2 * per; i < idx0 - per; i++ )
{
dis = 0;
for( z = 0; z < per; z++ )
{
x = i - per + z + 1;
if( normalizationmode == "0 to 1" )
{
cpatC[z] = Remap( C[x], lper[i], hper[i], 0, 1 );
}
if( normalizationmode == "Percentage" )
{
cpatC[z] = Remap( C[x], lper[i], hper[i], 0, SafeDivide( hper[i] - lper[i], lper[i] ) * 100 );
}
// avoid parts with bad data
if( lper[x] == hper[x] )
{
dis = 1e12;
}
else
{
dis = sqrt( ( cpatC[z] - patC[z] ) ^ 2 ) + dis;
}
}
distance[i] = SafeDivide( dis, per ); // average distance per bar
}
StaticVarSet( "distance", distance );
}
function patternDefinition2()
{
for( z = 0; z < per; z++ )
{
x = idx0 - per + z + 1;
if( normalizationmode == "0 to 1" )
{
patO[z] = Remap( O[x], lper[idx0], hper[idx0], 0, 1 );
patH[z] = Remap( H[x], lper[idx0], hper[idx0], 0, 1 );
patL[z] = Remap( L[x], lper[idx0], hper[idx0], 0, 1 );
patC[z] = Remap( C[x], lper[idx0], hper[idx0], 0, 1 );
}
if( normalizationmode == "Percentage" )
{
hh = SafeDivide( hper[idx0] - lper[idx0], lper[idx0] ) * 100;
patO[z] = Remap( O[x], lper[idx0], hper[idx0], 0, hh );
patH[z] = Remap( H[x], lper[idx0], hper[idx0], 0, hh );
patL[z] = Remap( L[x], lper[idx0], hper[idx0], 0, hh );
patC[z] = Remap( C[x], lper[idx0], hper[idx0], 0, hh );
}
if( showbarnumbering )
PlotTextSetFont( "" + z, ft, sz, x, yymin, colorBlack, colorWhite, 0 );
}
for( i = 2 * per; i < idx0 - per; i++ )
{
dis = 0;
for( z = 0; z < per; z++ )
{
x = i - per + z + 1;
if( normalizationmode == "0 to 1" )
{
cpatO[z] = Remap( O[x], lper[i], hper[i], 0, 1 );
cpatH[z] = Remap( H[x], lper[i], hper[i], 0, 1 );
cpatL[z] = Remap( L[x], lper[i], hper[i], 0, 1 );
cpatC[z] = Remap( C[x], lper[i], hper[i], 0, 1 );
}
if( normalizationmode == "Percentage" )
{
hh = SafeDivide( hper[i] - lper[i], lper[i] ) * 100;
cpatO[z] = Remap( O[x], lper[i], hper[i], 0, hh );
cpatH[z] = Remap( H[x], lper[i], hper[i], 0, hh );
cpatL[z] = Remap( L[x], lper[i], hper[i], 0, hh );
cpatC[z] = Remap( C[x], lper[i], hper[i], 0, hh );
}
// avoid parts with bad data
if( lper[x] == hper[x] )
{
dis = 1e12;
}
else
{
dis = sqrt( ( cpatO[z] - patO[z] ) ^ 2
+ ( cpatH[z] - patH[z] ) ^ 2
+ ( cpatL[z] - patL[z] ) ^ 2
+ ( cpatC[z] - patC[z] ) ^ 2 ) + dis;
}
}
distance[i] = SafeDivide( dis, per ); // average distance per bar
}
StaticVarSet( "distance", distance );
}
function patternDefinition3()
{
for( z = 0; z < per; z++ )
{
x = idx0 - per + z + 1;
if( normalizationmode == "0 to 1" )
{
patC[z] = Remap( C[x], lper[idx0], hper[idx0], 0, 1 );
patBBOT[z] = Remap( bbot[x], lper[idx0], hper[idx0], 0, 1 );
patBTOP[z] = Remap( btop[x], lper[idx0], hper[idx0], 0, 1 );
}
if( normalizationmode == "Percentage" )
{
hh = SafeDivide( hper[idx0] - lper[idx0], lper[idx0] ) * 100;
patC[z] = Remap( C[x], lper[idx0], hper[idx0], 0, hh );
patBBOT[z] = Remap( bbot[x], lper[idx0], hper[idx0], 0, hh );
patBTOP[z] = Remap( btop[x], lper[idx0], hper[idx0], 0, hh );
}
if( showbarnumbering )
PlotTextSetFont( "" + z, ft, sz, x, yymin, colorBlack, colorWhite, 0 );
}
for( i = ( 2 * per + 20 ); i < idx0 - per; i++ )
{
dis = 0;
for( z = 0; z < per; z++ )
{
x = i - per + z + 1;
if( normalizationmode == "0 to 1" )
{
cpatC[z] = Remap( C[x], lper[i], hper[i], 0, 1 );
cpatBBOT[z] = Remap( bbot[x], lper[i], hper[i], 0, 1 );
cpatBTOP[z] = Remap( btop[x], lper[i], hper[i], 0, 1 );
}
if( normalizationmode == "Percentage" )
{
hh = SafeDivide( hper[i] - lper[i], lper[i] ) * 100;
cpatC[z] = Remap( C[x], lper[i], hper[i], 0, hh );
cpatBBOT[z] = Remap( bbot[x], lper[i], hper[i], 0, hh );
cpatBTOP[z] = Remap( btop[x], lper[i], hper[i], 0, hh );
}
// avoid parts with bad data
if( lper[x] == hper[x] )
{
dis = 1e12;
}
else
{
dis = sqrt( ( cpatC[z] - patC[z] ) ^ 2
+ ( cpatBBOT[z] - patBBOT[z] ) ^ 2
+ ( cpatBTOP[z] - patBTOP[z] ) ^ 2 ) + dis;
}
}
distance[i] = SafeDivide( dis, per ); // average distance per bar
}
StaticVarSet( "distance", distance );
}
function patternDefinition4()
{
for( z = 0; z < per; z++ )
{
x = idx0 - per + z + 1;
if( normalizationmode == "0 to 1" )
{
patMA1[z] = Remap( ma1[x], lper[idx0], hper[idx0], 0, 1 );
patMA2[z] = Remap( ma2[x], lper[idx0], hper[idx0], 0, 1 );
patMA3[z] = Remap( ma3[x], lper[idx0], hper[idx0], 0, 1 );
patC[z] = Remap( C[x], lper[idx0], hper[idx0], 0, 1 );
}
if( normalizationmode == "Percentage" )
{
hh = SafeDivide( hper[idx0] - lper[idx0], lper[idx0] ) * 100;
patMA1[z] = Remap( ma1[x], lper[idx0], hper[idx0], 0, hh );
patMA2[z] = Remap( ma2[x], lper[idx0], hper[idx0], 0, hh );
patMA3[z] = Remap( ma3[x], lper[idx0], hper[idx0], 0, hh );
patC[z] = Remap( C[x], lper[idx0], hper[idx0], 0, hh );
}
if( showbarnumbering )
PlotTextSetFont( "" + z, ft, sz, x, yymin, colorBlack, colorWhite, 0 );
}
for( i = 300; i < idx0 - per; i++ )
{
dis = 0;
for( z = 0; z < per; z++ )
{
x = i - per + z + 1;
if( normalizationmode == "0 to 1" )
{
cpatMA1[z] = Remap( ma1[x], lper[i], hper[i], 0, 1 );
cpatMA2[z] = Remap( ma2[x], lper[i], hper[i], 0, 1 );
cpatMA3[z] = Remap( ma3[x], lper[i], hper[i], 0, 1 );
cpatC[z] = Remap( C[x], lper[i], hper[i], 0, 1 );
}
if( normalizationmode == "Percentage" )
{
hh = SafeDivide( hper[i] - lper[i], lper[i] ) * 100;
cpatMA1[z] = Remap( ma1[x], lper[i], hper[i], 0, hh );
cpatMA2[z] = Remap( ma2[x], lper[i], hper[i], 0, hh );
cpatMA3[z] = Remap( ma3[x], lper[i], hper[i], 0, hh );
cpatC[z] = Remap( C[x], lper[i], hper[i], 0, hh );
}
// avoid parts with bad data
if( lper[x] == hper[x] )
{
dis = 1e12;
}
else
{
dis = sqrt( ( cpatMA1[z] - patMA1[z] ) ^ 2
+ ( cpatMA2[z] - patMA2[z] ) ^ 2
+ ( cpatMA3[z] - patMA3[z] ) ^ 2
+ ( cpatC[z] - patC[z] ) ^ 2 ) + dis;
}
}
distance[i] = SafeDivide( dis, per ); // average distance per bar
}
StaticVarSet( "distance", distance );
}
if( calculationMode == "Continuous Mode" )
{
if( patternType == "Pattern 1" )
{
patternDefinition1();
}
if( patternType == "Pattern 2" )
{
patternDefinition2();
}
if( patternType == "Pattern 3" )
{
patternDefinition3();
}
if( patternType == "Pattern 4" )
{
patternDefinition4();
}
}
if( calculationMode == "Trigger Mode" )
{
if( calculationTrigger )
{
Say( "Calculate Fit" );
if( patternType == "Pattern 1" )
{
patternDefinition1();
}
if( patternType == "Pattern 2" )
{
patternDefinition2();
}
if( patternType == "Pattern 3" )
{
patternDefinition3();
}
if( patternType == "Pattern 4" )
{
patternDefinition4();
}
Say( "Finished" );
}
}
distance = Nz( StaticVarGet( "distance" ) );
sdistance = Sort( distance, 0, -1, False ); // return sorted value
sdistancei = Sort( distance, 0, -1, True ); // return the index corresponding to the sorted value
SetChartBkColor( colorBlack );
SetChartOptions( 0, chartShowDates );
Plot( C, "", colorWhite, stylecandle, Null, Null, 0, 0, 1 );
Plot( btop, "", colorRed, styleLine | styleNoLabel | styleNoRescale, Null, Null, 0, -2, 1 );
Plot( bbot, "", colorGreen, styleLine | styleNoLabel | styleNoRescale, Null, Null, 0, -2, 1 );
Plot( ma1, "", colorRed, styleLine | styleNoLabel | styleNoRescale, Null, Null, 0, -2, 1 );
Plot( ma2, "", colorGreen, styleLine | styleNoLabel | styleNoRescale, Null, Null, 0, -2, 1 );
Plot( ma3, "", colorBlue, styleLine | styleNoLabel | styleNoRescale, Null, Null, 0, -2, 1 );
// function helps to avoid selecting 2 patterns within a distance of "per" bars
function testValidity( aa, disi, per )
{
val = 1;
for( i = 0; i < 50; i++ )
{
if( aa[i] == 0 AND i == 0 )
{
val = 1;
break;
}
else
if( abs( aa[i] - disi ) < per )
{
val = 0;
break;
}
else
if( disi <= per )
{
val = 0;
break;
}
}
return val;
}
cnt = 0;
for( i = 0; i < BarCount; i++ )
{
fitdummyY = 0;
forcastdummyY = 0;
// avoid selecting 2 patterns within a distance of per bars, use testValidity
if( testValidity( bestFitsStorageArray, sdistancei[i], per ) )
{
bestFitsStorageArray[cnt] = idx = sdistancei[i];
shift = npred - Min( BarCount - 1 - idx0, npred );
for( j = 0; j < per; j++ )
{
x = idx0 + j - per + 1;
x1 = idx + j - per + 1;
//_TRACE( "x1: " + x1 );
y = Remap( C[x1], lper[idx], hper[idx], lper[idx0], hper[idx0] );
fitdummyY[x] = y;
}
StaticVarSet( "fit" + cnt, fitdummyY );
for( j = per; j < per + npred; j++ )
{
x = idx0 + j - per + 1 - shift;
x1 = idx + j - per + 1;
y = Remap( C[x1], lper[idx], hper[idx], lper[idx0], hper[idx0] );
forcastdummyY[x] = y;
}
StaticVarSet( "forcast" + cnt, forcastdummyY );
cnt = cnt + 1;
}
if( cnt > nfits )
{
StaticVarSet( "bestFitsStorageArray", bestFitsStorageArray );
break;
}
}
if( displayType == "Show Average Fit Plus Forcasts" )
{
totfit = 0;
totforcast = 0;
for( i = 0; i < nfits; i++ )
{
ff = StaticVarGet( "fit" + i );
Plot( IIf( ff, ff, Null ), "", colorAqua, styleDashed | styleNoRescale | styleNoLabel, Null, Null, 0, 0, 1 );
totfit = totfit + StaticVarGet( "fit" + i );
ff = StaticVarGet( "forcast" + i );
Plot( IIf( ff, ff, Null ), "", colorViolet, styleDashed | styleNoRescale | styleNoLabel, Null, Null, shift, 0, 1 );
totforcast = totforcast + StaticVarGet( "forcast" + i );
PlotTextSetFont( "" + ( i + 1 ), ft, sz, idx0 + 1 + npred, ff[idx0 + npred - shift], colorBlack, colorWhite, 0 );
}
// average fit
totfit = totfit / nfits;
Plot( IIf( totfit, totfit, Null ), "", colorAqua, styleDots | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 3 );
// average forcast
totforcast = totforcast / nfits;
Plot( IIf( totforcast, totforcast, Null ), "", colorViolet, styleDots | styleNoRescale | styleNoLabel, Null, Null, shift, 1, 3 );
}
if( displayType == "Show Average Fit Standard Deviation Cone" )
{
totfit = 0;
totforcast = 0;
for( i = 0; i < nfits; i++ )
{
ff = StaticVarGet( "fit" + i );
totfit = totfit + StaticVarGet( "fit" + i );
ff = StaticVarGet( "forcast" + i );
totforcast = totforcast + StaticVarGet( "forcast" + i );
}
// average fit
totfit = totfit / nfits;
Plot( IIf( totfit, totfit, Null ), "", colorAqua, styleDots | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 3 );
// average forcast
totforcast = totforcast / nfits;
Plot( IIf( totforcast, totforcast, Null ), "", colorViolet, styleDots | styleNoRescale | styleNoLabel, Null, Null, shift, 1, 3 );
// error cone forecast
for( i = 0; i < npred; i++ )
{
ss = 0;
x = idx0 + 1 + i;
shift = npred - Min( BarCount - 1 - idx0, npred );
for( j = 0; j < nfits; j++ )
{
ff = StaticVarGet( "forcast" + j );
ss = ( ff[x - shift] - totforcast[x - shift] ) ^ 2 + ss;
}
topcone[x - shift] = totforcast[x - shift] + sqrt( SafeDivide( ss, nfits ) );
botcone[x - shift] = totforcast[x - shift] - sqrt( SafeDivide( ss, nfits ) );
}
topcone = IIf( 0, Null, topcone );
botcone = IIf( 0, Null, botcone );
PlotOHLC( topcone, topcone, botcone, botcone, "", ColorRGB( 0, 0, 60 ), styleCloud | styleNoLabel | styleNoRescale, Null, Null, shift, -10, 1 );
Plot( topcone, "", colorblue, styleLine | styleNoLabel | styleNoRescale, Null, Null, shift, -10, 3 );
Plot( botcone, "", colorblue, styleLine | styleNoLabel | styleNoRescale, Null, Null, shift, -10, 3 );
// error cone data fits
topcone = botcone = Null;
for( i = 0; i < per; i++ )
{
ss = 0;
x = idx0 - per + i + 1;
//shift = npred - Min( BarCount - 1 - idx0, npred );
shift = 0;
for( j = 0; j < nfits; j++ )
{
ff = StaticVarGet( "fit" + j );
ss = ( ff[x - shift] - totfit[x - shift] ) ^ 2 + ss;
}
topcone[x - shift] = totfit[x - shift] + sqrt( SafeDivide( ss, nfits ) );
botcone[x - shift] = totfit[x - shift] - sqrt( SafeDivide( ss, nfits ) );
}
topcone = IIf( 0, Null, topcone );
botcone = IIf( 0, Null, botcone );
PlotOHLC( topcone, topcone, botcone, botcone, "", ColorRGB( 0, 0, 60 ), styleCloud | styleNoLabel | styleNoRescale, Null, Null, shift, -10, 1 );
Plot( topcone, "", colorblue, styleLine | styleNoLabel | styleNoRescale, Null, Null, shift, -10, 3 );
Plot( botcone, "", colorblue, styleLine | styleNoLabel | styleNoRescale, Null, Null, shift, -10, 3 );
}
// draw box around pattern that needs to be fitted
pat = IIf( idx0 == BarIndex(), 1, 0 );
Plot( pat, "", colorYellow, styleDashed | styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -3, 1 );
GfxSetZOrder( -2 );
GfxSetCoordsMode( 1 );
GfxSelectSolidBrush( ColorRGB( 50, 50, 10 ) );
GfxSelectPen( ColorYellow, 3, 0 );
if( !IsEmpty( hper[idx0] ) AND !IsEmpty( lper[idx0] ) )
GfxPolyline( idx0, hper[idx0], idx0, lper[idx0], idx0 - per + 1, lper[idx0], idx0 - per + 1, hper[idx0], idx0, hper[idx0] );
PlotTextSetFont( "" + patternText, ft, sz, idx0 + 1, hper[idx0], colorBlack, colorWhite, 0 );
// show boxes around the best fits
GfxSelectPen( colorAqua, 3, 0 );
for( i = 0; i < nfits; i++ )
{
idx0 = bestFitsStorageArray[i];
if( !IsEmpty( hper[idx0] ) AND !IsEmpty( lper[idx0] ) )
{
GfxPolyline( idx0, hper[idx0], idx0, lper[idx0], idx0 - per + 1, lper[idx0], idx0 - per + 1, hper[idx0], idx0, hper[idx0] );
PlotTextSetFont( "" + ( i + 1 ) + " best", ft, sz, idx0, hper[idx0], colorBlack, colorWhite, 0 );
pat = IIf( idx0 == BarIndex(), 1, 0 );
Plot( pat, "", colorAqua, styleDashed | styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -3, 1 );
}
}
Title = EncodeColor( colorAqua ) + "Number of Fits: " + nfits + " | "
+ EncodeColor( colorYellow ) + " Pattern Size: " + per + " | "
+ EncodeColor( colorBrightGreen ) + " Number of bars forcasted: " + npred + " | "
+ EncodeColor( colorPink ) + " Pattern Type: " + patterntype + " | "
+ EncodeColor( colorOrange ) + " Normalization Mode: " + normalizationmode + " | ";