How to set value of some previous bars?

Hi

Array named "position" says how many bars back I should go and set some flag, in array named "arrayboolean". So for example, if I have the following values set:

position = NULL;
position[barcount - 5]=3;
position[barcount - 40]=9;
arrayboolean = false;

I want to create a formula (array operation without loop) that will set :
arrayboolean[barcount - 8]=true; // -5 -3 = -8
arrayboolean[barcount - 49]=true; // -40 - 9 = -49

How can I do this?

PS: I do not mind if the formula looks into the future.

Here is a rather efficient loop that does this:

    arrayboolean = False;
    i = BarCount - 1;

    while( i > 0 )
    {
        if( position[i] )
        {
            i = i - position[i];
            arrayboolean[i] = True;
        }

        i = i - 1;
    }

Still looking for an array equivalent.

Maybe Using ValueWhen get Barindex of position occurrence .... (that is 1 & 2)

i = 1st  - 2nd;
arrayboolean[i] = True;
//or ...
i = LastValue(barindex()) - 1st ;
arrayboolean[i] = True;

@Fossil

Thank you for the tip. ValueWhen does work, when I set n=0:
ValueWhen(EXPRESSION, ARRAY, n = 1)

However it does not detect the very first (leftmost) bar :
position[barcount - 40]

Therefore the loop version correctly produces 3 UpArrows, while the array version produces only 2 UpArrows.

I could find a workaround and get that leftmost bar. But I am wondering if I am using the ValueWhen and n=0 wrongly.

Here is the working code:

procedure Plot_Down_arrow( HighPointsBool )
{
    PlotShapes( HighPointsBool * shapeDownArrow, colorRed, 0, H, -20 );
}

procedure Plot_up_arrow( LowPointsBool )
{
    PlotShapes( LowPointsBool * shapeUpArrow, colorGreen, 0, L, -20 );
}

function from_loop( position )
{
    local
    arrayboolean ;

    arrayboolean = False;
    i = BarCount - 1;

    while( i > 0 )
    {
        if( position[i] )
        {
            i = i - position[i];
            arrayboolean[i] = True;
        }

        i = i - 1;
    }

    return     arrayboolean ;
}

function from_array( position )
{
    local
    arrayboolean ;

    arrayboolean = False;

    distan = ValueWhen( NOT IsNull( position ), position, 0 );
    bindex = ValueWhen( NOT IsNull( position ), BarIndex(), 0 );
    arrayboolean = ( BarIndex() == ( bindex - distan ) );

    addcolumn( distan, "distan", 1.0 );
    addcolumn( bindex, "bindex", 1.0 );

    return arrayboolean;
}

filter = BarIndex() > BarCount - 100;

position = NULL;
position[barcount - 5] = 3;
position[barcount - 20] = 7;
position[barcount - 40] = 9;
arrayboolean = false;
Plot_Down_arrow( NOT IsNull( position ) );

addcolumn( position, "position", 1.0 );
//arrayboolean = from_loop( position );
arrayboolean = from_array( position );

Plot_Up_arrow( arrayboolean );

looking at this code, how familiar are you with programming in general?

Shouldn't you be using another variable instead of i

I mean when you enter loop with I = 100, and then jump down I to say 90, what happens to the elements at (index) position that is b/w 91 and 99 ?

Array solution does not always exist. You need to get the capability right I guess.
Let us loosely define Array processing as computing all the elements with their respective index.
This means, that all the indices need to be aligned.
Already explained in the manual otherwise you would have to iterate through all, or a part of the elements.

Thank you for asking. Yes, when I find a value at position[i] and position[i] contains the value 9, then I know that between i-9 and i there are no other position[] values to examine. So I have tried to optimize my loop and save some itterations. This is why I mentioned:

The next step would be to scan the array not down to 0, but down to the first meaningfull value of position[].

However @Fossil 's idea worked and I just need to figure what is going wrong with the first bar.

Try this code

PV = Position_Values   = ValueWhen(IsTrue(Position),Position);
PB = Position_BarIndex = ValueWhen(IsTrue(Position),BarIndex());
DF = Array_Differences = ValueWhen(IsTrue(Position),ArrayBoolean[PB-PV] = 1);

I am not completely sure that this will achieve what you want but i hope it will :slight_smile:

Just another Important point , you should initialize the variable "position" equal to zero Position = 0, OR you would need to use NZ() function

@Sebastian
You are using ArrayBoolean without initializing it. I amnot sure how to use your code.

You already initialized ArrayBoolean equal to false

@Sebastian

I tried to insert your code and test it. This definitely did not work. Could you tell me where you think it fits better?

function from_array( position )
{
    local
    arrayboolean ;

    arrayboolean = False;

    distan = ValueWhen( NOT IsNull( position ), position, 0 );
    bindex = ValueWhen( NOT IsNull( position ), BarIndex(), 0 );

PV = Position_Values   = ValueWhen(IsTrue(Position),Position);
PB = Position_BarIndex = ValueWhen(IsTrue(Position),BarIndex());
DF = Array_Differences = ValueWhen(IsTrue(Position),ArrayBoolean[PB-PV] = 1);

    // arrayboolean = ( BarIndex() == ( bindex - distan ) );

    addcolumn( distan, "distan", 1.0 );
    addcolumn( bindex, "bindex", 1.0 );

    return arrayboolean;
}

