The importance of consistency in percentage returns when investing It is said that 


  Being consistent in percentage annual returns leads to larger amount over time.


That is for any given principal, getting 20% successively for 2 years is better than 30% for first year and 10% for second year even though both percentages add to 40. First case yields 44% while the later one yields 43%. 

I have tried to simulate this for arbitrary number of years and arbitrary percentages using Python 3. The obvious added constraint is that sum of percentages is constant (otherwise, inconsistent arbitrarily high percentages will obviously beat consistent low percentages).

from operator import mul
from functools import reduce
import numpy as np
from collections import namedtuple
from typing import List, Tuple

def avg_cagr(percents: List[int]) -&gt; float:
    '''Given (successive) % annual growth rates, returns average Compound Annual Growth Rate'''
    amount = reduce(mul, [1+p/100 for p in percents])
    return (amount**(1/len(percents)) - 1)*100

def dirichlet(n: int = 5, amount: float = 100) -&gt; List[float]:
    '''Returns n random numbers which sum to "amount"'''
    random_returns = np.random.dirichlet(alpha=np.ones(n), size=1)[0]*amount
    return random_returns

def simulate_returns(n: int = 5, amount: float = 100, iterations: int = 40) -&gt; List[Tuple[float, float]]:
    '''Generate bunch of random percentages that sum to a constant and compare average CAGR with their deviation'''
    net_returns = namedtuple('net_returns', 'deviation CAGR')
    results = []
    for _ in range(iterations):
        random_returns = dirichlet(n, amount)
        avg_returns = avg_cagr(random_returns)
        deviation = np.std(random_returns)
        results.append(net_returns(deviation, avg_returns))
    return sorted(results, key=lambda x: x.CAGR, reverse=True)

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


Key Ideas in the code:


Dirichlet distribution is used to generate bunch of random numbers that sum to a constant
Standard deviation is used to illustrate consistency


Result: Simulation agrees with maxim.
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)