Python code: 14-period RSI from scratch (free download)

Python code: 14-period RSI from scratch (free download)
Every business has a price it cares about: the goods bought for resale, the raw material, the competitor's product, the currency customers pay in. When that price swings hard, one question shows up on its own: did it rise a lot or only a little over the past weeks? The relative strength index, RSI for short, answers that question with a single number: it measures whether the price rose a lot or a little over the last days, on a scale from zero to one hundred. This article explains what sits behind that number, what overbought and oversold really mean, and hands you a Python program that works it out from scratch, with no technical-analysis library, so you can run it on your own machine and watch the table appear on screen.
The code is aimed at the curious small-business owner, at the bookkeeper who reads reports and at the warehouse clerk who watches stock prices move. You do not need to be a programmer: the download ships the code commented line by line, plus a short instruction file.
⬇ Download the code (ZIP)Notice: this is educational material: it is not a recommendation to buy or sell. The sample prices in the download are made up and the historical data is quoted only to practise the arithmetic. A past result guarantees nothing about the future. Before you make any money decision, ask a licensed professional.
What comes in the download
| File | What it is for |
|---|---|
rsi_desde_cero.py | The program, commented line by line and written with the Python standard library only. |
datos/prices.csv | One hundred and eighty daily closes as a sample, made-up prices, to practise the arithmetic. |
salida_ejemplo.txt | The real output you should get when you run it, so you can compare. |
README.md | The written instructions: what it does, how to run it and what each result means. |
salida/rsi.csv | The file it writes when it runs: date, close, up move, down move and RSI for every day. |
What the program does, step by step
- It reads
datos/prices.csv, which holds the close of each day. - It compares every close with the previous one and splits what went up from what went down. A single day never counts in both columns at once.
- It works out two fourteen-day averages: one of the up moves and one of the down moves. Those two averages are the raw material of the index.
- It turns both averages into one number between zero and one hundred. When up moves outweigh down moves, the number climbs towards one hundred; when down moves weigh more, it slides towards zero.
- It applies Wilder smoothing, which gives the most recent day extra weight without forgetting the history.
- It prints the last fifteen rows with their RSI and counts how many days ended above seventy (overbought) and how many below thirty (oversold).
- It saves everything to
salida/rsi.csv, a file that opens in any spreadsheet with no conversions.
How to run it
All you need is Python 3.11 or newer installed (the normal download from python.org, the same one for Windows, Mac and Linux). Unzip the package into a folder, open the terminal in that folder and type the name of the program:
python rsi_desde_cero.py
There is nothing else to install: the program uses the Python standard library only, so no endless list of packages appears. If the computer answers that Python is not recognised, try python3 or install it again ticking the box that adds Python to the PATH. When it finishes, the program writes the result to salida/rsi.csv and shows the educational notice once more.
The code, explained
These are four real parts of the program, copied exactly as they appear in the file inside the package. Under each one we explain what it does, in plain words.
1. The paths. The program first works out the folder where it lives. That is why it behaves the same whether you open it from the desktop or from the terminal, and it does not care where you are standing when you run it:
# # Folder of this very file: the program runs from anywhere
BASE = Path(__file__).resolve().parent
ENTRADA = BASE / "datos" / "prices.csv" # # sample prices shipped inside the ZIP
SALIDA = BASE / "salida" / "rsi.csv" # # RSI result, ready to open in Excel
2. The formula. Here is the heart of the index. Relative strength is the average of the up moves divided by the average of the down moves, and the RSI squeezes that ratio onto a scale from zero to one hundred. If those two weeks held no down move at all, the index reads one hundred; if nothing moved either way, it reads fifty. None of this looks at tomorrow: it only summarises what already happened.
def rsi_de(media_subidas: Decimal, media_bajadas: Decimal) -> Decimal:
"""Turns the two averages (up and down) into the RSI value, between 0 and 100."""
if media_bajadas == 0:
# # With no down moves in the average the RSI is 100; with neither move it is 50
return Decimal("100.00") if media_subidas > 0 else Decimal("50.00")
fuerza = media_subidas / media_bajadas
return redondear(Decimal("100") - Decimal("100") / (Decimal("1") + fuerza))
3. Wilder smoothing. The first average is a plain average of the first fourteen days; from then on the program uses (previous times thirteen, plus the new day) divided by fourteen. That detail is what separates the classic RSI from a common moving average: the newest figure carries a little more weight than the old ones.
# # Wilder smoothing: the first average is simple, then (previous * 13 + new) / 14
media_subidas = sum((f["subida"] for f in filas[1:PERIODOS + 1]), Decimal("0")) / PERIODOS
media_bajadas = sum((f["bajada"] for f in filas[1:PERIODOS + 1]), Decimal("0")) / PERIODOS
4. The honest part. The program prints its reading in words and says it without decoration: the RSI describes what ALREADY happened, that is, how much the price rose and fell over the last days. Nobody can know whether it will rise or fall tomorrow. A low reading is not an order to buy and a high reading is not an order to sell; they are labels for the recent past.
print(" The RSI measures what ALREADY happened: how much price rose and fell in the last days.")
print(" Nobody can know whether it will rise or fall tomorrow: the past guarantees nothing.")
What you will see on screen
With the sample data the program prints the last fifteen rows. This is a literal slice of the real output, with the final days in the file:
Date Close Up Down RSI --------------------------------------------------- 2026-06-23 118.49 1.53 0.00 50.19 2026-06-24 116.43 0.00 2.06 45.05 2026-06-25 117.39 0.96 0.00 47.74 2026-06-26 115.28 0.00 2.11 42.79 2026-06-27 115.53 0.25 0.00 43.54 2026-06-28 117.18 1.65 0.00 48.33 2026-06-29 116.97 0.00 0.21 47.77 2026-06-30 117.24 0.27 0.00 48.59 ---------------------------------------------------
At the end it sums up the whole exercise: of the one hundred and sixty-six days that carry an RSI value, thirty-one landed in overbought, five in oversold and one hundred and thirty in the neutral zone. On the last day in the file the RSI was 48.59, which is neither extreme.
Both ideas deserve a calm sentence. Overbought does not mean the price is expensive or that it has to fall: it means that over those two weeks the up moves outweighed the down moves enough to push the index past seventy. Oversold is the mirror image: the down moves dominated and the index dropped below thirty. Both are ways of saying that a lot happened in a short time, not signals that announce tomorrow. In the sample, roughly one day in five with an index value ended at an extreme, which is useful in itself: a restless price spends a good part of its life in the extremes.
Common mistakes and tips
- The first fourteen rows have no RSI, and that is not a bug. The index needs fourteen days of history to start, so the first value shows up in row fifteen.
- The file cannot be found. That almost always means the terminal was opened in another folder. The program looks for
datos/prices.csvnext to itself, so simply open the terminal inside the unzipped folder. - Prices are handled with exact decimals. The program uses the Decimal class rather than floating-point numbers, so rounding never drags in those tiny errors that appear when binary decimals are added up.
- Change the data and the result changes, which is the interesting part. Swap the price file for your own and the RSI is recomputed on its own. Keep the same columns and the same date order, oldest first.
- Do not read the index on its own. Two very different series can print the same RSI for opposite reasons: one drifting up every day and one bouncing violently. The number summarises movement, not causes.
- Dates in a row, no gaps. If you delete holidays or weekends the program will not complain, but the average changes meaning. Use complete series.
- Do not fight the console. If the table looks crooked, resize the window or change the font; the file
salida/rsi.csvkeeps the numbers in full.
When this is not enough
This program answers one very narrow question from one price file. As a business grows, the problem stops being an indicator and becomes the whole stock ledger: what came in, what went out, what each unit cost, what the warehouse is worth today and who moved what. Excel and loose scripts stop being enough there: that is where Kardex Tauro comes in, a free program that keeps the inventory, the stock ledger and the costs of a small business in order without you building any formula. The idea is simple: a script is for learning and experimenting; software is for the daily grind. You will find it on the blog site.
If you want to use your own prices
Replace datos/prices.csv with your own file and run the program again. The format is minimal: one header row and one row per day, separated by commas, with the dates in order from oldest to newest.
| Column | What it holds |
|---|---|
date | The day in year-month-day form, in chronological order. |
close | The closing price for that day. |
The real data inside the package is practice history taken from two public sources: CoinGecko (api.coingecko.com) for bitcoin, and the Federal Reserve Bank of St. Louis, series SP500, https://fred.stlouisfed.org/series/SP500. Both were downloaded on 2026-09-25 and are quoted here only to practise the arithmetic, never to judge the market. The program needs no website to work: the data travels inside the ZIP.
Notice: we repeat it because it matters: this is educational material and it is not a recommendation to buy or sell. The source of the real data is cited above, with its link in plain sight, and the package carries the same disclaimer in writing inside the instruction file. No past result guarantees anything about the future; ask a licensed professional before you invest.
⬇ Download the code (ZIP)Download the package, run it with your own numbers and compare the output with the one shown in this article. Learning with your own data, calculator in hand, is the fastest way to understand what an indicator says and what it does not. If it helps, pass it on to your bookkeeper or to whoever runs the warehouse.