# Looking AFL for blending of two & more candles as per picture

Request if some one can help to write a AFL.

@jagdishpahuja What the image you have shared is showing is just an example of how to read candlesticks of differing time frames. For example, if the first two candles are from a 1 minute time frame, the 3rd candle would be a two minute time frame. No AFL is needed for that.

Sir,
it is the daily time frame. When two candles are merged or joined or blended, the resultant candle gives a different shape. ( also known as hidden price behavior ).
if AFL is written it is a very useful tool to see what is happening in bunch of candles .
I have taken an example only for two candles to make simple but it could be more than 2 candles .
Sir , Please see this link ----[Math of candlesticks--A new way of looking at candles formation.]
Candlestick Math - A New Way Of Using Candlesticks - YouTube) a "you tube " link to understand the concept.
Thanks for showing interest . You may contact at --- jkpahuja12@gmail.com
Regards

Yes I understand that and know exactly what you are talking about. What I am saying is that you don't need to to have a particular AFL (not to my knowledge...I could be wrong) to do this. You just need to look at different time frames. For example, if you want to see more specifically what a weekly candle did, you need to switch your time frame from weekly to a daily time frame. You would then be able to view the weekly candle as 5 daily candles. You also do this with lower time frames if you have intraday data rather than EOD (End of Day).

there was a similar question here:

code below I adjusted a bit. Probably it can be coded differently as well. Example chart shows ES-mini 5min chart and overlapping are the 1 hour (60min) candles

``````CellHeight = Param( "Cell Height", 30, 20, 50, 1 );
CellWidth = Param( "Cell Width", 200, 100, 1000, 1 );
CellXSpace = Param( "Cell X Space", 0, 0, 50, 1 );
CellYSpace = Param( "Cell Y Space", 2, 0, 50, 1 );
transx = Param( "Move Button Pack (X-Axis, bars)", 0, 0, 2000, 10 );
transy = Param( "Move Button Pack (Y-Axis, bars)", 20, 0, 2000, 5 );
drawnodraw = ParamToggle( "Draw Base timeframe", "no|yes", 1 );
useGuiParam = ParamList( "Use Gui or Param", "GUI|PARAM", 0 );
tt = Param( "Set timeframe", 1, 1, 240, 1 );
timestep = in1Minute;

GfxSetZOrder( -5 );
GfxSetCoordsMode( 1 );
SetChartBkColor( ColorRGB( 0, 0, 0 ) );
SetChartOptions( 0, chartShowArrows | chartShowDates );

if( useGuiParam == "GUI" )
{
x0 = 0 + transx;
y0 = 0 + transy;
idSlider = 1;
row = 1;
col = 1;

slider = GuiSlider( idslider, x0 + CellWidth * ( col - 1 ) + CellXSpace * ( col - 1 ), y0 + ( row - 1 ) * CellHeight + ( row - 1 ) * CellYSpace, CellWidth, CellHeight, notifyEditChange );

if( slider == guiNew OR trigger )
{
GuiSetValue( idSlider, 5 );
GuiSetRange( idSlider, 1, 240, 1, 5 );
GuiEnable( idSlider, True );
}

tf = timestep * GuiGetValue( idSlider ); // set timeframe here
}
else
if( useGuiParam == "PARAM" )
{
tf = timestep * tt;
}

bi = BarIndex();
fvb = FirstVisibleValue( bi ) - 50;
lvb = LastVisibleValue( bi );

Title = Name() +
" | " + Now( 1 ) + " | " + Now( 2 ) +
" | " + EncodeColor( colorGold ) + tf / 60 + " Min" + " | " + EncodeColor( colorWhite );

exp1 = expandFirst;
lastbarOfPeriod = Nz( TimeFrameExpand( 1, tf, expandPoint ) );
firstbarOfPeriod = Ref( lastbarOfPeriod, -1 );
stepf = ValueWhen( lastbarOfPeriod, bi );

if( !( tf > Interval() ) )
{
Plot( C, "C", colorWhite, styleCandle, Null, Null, 0, 0, 1 );
}
else
{
if( drawnodraw )
{
Plot( C, "C", colorWhite, styleCandle, Null, Null, 0, 2, 1 );
}
else
{
Plot( C, "C", colorWhite, styleCandle | styleNoDraw, Null, Null, 0, 0, 1 );
}

}

TimeFrameSet( tf );
prcH = H;
prcL = L;
prcO = O;
prcC = C;
TimeFrameRestore();

prcH = TimeFrameExpand( prcH, tf, exp1 );
prcL = TimeFrameExpand( prcL, tf, exp1 );
prcO = TimeFrameExpand( prcO, tf, exp1 );
prcC = TimeFrameExpand( prcC, tf, exp1 );

flg = 0;
prevPrice = 0;

if( tf > Interval() )
{
for( i = fvb + 1; i <= lvb; i++ )
{
if( lastbarOfPeriod[i] )
{
// body
x0 = stepf[i - 1] + 1;
x1 = stepf[i];
y0 = prcO[i];
y1 = prcC[i];

if( y0 > y1 )
{
clr = ColorRGB( 255, 204, 204 );
flg = 0;
}
else
if( y0 < y1 )
{
clr = ColorRGB( 204, 255, 255 );
flg = 0;
}
else
{
clr = colorLightGrey;
flg = 1;
}

GfxSetZOrder( -1 );

if( flg == 0 )
{
GfxSelectPen( clr, 1, 0 );
GfxSelectSolidBrush( clr );
GfxRectangle( x0, y0, x1, y1 );
}
else
if( flg == 1 )
{
GfxSelectPen( clr, 1, 0 );
GfxMoveTo( x0, y0 );
GfxLineTo( x1, y1 );
}

// wicks
GfxSelectPen( clr, 4, 0 );
x = ( x0 + x1 ) / 2;
y0 = prcH[i];
y1 = prcL[i];
GfxMoveTo( x, y0 );
GfxLineTo( x, y1 );
}
}
}
``````

3 Likes

