Getting some of digits of price

Hi Trying below code...Problem is I am not able to backtest this logic & it always seems to consider the last bar for signal generation ( I cannot back test it!)

SetChartOptions( 0, chartShowDates );
ScripName = Name();

// define reusable function
function SumDigits(price)
{
   SumOfDigits=0;
   strVal = StrReplace(NumToStr(price), ".", "" );

   StrLength = StrLen(strVal);

    // iterate through the lines of input file
    for( i = 0;  i < StrLength ; i++ ) 
    {
     SumOfDigits=SumOfDigits+ StrToNum(StrMid(strVal,i,1));
    }
  
   return SumOfDigits;
}


prevLow=Ref(L,-1);
prevHigh=Ref(H,-1);

prevLowStr  = SumDigits(prevLow);
prevHighStr = SumDigits(prevHigh);

BuySig  = (Ref(prevLowStr,-1)==11 OR (Ref(prevLowStr,-1))==22 OR (Ref(prevLowStr,-1))==33 OR (Ref(prevLowStr,-1))==44);
SellSig = (Ref(prevHighStr,-1 )==11 OR Ref(prevHighStr,-1 )==22 OR Ref(prevHighStr,-1 )==33 OR Ref(prevHighStr,-1 )==44);

Buy =  BuySig  ;
Short = SellSig ;

Filter = Buy OR Short ;

AddColumn( Buy, "Buy", 1);
AddColumn( Short, "Short", 1);
AddColumn( C, "Close");
AddColumn(prevLowStr  ,"prevLowStr");

@prithvibhat in your user-defined function, you receive an array (price) and you are supposed to return another array (SumOfDigits), so you need to process all the elements of the input array.

function SumDigits( price )
{
    local i, j;
    
    SumOfDigits = 0; // will return an array

	// you need to process the input "price" array
    for( j = 0; j < BarCount; j++ )
    {
        strVal = StrReplace( NumToStr( price[j] ), ".", "" );
        StrLength = StrLen( strVal );
        for( i = 0;  i < StrLength ; i++ )
        {
            SumOfDigits[j] = SumOfDigits[j] + StrToNum( StrMid( strVal, i, 1 ) );
        }
    }
    return SumOfDigits;
}

I simply modified your function (no check on the rest of code) accessing each element of the input array using a loop and the [ ] bracket operator. The same logic is used to assign the calculated values to each element of the array that will be returned.

Excerpt from the user manual:

Accessing array elements: [ ] - subscript operator

An array identifier followed by an expression in square brackets ([ ]) is a subscripted representation of an element of an array object.

arrayidentifier [ expression ]

It represents the value of expression-th element of array.

1 Like

hi , Thanks for the response...

I tried your method but the results still considers the last bar ..Basically if I run the exploration if the last bar is meeting this criteria , in my results i have every bar having the Buy/Sell generated ...

I know abt ExRem function , but since we are looking at a very specific condition on the previous bar the signal shouldn't repeat.

To be more precise, if my last but one bar for the day meets this criteria I have Buy/Sell generated for every bar during the day

I presume because we are using some string functions it is messing up things...

Seems quite complicated to do simple things using afl!

I just need to generate lets say buy or sell signal if sum of digits of prev candle , low or high=11..We need to add up decimals too!

Of course backtesting should work too

@prithvibhat, if a conceptually simple problem is difficult to implement in code, it's often a sign that you're not taking the best approach to the solution. Below is an example of how I would solve it, and this one doesn't use looping. Note that you need to specify how many places after the decimal point you want to pay attention to (precision), because with floating point numbers there may be a lot more digits there than you want to consider.

function SumDigits(price,precision)
{
	// Round the price to 'precision' places after the decimal, and get rid of the decimal point
	remainingDigits = round(price * (10 ^ precision));
	
	sumDigs = 0;
	while (LastValue(Cum(remainingDigits)) > 0)
	{
		// Add the right most digit to the sum, and then move the remaining digits over
		sumDigs += remainingDigits % 10;
		remainingDigits = floor(remainingDigits/10);
	}
	
	return sumDigs;
}

// Test
sd = SumDigits(C,4);

Filter = True;
AddColumn(C, "Close", 1.4);
AddColumn(sd, "Sum of Digits");
3 Likes

