The Fix: Making Signal Generation Order-Invariant
One of the biggest “oh wow” moments during debugging was realizing the issue wasn’t an indicator at all.
It was bar ordering.
Some parts of the pipeline were feeding candles newest-first instead of oldest-first. Most indicator math quietly assumes chronological order, so when that assumption breaks, you don’t get an error — you get a strategy that runs perfectly… in reverse.
So I changed the signal generator to be order-invariant.
Now, before any indicators are computed:
- Bars are explicitly sorted chronologically
- If reversed ordering is detected, the system logs a one-time warning per symbol
That turns what used to be a silent catastrophic failure into something I can immediately see and verify.
This single change explained a lot of strange behavior we’d been chasing for months.
Pulling the System Away from Noise
Another thing I noticed while watching live behavior: the engine was simply reacting to too much micro-movement.
It wasn’t dumb — it was over-sensitive.
So for training and backtests, I’ve moved the default to 5-minute bars:
- If native 5m data exists, we use it
- Otherwise, 1m bars are resampled → 5m
This pushes the model toward decisions that reflect structure, not every tiny wiggle.
Since doing this, trade counts immediately started dropping — which is exactly what I wanted to see.
Fewer meaningless trades = fewer fees = more room for edge.
Killing Doomed Training Runs Early
Before this pass, a bad training iteration could lose nearly all capital in the first month… and then keep simulating for another two years.
That’s a massive waste of power and it pollutes optimizer scoring.
Now I’ve added an early-exit rule:
- If net liquidation ≤ 0, the iteration stops immediately
- The optimizer moves on to the next candidate
This keeps training focused on configurations that at least survive long enough to be evaluated.
It also makes optimizer output much cleaner.

Hardening Execution for Broker Reality
Interactive Brokers is powerful, but real-world messy.
I’ve been tightening execution logic to deal with things like:
- Missing market data in paper trading
- Contracts with strict minimum tick sizes
- Stop/limit rejections
Current behavior:
- Use recent historical bars as fallback price proxies
- Round all prices to
minTick - Fall back to best-effort pricing in paper mode
The goal here isn’t perfection.
It’s predictability.
If something fails, I want it to fail in a known, explainable way — not silently.
Terminal-First Monitoring
I’m deliberately keeping monitoring simple and local while things are evolving.
Sentinel now always writes:
- A heartbeat file → proves the loop is alive
- A trade journal (JSONL) → records entries, exits, partials
No dashboards.
No web UI.
Just files I can tail in a terminal while watching behavior.
It fits the current “vibe coding” phase perfectly: fast iteration, fast feedback.
Takeaway
Right now, development isn’t about fancy indicators.
It’s about foundations.
If a system looks busy but doesn’t grow:
- Check data ordering
- Check noise level
- Check fees
Because edge doesn’t die loudly.
It usually bleeds quietly.
T



