Skip to main content
No. of Recommendations: 0
I'm a newcomer to GTR1. After applying one or more filters, I'd like the final step to retrieve a
random n number of stocks from the sample, rather than Top n of something or Bot n of something.
Is there a way to do that?

Thanks,
Ears
Print the post Back To Top
No. of Recommendations: 0
… I’d like the final step to retrieve a random n number of stocks …

There is no way to do this in gtr1, as far as I know. If the last step is not a top or bottom operator, you get all the results that match.
Print the post Back To Top
No. of Recommendations: 3
Here is one way for getting "random" stock list discussed in message 247141.



The first step of my screen is essentially going to randomly divide the market into 90 groups. I do so by grouping stocks according to the first two significant digits of their security-specific actual shares outstanding. Thus, for example, if two stocks A and B have shares outstanding 5,628,299,182 and 56,389,491, respectively, then they are in the same group, because their shares outstanding both begin with "56". The GTR1 expression for calculating the first two significant digits is

int(ratio(sho.a,pow(10,linear(1,int(ratio(ln(sho.a),ln(linear(10,1)))),-1,1))))

(Note to nerds: While the formula is mathematically correct, don't expect it to work perfectly in the wacky world of 32-bit floating point representations.)

My screen will select one of these 90 groups and then further screen for 5 stocks using more reasonable steps:

ratio(gprc(1),hgprc(1,252)) top 50%
trp(1,20) top 5

The first of these two steps takes the top 50% by the ratio of price to 52-week high, while the second step takes the top 5 stocks by four-week total return. The link to the parameterizable family of screens is this: http://gtr1.backtest.org/2012/?s19970902e20051230::sho.a:gt0......

Now, I'm going to simulate a good dataminer and test all 90 possible variants of this strategy at once. Click "Run Backtest", and when the parameter value box appears, enter a vertical list of the numbers 10, 11, 12, ... 99 and click "Run Backtest".
Print the post Back To Top
No. of Recommendations: 3
You could use the mod function as discussed in post 263246. For example:
RanC: if(csoq1d.s>0,mod(csoq1d.s,97),50)
Print the post Back To Top
No. of Recommendations: 0
Building on aussi's idea...

If gtr1 has the "mod" operator, you could get a random-ish selection by doing something like "(shares_outstanding mod N) == 0"
Print the post Back To Top
No. of Recommendations: 5
There is an interesting detail when you think about random numbers in GTR1.

Do you want them to be really random, as in a different number every time it's referenced, every time you do a run?
Same number for all stocks in a given holding period, or maybe for a given set of start dates?
Or just effectively random for each stock on a given date, but you get the same result if you run precisely the same thing again?


If the latter will do, this is an expression I used to generate "random" numbers with GTR1

This is old so it uses the VL fields, but you get the idea.
It mixes in the lower digits of a bunch of fields that depend heavily on a particular stock on a particular day.
Price, EPS, dividend, recent return in a few different lookbacks.

Define field pseudoa as linear(1,mod(vprc,1),-10,mod(ces.v,.1),10,mod(cdv.v,.1),-1,tr(0,6),1,tr(6,6),-1,tr(12,6),1,tr(18,6))
Define field pseudorand as mod(linear(param0,pseudoa),param1)

Then put a bunch of pairs of numbers into the parameters field.

I used it to test the viability of strategies of picking a bunch of "random" stocks, hold for a year, and repeat.
Each pair of numbers in the params box gave me a completely different set of "random" stocks, so I could look at the distribution of returns.
I just picked the stocks by having a step "pseudorand top 40"

Jim
Print the post Back To Top
No. of Recommendations: 7
earslookin:
I'm a newcomer to GTR1. After applying one or more filters, I'd like the final step to retrieve a random n number of stocks from the sample, rather than Top n of something or Bot n of something. Is there a way to do that?

A rand()-like function isn't needed (not to mention problematic, given that the caching system depends on a given input always producing the same output), because you can feed random numbers to the backtester via parameterization. All you need to do then is combine param0, param1, etc, with some other junk that varies both daily and by stock.

For generating the "junk", you can do as others have suggested (or as I did in the post aussi referenced), or you can use the handier field function hash() (source code below) that just computes a dumb 32-bit hash of all of its arguments (which can be any number of field references, constants or parameter references), as represented by 32-bit floats, concatenated together, reinterpreting the unsigned integer hash value as a 32-bit float. (Since some small percentage of 32 bits are "NaN"s of various kinds, the code has to do some additional monkeying with the result until it actually gets a number).

For example, suppose we want to run 254 backtests on Zacks Rank 1 stocks (which actually means 254 * 20 = 5,008 backtests if the holding period is 20 market days), with each cycle of each of the 254 variants (the maximum allowed in one test) holding a (hopefully) different random ten stocks. To do this, first define

Junk: hash(aprc,dspo(1),param0)

Note that closing price (aprc) mostly varies by stock, and dspo(1) also varies by stock, but also by market day. Then add a step to take the top 10 by Junk, as at http://gtr1.net/2013/?!!QlpoMTFBWSZTWb3y!2FnUAABcdgAIFcHAAEC...

We then need a list of random floating point numbers (within the range of 32-bit floats, as explained at https://en.wikipedia.org/wiki/Single-precision_floating-poin...) for "param0". To get this, I entered the formula

=10^(50*(RAND()-0.5))

in cell A1 of an Excel worksheet and copied it down to cell A254 (the purpose of exponentiation is to get a good range in the exponent portion of the float variable). This gave me the following:

3.74363E+19
2.94871E-07
3.94518E-08
1.41466E-06
2.53801E-19
7.43757E-19
498613930.9
2.04677E+14
3.30376E-18
1.25426E-05
1.08719E-14
3.90237E-11
1.42655E-10
8.30519E+11
7.27951E-10
4.58474E+22
1811.912169
246528791.9
594923.5115
0.02784454
90934876625
1.19358E+18
8.31642E+22
4.83684E+13
0.014288255
5.14176E-12
4.004E+21
85846769.48
8.5601E-19
2.14762E-14
1.20772E+21
2.76851E-06
7.16975E-23
0.000281686
12050000011
1.28626E+13
21198154.99
1.46909E-16
1391890.047
4.37999E+18
16594995.26
6.10369E+20
1.20948E-16
0.005132419
7.76767E-15
0.009810152
1340278.964
95094.45409
328291732.8
8.05246E+24
5.09984E-11
708660.3415
1.03151E-15
1.57941E+20
4594.533934
2.24109E+23
31147389.68
0.593003707
6.61625E-08
4.67539E+13
4.77983E+20
1.02122E+16
9.45812E-07
291546525.3
1.2486E+19
1.89557E-05
7.89433E-05
5.54749E-20
4.07615E+12
2.51237E-05
5.92054E+11
2.76251E+20
3.57047E-13
3.62917E-23
5.02846E+11
2.78985E+24
8.37736E-18
967.693867
9.69602E-07
0.000105548
1.29631E-06
85644.54105
1.09546E+21
6.66182E+19
5.99924E-10
1113865148
2.28008E-07
2.04927E-23
20.86532623
9.51028E-09
1.18589E+17
3.32308E-06
8.93119E-20
3.2797E-11
4.75019E-19
8521040.169
1.8095E-14
6870075149
2.60201E-13
8.5863E+20
6.17859E-10
0.264710854
6.76788E-23
0.000206232
2.82815E-25
6.36733E-18
8.74185E-12
5.61162E-18
5.50827E+13
0.11831277
2.80864E-16
23345779703
1.47085E+21
23886902.9
1.72597E+13
6.57736E+13
5.37702E-15
6.64354E+15
4.28211E-08
4.19097E-21
4.75949E-16
0.592706659
1846.406357
1.72465E+19
1.20605E-06
1.36349E+20
6.9242E+19
2650316187
2.63572E-13
5.3462E+22
8.40944E-21
2.03927E-10
0.001312276
872415.2493
7.7181E+13
4.88185E-13
97896655694
2.81979E+22
7.78787E-16
1.24078E+17
5.88934E+22
5.25403E-20
25.23978894
1.67567E+13
2.41714E-06
5.92224E+14
4.43241E-08
7.05654E-09
306036604.4
3.12888E-19
8.10894E+14
0.020427995
286.2602838
2.88141E+21
1.42951E-10
2.50695E+11
2.57176E-21
435391.4259
6.40075E+12
1.71938E-07
1.99467E-08
2.37369E-14
4.21115E+22
5.0662E+12
8617396.059
2.73725E-08
1.89473E+20
1.12011E+12
1.20944E+16
1.37493E-25
0.043809977
4.18903E+22
7.12963E+21
9.88494E-05
1028525.84
4.56028E+23
2.60605E-25
1.35063E-20
1.12391E+12
4.76146E+16
2.22287E+22
7.16833E+15
6.18142E+21
0.66722258
0.001442097
8.44666E-23
1.4419E+15
67047.77785
5842229906
5.60523E-08
3.69349E-21
1.27197E+15
6.92386E-20
3.23394E-08
1.15818E-19
1.37157E-09
1.33671E+21
7.84937E-10
4.04035E-22
1.70736E+13
7.66744E-16
5.23007E+14
1.39329E-19
1.71723E+17
1.11816E-09
9.10437E-11
198126.473
0.860186093
1.18367E+16
0.038659823
9.59412E-22
3.7941E-09
1.16295E+19
3963132142
6.2739E-12
0.030738163
6.05978E-11
0.029533996
1.64992E-17
4.21504E+19
2.50418E+17
1.66571E-18
4.46524E-05
1.50293E+15
1.91758E+20
1.42793E-24
9.26673E+14
0.000488946
78872720317
15.57444438
1.08952E+23
0.020296489
0.901449871
1.03332E-06
7.06954E-24
1.54659E+18
1.50498E-12
4.52384E+14
66679.59882
53392117785
1.90139E-17
1.89105E+11
3.54552E-13
1.07994E+15
1326135924
3.8814E-10
3.18937E+17
6.02346E-11
2.59979E-18
11469.61019
1.09865E+19
2.73137E-25
2.14987E+15
2.90517E-14

I then copied and pasted the above list into the parameter box when it appeared after clicking "Run Backtest" at the above link the first time. Clicking "Run Backtest" again, I get the following (truncated) results:

Results
For all 20 trading cycles of each variant (0 to 253), the following statistics are calculated from 19991220 to 20200702 over daily closing portfolio values:
CAGR (Compound Annual Growth Rate)
GSD(20) (annualized Geometric Standard Deviation of 20-day returns)
AT (Annualized Turnover)

                               Cycle:         0         1         2         3         4         5  ...
param0 Variant Avg 1st Trades: 19991220 19991221 19991222 19991223 19991227 19991228 ...
3.74E+19 0 12.45 16.04 4.15 13.84 11.58 15.22 13.94 ...
31.49 32.32 31.68 30.15 29.93 33.12 32.15 ...
12.36 12.34 12.40 12.40 12.39 12.43 12.39 ...

2.95E-07 1 13.91 20.62 7.99 19.10 19.63 14.94 8.93 ...
32.00 30.75 32.27 30.96 31.59 33.48 30.38 ...
12.36 12.40 12.41 12.41 12.41 12.45 12.39 ...

3.95E-08 2 12.97 16.06 12.08 20.12 12.11 16.68 10.76 ...
31.46 30.09 32.51 30.26 30.42 31.81 31.72 ...
12.36 12.37 12.40 12.42 12.39 12.44 12.35 ...

1.41E-06 3 13.79 16.40 9.30 20.05 14.05 22.13 11.19 ...
31.86 32.95 31.49 30.16 31.19 36.27 31.70 ...
12.35 12.29 12.42 12.38 12.35 12.34 12.41 ...

2.54E-19 4 13.40 19.06 10.92 19.25 12.89 20.19 9.02 ...
31.98 31.01 31.69 31.54 32.31 36.50 32.73 ...
12.36 12.36 12.43 12.35 12.32 12.34 12.40 ...

7.44E-19 5 13.19 15.50 12.28 16.99 10.33 13.42 11.50 ...
31.61 32.38 32.61 30.95 29.88 32.62 31.14 ...
12.36 12.35 12.43 12.43 12.42 12.45 12.32 ...

4.99E+08 6 14.28 15.16 8.06 21.25 23.31 13.44 9.23 ...
31.83 31.93 32.59 32.04 29.93 33.45 31.51 ...
12.36 12.40 12.42 12.42 12.37 12.37 12.38 ...

2.05E+14 7 14.01 15.71 8.87 16.68 14.02 15.33 9.09 ...
31.50 32.35 29.58 31.55 29.73 32.40 33.56 ...
12.35 12.40 12.40 12.42 12.37 12.39 12.36 ...

3.30E-18 8 12.39 17.26 7.81 20.19 13.75 17.45 7.57 ...
31.64 30.60 31.13 31.06 32.49 30.29 32.35 ...
12.36 12.35 12.42 12.37 12.41 12.41 12.42 ...

1.25E-05 9 14.05 11.23 6.55 18.55 15.62 16.78 9.93 ...
31.64 33.59 30.43 29.45 29.44 31.89 32.67 ...
12.37 12.41 12.42 12.39 12.40 12.41 12.37 ...

... ... ... ... ... ... ... ... ... ...


I would think that the portfolios generated in this manner would be random enough for your purposes.

Robbie Geary


__inline void calc_hash(investment* pinvst, field_entry* pfield)
{
int m;
unsigned int h = 0;
float x = 0;
for (m = 0; m < pfield->argc; m++) {
if (pfield->fieldargs[m] >= 0) {
x = Fields[pfield->fieldargs[m]].pValues[pinvst - Investments];
} else x = pfield->constargs[m];
int i;
unsigned char* p = reinterpret_cast<unsigned char*>(&x);
for (i = 0; i < sizeof(x); i++) h = 37 * h + p[i];
}
while (true) {
x = *reinterpret_cast<float*>(&h);
if (x == x && ((2 * x > x && 0.5 * x < x) || x == 0)) break;
h *= 37;
}
pfield->pValues[pinvst - Investments] = x;
}
Print the post Back To Top
No. of Recommendations: 0
Thank you, all! Exactly what I was looking for. Much appreciate your willingness to help out a GTR1
rookie. -Ears
Print the post Back To Top