# QuantFinanceToGo, module 16: Monte Carlo Simulation. Exercise 2 (easy).
# Runs on its own with Python 3 and numpy. Fill in the lines marked TODO.
#
# The model: $10,000 over 30 years, yearly log returns from a bell
# with the mean g = 0.08 - 0.2^2 / 2 = 0.06 and the sd 0.2.
# a) Write median_of_run(rng, paths): simulate paths final values with the
#    generator rng and return their median.
# b) Two generators with the same seed: do they give the same median?
# c) One generator used again gives a new run. Make 100 runs of 1,000 paths
#    and compare the spread of the logs of their medians with the theory
#    sqrt(pi / 2) * 0.2 * sqrt(30) / sqrt(1000).
import math
import numpy as np

start, years, g, sigma = 10000, 30, 0.06, 0.2
rng_a = np.random.default_rng(2)                # two generators, same seed
rng_b = np.random.default_rng(2)

def median_of_run(rng, paths):
    # TODO: draw (paths, years) log returns, add them up per path,
    #       turn them into final values and return their median
    return None

if median_of_run(np.random.default_rng(0), 10) is None:
    print("Exercise 2 is not solved yet. Fill in the lines marked TODO.")
else:
    first, twin = median_of_run(rng_a, 1000), median_of_run(rng_b, 1000)
    print(f"seed 2 in two generators: ${first:,.2f} and ${twin:,.2f}")
    print(f"the first generator again: ${median_of_run(rng_a, 1000):,.2f}")
    logs = np.log([median_of_run(rng_a, 1000) for _ in range(100)])
    theory = math.sqrt(math.pi / 2) * sigma * math.sqrt(years) / math.sqrt(1000)
    print(f"100 runs of 1,000 paths: medians from ${math.exp(logs.min()):,.0f} "
          f"to ${math.exp(logs.max()):,.0f}")
    print(f"spread of their logs {logs.std(ddof=1):.2%}   theory {theory:.2%}")