Just to save my time and your time , Put a full complete pseudo-code code that you would like to imitate its result using array , and i will do this right now for you (Only if it was small) , if it's long code i may need more time

The full working code is on the 4th post. It is ALMOST complete. As described on that post, the only problem is with the leftmost bar.

Ok give a moment to check it

@Sebastian, just a side note to your upper lines... it is not correct code (third line). You are using arrays (PB and PV) within subscript (array element) operator "[ ]" there and trying to assign 1 to array element.

1 Like

I found a quick and dirty way to make it work. I inserted this statement :

    position[0] = 5000;

inside the from_array function. This way I create a dummy leftmost bar that Amibroker ignores and is forced to process the real leftmost bar, that I care.

However I wonder why ValueWhen behaves like this. Do I have to do this workaround everythime n=0?

procedure Plot_Down_arrow( HighPointsBool )
{
    PlotShapes( HighPointsBool * shapeDownArrow, colorRed, 0, H, -20 );
}

procedure Plot_up_arrow( LowPointsBool )
{
    PlotShapes( LowPointsBool * shapeUpArrow, colorGreen, 0, L, -20 );
}

function from_loop( position )
{
    local
    arrayboolean ;

    arrayboolean = False;
    i = BarCount - 1;

    while( i > 0 )
    {
        if( position[i] )
        {
            i = i - position[i];
            arrayboolean[i] = True;
        }

        i = i - 1;
    }

    return     arrayboolean ;
}

function from_array( position )
{
    local
    arrayboolean ;

    position[0] = 5000;
    arrayboolean = False;

    distan = ValueWhen( NOT IsNull( position ), position, 0 );
    bindex = ValueWhen( NOT IsNull( position ), BarIndex(), 0 );
    arrayboolean = ( BarIndex() == ( bindex - distan ) );

    addcolumn( position, "position", 1.0 );
    addcolumn( distan, "distan", 1.0 );
    addcolumn( bindex, "bindex", 1.0 );

    return arrayboolean;
}

filter = BarIndex() > BarCount - 100;

position = NULL;

position[barcount - 5] = 3;
position[barcount - 20] = 7;
position[barcount - 40] = 9;
arrayboolean = false;
Plot_Down_arrow( NOT IsNull( position ) );

//arrayboolean = from_loop( position );
arrayboolean = from_array( position );

Plot_Up_arrow( arrayboolean );

@fxshrat, thanks you very much for that :sunflower: , you are right and i agree with you , unfortunately i just realized this in late time


@bobptz, unfortunately i did not manage to produce an identical result to your loop version using a pure array_based solution , may be there's a way to achieve that using arrays but i could not get it right now , the point that deserve to focus on is how to make loop process efficient as much as possible instead of code conversion.

That what i managed to write , it's similar to your one , nothing new about it

PV = Position_Values    = IIf(IsTrue(Position),Position,0);
PB = Position_BarIndex  = IIf(IsTrue(Position),BarIndex(),0);
DF = Array_Differences  = PB-PV;

AB = Array_Boolean      = 0;

for ( i = 0; i < BarCount; i++ )
{
	if(DF[i]) {AB[i] = DF[i];}
}

Plot(AB,"Array Boolean",colorOrange,styleLine|styleOwnScale);

I wonder when i will be able to write a correct code from the first time without any further modification :blush:

//This line should be 
if(DF[i]) {AB[i] = DF[i];}

// Replaced by this one 
if(DF[i]) {AB[DF[i]] = 1;}

Maybe @Tomasz can help in this issue? Why can't I use ValueWhen with (n=0) to detect the first non-null occurence of a value (eg in array position)?

You can see at the screenshot that array distan is correctly set to 7 and array bindex to 11.481. However they do not take any values and seem to ignore the position[11471]=9 (that came from position[barcount - 20] = 9;).

ab

position = NULL;
position[barcount - 4] = 3;
position[barcount - 10] = 7;
position[barcount - 20] = 9;

distan = ValueWhen( NOT IsNull( position ), position, 0 );
bindex = ValueWhen( NOT IsNull( position ), BarIndex(), 0 );

addcolumn( position, "position", 1.0 );
addcolumn( distan, "distan", 1.0 );
addcolumn( bindex, "bindex", 1.0 );
addcolumn( BarIndex(), "BarIndex()", 1.0 );

By n=0 due mean the first occurrence starting from left ?
like var1[0] = 1; where this is the first element.

n=0 refers to the future occurrence and n=1 is the most recent.
n=2 is the 2nd most recent, and so on.
so a True condition going backwards, (ie. towards lower BarIndex() ) will have a larger value on n.

Another thing, if you are running ValueWhen(), the n is relative from the Bar index in reference.

So for any bar, the most recent occurrence for it will n = 1, and the immediate next will be n=0.
does this make sense to you?

@bobptz

here, put this code in a chart

Plot( C, "Close", colorDefault, ParamStyle("Style") | GetPriceStyle() );

bi = BarIndex();
mod = bi % 5 == 0;
fa = ValueWhen( mod, bi, 2); // far
nr = ValueWhen( mod, bi, 1); // recent
fu = ValueWhen( mod, bi, 0); // future

b = SelectedValue( bi );

printf("%g %g %g %g ", bi[b], fa[b], nr[b], fu[b]);

Observe the relative bar index from the current bar.
Select a bar and move through them either side.

image

hehe, he has already scratched his head enough preparing manuals :smiley: