Why my Indicator end value change when the chart scale change

I have created an indicator to check the performance of stocks of different cap size. The problem is that the end value of the indictor changes when I scale up and down the chart, which is not what I want.

I set the initial value of the indicator as 100. And the value of the i + 1 bar = value of i bar * (1 + i+1 bar's return)

image
image

Small_NumberOfStock = IIf(Foreign("HKSmallCap","I") == 0, HHV(Foreign("HKSmallCap","I"),10),Foreign("HKSmallCap","I"));
Mid_NumberOfStock = IIf(Foreign("HKMidCap","I") == 0, HHV(Foreign("HKMidCap","I"),10),Foreign("HKMidCap","I"));
Large_NumberOfStock = IIf(Foreign("HKLargeCap","I") == 0, HHV(Foreign("HKLargeCap","I"),10),Foreign("HKLargeCap","I"));
All_NumberOfStock = IIf(Foreign("HKTotal","I") == 0, HHV(Foreign("HKTotal","I"),10),Foreign("HKTotal","I"));

Small_IndexDailyReturn = Nz(Foreign("HKSmallCap","C") / Small_NumberOfStock, 0);
Mid_IndexDailyReturn = Nz(Foreign("HKMidCap","C") / Mid_NumberOfStock, 0);
Large_IndexDailyReturn = Nz(Foreign("HKLargeCap","C") / Large_NumberOfStock, 0);
All_IndexDailyReturn = Nz(Foreign("HKTotal","C") / All_NumberOfStock, 0);

HKSmallCap[0] = 100;
HKMidCap[0] = 100;
HKLargeCap[0] = 100;
HKIndex[0] = 100;

for( i = 1; i < BarCount; i++ )
{
  HKSmallCap[i] = HKSmallCap[i-1] * ( 1 + Small_IndexDailyReturn[i] );
  HKMidCap[i] = HKMidCap[i-1] * ( 1 + Mid_IndexDailyReturn[i] );
  HKLargeCap[i] = HKLargeCap[i-1] * ( 1 + Large_IndexDailyReturn[i] );
  HKIndex[i] = HKIndex[i-1] * ( 1 + All_IndexDailyReturn[i] );
}

if(ParamToggle("HKSmall","No|Yes",1))
{Plot(HKSmallCap,"HKSmallCap", ParamColor("Short", colorRed), ParamStyle("StyleSmall",styleOwnScale));}
if(ParamToggle("HKMid","No|Yes",1))
{Plot(HKMidCap,"HKMidCap", ParamColor("Mid", colorYellow), ParamStyle("StyleMid",styleOwnScale));}
if(ParamToggle("HKLarge","No|Yes",1))
{Plot(HKLargeCap,"HKLargeCap", ParamColor("Large", colorGreen), ParamStyle("StyleLarge",styleOwnScale));}
if(ParamToggle("HKAll","No|Yes",0))
{Plot(HKIndex,"HKIndex", ParamColor("All", colorAqua), ParamStyle("StyleAll",styleOwnScale));}

Check out here
https://www.amibroker.com/guide/h_understandafl.html
https://www.amibroker.com/kb/2008/07/03/quickafl/

SetBarsRequired(sbrall);
3 Likes

Thank you! problem solved. Never notice this even though I have written so many formulas before.

Frankly speaking using SetBarsRequired(sbrAll) is NOT the way to go. Requesting all bars always is bad idea because it slows down things for no reason. Your indicator is constructed so that it calculates running (cumulative) product of bar-by-bar changes and due to its cumulative nature it should produce different values if amount of data processed changes. 10-year performance is obviously different than say 1-year performance. So changing values are actually correct.
NOT using all bars is better because you can then see performance relative to visible bars only which is more flexible (as you may compare performance in different ranges).

1 Like

You do not need to use loop. You can just use Prod function. Also you do not need "thousands" of same calls of Foreign. You just need 4 times SetForeign since it is four symbols with 2 arrays each.

Version(6.20);// code requires AB 6.20 minimum

/// @link https://forum.amibroker.com/t/why-my-indicator-end-value-change-when-the-chart-scale-change/8127/5
SetForeign("HKSmallCap");
HKSmallCap_I = OI;
HKSmallCap_C = C;

SetForeign("HKMidCap");
HKMidCap_I = OI;
HKMidCap_C = C;

SetForeign("HKLargeCap");
HKLargeCap_I = OI;
HKLargeCap_C = C;

SetForeign("HKTotal");
HKTotal_I = OI;
HKTotal_C = C;

RestorePriceArrays();

Small_NumberOfStock = IIf( HKSmallCap_I == 0, HHV( HKSmallCap_I, 10 ), HKSmallCap_I );
Mid_NumberOfStock = IIf( HKMidCap_I == 0, HHV( HKMidCap_I, 10 ), HKMidCap_I );
Large_NumberOfStock = IIf( HKLargeCap_I == 0, HHV( HKLargeCap_I, 10 ), HKLargeCap_I );
All_NumberOfStock = IIf( HKTotal_I == 0, HHV( HKTotal_I, 10 ), HKTotal_I );

Small_IndexDailyReturn = Nz(HKSmallCap_C / Small_NumberOfStock, 0);
Mid_IndexDailyReturn = Nz(HKMidCap_C / Mid_NumberOfStock, 0);
Large_IndexDailyReturn = Nz(HKLargeCap_C / Large_NumberOfStock, 0);
All_IndexDailyReturn = Nz(HKTotal_C / All_NumberOfStock, 0);

range = Cum(1)-1;
HKSmallCap = Prod( Small_IndexDailyReturn+1, range );
HKMidCap = Prod( Mid_IndexDailyReturn+1, range );
HKLargeCap = Prod( Large_IndexDailyReturn+1, range );
HKIndex = Prod( All_IndexDailyReturn+1, range );

if(ParamToggle("HKSmall","No|Yes",1))
{Plot(HKSmallCap,"HKSmallCap", ParamColor("Short", colorRed), ParamStyle("StyleSmall",styleOwnScale));}
if(ParamToggle("HKMid","No|Yes",1))
{Plot(HKMidCap,"HKMidCap", ParamColor("Mid", colorYellow), ParamStyle("StyleMid",styleOwnScale));}
if(ParamToggle("HKLarge","No|Yes",1))
{Plot(HKLargeCap,"HKLargeCap", ParamColor("Large", colorGreen), ParamStyle("StyleLarge",styleOwnScale));}
if(ParamToggle("HKAll","No|Yes",0))
{Plot(HKIndex,"HKIndex", ParamColor("All", colorAqua), ParamStyle("StyleAll",styleOwnScale));}
4 Likes

Just heads up that Prod() function is available from 6.20 so adding

Version( 6.20 );

on the top of the formula would help those who blindly copy-paste codes.

1 Like

Thank you! just learn better way to code and the use of 'SetForeign' and 'Prod'

Yes, you are right. but I would like to use it as an index (like sp 500, e.g.), so that I can compare the value more easily (like today it's 2,567, yesterday it's 2,525, last week it's 2,480)