Everything out there can be written differently.

Here is AFL with less looping code (so should be faster).

``````/// @link https://forum.amibroker.com/t/looking-afl-for-blending-of-two-more-candles-as-per-picture/26730/6
/// by fxshrat@gmail.com
tmfrm = Param("Interval (minutes)", 60, 1, 240, 1)*60;
bi = BarIndex();
fvb = FirstVisibleValue(bi);
lvb = LastvisibleValue(bi);
num_bars = lvb-fvb+1;
is_lastbar = bi == LastvisibleValue(bi);
is_point = TimeFrameExpand(1, tmfrm, expandPoint);
bar_flag = Ref(Nz(is_point)>0,-1);

SetChartOptions( 0, chartShowDates | chartShowArrows | chartWrapTitle );
Plot( C, "", colorDefault, styleCandle, Null, Null, 0, 1 );

if ( num_bars < 500 )
Plot( bar_flag, "", colorRed, styleHistogram | styleOwnScale | styleNoLabel | styleDashed, 0, 1, 0, 0 );

arrstr = ",O,H,L,C,V";
TimeFrameSet( tmfrm );
ltf_int = Interval(2);
ltf_rc = ROC(C, 1);
for ( i = 1; i < 6; i++ )
VarSet("ltf_arr"+i, VarGet(StrExtract(arrstr, i)));
TimeFrameRestore();

for ( i = 1; i < 6; i++ ) {
ltf_expand = TimeFrameExpand(VarGet("ltf_arr"+i), tmfrm, expandFirst);
VarSet("LTFexpand"+i, ltf_expand);
}

barcolor = IIf(LTFexpand4 > LTFexpand1, colorDarkGreen, colorDarkRed);
whisker_color = colorGrey50;

fbi = Min(lvb,ValueWhen(bar_flag,bi+0.5));
lbi = bi+0.5;
half_bar = (lbi+fbi)/2;
whisker_cond = half_bar < lvb;
lbi = Min(lvb,lbi);
lbp = Ref(bar_flag,1) OR is_lastbar;
is_visible = bi >= fvb AND bi <= LastVisibleValue(ValueWhen(lbp,bi,0));

maxbody = Max(LTFexpand1, LTFexpand4);
minbody = Min(LTFexpand1, LTFexpand4);
minbody = Max(Status("axisminy"), minbody);

if ( Interval() < tmfrm ) {
GfxSetZOrder(-1);
GfxSetCoordsMode(1);
GfxSelectPen(whisker_color, 5, 0x200);
for ( i = 0; i < BarCount; i++ ) {
if ( is_visible[i] ) {
if ( lbp[ i ] ) {
if ( whisker_cond[i] ) {
GfxMoveTo(half_bar[i],LTFexpand3[i]);
GfxLineTo(half_bar[i],LTFexpand2[i]);
}
GfxFillSolidRect(fbi[i],minbody[i],lbi[i],maxbody[i],barcolor[i]);
}
}
}
} else {
SetBarFillColor(barcolor);
Plot( C, "Price", colorDefault, styleCandle );
}

_N(Title = StrFormat("{{NAME}} - STF: {{INTERVAL}}, LTF: " + ltf_int +
" - {{DATE}} | Op:%g, Hi:%g, Lo:%g, Close:%g (%.2f%%), Vol:%g {{VALUES}}",
LTFexpand1, LTFexpand2, LTFexpand3, LTFexpand4,
SelectedValue(TimeFrameExpand(ltf_rc, tmfrm, expandFirst)), LTFexpand5 ));
//
SetBarsRequired(Min(1000,num_bars));
``````

6 Likes

While the above solutions provide an excellent visualization, I think that we are missing one key point about the "Candlestick math".

AFAIU, the linked video, suggests applying the consolidation (to interpret some classic pattern better) to any number of bars arbitrarily starting at any bar and NOT at specific predefined points.

For example:

5 minutes bars consolidated to Hourly with a database start time set at 00:50:00

Same 5 minutes bars consolidated to Hourly with a database start time set to 00:15:00:

As you can see, the resulting "patterns" may differ significantly.

For this reason, I think that to be able to achieve what is described in the video it would be necessary to have the ability to dynamically "offset" the "timeframe" functions consolidation boundaries.
Emulating this feature now seems only possible manually changing the "intraday" settings of the database selecting a different RTH start time (with the "Preferences/Intraday" checkbox "Align minutes bars to regular market hours" selected).

Although I doubt the usefulness of such a technique, I wonder if my observation is correct or I'm missing something?

2 Likes

you could calculate it a bit differently and build in a base time offset.

``````drawnodraw = ParamToggle( "Draw Base timeframe", "no|yes", 1 );
basetimeframeMultiplier = Param( "Base Timeframe Multiplier", 5, 1, 240, 1 );
offset = Param( "Base Timeframe Offset", 0, 0, 20, 1 );
baseTimestep = Interval();

GfxSetZOrder( -5 );
GfxSetCoordsMode( 1 );
SetChartBkColor( ColorRGB( 0, 0, 0 ) );
SetChartOptions( 0, chartShowArrows | chartShowDates );

tf = baseTimestep * basetimeframeMultiplier;

bi = BarIndex();
fvb = FirstVisibleValue( bi ) - 50;
lvb = LastVisibleValue( bi );

Title = Name() +
" | " + Now( 1 ) + " | " + Now( 2 ) +
" | " + EncodeColor( colorGold ) + tf / 60 + " Min" + " | " + EncodeColor( colorWhite );

lastbarOfPeriod = Ref( Nz( TimeFrameExpand( 1, tf, expandPoint ) ), -offset );
lastbarOfPeriod = IIf( bi == BarCount - 1, 1, lastbarOfPeriod );
firstbarOfPeriod = Ref( lastbarOfPeriod, -1 );
stepf = ValueWhen( lastbarOfPeriod, bi );

