Parameters, defaults, and the number you will regret
Your rule has a 20 and a 50 in it. Both are decisions, both are currently invisible, and both have a price.
Hard-coded numbers are invisible assumptions
function signal(bars) { return sma(bars, 20) > sma(bars, 50); } // two hidden decisions
Lift them out:
type Params = { fast: number; slow: number; costBps: number };
const DEFAULTS: Params = { fast: 20, slow: 50, costBps: 10 };
Three benefits and one trap.
The benefits: the assumptions are now listed in one place where a reviewer can see them; the report you export in unit 4 can print them beside the result, which is what makes it reproducible; and you can vary one without editing the strategy.
The trap, which is the point of this lesson
The moment parameters are easy to change, you will change them until the curve looks good. That is not research, it is fitting the answer to the sample, and it is the most common way an honest person produces a dishonest backtest.
It does not feel like cheating. It feels like tuning. You try 20/50, then 10/30, then 15/40, keep the best, and report it — without reporting the other eleven you tried. The number you publish is then the maximum of twelve draws, not a typical result, and the gap between those two is the entire subject of unit 4.
Two rules that cost nothing and help enormously
Log every run. Append parameters plus result to a file, automatically, every time. Not to be tidy — so that when you report a result you can count how many attempts it took to find it. Twelve attempts is fine and normal; twelve attempts reported as one is the problem.
Set defaults before you look. Write down the parameters you would have chosen on theory alone, run those first, and keep that number. It is your honest baseline, and everything found afterwards gets compared to it rather than replacing it.
Cost is a parameter too
Note costBps sits in the same struct as fast and slow. That is deliberate: it makes cost a stated assumption of the run rather than a setting buried somewhere, and it means the exported report shows what you assumed.
Ten basis points — 0.10% per trade — is a defensible retail default for liquid US equities and is what this course uses. It is a choice, not a fact, and unit 3 explains what it stands in for.
Try it now
Add the run log before you tune anything, and make it automatic — a manual log is a log you stop keeping on the day it matters. Then run your theory-chosen defaults once and write that number in PLAN.md where you cannot quietly replace it.