@prithvibhat the function I posted here works, and @mradtke provided you a better (and faster) alternative in which you directly manipulate the entire array values without a loop over the individual elements (the resulting array values should be the same if both functions process digits that have the same precision).

In any case, once you have fixed the user-defined function, it is the rest of your formula that you need to double check: you used "Short" instead of what probably should have been "Sell".

Here below is a revised formula (that probably it is not yet what you want) but at least shows, in the exploration, the values you are using/calculating (and also works in backtest mode - even if such "magic numbers" based system seems not to be particularly profitable)

function SumDigitsLoop( price )
{
    local i, j;

    SumOfDigits = 0; // will return an array

// you need to process the input "price" array
    for( j = 0; j < BarCount; j++ )
    {
        strVal = StrReplace( NumToStr( price[j] ), ".", "" );
        StrLength = StrLen( strVal );

        for( i = 0;  i < StrLength ; i++ )
        {
            SumOfDigits[j] = SumOfDigits[j] + StrToNum( StrMid( strVal, i, 1 ) );
        }
    }

    return SumOfDigits;
}

// https://forum.amibroker.com/t/getting-some-of-digits-of-price/7033/5
function SumDigits( price, precision )
{
	// Round the price to 'precision' places after the decimal, and get rid of the decimal point
    remainingDigits = round( price * ( 10 ^ precision ) );

    sumDigs = 0;

    while( LastValue( Cum( remainingDigits ) ) > 0 )
    {
	// Add the right most digit to the sum, and then move the remaining digits over
        sumDigs += remainingDigits % 10;
        remainingDigits = floor( remainingDigits / 10 );
    }

    return sumDigs;
}

prevLow = Ref( L, -1 );
prevHigh = Ref( H, -1 );
prevLowDigitSum = SumDigitsLoop( prevLow );
prevHighDigitSum = SumDigitsLoop( prevHigh );
prevLowDigitSum2 = SumDigits( prevLow, 2 );  // uset for comparison
prevHighDigitSum2 = SumDigits( prevHigh, 2 ); 

// Backtest options
maxpos = 10; // maximum number of open positions
SetOption( "InitialEquity", 100000 ); // set initial equity = 100K
SetOption( "MaxOpenPositions", maxpos );
SetPositionSize( 100 / maxpos, spsPercentOfEquity );

Buy = ( ( prevLowDigitSum % 11 ) == 0 );
Sell = ( ( prevHighDigitSum % 11 ) == 0 );

Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );

// Exploration
Filter = 1; // Buy OR Sell ;

AddColumn( IIf( Buy, 1, Null ), "Buy", 1 );
AddColumn( IIf( Sell, 1, Null ), "Sell", 1 );
AddColumn( C, "Close" );
AddColumn( L, "Low" );
AddColumn( prevLow , "Pr.L" );
AddColumn( prevLowDigitSum, "Pr.L.D.Sum Loop" );
AddColumn( prevLowDigitSum2, "Pr.L.D.Sum" );
AddColumn( H, "High" );
AddColumn( prevHigh, "Pr.H" );
AddColumn( prevHighDigitSum, "Pr.H.D.Sum Loop" );
AddColumn( prevHighDigitSum2, "Pr.H.D.Sum" );
SetSortColumns( -2 );

Here is an exploration result:

immagine

To better understand if your logic is correct I suggest using a single instrument for your explorations so you can see/verify the previous days' values. (Set the "Apply to" field to "Current").

4 Likes

Thorough and helpful response as always, @beppe!

1 Like

@mradtke Thanks a lot, looping through was killing time on one mn tf..This is excellent..

@beppe Bro u r amazing to have gotten so much patience to do the code snippet...Thanks...Really appreciate!

Moderator comment: We do NOT allow SMS style of writing on this forum. Please use proper English. This is not Facebook. Show some respect to people who spent their time writing elaborate responses by thanking them properly, without grammar and spelling errors.

@prithvibhat, note that my modified example was tested exclusively with EOD data - "Long only" (defining the Buy/Sell array)

It is not clear if you actually want to go both "Long and Short": in such case, you need to add the rules to close the opened positions (defining all the Buy/Sell and Short/Cover arrays).

Moreover, since you plan to use it intraday, probably, you should also take care of eventually closing all the positions before the day session terminates.

(And obviously remove the duplicate slower function, leaving only the "array" processing one).

@beppe understood...Thanks for your time & patience!

1 Like