if( !( tf > Interval() ) )
{
Plot( C, "C", colorWhite, styleCandle, Null, Null, 0, 0, 1 );
}
else
{
if( drawnodraw )
{
Plot( C, "C", colorWhite, styleCandle, Null, Null, 0, 2, 1 );
}
else
{
Plot( C, "C", colorWhite, styleCandle | styleNoDraw, Null, Null, 0, 0, 1 );
}

}

Plot( lastbarOfPeriod, "", ColorRGB( 85, 85, 85 ), styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );
Plot( firstbarOfPeriod, "", ColorRGB( 0, 85, 85 ), styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );

prcH = HighestSince( firstbarOfPeriod, H, 1 );
prcL = LowestSince( firstbarOfPeriod, L, 1 );
prcO = ValueWhen( firstbarOfPeriod, O, 1 );
prcC = ValueWhen( lastbarOfPeriod, C, 1 );

flg = 0;
prevPrice = 0;

if( tf > Interval() )
{
for( i = fvb + 1; i <= lvb; i++ )
{
if( lastbarOfPeriod[i] )
{
// body
x0 = stepf[i - 1] + 1;
x1 = stepf[i];
y0 = prcO[i];
y1 = prcC[i];

if( y0 > y1 )
{
clr = ColorRGB( 255, 204, 204 );
flg = 0;
}
else
if( y0 < y1 )
{
clr = ColorRGB( 204, 255, 255 );
flg = 0;
}
else
{
clr = colorLightGrey;
flg = 1;
}

GfxSetZOrder( -1 );

if( flg == 0 )
{
GfxSelectPen( clr, 1, 0 );
GfxSelectSolidBrush( clr );
GfxRectangle( x0, y0, x1, y1 );
}
else
if( flg == 1 )
{
GfxSelectPen( clr, 1, 0 );
GfxMoveTo( x0, y0 );
GfxLineTo( x1, y1 );
}

// wicks
GfxSelectPen( clr, 4, 0 );
x = ( x0 + x1 ) / 2;
y0 = prcH[i];
y1 = prcL[i];
GfxMoveTo( x, y0 );
GfxLineTo( x, y1 );
}
}
}

``````

better make that, see code below. It is feierabend at my house early usually

``````drawnodraw = ParamToggle( "Draw Base timeframe", "no|yes", 1 );
basetimeframeMultiplier = Param( "Base Timeframe Multiplier", 5, 1, 240, 1 );
offset = Param( "Base Timeframe Offset", 0, 0, 20, 1 );
baseTimestep = Interval();

SetBarsRequired( sbrAll );

GfxSetZOrder( -5 );
GfxSetCoordsMode( 1 );
SetChartBkColor( ColorRGB( 0, 0, 0 ) );
SetChartOptions( 0, chartShowArrows | chartShowDates );

tf = baseTimestep * basetimeframeMultiplier;

bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );

Title = Name() +
" | " + Now( 1 ) + " | " + Now( 2 ) +
" | " + EncodeColor( colorGold ) + tf / 60 + " Min" + " | " + EncodeColor( colorWhite );

lastbarOfPeriod = Ref( Nz( TimeFrameExpand( 1, tf, expandPoint ) ), -offset );
lastbarOfPeriod = IIf( bi == BarCount - 1, 1, lastbarOfPeriod );
firstbarOfPeriod = Ref( lastbarOfPeriod, -1 );
stepf = ValueWhen( lastbarOfPeriod, bi );

if( !( tf > Interval() ) )
{
Plot( C, "C", colorWhite, styleCandle, Null, Null, 0, 0, 1 );
}
else
{
if( drawnodraw )
{
Plot( C, "C", colorWhite, styleCandle, Null, Null, 0, 2, 1 );
}
else
{
Plot( C, "C", colorWhite, styleCandle | styleNoDraw, Null, Null, 0, 0, 1 );
}

}

Plot( lastbarOfPeriod, "", ColorRGB( 85, 85, 85 ), styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );
Plot( firstbarOfPeriod, "", ColorRGB( 0, 85, 85 ), styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -1, 1 );

prcH = HighestSince( firstbarOfPeriod, H, 1 );
prcL = LowestSince( firstbarOfPeriod, L, 1 );
prcO = ValueWhen( firstbarOfPeriod, O, 1 );
prcC = ValueWhen( lastbarOfPeriod, C, 1 );

flg = 0;
prevPrice = 0;

if( tf > Interval() )
{
for( i = fvb + 1; i <= lvb; i++ )
{
if( lastbarOfPeriod[i] )
{
// body
x0 = stepf[i - 1] + 1;
x1 = stepf[i];
y0 = prcO[i];
y1 = prcC[i];

if( y0 > y1 )
{
clr = ColorRGB( 255, 204, 204 );
flg = 0;
}
else
if( y0 < y1 )
{
clr = ColorRGB( 204, 255, 255 );
flg = 0;
}
else
{
clr = colorLightGrey;
flg = 1;
}

GfxSetZOrder( -1 );

if( flg == 0 )
{
GfxSelectPen( clr, 1, 0 );
GfxSelectSolidBrush( clr );
GfxRectangle( x0, y0, x1, y1 );
}
else
if( flg == 1 )
{
GfxSelectPen( clr, 1, 0 );
GfxMoveTo( x0, y0 );
GfxLineTo( x1, y1 );
}

// wicks
GfxSelectPen( clr, 4, 0 );
x = ( x0 + x1 ) / 2;
y0 = prcH[i];
y1 = prcL[i];
GfxMoveTo( x, y0 );
GfxLineTo( x, y1 );
}
}
}

``````
1 Like

Different version with less looping code

``````/// @link https://forum.amibroker.com/t/looking-afl-for-blending-of-two-more-candles-as-per-picture/26730/11
/// by fxshrat@gmail.com
tmfrm = Param("Interval (minutes)", 60, 1, 240, 1)*60;
bar_shift = Param( "Bar Shift", 0, 0, 60, 1 );
bi = BarIndex();
fvb = FirstVisibleValue(bi);
lvb = LastvisibleValue(bi);
num_bars = lvb-fvb+1;
is_lastbar = bi == LastvisibleValue(bi);
is_point = TimeFrameExpand(1, tmfrm, expandPoint);
bar_flag = Ref(Nz(is_point)>0,-1-bar_shift);

