Copy this standard-library-only script into a .py file and run it with Python 3. It prints the input-derived metrics, all three rankings, the three-month risk-window case and the 1% monthly downside-target case. It also asserts the missing-data, zero-risk, negative-return, skip and tie policies. Dates, data acquisition, trades and portfolio returns are outside this calculation; inputs must already be consecutive monthly returns in chronological order.
Standalone ranking calculation. Teaching data only; no portfolio backtest or Pine strategy orders.python
from math import isfinite, prod, sqrt
from statistics import mean, stdev
DATA = {
"A": [0.15, -0.06, 0.08, -0.03, 0.10, 0.02],
"B": [0.04, -0.01, 0.03, 0.02, -0.01, 0.04],
"C": [0.06, -0.001, 0.005, 0.005, 0.005, 0.005],
}
EPS = 1e-10 # Monthly decimal-return denominator exclusion threshold.
def metrics(history, lookback=6, risk_window=6, skip=0, target=0.0):
if (not isinstance(lookback, int) or lookback < 1
or not isinstance(risk_window, int) or risk_window < 2
or not isinstance(skip, int) or skip < 0
or not isfinite(target)):
raise ValueError("Invalid window, skip or target")
end = len(history) - skip
required = max(lookback, risk_window)
if end < required:
return None
window = history[end - required:end]
# Missing, nonfinite or total-loss data is not a usable live candidate.
if any(x is None or not isfinite(x) or x <= -1 for x in window):
return None
returns = history[end - lookback:end]
risk = history[end - risk_window:end]
R = prod(1 + x for x in returns) - 1
s = stdev(risk)
d = sqrt(sum(min(x - target, 0.0) ** 2 for x in risk) / len(risk))
if not all(isfinite(x) for x in (R, s, d)):
return None
return {"R": R, "s": s, "d": d, "mean": mean(returns),
"below": sum(x < target for x in risk),
"vol_score": R / s if s > EPS else None,
"down_score": R / d if d > EPS else None}
def rank(rows, field):
valid = [(name, row[field]) for name, row in rows.items()
if row is not None and row[field] is not None]
return [name for name, value in sorted(valid, key=lambda x: (-x[1], x[0]))]
def positive_winner(rows, field):
order = rank(rows, field)
return order[0] if order and rows[order[0]]["R"] > 0 else "CASH"
rows = {name: metrics(values) for name, values in DATA.items()}
for name, row in rows.items():
print(name, {key: round(value, 9) for key, value in row.items()})
for field in ("R", "vol_score", "down_score"):
print(field, rank(rows, field))
assert rank(rows, "R") == ["A", "B", "C"]
assert rank(rows, "vol_score") == ["B", "C", "A"]
assert rank(rows, "down_score") == ["C", "B", "A"]
short = {k: metrics(v, risk_window=3) for k, v in DATA.items()}
print("W=3", short, rank(short, "vol_score"))
print("T=1%", {k: metrics(v, target=0.01) for k, v in DATA.items()})
assert short["C"]["vol_score"] is None
assert metrics([0.01] * 6)["vol_score"] is None
assert metrics([0.01] * 6)["down_score"] is None
assert metrics([0.0] * 6)["R"] == 0
assert metrics([None] + DATA["A"][1:]) is None
assert metrics([float("nan")] + DATA["A"][1:]) is None
assert metrics([-1.0] + DATA["A"][1:]) is None
assert metrics(DATA["A"], skip=1) is None # Five returns are insufficient.
assert metrics([0.99] + DATA["A"] + [-0.9], skip=1) == rows["A"]
assert metrics([0.01, 0.01 + 1e-12] * 3)["vol_score"] is None
negative = {"N": metrics([-0.02, -0.01] * 3)}
assert rank(negative, "vol_score") == ["N"]
assert positive_winner(negative, "vol_score") == "CASH"
assert rank({"B": rows["A"], "A": rows["A"]}, "R") == ["A", "B"]
print("All policy checks passed")