Exercise · m04a_levels.py
Algorithmic support/resistance, gaps and anchored VWAP
not run yet
Not saved: sign up to keep your code"""M04A exercise 2: algorithmic support/resistance, gaps and anchored VWAP (notes §4A.2-4A.4).
Input bars are a DataFrame with columns open, high, low, close, volume and a
DatetimeIndex (one row per bar), e.g. toolkit.data.synthetic_ohlcv().
Definitions used (Definitions 4A.3-4A.6 in the notes):
* Swing high at bar u with half-width k: H_u > H_{u-j} and H_u > H_{u+j} for j = 1..k.
It is only KNOWN at bar u + k (its confirmation bar). Swing lows mirror this with L.
* A level is a cluster of confirmed pivot prices: sort the prices and split
wherever two neighbours differ by more than tol (single linkage). The level is
the cluster mean; its strength is the number of pivots in it.
* Gap on bar t: g_t = ln(O_t / C_{t-1}). An up-gap (g > 0) is filled on bar t if
L_t <= C_{t-1}; any other gap (g <= 0) is filled if H_t >= C_{t-1}.
* Under driftless intraday Brownian motion with daily volatility s (in log terms)
started at the open, P(fill) = 2 Phi(-|g|/s) (reflection principle).
* Anchored VWAP from bar a: sum_{a<=u<=t} P_u V_u / sum V_u, with P_u = (H+L+C)/3.
"""
from __future__ import annotations
import numpy as np
import pandas as pd
from scipy.stats import norm
def swing_pivots(ohlc: pd.DataFrame, k: int) -> pd.DataFrame:
"""All swing highs and lows with half-width k (strict inequalities).
Returns a DataFrame with columns kind ('high' or 'low'), price, pivot_pos (int
position of the pivot bar), confirm_pos (= pivot_pos + k), sorted by
confirm_pos then kind (stable). Bars within k of either end cannot be pivots.
"""
raise NotImplementedError
def cluster_levels(prices, tol: float) -> pd.DataFrame:
"""Single-linkage clusters of prices whose sorted neighbours differ by <= tol.
Returns DataFrame(level, strength, low, high) sorted by level, one row per cluster.
"""
raise NotImplementedError
def levels_asof(ohlc: pd.DataFrame, t: int, k: int, tol: float, lookback: int = 250) -> pd.DataFrame:
"""Support/resistance levels known at the close of bar position t.
Use only bars in positions max(0, t - lookback + 1) .. t, and only pivots
whose confirmation bar is <= t. Return cluster_levels of their prices.
The result must not change if any bar after t is altered.
"""
raise NotImplementedError
def gap_table(ohlc: pd.DataFrame) -> pd.DataFrame:
"""Per-bar gap statistics, from the second bar on (same index as ohlc[1:]).
Columns: gap (log), up (bool, gap > 0), filled (bool), oc (log open-to-close return).
"""
raise NotImplementedError
def gap_fill_prob_bm(gap, sigma_intraday):
"""2 Phi(-|gap| / sigma_intraday); vectorised over numpy arrays."""
raise NotImplementedError
def anchored_vwap(ohlc: pd.DataFrame, anchor_pos: int) -> pd.Series:
"""Anchored VWAP using typical price (H+L+C)/3; NaN before the anchor bar.
Return a Series on ohlc.index."""
raise NotImplementedError
No runs yet
The stub's functions raise
NotImplementedError until you write them. Fill in one, press
Run tests, and watch its tests turn green.Reference solution
Available after your first run, with an account approved for code runs.