SetChartOptions( 0, chartShowDates | chartShowArrows | chartWrapTitle );
Plot( C, "", colorDefault, styleCandle, Null, Null, 0, 1 );

if ( num_bars < 500 )
Plot( bar_flag, "", colorRed, styleHistogram | styleOwnScale | styleNoLabel | styleDashed, 0, 1, 0, 0 );

TimeFrameSet( tmfrm );
ltf_int = Interval(2);
TimeFrameRestore();

LTFexpand1 = ValueWhen(bar_flag, O);
LTFexpand2 = HighestSince(bar_flag, H);
LTFexpand3 = LowestSince(bar_flag, L);
LTFexpand4 = ValueWhen(Ref(bar_flag,1), C);
LTFexpand5 = SumSince(bar_flag, V)+ValueWhen(bar_flag,V);
ltf_rc = (LTFexpand4-LTFexpand1)/LTFexpand1*100;

barcolor = IIf(LTFexpand4 > LTFexpand1, colorDarkGreen, colorDarkRed);
whisker_color = colorGrey50;

fbi = Min(lvb,ValueWhen(bar_flag,bi+0.5));
lbi = bi+0.5;
half_bar = (lbi+fbi)/2;
whisker_cond = half_bar < lvb;
lbi = Min(lvb,lbi);
lbp = Ref(bar_flag,1) OR is_lastbar;
is_visible = bi >= fvb AND bi <= LastVisibleValue(ValueWhen(lbp,bi,0));

maxbody = Max(LTFexpand1, LTFexpand4);
minbody = Min(LTFexpand1, LTFexpand4);
minbody = Max(Status("axisminy"), minbody);

if ( Interval() < tmfrm ) {
GfxSetZOrder(-1);
GfxSetCoordsMode(1);
GfxSelectPen(whisker_color, 5, 0x200);
for ( i = 0; i < BarCount; i++ ) {
if ( is_visible[i] ) {
if ( lbp[ i ] ) {
if ( whisker_cond[i] ) {
GfxMoveTo(half_bar[i],LTFexpand3[i]);
GfxLineTo(half_bar[i],LTFexpand2[i]);
}
GfxFillSolidRect(fbi[i],minbody[i],lbi[i],maxbody[i],barcolor[i]);
}
}
}
} else {
SetBarFillColor(barcolor);
Plot( C, "Price", colorDefault, styleCandle );
}

_N(Title = StrFormat("{{NAME}} - STF: {{INTERVAL}}, LTF: " + ltf_int +
" - {{DATE}} | Op:%g, Hi:%g, Lo:%g, Close:%g (%.2f%%), Vol:%g {{VALUES}}",
LTFexpand1, LTFexpand2, LTFexpand3, LTFexpand4, SelectedValue(ltf_rc), LTFexpand5 ));
//
SetBarsRequired(Min(1000,num_bars));
``````

3 Likes

Has to be

``````LTFexpand4 = ValueWhen(Ref(bar_flag,1) OR is_lastbar, C);
``````

Needs an expansion call after restore in new AB versions.
Since `ltf_int` is string but not array you normally don't need expand.
But in new versions warning message occurs if forgetting expand call after restoration.

``````/// @link https://forum.amibroker.com/t/looking-afl-for-blending-of-two-more-candles-as-per-picture/26730/12
/// by fxshrat@gmail.com
tmfrm = Param("Interval (minutes)", 60, 1, 240, 1)*60;
bar_shift = Param( "Bar Shift", 0, 0, 60, 1 );
bi = BarIndex();
fvb = FirstVisibleValue(bi);
lvb = LastvisibleValue(bi);
num_bars = lvb-fvb+1;
is_lastbar = bi == LastvisibleValue(bi);

TimeFrameSet( tmfrm );
ltf_int = Interval(2);
TimeFrameRestore();
//ltf_int = ""+ tmfrm/60 + " minutes";

is_point = TimeFrameExpand(1, tmfrm, expandPoint);
bar_flag = Ref(Nz(is_point)>0,-1-bar_shift);

LTFexpand1 = ValueWhen(bar_flag, O);
LTFexpand2 = HighestSince(bar_flag, H);
LTFexpand3 = LowestSince(bar_flag, L);
LTFexpand4 = ValueWhen(Ref(bar_flag,1) OR is_lastbar, C);
LTFexpand5 = SumSince(bar_flag, V)+ValueWhen(bar_flag,V);
ltf_rc = (LTFexpand4-LTFexpand1)/LTFexpand1*100;

barcolor = IIf(LTFexpand4 > LTFexpand1, colorDarkGreen, colorDarkRed);
whisker_color = colorGrey50;

fbi = Min(lvb,ValueWhen(bar_flag,bi+0.5));
lbi = bi+0.5;
half_bar = (lbi+fbi)/2;
whisker_cond = half_bar < lvb;
lbi = Min(lvb,lbi);
lbp = Ref(bar_flag,1) OR is_lastbar;
is_visible = bi >= fvb AND bi <= LastVisibleValue(ValueWhen(lbp,bi,0));

maxbody = Max(LTFexpand1, LTFexpand4);
minbody = Min(LTFexpand1, LTFexpand4);
minbody = Max(Status("axisminy"), minbody);

SetChartOptions( 0, chartShowDates | chartShowArrows | chartWrapTitle );

