First, you'd rather simulate $\log(X)$ rather than $X$; thus, there is no level dependency in your discretisation scheme, making it more accurate. $$Z_t = \log(S_t)$$ $$dZ_t = \left(r - \frac{\sigma^2}{2}\right)dt + \sigma dW_t$$ You can even run one single time step, and the distribution of your final price will still be as accurate!
Second, the different time to maturity (3 vs 10) certainly explains a large part of the difference :)
Third, I would advise you to take advantage of vectorisation rather than using a loop.
My suggestions are summarised in the following code:
S0 = 30
Z_T = np.log(S0) + (r - 0.5 * sigma**2)*ttm + sigma*np.random.normal(0, np.sqrt(ttm), N)
S_T = np.exp(Z_T)
payoff = np.maximum(S_T - K, 0)
price = np.exp(-r*ttm)*np.average(payoff)
price
That yields 8.48 as well.