Course contents
Turning a rule into code
A classic beginner strategy is the moving-average crossover, buy when a fast average crosses above a slow one, and you now have every tool to express that rule in code and mark the signals on the data. This is a rule made computable, not yet a recommendation.
- Compute two moving averages and generate a crossover signal in pandas
- Mark the entry and exit points on the data
- Stress that a codeable rule is not a proven one
You now have every tool you need to take a real trading rule and express it in code. The classic beginner rule is the moving-average crossover: hold the stock when a fast moving average is above a slow one, and step aside when it drops below. It is simple, famous, and a perfect vehicle for the final part of this course, because building it teaches the last coding pieces, and testing it teaches the hardest and most important lesson of all. This chapter builds the rule. The next tests it honestly, and the result may surprise you.
From rule to signal
The rule turns into two moving averages and a comparison, which you can do in your sleep by now.
# A moving-average crossover: a rule expressed in code (NOT a recommendation).
import pandas as pd
df = pd.read_csv("sample_prices.csv", parse_dates=["Date"], index_col="Date")
df["fast"] = df["Close"].rolling(20).mean()
df["slow"] = df["Close"].rolling(50).mean()
# Stance: 1 (long) when the fast average is above the slow one, else 0.
df["signal"] = (df["fast"] > df["slow"]).astype(int)
df["crossover"] = df["signal"].diff() # +1 = crossed up, -1 = crossed down
print("Buy signals (fast crossed above slow):", int((df["crossover"] == 1).sum()))
print("Sell signals (fast crossed below slow):", int((df["crossover"] == -1).sum()))
print(df[["Close", "fast", "slow", "signal"]].dropna().tail(3).round(2))Buy signals (fast crossed above slow): 3
Sell signals (fast crossed below slow): 2
Close fast slow signal
Date
2024-09-04 1376.16 1329.54 1301.95 1
2024-09-05 1372.34 1333.81 1302.93 1
2024-09-06 1417.68 1339.80 1304.96 1The signal column is 1 whenever the fast 20-day average is above the slow 50-day one, a long stance, and 0 otherwise. Taking its diff finds the moments the stance changes: a plus one marks a crossover up, a buy point, and a minus one a crossover down, an exit. On this sample the rule fired 3 buy signals and 2 sell signals, and the last rows show the signal holding at 1 through a recent uptrend. In a few lines you have turned a described rule into a precise, computable set of entries and exits.
A rule is not yet a strategy
Here is the caution that the whole final part rests on, first raised back in the conditionals chapter. You have written a rule and marked where it fires, but you have not shown, or even asked, whether following it makes money. It is dangerously easy at this point to feel that because the code runs and the signals look sensible on the chart, the strategy is good. It is not established at all. A crossover is one of thousands of rules you could code, and the fact that Python executes it cleanly says precisely nothing about its profitability.
There is also a subtle trap waiting in how you test it, worth flagging before the next chapter. The signal on a given day is computed from that day's closing price, so you could not actually have acted on it until the next day. Pretending you bought at today's close using a signal that needed today's close to compute is a form of cheating called lookahead bias, and it makes hopeless strategies look brilliant. The next chapter handles it correctly by acting on yesterday's signal, and it is the difference between an honest test and a fantasy.
What to carry forward
The crossover rule becomes code in a few lines: a signal that is 1 when the fast average leads the slow one, and diff to mark the crossovers, here 3 buys and 2 sells on the sample. But you have only expressed the rule, not proven it, and how you test it matters enormously, because acting on a signal computed from today's close is lookahead cheating.
The next chapter runs this rule over the history properly, with no peeking and with costs, and asks the real question: would it actually have made money?