if ( Interval() < tmfrm ) {
Plot( C, "", colorDefault, styleCandle, Null, Null, 0, 1 );
if ( num_bars < 500 )
Plot( bar_flag, "", colorRed, styleHistogram | styleOwnScale | styleNoLabel | styleDashed, 0, 1, 0, 0 );
//
GfxSetZOrder(-1);
GfxSetCoordsMode(1);
GfxSelectPen(whisker_color, 5, 0x200);
for ( i = 0; i < BarCount; i++ ) {
if ( is_visible[i] ) {
if ( lbp[ i ] ) {
if ( whisker_cond[i] ) {
GfxMoveTo(half_bar[i],LTFexpand3[i]);
GfxLineTo(half_bar[i],LTFexpand2[i]);
}
GfxFillSolidRect(fbi[i],minbody[i],lbi[i],maxbody[i],barcolor[i]);
}
}
}
} else {
SetBarFillColor(barcolor);
Plot( C, "Price", colorDefault, styleCandle );
}

_N(Title = StrFormat("{{NAME}} - STF: {{INTERVAL}}, LTF: " + ltf_int +
" - {{DATE}} | Op:%g, Hi:%g, Lo:%g, Close:%g (%.2f%%), Vol:%g {{VALUES}}",
LTFexpand1, LTFexpand2, LTFexpand3, LTFexpand4, SelectedValue(ltf_rc), LTFexpand5 ));
//
SetBarsRequired(Min(1000,num_bars));
``````

Or just remove Timeframeset:

``````/// @link https://forum.amibroker.com/t/looking-afl-for-blending-of-two-more-candles-as-per-picture/26730/12
/// by fxshrat@gmail.com
tmfrm = Param("Interval (minutes)", 60, 1, 240, 1)*60;
bar_shift = Param( "Bar Shift", 0, 0, 60, 1 );
bi = BarIndex();
fvb = FirstVisibleValue(bi);
lvb = LastvisibleValue(bi);
num_bars = lvb-fvb+1;
is_lastbar = bi == LastvisibleValue(bi);

ltf_int = ""+ tmfrm/60 + " minutes";

is_point = TimeFrameExpand(1, tmfrm, expandPoint);
bar_flag = Ref(Nz(is_point)>0,-1-bar_shift);

LTFexpand1 = ValueWhen(bar_flag, O);
LTFexpand2 = HighestSince(bar_flag, H);
LTFexpand3 = LowestSince(bar_flag, L);
LTFexpand4 = ValueWhen(Ref(bar_flag,1) OR is_lastbar, C);
LTFexpand5 = SumSince(bar_flag, V)+ValueWhen(bar_flag,V);
ltf_rc = (LTFexpand4-LTFexpand1)/LTFexpand1*100;

barcolor = IIf(LTFexpand4 > LTFexpand1, colorDarkGreen, colorDarkRed);
whisker_color = colorGrey50;

fbi = Min(lvb,ValueWhen(bar_flag,bi+0.5));
lbi = bi+0.5;
half_bar = (lbi+fbi)/2;
whisker_cond = half_bar < lvb;
lbi = Min(lvb,lbi);
lbp = Ref(bar_flag,1) OR is_lastbar;
is_visible = bi >= fvb AND bi <= LastVisibleValue(ValueWhen(lbp,bi,0));

maxbody = Max(LTFexpand1, LTFexpand4);
minbody = Min(LTFexpand1, LTFexpand4);
minbody = Max(Status("axisminy"), minbody);

SetChartOptions( 0, chartShowDates | chartShowArrows | chartWrapTitle );

if ( Interval() < tmfrm ) {
Plot( C, "", colorDefault, styleCandle, Null, Null, 0, 1 );
if ( num_bars < 500 )
Plot( bar_flag, "", colorRed, styleHistogram | styleOwnScale | styleNoLabel | styleDashed, 0, 1, 0, 0 );
//
GfxSetZOrder(-1);
GfxSetCoordsMode(1);
GfxSelectPen(whisker_color, 5, 0x200);
for ( i = 0; i < BarCount; i++ ) {
if ( is_visible[i] ) {
if ( lbp[ i ] ) {
if ( whisker_cond[i] ) {
GfxMoveTo(half_bar[i],LTFexpand3[i]);
GfxLineTo(half_bar[i],LTFexpand2[i]);
}
GfxFillSolidRect(fbi[i],minbody[i],lbi[i],maxbody[i],barcolor[i]);
}
}
}
} else {
SetBarFillColor(barcolor);
Plot( C, "Price", colorDefault, styleCandle );
}

_N(Title = StrFormat("{{NAME}} - STF: {{INTERVAL}}, LTF: " + ltf_int +
" - {{DATE}} | Op:%g, Hi:%g, Lo:%g, Close:%g (%.2f%%), Vol:%g {{VALUES}}",
LTFexpand1, LTFexpand2, LTFexpand3, LTFexpand4, SelectedValue(ltf_rc), LTFexpand5 ));
//
SetBarsRequired(Min(1000,num_bars));
``````
3 Likes

Nice job!

Maybe an even better (or at least alternative) approach allows the user to select a single candle clicking on it X times in succession to "consolidate" only that bar and the following 1, 2, 3... X bars.
Resetting the selection could be done using a right or center mouse button click.
(Or select a bar and then click on some progressively numbered GuiButtons/or Slider that indicate how many bars to "sum", or <add your own idea>).

Ideally, the user can save the (multiple) selections using persistent staticVars (or in some other ways), so the individual "patterns" will be permanently stored associated with specific tickers/charts.

I reiterate my doubts about the usefulness of the thing, but still, to me, it seems like a good exercise for AFL learners with enough time and desire to improve their overall AmiBroker programming skills.

One may use range marker (Begin marker - green one) to select start bar being saved to static var.
If setting new begin value then first click price axis.

If you click "Remove Range" then make sure there is no range marker set.

``````/// @link https://forum.amibroker.com/t/looking-afl-for-blending-of-two-more-candles-as-per-picture/26730/15
/// by fxshrat@gmail.com
tmfrm = Param("Interval (minutes)", 60, 1, 240, 1)*60;
bar_shift = Param( "Bar Shift", 0, 0, 60, 1 );
persist = True;

button = GuiButton( "Remove Range", 1, 1, 20, 90, 25, 1 );
but_trigger = GuiGetEvent(0, 0) == 1 && GuiGetEvent(0, 1) == 1;

