SigmaField
Mathematical Foundations for Quant Finance
0 of 256 lessons
      1. 5.11.1 Random walksConcept · 30 min
      2. 5.11.2 Markov chainsConcept · 35 min
      3. 5.11.3 Practice set: discrete-time processesPractice set · 25 min
      4. 5.11.4 Case study: pricing on a multi-step binomial treeCase study · 35 min

Level 5, Probability and statistics 5.11 Discrete-time processes Lesson 3 of 4

Practice setLesson 5.11.3 in Level 5, Probability and statistics. About 25 minutes.

Practice set: discrete-time processes

Random walks

Random walks (lesson 5.11.1)

0 of 12 correct

  1. 1.
  2. 2.
  3. 3.
  4. 4.
  5. 5.
  6. 6.
  7. 7.
  8. 8.
  9. 9.
  10. 10.
  11. 11.
  12. 12.
How to type answers
  • Powers with ^: x^7, 2^(1/3), a^-2.
  • Multiply with * or by writing side by side: 3x^2, 2(x+1).
  • ln(x) is the natural log, log(x, 2) is log base 2, e is Euler's number, sqrt(x) is a square root.
  • sin(x), cos(x) and tan(x) take radians; write pi for π and sin(x)^2 for sin²x.
  • Your first answer to each question is saved: it counts towards your score and brings the question back for review.
  • Exact answers like ln(20)/ln(3) are best. Decimals need about 4 significant figures.

Markov chains

Markov chains (lesson 5.11.2)

0 of 10 correct

  1. 1.
  2. 2.
  3. 3.
  4. 4.
  5. 5.
  6. 6.
  7. 7.
  8. 8.
  9. 9.
  10. 10.
How to type answers
  • Powers with ^: x^7, 2^(1/3), a^-2.
  • Multiply with * or by writing side by side: 3x^2, 2(x+1).
  • ln(x) is the natural log, log(x, 2) is log base 2, e is Euler's number, sqrt(x) is a square root.
  • sin(x), cos(x) and tan(x) take radians; write pi for π and sin(x)^2 for sin²x.
  • Your first answer to each question is saved: it counts towards your score and brings the question back for review.
  • Exact answers like ln(20)/ln(3) are best. Decimals need about 4 significant figures.

Coding exercise

Exercise

The stationary distribution

Write stationary(P), which returns the stationary distribution of a transition matrix P, as in lesson 5.11.2. P is a NumPy array or nested lists, with rows the state now.

  • Raise ValueError unless P is square, every entry lies between 0 and 1, and every row adds up to 1 within 10−910^{-9}.
  • Solve πP=π\boldsymbol{\pi}P = \boldsymbol{\pi} with the entries adding up to 1. Raise ValueError if the answer is not unique: then P⊤−IP^\top - I has rank below n−1n - 1.
  • Return an array of nn probabilities that add up to 1.

Running the chain for many steps is not enough: the tests include a chain that swings and never settles. They also use the weather chain, lesson 3.6.2's towns and the rating table of case study 5.1.6. A chain with two absorbing states and some broken tables must raise ValueError.

See the tests
import numpy as np

WEATHER = [[0.7, 0.2, 0.1], [0.3, 0.4, 0.3], [0.2, 0.3, 0.5]]
RATINGS = [[0.90, 0.08, 0.015, 0.005], [0.05, 0.85, 0.08, 0.02], [0.01, 0.09, 0.80, 0.10], [0.0, 0.0, 0.0, 1.0]]


def expect_value_error(call, why):
    try:
        call()
    except ValueError:
        return
    raise AssertionError(f"expected ValueError: {why}")


def test_weather():
    """The weather chain of lesson 5.11.2 has stationary distribution (21/46, 13/46, 6/23)"""
    expect_close(np.asarray(stationary(WEATHER)), np.array([21 / 46, 13 / 46, 6 / 23]), what="stationary(weather)", rel=1e-9)


def test_two_towns():
    """Lesson 3.6.2's two towns, as rows: (2/3, 1/3)"""
    expect_close(np.asarray(stationary(np.array([[0.9, 0.1], [0.2, 0.8]]))), np.array([2 / 3, 1 / 3]), what="stationary(towns)", rel=1e-9)


def test_swinging_chain():
    """A chain that swings between two states never settles, but (1/2, 1/2) is still stationary"""
    expect_close(np.asarray(stationary([[0, 1], [1, 0]])), np.array([0.5, 0.5]), what="stationary([[0, 1], [1, 0]])", rel=1e-9)


def test_three_cycle():
    """A chain that cycles 1 → 2 → 3 → 1 has stationary distribution (1/3, 1/3, 1/3)"""
    expect_close(np.asarray(stationary([[0, 1, 0], [0, 0, 1], [1, 0, 0]])), np.array([1, 1, 1]) / 3, what="stationary(cycle)", rel=1e-9)


def test_absorbing():
    """The rating table of case study 5.1.6 ends in default: (0, 0, 0, 1)"""
    expect_close(np.asarray(stationary(RATINGS)), np.array([0.0, 0.0, 0.0, 1.0]), what="stationary(ratings)", abs_tol=1e-9)


def test_any_chain():
    """For a seeded 5-state chain, the answer is a pmf with πP = π"""
    rng = np.random.default_rng(5113)
    P = rng.random((5, 5))
    P /= P.sum(axis=1, keepdims=True)
    pi = np.asarray(stationary(P))
    expect_close(pi.sum(), 1.0, what="sum of the entries", rel=1e-9)
    assert (pi >= 0).all(), f"entries must not be negative, got {pi}"
    expect_close(pi @ P, pi, what="πP", abs_tol=1e-12)


def test_not_unique():
    """Two absorbing states, as in the walk between 0 and 2, leave many stationary distributions: ValueError"""
    expect_value_error(lambda: stationary([[1, 0, 0], [0.5, 0, 0.5], [0, 0, 1]]), "(1 - w, 0, w) is stationary for every w")
    expect_value_error(lambda: stationary(np.eye(2)), "every distribution is stationary for the identity")


def test_bad_matrices():
    """A row adding up to 1.01, a negative entry or a matrix that is not square raise ValueError"""
    expect_value_error(lambda: stationary([[0.7, 0.31], [0.2, 0.8]]), "the first row adds up to 1.01")
    expect_value_error(lambda: stationary([[1.2, -0.2], [0.5, 0.5]]), "an entry is negative")
    expect_value_error(lambda: stationary([[0.5, 0.5, 0.0], [0.1, 0.9, 0.0]]), "a 2 × 3 matrix is not a transition matrix")

Free further reading

Optional. This lesson covers what you need; these add more examples and practice. All are free to read.

  • Markov chains

    probabilitycourse.com. Free book.

    Discrete-time Markov chains and transition matrices.