Ready to go further
Next: test a rule properly
The backtesting guide covers how to test without fooling yourself, with realistic costs and untouched data.
What is included
- What it is, in plain words
- The formula or mechanism, with exact arithmetic
- How it hits grid, martingale and DCA bots
- A check you can run before you switch a bot on
Who it is for
- People who run or plan to run a trading bot
- Anyone reading a backtest or a bot sales page
- Readers who want the numbers, not the pitch
- Not advice, and not a signal service
Key facts
- A trading bot is five parts: data in, a signal, risk rules, order handling and a record of what it did. The signal is the small part. Most bots fail in the other four.
- The code on this page is plain Python 3 with no libraries. We ran it, and the JavaScript on this page repeats its arithmetic and must match it, or the page does not build. It prints 33 position changes, a result of +2.37 after costs and a worst fall of 4.88 points (calculated by us on 29 Oct 2026).
- That one run looks fine, on prices that are random by construction. Over 300 different random series the same rule averaged -0.27 before costs and -1.81 after, and it made money after costs in 32.0% of them.
- A single backtest tells you how one history behaved. It does not tell you whether the rule has an edge, and a rule with no edge still wins on some histories.
- Start in paper trading, keep keys and permissions small, and give the bot a stop that does not depend on the bot working.
The five parts of a bot
- Data in. Prices from a source you trust, checked for gaps, bad ticks and time zones. A bot that trusts bad data does the wrong thing quickly.
- The signal. The rule that says buy, sell or do nothing. It is usually short, as below.
- Risk rules. The size of each trade, the most it may lose in a day, and when it must stop. See position sizing and daily drawdown rules.
- Order handling. Sending orders, checking they filled, and handling the ones that did not. See stop loss orders and slippage.
- A record. A log of every decision, order and fill, so you can compare what the bot did with what the backtest said it would do.
A backtest you can run
The code makes 500 bars of made-up prices with a simple generator, so it gives the same answer on every machine. It holds a position when a 5-bar average is above a 20-bar average and holds nothing otherwise, and it pays a cost of 0.05 points each time the position changes. Save it as a file and run it with Python 3.
# A tiny moving average crossover backtest with no libraries.
SEED = 20261029
BARS = 500
FAST, SLOW = 5, 20
COST = 0.05 # points paid each time the position changes
state = SEED
def rand(): # the same simple generator on every machine
global state
state = (1664525 * state + 1013904223) % 4294967296
return state / 4294967296
def make_prices():
prices = [100.0]
for _ in range(BARS - 1):
step = sum(rand() for _ in range(12)) - 6 # roughly a bell curve
prices.append(prices[-1] + 0.3 * step)
return prices
def sma(values, n, i):
return sum(values[i - n + 1:i + 1]) / n
prices = make_prices()
position, equity, peak, worst = 0, 0.0, 0.0, 0.0
changes = 0
for i in range(SLOW, len(prices)):
move = prices[i] - prices[i - 1]
equity += position * move # result of holding the last position
want = 1 if sma(prices, FAST, i) > sma(prices, SLOW, i) else 0
if want != position:
equity -= COST
changes += 1
position = want
peak = max(peak, equity)
worst = max(worst, peak - equity)
print("position changes:", changes)
print("result after costs:", round(equity, 2))
print("worst fall from a peak:", round(worst, 2))
It prints 33 position changes, +2.37 after costs and a worst fall of 4.88 points. With the cost set to 0 it prints +4.02, so the 33 changes cost 1.65 points in total.
Why one run proves little
The prices above have no pattern in them. Any rule applied to them has no edge, and still the run finished ahead. To see how much that means, the same rule was run on 300 different random series. Before costs the average result was -0.27, close to zero as it should be. After the cost it was -1.81, with about 30.9 position changes a series. The best series ended at +12.46 and the worst at -16.00. A trader who saw only the best one would have a convincing story.
This is why a good backtest is where the work starts. Test on data the rule was not built on, count every cost, and keep a final stretch untouched. See backtesting, overfitting and the Monte Carlo simulator.
What the code leaves out
- Real data and real fills. It trades at the bar price with no spread and no delay. Real orders do not.
- Risk rules. It has no stop, no size limit and no daily loss limit.
- Running live. It does not handle a lost connection, a restart, a rejected order or a position that is not what the bot thinks.
- Secrets. A live bot uses an account key. Give the key the smallest permission it needs, never allow withdrawals, keep it out of the code and out of any repository, and rotate it if it leaks.
A safe order of work
Run the backtest, then forward test on new data, then paper trade for weeks, then trade a very small size, and only then think about more. At each step compare the real results with the backtest. See forward testing and paper trading.
What this page does not tell you
It does not give a strategy to trade. The prices are random, the cost is made up, and this is education, not advice.
Keep Going
Related Tools and Guides
Keep exploring
FAQ
Frequently Asked Questions
How do I build a trading bot in Python?
Build it in parts: get clean data, write the signal, add risk rules, handle orders and keep a log. Backtest first, then paper trade, then a very small size.
Do I need libraries to write a trading bot in Python?
Not for the idea. The example on this page uses only the standard library. Real bots usually add libraries for data and orders, and each one is another thing to check.
Can a Python trading bot make money?
It can only if the rule has an edge after costs, and that has to be shown on real data. The code is the easy part.
Why did my backtest look good and the live bot lose?
Common causes are costs left out, fills that were too kind, a rule fitted to the past and luck. The random-price test on this page shows how luck alone can produce a good run.
How do I keep a trading bot safe?
Use small permissions with no withdrawals, keep keys out of the code, set a daily loss limit and a stop, log everything, and start with paper trading.
Are the numbers on this page real?
Example numbers are made up to show how the maths works, and the page says so. A figure only counts as exact when the page says it was calculated on a stated date. Nothing you enter in a calculator leaves your browser.
Can I use this to decide whether to run a bot?
It can show whether a bot's numbers hold together and how much an account can lose. It cannot say what the market will do, and it is not advice. Use it to ask better questions, then read the terms of your own broker or exchange.
Is this financial advice?
No. It is general education. The prices are random and the cost is made up, and it does not consider your situation.
Know the Risk Before You Run It
Free calculators and guides, added every week. Leave your details and we will email you when new ones go up.
Trading carries a risk of loss