Build the relative strength index from daily changes, Wilder smoothing, and the 0 to 100 formula.
The relative strength index compares the size of recent up moves to the size of recent down moves and puts the answer on a scale from 0 to 100. All up moves gives 100, all down moves gives 0, and an even split gives 50.
In this lesson I build it from scratch on nine closes I can check by hand, then run RSI(14) on AAPL and count how many days sat below 30 and above 70.
Step 1. Split the daily change into a gain and a loss
diff() gives the change from yesterday to today. clip(lower=0) replaces every negative value with zero, so gain keeps the up moves. Flip the sign first and clip again, and loss keeps the down moves as positive numbers.
close delta gain loss
0 100.0 NaN NaN NaN
1 102.0 2.0 2.0 0.0
2 101.0 -1.0 0.0 1.0
3 104.0 3.0 3.0 0.0
4 103.5 -0.5 0.0 0.5
5 107.0 3.5 3.5 0.0
6 106.0 -1.0 0.0 1.0
7 110.0 4.0 4.0 0.0
8 109.0 -1.0 0.0 1.0
Every row has a number in exactly one of the two columns and a zero in the other. Row 0 is NaN because there is no day before it.
Step 2. Smooth both with Wilder’s average
Wilder’s average is an exponentially weighted mean with alpha = 1 / n. That is ewm from Lesson 26 with adjust=False, which runs the recursion today = (1 - alpha) * yesterday + alpha * new. min_periods=n holds the output back until n real values have gone in.
The formula squashes any ratio into 0 to 100. A ratio of 1 gives 50. A ratio of 0, meaning no up moves at all, gives 0. If there are no down moves the average loss is 0, the ratio is infinite, and the answer lands on exactly 100.
print(rsi14.describe().round(2))# -> count 1552.00# -> mean 52.65# -> std 11.61# -> min 19.60# -> 25% 44.64# -> 50% 52.92# -> 75% 61.62# -> max 81.57# -> Name: Close, dtype: float64
count 1552.00
mean 52.65
std 11.61
min 19.60
25% 44.64
50% 52.92
75% 61.62
max 81.57
Name: Close, dtype: float64
The mean sits just above 50, which is what a price that drifted up over six years gives. The readings stay bunched: half of them fall between 44.6 and 61.6.
Step 5. Count the days below 30 and above 70
30 and 70 are the levels RSI is usually read against. Counting them is a boolean mask from Lesson 13 and a .sum().
One up day of 2.92 on 2023-06-26 moves the reading from 19.60 to 33.23. With n = 14 each new day carries a weight of 1/14, and after a run of losses the average gain is close to zero, so a single gain lifts the ratio a long way.
Step 6. The window sets the spread
A shorter window puts more weight on the newest day, so the readings swing wider and hit the levels more often.