cid = GetChartID();
bi = BarIndex();
dt = DateTime();
begin_val = BeginValue(dt);
fvb_dt = FirstVisibleValue(dt);
fvb = FirstVisibleValue(bi);
lvb = LastvisibleValue(bi);
num_bars = lvb-fvb+1;
is_lastbar = bi == LastvisibleValue(bi);

ltf_int = ""+ tmfrm/60 + " minutes";

is_point = TimeFrameExpand(1, tmfrm, expandPoint);

// static vars start ----------------------------------
if ( begin_val != Nz(StaticVarGet("LTF_begin_dt_"+cid)) AND begin_val > fvb_dt) {
StaticVarSet("LTF_begin_dt_"+cid, begin_val, persist);
StaticVarSet("LTF_ispoint_dt"+cid, BeginValue(ValueWhen(is_point, dt)), persist);
}
if ( but_trigger ) {
StaticVarRemove("LTF_*");
}
begin_dt = StaticVarGet("LTF_begin_dt_"+cid);
begin_bi = ValueWhen(DateTimeDiff(dt,begin_dt) == 0, bi);

ispoint_dt = StaticVarGet("LTF_ispoint_dt"+cid);
ispoint_bi = ValueWhen(DateTimeDiff(dt,ispoint_dt)==0, bi);
// static vars end -----------------------------------

bar_shift = IIf(IsNull(begin_bi), bar_shift, LastVisibleValue(ispoint_bi) - begin_bi+1);

is_begin = bi>=begin_bi;
is_range = IIf(IsNull(begin_dt), 1, is_begin AND bi <= lvb);
bar_flag = Ref(Nz(is_point)>0,-1+bar_shift)*is_range;

LTFexpand1 = ValueWhen(bar_flag, O);
LTFexpand2 = HighestSince(bar_flag, H);
LTFexpand3 = LowestSince(bar_flag, L);
LTFexpand4 = ValueWhen(Ref(bar_flag,1) OR is_lastbar, C);
LTFexpand5 = SumSince(bar_flag, V)+ValueWhen(bar_flag,V);
ltf_rc = (LTFexpand4-LTFexpand1)/LTFexpand1*100;

barcolor = IIf(LTFexpand4 > LTFexpand1, colorDarkGreen, colorDarkRed);
whisker_color = colorGrey50;

fbi = Min(lvb,ValueWhen(bar_flag,bi+0.5));
lbi = bi+0.5;
half_bar = (lbi+fbi)/2;
whisker_cond = half_bar < lvb;
lbi = Min(lvb,lbi);
lbp = Ref(bar_flag,1) OR is_lastbar;
is_visible = bi >= Max(fvb,Nz(begin_bi)) AND bi <= LastVisibleValue(ValueWhen(lbp,bi,0));

maxbody = Max(LTFexpand1, LTFexpand4);
minbody = Min(LTFexpand1, LTFexpand4);
minbody = Max(Status("axisminy"), minbody);

if ( Interval() < tmfrm ) {
Plot( C, "", colorDefault, styleCandle, Null, Null, 0, 1 );
if ( num_bars < 500 )
Plot( bar_flag, "", colorRed, styleHistogram | styleOwnScale | styleNoLabel | styleDashed, 0, 1, 0, 0 );
//
GfxSetZOrder(-1);
GfxSetCoordsMode(1);
GfxSelectPen(whisker_color, 5, 0x200);
for ( i = 0; i < BarCount; i++ ) {
if ( is_visible[i] ) {
if ( lbp[ i ] ) {
if ( whisker_cond[i] ) {
GfxMoveTo(half_bar[i],LTFexpand3[i]);
GfxLineTo(half_bar[i],LTFexpand2[i]);
}
GfxFillSolidRect(fbi[i],minbody[i],lbi[i],maxbody[i],barcolor[i]);
}
}
}
} else {
SetBarFillColor(barcolor);
Plot( C, "Price", colorDefault, styleCandle );
}

_N(Title = StrFormat("{{NAME}} - STF: {{INTERVAL}}, LTF: " + ltf_int +
" - {{DATE}} | Op:%g, Hi:%g, Lo:%g, Close:%g (%.2f%%), Vol:%g {{VALUES}}",
LTFexpand1, LTFexpand2, LTFexpand3, LTFexpand4, SelectedValue(ltf_rc), LTFexpand5 ));
//
SetBarsRequired(Min(1000,num_bars));
``````

2 Likes

Sir,
You are very near to the solution with some modifications'

Time set should be of each candle 's OHLC which are being consolidated or merged together. it would not worked with minutes time.
Regards
jagdishpahuja

Use DateTimeToStr() function

``````DateTimeToStr(SelectedValue(ValueWhen(bar_flag, dt)))
``````

-->

``````_N(Title = StrFormat("{{NAME}} - LTF: " + ltf_int +
" - %s | Op:%g, Hi:%g, Lo:%g, Close:%g (%.2f%%), Vol:%g {{VALUES}}",
DateTimeToStr(SelectedValue(ValueWhen(bar_flag, dt))),
LTFexpand1, LTFexpand2, LTFexpand3, LTFexpand4, SelectedValue(ltf_rc), LTFexpand5 ));
``````

changing to:

``````bar_flag2  = bar_flag OR is_lastbar;
// OHLC
LTFexpand1 = ValueWhen(bar_flag, O);
LTFexpand2 = ValueWhen(bar_flag2, Nz(Ref(HighestSince(bar_flag, H),-1)),0);
LTFexpand3 = ValueWhen(bar_flag2, Nz(Ref(LowestSince(bar_flag, L),-1)),0);
LTFexpand4 = ValueWhen(bar_flag2, Ref(C,-(!is_lastbar)), 0);
// Volume
cs_vol = SumSince(bar_flag, V)+Nz(ValueWhen(bar_flag,V));
LTFexpand5 = ValueWhen(bar_flag2, Ref(cs_vol,-(!is_lastbar)), 0);
``````

