The importance of consistency in percentage returns when investing
For me the code looks rather okay, I have just a few small remarks:

 Formatting 

The line

print('\n'.join(('dev=' + str(round(result.deviation, 2)) + ', ' + 'CAGR=' + str(round(result.CAGR, 2))) for result in results))


is very hard to read, could you possibly split it or use a function?

def format_result(result):
    dev = round(result.deviation,2)
    cagr = round(result.CAGR,2)
    return f'dev={str(dev)}, CAGR={str(cagr)}'


and then just 

print('\n'.join(format_result(result) for result in results))


 Performance 

I'm unsure whether you need an extreme performance but it seems that potentially you might want to run the code large number of iterations. 

namedtuple

namedtuple datastructure is extremely handy if you want to use it to make your code looks better. However, if you care about performance (i.e. you will be using many of them) you might be better off with usual tuple. 
Reference: link1, link2, link3.

list.append

In this section I'll be referring to results.append(net_returns(deviation, avg_returns)). append is rather a slow operation if you know a list size before the appending. I think your code would be faster if you allocated results list first and then just put each net return on it's place. 

reverse=True

As tempting it is, it might have a performance hit as well. As one might see in source code the list is actually reversed to keep the stability. It should be better just to pass a negative value to your lambda:

return sorted(results, key=lambda x: -x.CAGR)