There is a huge difference between building a trading bot that places trades and building one that has any realistic chance of making money.
Recently I started a new Python project with a fairly straightforward goal:
Build a fast crypto scalper that can watch live market microstructure, identify short-term opportunities and automatically enter and exit small trades.
The original idea was deliberately simple. Rather than trying to predict whether Bitcoin would be higher tomorrow, I wanted to look at extremely short-term movements — seconds rather than hours — and see whether information from the live order book and trade tape could provide enough of an edge for frequent small trades.
The result has turned into a much more interesting engineering project than I initially expected.
The basic idea
The application currently connects to OKX and consumes live market data for instruments such as:
- BTC-USDT-SWAP
- ETH-USDT-SWAP
- SOL-USDT-SWAP
The system uses the exchange’s live WebSocket feeds rather than repeatedly polling REST endpoints.
That gives us access to data such as:
- best bid and ask
- Level 2 order-book depth
- public trades
- aggressive buy and sell volume
- spread
- short-term price movement
- market depth imbalance
- microprice pressure
- realised volatility
- trading activity
The application then converts this stream into a set of continuously updated features that the trading engine can evaluate.
The important part is that this is not a candle-based strategy.
A one-minute candlestick throws away an enormous amount of information. For a strategy that may only hold a position for 10 or 20 seconds, the events happening inside that candle are potentially much more important than the candle itself.
Building the trading workstation
The project is a Python desktop application with a PySide6 interface.
The current workstation includes separate views for:
- Positions
- Orders
- OKX connection status
- Level 2 market microstructure
- Research data
- Future outcome analysis
- Edge research
- Fast Scalping
The application starts its market-data connections automatically and records feature snapshots locally while it runs.
A simplified version of the architecture looks like this:
OKX WebSockets
|
+---- Ticker
|
+---- Level 2 Order Book
|
+---- Public Trade Tape
|
v
Market Data Engine
|
v
Feature Engine
|
v
Fast Scalp Strategy
|
+------+------+
| |
v v
Risk Engine Paper Execution
|
v
Trade Evidence
|
v
SQLite / CSV
The separation between the market-data layer, strategy and execution simulator has been important.
It means we can keep changing the strategy without rewriting the WebSocket infrastructure every time.
Looking inside the order book
One of the more interesting parts of the project is the microstructure view.
Rather than simply displaying the current Bitcoin price, the application reconstructs the Level 2 book and calculates metrics such as order-book imbalance.
For example, if the top levels of the book contain significantly more bid liquidity than ask liquidity, the imbalance becomes positive.
Conceptually:
Bid depth = 1,250 BTC
Ask depth = 750 BTC
Imbalance =
(Bid - Ask) / (Bid + Ask)
= 0.25
That does not mean the price is guaranteed to rise.
Large orders can disappear, liquidity can be spoofed, and aggressive trades can overwhelm the resting book.
But when book imbalance is combined with actual trades, it becomes considerably more useful.
Trade delta and aggressive flow
The application also tracks public trades and attempts to measure whether buyers or sellers are currently being more aggressive.
For example:
Aggressive buys: 180
Aggressive sells: 100
That creates positive trade delta.
We calculate this across several windows, including roughly:
1 second
5 seconds
30 seconds
This gives the strategy both an immediate signal and some context.
A sudden burst of aggressive buyers means something different if the previous 30 seconds were strongly bearish.
The scoring engine
The first automated version uses a directional score ranging approximately from:
-100 = strongly bearish
0 = neutral
+100 = strongly bullish
The score combines several live features including:
- 1-second trade delta
- 5-second trade delta
- 30-second trade delta
- Level 2 imbalance
- short-term momentum
- microprice pressure
- volume acceleration
A sufficiently strong positive score can generate a Long signal, while a strong negative score can generate a Short signal.
The application also allows the trader to explicitly choose:
Long
Short
Both
For much of the recent testing I have concentrated on Long-only trading.
That has turned out to be useful because Long and Short signals do not necessarily behave symmetrically.
Maker-first execution
One of the biggest lessons from this project has been that fees can destroy a scalping strategy surprisingly quickly.
Initially the idea was simply:
Signal
|
v
Enter
|
v
Take a small profit
|
v
Repeat
The problem is that every entry and exit costs money.
On the OKX demo account used during testing, the API reported approximately:
Maker: 2 bps per side
Taker: 5 bps per side
One basis point is 0.01%.
A maker entry followed by a maker exit therefore has a theoretical fee floor of around:
4 bps round trip
A maker entry followed by a taker exit costs considerably more.
This immediately creates a major problem for a strategy trying to capture 1 or 2 basis points.
Even if the direction is correct, the trade can still lose money.
Why maker orders matter
The strategy therefore uses a maker-first entry model.
For a Long:
Current bid: 75,900.00
Current ask: 75,900.10
Place BUY at:
75,900.00
The simulator does not simply assume the order fills.
The market must actually come back and trade through or touch the resting order during the configured entry lifetime.
If it does not fill, the order expires.
This has another interesting consequence: maker orders introduce adverse-selection risk.
A resting buy order is often filled precisely because sellers are moving into it.
That means a maker fill is not necessarily the free advantage it initially appears to be.
This is something the project is now explicitly investigating.
Paper trading before real execution
Although the application uses live OKX market data and authenticates against a demo account, automated execution is currently deliberately restricted to paper trading.
That gives us:
Live market data
+
Live order book
+
Live trade tape
+
Simulated orders
without risking real capital while the strategy is still being developed.
Every completed simulated trade records information including:
- entry time
- exit time
- side
- entry score
- exit score
- entry price
- exit price
- hold duration
- gross P&L
- fees
- net P&L
- exit reason
More recently, we started recording much more detailed path information as well.
MFE and MAE
Two particularly useful metrics are:
MFE — Maximum Favourable Excursion
How far the trade moved in our favour while it was open.
MAE — Maximum Adverse Excursion
How far it moved against us.
Suppose we enter Bitcoin Long and the trade behaves like this:
Entry 75,900
Low 75,888
High 75,938
Exit 75,920
The exit price alone doesn’t tell us the full story.
The trade may have had enough potential profit to justify a different exit strategy.
Recording MFE and MAE allows us to ask questions like:
- Are our targets too ambitious?
- Are stops too tight?
- Are we exiting profitable trades too early?
- Do losing trades immediately move against us?
- How much movement normally exists after a strong signal?
We also record approximate prices after:
1 second
3 seconds
5 seconds
10 seconds
20 seconds
That is proving extremely useful.
A surprising result
One of the recent Long-only tests produced a result that initially looked promising.
Of 12 completed trades:
9 / 12 were positive before fees
The average trade captured positive price movement.
At around five seconds after entry, most positions were also still moving in the expected direction.
That sounds great.
Except the magnitude was tiny.
The average maximum favourable movement was only around a few basis points.
The best trade moved a little over 6 bps in our favour.
The problem was the fee floor.
A strategy can therefore be right surprisingly often and still lose money.
That is probably the most useful lesson from the project so far.
Accuracy alone is not enough.
The actual equation is closer to:
Trading Edge
-
Fees
-
Spread
-
Slippage
-
Adverse Selection
=
Real Edge
If the result is negative, a 90% directional hit rate is irrelevant.
Dynamic exits
Another early version of the strategy waited for either:
- take profit
- stop loss
- maximum hold time
That turned out to be too simplistic for very short-term trading.
Imagine a Long position was entered with a strong score of:
+70
Five seconds later the score collapses to:
+5
and then becomes:
-30
The reason for entering the trade has disappeared.
Waiting another 15 seconds for a fixed stop or target makes very little sense.
The current strategy therefore supports dynamic exits.
A position can now exit because:
- the hard profit target is reached
- the stop is reached
- the maximum holding period expires
- the microstructure signal fades
- a strong opposite signal persists
- an existing profit needs protecting
Reversal logic also includes persistence.
The engine deliberately avoids reacting to every individual tick because short-term order-book signals can flip rapidly.
For example:
Minimum hold before reversal exit: 5 sec
Reversal must persist:
1.5 sec
This reduces the chance of getting thrown out of a position due to a single noisy market update.
The newest experiment: only trade active markets
Recent results suggest another important problem.
The strategy can correctly identify direction, but sometimes the market simply does not move enough.
If Bitcoin moves only 1–2 bps after a signal, there is no realistic opportunity to pay a 4+ bps round-trip cost.
So the latest experimental version adds a Market Activity Gate.
Before opening a new trade, the strategy now checks whether the market is active enough.
The initial conditions include:
Strong microstructure score
+
Minimum recent 10-second range
+
Minimum realised volatility
+
Minimum recent trade activity
+
Acceptable spread
The recent range requirement is also fee-aware.
If maker fees increase, the required amount of recent movement automatically increases as well.
The UI can now report something like:
Market viability: BLOCKED
Range:
2.8 / 5.0 bps
10s realised volatility:
0.052 / 0.080 bps
Trades in last 5s:
42 / 15
ENTRY BLOCKED — MARKET TOO QUIET
This is a much better failure mode than entering a technically correct trade that has almost no chance of earning enough to cover transaction costs.
Exporting trading evidence
One of my favourite additions is the Export Analysis Bundle feature.
After a trading session, the application creates a ZIP containing:
trades.csv
trade_evidence.json
summary.json
profile.json
README.txt
The export contains no API keys or credentials.
It allows us to analyse complete trading sessions rather than making tuning decisions from a few visible trades.
Among other things, we can compare:
- Long versus Short
- entry scores
- hold duration
- fee drag
- exit reasons
- MFE
- MAE
- volatility at entry
- recent market range
- trading activity
- signal strength
This has already prevented several bad assumptions.
For example, lowering the take-profit target initially sounded sensible.
The actual data showed that doing so would simply create more trades that were technically winners but still negative after fees.
The GUI has been a project of its own
Because this is intended to be something I can actually monitor while it runs, I did not want the project to remain a collection of command-line scripts.
The current desktop interface provides live visibility into:

Market data
Level 2
Trade tape
Feature values
Positions
Orders
Trading configuration
Strategy state
Paper trades
Scanner metrics
Market viability
Supporting smaller laptop screens was unexpectedly painful.
Desktop layouts that looked perfectly good on a large monitor became almost unusable on a 14 or 15-inch laptop.
The application now has a more aggressive compact mode that hides secondary panels such as the manual order ticket and activity log when space is limited.
I also had to explicitly disable mouse-wheel changes on trading controls.
Accidentally changing a stop loss because the mouse happened to be hovering over a numeric field while scrolling is not exactly ideal behaviour for a trading application.
Where the project goes next
The next stage is not simply “turn on real trading.”
There is still a lot to prove.
The current focus is establishing whether there is a repeatable edge after execution costs.
Some of the questions we are investigating now include:
- Does the activity gate significantly improve MFE?
- Which volatility regimes produce the best trades?
- Are maker fills suffering from adverse selection?
- Is Long-only structurally stronger for this signal?
- What is the optimum hold duration?
- Is the current score weighting correct?
- Should the strategy dynamically change its target based on current volatility?
- Can a maker-first exit model materially reduce fee drag?
- How closely will simulated fills match real exchange behaviour?
Only after the paper strategy demonstrates credible positive expectancy would moving to automated demo exchange orders make sense.
And only after that behaves correctly would real capital even become a discussion.
The biggest lesson so far
When people think about algorithmic trading, they tend to focus on finding the perfect indicator.
That has not been the hardest part of this project.
The much harder problem is:
Finding a movement large and reliable enough that something remains after fees, spread, slippage and imperfect execution.
A model can correctly predict that Bitcoin is about to move up.
That prediction is worthless if Bitcoin moves 0.01% and trading the move costs 0.05%.
That distinction has changed the direction of the project significantly.
Instead of asking:
“Can we predict the next tiny price movement?”
the better question is becoming:
“Can we identify the moments where both direction and sufficient opportunity exist?”
That is a considerably more interesting problem.
And that is where the project currently stands.