So that `Title` output shows same values over the full length of longer time frame bar.

So new code of this version:

``````/// @link https://forum.amibroker.com/t/looking-afl-for-blending-of-two-more-candles-as-per-picture/26730/17
/// by fxshrat@gmail.com
tmfrm = Param("Interval (minutes)", 60, 1, 240, 1)*60;
bar_shift = Param( "Bar Shift", 0, 0, 60, 1 );
persist = True;

button = GuiButton( "Remove Range", 1, 1, 20, 90, 25, 1 );
but_trigger = GuiGetEvent(0, 0) == 1 AND GuiGetEvent(0, 1) == 1;

cid = GetChartID();
bi = BarIndex();
dt = DateTime();
begin_val = BeginValue(dt);
fvb_dt = FirstVisibleValue(dt);
fvb = FirstVisibleValue(bi);
lvb = LastvisibleValue(bi);
num_bars = lvb-fvb+1;
is_lastbar = bi == LastvisibleValue(bi);

ltf_int = ""+ tmfrm/60 + " minutes";

is_point = TimeFrameExpand(1, tmfrm, expandPoint);

// static vars start ----------------------------------
if ( begin_val != Nz(StaticVarGet("LTF_begin_dt_"+cid)) AND begin_val > fvb_dt) {
StaticVarSet("LTF_begin_dt_"+cid, begin_val, persist);
StaticVarSet("LTF_ispoint_dt"+cid, BeginValue(ValueWhen(is_point, dt)), persist);
}
if ( but_trigger ) {
StaticVarRemove("LTF_*");
}
begin_dt = StaticVarGet("LTF_begin_dt_"+cid);
begin_bi = ValueWhen(DateTimeDiff(dt,begin_dt) == 0, bi);

ispoint_dt = StaticVarGet("LTF_ispoint_dt"+cid);
ispoint_bi = ValueWhen(DateTimeDiff(dt,ispoint_dt)==0, bi);
// static vars end -----------------------------------

bar_shift = IIf(IsNull(begin_bi), bar_shift, LastVisibleValue(ispoint_bi) - begin_bi+1);

is_begin = bi>=begin_bi;
is_range = IIf(IsNull(begin_dt), 1, is_begin AND bi <= lvb);
bar_flag = Ref(Nz(is_point)>0,-1+bar_shift)*is_range;

bar_flag2  = bar_flag OR is_lastbar;
// OHLC
LTFexpand1 = ValueWhen(bar_flag, O);
LTFexpand2 = ValueWhen(bar_flag2, Nz(Ref(HighestSince(bar_flag, H),-1)),0);
LTFexpand3 = ValueWhen(bar_flag2, Nz(Ref(LowestSince(bar_flag, L),-1)),0);
LTFexpand4 = ValueWhen(bar_flag2, Ref(C,-(!is_lastbar)), 0);
// Volume
cs_vol = SumSince(bar_flag, V)+Nz(ValueWhen(bar_flag,V));
LTFexpand5 = ValueWhen(bar_flag2, Ref(cs_vol,-(!is_lastbar)), 0);
// ROC
ltf_rc = (LTFexpand4-LTFexpand1)/LTFexpand1*100;

barcolor = IIf(LTFexpand4 > LTFexpand1, colorDarkGreen, colorDarkRed);
whisker_color = colorGrey50;

fbi = Min(lvb,ValueWhen(bar_flag,bi+0.5));
lbi = bi+0.5;
half_bar = (lbi+fbi)/2;
whisker_cond = half_bar < lvb;
lbi = Min(lvb,lbi);
lbp = Ref(bar_flag,1) OR is_lastbar;
is_visible = bi >= Max(fvb,Nz(begin_bi)) AND bi <= LastVisibleValue(ValueWhen(lbp,bi,0));

maxbody = Max(LTFexpand1, LTFexpand4);
minbody = Min(LTFexpand1, LTFexpand4);
minbody = Max(Status("axisminy"), minbody);

if ( Interval() < tmfrm ) {
Plot( C, "", colorDefault, styleCandle, Null, Null, 0, 1 );
if ( num_bars < 500 )
Plot( bar_flag, "", colorRed, styleHistogram | styleOwnScale | styleNoLabel | styleDashed, 0, 1, 0, 0 );
//
GfxSetZOrder(-1);
GfxSetCoordsMode(1);
GfxSelectPen(whisker_color, 5, 0x200);
for ( i = 0; i < BarCount; i++ ) {
if ( is_visible[i] ) {
if ( lbp[ i ] ) {
if ( whisker_cond[i] ) {
GfxMoveTo(half_bar[i],LTFexpand3[i]);
GfxLineTo(half_bar[i],LTFexpand2[i]);
}
GfxFillSolidRect(fbi[i],minbody[i],lbi[i],maxbody[i],barcolor[i]);
}
}
}
} else { // if tmfrm <= Interval()
SetBarFillColor(Nz(barcolor,colorWhite));
Plot( C, "Price", colorDefault, styleCandle );
}
//
_N(Title = StrFormat("{{NAME}} - LTF: " + ltf_int +
" - %s | Op:%g, Hi:%g, Lo:%g, Close:%g (%.2f%%), Vol:%g {{VALUES}}",
DateTimeToStr(SelectedValue(ValueWhen(bar_flag, dt))),
LTFexpand1, LTFexpand2, LTFexpand3, LTFexpand4, SelectedValue(ltf_rc), LTFexpand5 ));
//
SetBarsRequired(Min(1000,num_bars));
``````

2 Likes

There is full code!
Learn reading but not just copy and pasting!

Unbelievable.

3 Likes

Sure sir, for me it is a new subject. Initially copy & paste keeps my interest active & alive.

sir

it is a very useful way to blending /consolidation of candles to understand the price action happening behind the hidden candles.

This is very important when the market is in range or consolidation mode. In the trending market no need for such exercise.

Regards

jagdish

Should be

