This is Part 2 of the NERV Trade engineering series. In Part 1, I showed where NERV Trade has reached today. Now we're going back to the beginning.
A Trading Bot Is Easy. A Trading Engine Is Not.
So where did NERV Trade actually start?
With a deceptively simple idea.
Market Data
↓
Analysis
↓
BUY / SELL
If you've ever experimented with algorithmic trading, this probably looks familiar.
Get some candles. Calculate indicators. Decide whether the market looks bullish or bearish. Generate a signal.
Maybe send an order.
At this stage, the interesting question seems to be:
How do I generate a good trading signal?
And that was where much of my attention naturally went at the beginning of NERV Trade.
But as the project evolved, I discovered something that completely changed how I thought about the system.
Generating the signal wasn't the difficult part.
The difficult part was deciding what the system should do after generating it—and proving that it would still behave correctly when things stopped going according to plan.
The First Version of the Problem
A basic trading program can be surprisingly small conceptually.
You have market data:
open
high
low
close
volume
You run some analysis.
The result might be:
BULLISH
BEARISH
NEUTRAL
A strategy interprets that result and eventually produces something like:
BUY
SELL
HOLD
For an experiment, that can be enough.
You can replay historical candles, print trades to the console, calculate theoretical profit and loss, and start tweaking the strategy.
It's satisfying because progress is immediate.
Add an indicator.
Change a threshold.
Run the simulation again.
Maybe the numbers improve.
It feels like you're building a trading system.
But you're mostly building the part that decides what it wants to do.
That distinction eventually became very important.
Then You Ask the Next Question
Suppose the strategy says:
BUY BTC
Great.
What happens now?
We need an order.
So perhaps the architecture becomes:
Market Data
↓
Analysis
↓
Strategy
↓
BUY
↓
Order
↓
Broker
Still pretty straightforward.
But then the questions start.
Did the broker receive the order?
Did it accept it?
Was the order rejected?
Did it execute immediately?
Was only part of it executed?
Is the remaining quantity still open?
Did the broker execute it more than once?
What if the application receives the same execution notification twice?
What if the application crashes after receiving the fill?
What if the broker accepts the order but the network connection dies before we receive the response?
Suddenly:
BUY
isn't nearly enough information.
The Broker Doesn't Return a Trade
This was one of the conceptual shifts that eventually shaped NERV Trade.
A strategy can express an intention.
A broker processes orders.
The market produces executions.
Those aren't the same thing.
Consider an order for 10 units.
You might imagine:
BUY 10
↓
FILLED 10
Reality can look more like:
BUY 10
↓
ACKNOWLEDGED
↓
FILL 3
↓
FILL 4
↓
FILL 3
↓
FILLED
Now the system needs to remember what happened between those steps.
It needs identity.
It needs state.
It needs lifecycle.
And eventually it needs persistence.
Then Failure Becomes Part of the Design
The happy path is easy to reason about.
Send Order
↓
Broker Accepts
↓
Receive Fill
↓
Update Position
But production systems don't live entirely on the happy path.
Consider this:
NERV
│
│ Send BUY order
▼
Broker
│
│ Order accepted
▼
X Connection lost
The broker has the order.
NERV doesn't know that.
What should the application do?
The obvious answer might be:
retry();
But retrying could create another real order.
So perhaps the order failed?
That's not true either.
We don't know whether it failed.
That means uncertainty itself becomes part of the domain.
And once that happens, a generic retry mechanism is no longer enough.
The system needs stable identities and a way to ask the broker:
What actually happened?
That is reconciliation.
I certainly wasn't thinking about reconciliation when the project was simply:
Market Data → Analysis → BUY / SELL
Then the Application Restarts
Now imagine the engine has been running for hours.
There are active trades.
Some orders are filled.
Others may still be open.
The system knows its exposure.
It knows which executions it has already processed.
Then:
Application stopped.
Maybe it crashed.
Maybe Kubernetes restarted the container.
Maybe we deployed a new version.
The reason doesn't really matter.
When the application comes back, what does it know?
If the answer is:
Nothing. Let's start again.
then we have a serious problem.
The broker didn't forget.
The account didn't forget.
The market didn't forget.
Only our application did.
A trading engine therefore needs to recover its understanding of the world and reconcile that understanding with external reality.
Market Data Has Its Own Version of the Same Problem
Execution isn't the only place where apparently simple assumptions break.
Market data does too.
Suppose our strategy runs on five-minute candles.
Easy enough.
Then we decide that a five-minute signal should be interpreted in the context of:
M5
M15
H1
H4
Now we have another set of questions.
When exactly does an M15 candle close?
Which M5 candles belong to it?
What happens while the current H1 candle is still forming?
When analyzing an M5 candle from 10:35, are we accidentally using information from an H1 candle that wasn't complete at 10:35?
That last question is particularly dangerous.
Because the system can look perfectly correct while quietly using information from the future.
Your backtest might even look fantastic.
It would also be lying to you.
Eventually the Architecture Started Looking Different
The original mental model was:
Market Data
↓
Analysis
↓
BUY / SELL
As each new problem appeared, the system had to acquire another responsibility.
Eventually the picture became closer to:
Market Data
↓
Multi-Timeframe State
↓
Analysis
↓
Strategy
↓
Risk
↓
Trade Intent
↓
Order Lifecycle
↓
Broker
↓
Executions
↓
Durable State
↓
Recovery & Reconciliation
That's a very different system.
And importantly, those boxes weren't added because I sat down at the beginning and designed the perfect trading architecture.
They appeared because increasingly difficult problems made the simpler architecture insufficient.
So What's the Difference Between a Bot and an Engine?
I'm not interested in creating a formal industry definition here.
For this project, I think about the distinction much more practically.
A trading bot can answer:
What should I trade?
A trading engine has to keep answering:
What happened?
What do I currently own?
What am I allowed to do?
What has already been processed?
What is still uncertain?
And can I prove that my internal state still agrees with reality?
That second set of questions turned out to dominate much of the engineering work in NERV Trade.
This Changed How I Measure Progress
Early in a trading project, progress is easy to see.
A new indicator appears.
A signal fires.
A backtest improves.
A chart looks better.
Later, some of the most important progress becomes almost invisible.
The same execution arriving twice changes state once.
A crash halfway through processing doesn't corrupt accounting.
An uncertain order isn't blindly submitted again.
A restart reconstructs the same state.
A missing market-data interval is detected instead of silently ignored.
A strategy cannot accidentally bypass risk controls.
None of those features produce an exciting trading chart.
But they're the things that started turning NERV Trade from an experiment into an engine.
But Before Orders, Brokers, and Databases...
There's an earlier problem we need to solve first.
Suppose I give NERV Trade the same sequence of market data twice.
Should it make the same decision?
That sounds like an easy question.
It isn't always.
Time, mutable state, candle boundaries, event ordering and partially formed market data can all introduce subtle differences.
And if the analysis isn't reproducible, debugging everything that comes afterward becomes dramatically harder.
So before worrying about real brokers, persistent orders or restart recovery, NERV Trade needed a more fundamental property:
determinism.
That became one of the earliest architectural principles of the project.
And that's where we'll go next.
Next in the NERV Trade series:
Deterministic Trading: Why the Same Market Data Must Produce the Same Decision
NERV Trade is part of NERV — Next-Generation Engineering for Runtime Velocity. This series documents the real engineering journey behind building a Java trading engine: the design decisions, failures, tests, architectural changes and lessons that shaped the system.

Post a Comment