``````bar_shift = IIf(IsNull(begin_dt), -bar_shift, LastVisibleValue(ispoint_bi) - begin_bi+1);
``````

If range marker plot was removed via GUI and bar shift being greater zero then last LTF bar(s) was plotted incorrectly.

New version:

``````/// @link https://forum.amibroker.com/t/looking-afl-for-blending-of-two-more-candles-as-per-picture/26730/21
/// by fxshrat@gmail.com
tmfrm = Param("Interval (minutes)", 60, 1, 7200, 1)*60;
bar_shift = Param( "Bar Shift (default one)", 0, 0, 60, 1 );
persist = True;

button = GuiButton( "Remove Range", 1, 1, 20, 90, 25, 1 );
but_trigger = GuiGetEvent(0, 0) == 1 AND GuiGetEvent(0, 1) == 1;

cid = GetChartID();
bi = BarIndex();
dt = DateTime();
begin_val = BeginValue(dt);
fvb_dt = FirstVisibleValue(dt);
fvb = FirstVisibleValue(bi);
lvb = LastvisibleValue(bi);
num_bars = lvb-fvb+1;
is_lastbar = bi == LastvisibleValue(bi);

ltf_int = ""+ tmfrm/60 + " minutes";

is_point = TimeFrameExpand(1, tmfrm, expandPoint);

// static vars start ----------------------------------
if ( begin_val != Nz(StaticVarGet("LTF_begin_dt_"+cid)) AND begin_val > fvb_dt) {
StaticVarSet("LTF_begin_dt_"+cid, begin_val, persist);
StaticVarSet("LTF_ispoint_dt"+cid, BeginValue(ValueWhen(is_point, dt)), persist);
}
if ( but_trigger ) {
StaticVarRemove("LTF_*");
}
begin_dt = StaticVarGet("LTF_begin_dt_"+cid);
begin_bi = ValueWhen(DateTimeDiff(dt,begin_dt) == 0, bi);

ispoint_dt = StaticVarGet("LTF_ispoint_dt"+cid);
ispoint_bi = ValueWhen(DateTimeDiff(dt,ispoint_dt)==0, bi);
// static vars end -----------------------------------

bar_shift = IIf(IsNull(begin_dt), -bar_shift, LastVisibleValue(ispoint_bi) - begin_bi+1);

is_begin = bi>=begin_bi;
is_range = IIf(IsNull(begin_dt), 1, is_begin AND bi <= lvb);
bar_flag = Ref(Nz(is_point)>0,-1+bar_shift)*is_range;

bar_flag2  = bar_flag OR is_lastbar;
// OHLC
LTFexpand1 = ValueWhen(bar_flag, O);
LTFexpand2 = ValueWhen(bar_flag2, Nz(Ref(HighestSince(bar_flag, H),-1)),0);
LTFexpand3 = ValueWhen(bar_flag2, Nz(Ref(LowestSince(bar_flag, L),-1)),0);
LTFexpand4 = ValueWhen(bar_flag2, Ref(C,-(!is_lastbar)), 0);
// Volume
cs_vol = SumSince(bar_flag, V)+Nz(ValueWhen(bar_flag,V));
LTFexpand5 = ValueWhen(bar_flag2, Ref(cs_vol,-(!is_lastbar)), 0);
// ROC
ltf_rc = (LTFexpand4-LTFexpand1)/LTFexpand1*100;

barcolor = IIf(LTFexpand4 > LTFexpand1, colorDarkGreen, colorDarkRed);
whisker_color = colorGrey50;

fbi = Min(lvb,ValueWhen(bar_flag,bi+0.5));
lbi = bi+0.5;
half_bar = (lbi+fbi)/2;
whisker_cond = half_bar < lvb;
lbi = Min(lvb,lbi);
lbp = Ref(bar_flag,1) OR is_lastbar;
is_visible = bi >= Max(fvb,Nz(begin_bi)) AND bi <= LastVisibleValue(ValueWhen(lbp,bi,0));

maxbody = Max(LTFexpand1, LTFexpand4);
minbody = Min(LTFexpand1, LTFexpand4);
minbody = Max(Status("axisminy"), minbody);

if ( Interval() < tmfrm ) {
Plot( C, "", colorDefault, styleCandle, Null, Null, 0, 1 );
if ( num_bars < 500 )
Plot( bar_flag, "", colorRed, styleHistogram | styleOwnScale | styleNoLabel | styleDashed, 0, 1, 0, 0 );
//
GfxSetZOrder(-1);
GfxSetCoordsMode(1);
GfxSelectPen(whisker_color, 5, 0x200);
for ( i = 0; i < BarCount; i++ ) {
if ( is_visible[i] ) {
if ( lbp[ i ] ) {
if ( whisker_cond[i] ) {
GfxMoveTo(half_bar[i],LTFexpand3[i]);
GfxLineTo(half_bar[i],LTFexpand2[i]);
}
GfxFillSolidRect(fbi[i],minbody[i],lbi[i],maxbody[i],barcolor[i]);
}
}
}
} else {// if tmfrm <= Interval()
SetBarFillColor(Nz(barcolor,colorWhite));
Plot( C, "Price", colorDefault, styleCandle );
}
//
_N(Title = StrFormat("{{NAME}} - LTF: " + ltf_int +
" - %s | Op:%g, Hi:%g, Lo:%g, Close:%g (%.2f%%), Vol:%g {{VALUES}}",
DateTimeToStr(SelectedValue(ValueWhen(bar_flag, dt))),
LTFexpand1, LTFexpand2, LTFexpand3, LTFexpand4, SelectedValue(ltf_rc), LTFexpand5 ));
// shorter interval's title
//_N( Title += StrFormat( "\n{{NAME}} - {{INTERVAL}} - {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%), Vol %g {{VALUES}}",
//                           O, H, L, C, SelectedValue( ROC( C, 1 ) ), V ) );
//
SetBarsRequired(Min(1000,num_bars));
``````

Moderator comment: removed offending content

2 Likes