I am building nalgo (working name), an algo trading platform for Indian markets. You connect your own broker account (Dhan today), write a strategy in a language that reads like English or start from a template, watch it on a live chart, and deploy it with one click. Every deployment runs inside a real NautilusTrader engine node, and the whole backend is pure Rust: no Python and no Node anywhere between the broker socket and the order. A repeat quote comes back in 12-24 ms instead of 1.3 s, and the indicator engine that drives both the chart and the strategy gets through 50,000 bars in under 10 ms, inside your browser. The paper trading engine is built and in testing on the backend, with its web app screens on the way. Live order execution is in testing too, and its numbers will follow. There is no public link yet - this post is the build story.
Algo trading in India is mostly plumbing
If you have tried to run a strategy against an Indian broker, you know the strategy is the easy part. Everything around it is what breaks:
- The session dies every day. Broker access tokens expire daily, so the bot that worked yesterday fails at 09:15 today.
- Sockets drop. A reconnect has to resubscribe every instrument without crossing the broker's limits on sockets and instruments per socket.
- The calendar is not simple. Holidays, special sessions, a closing auction session since August 2026, and commodity hours that move with daylight saving in New York.
- Every contract has rules. Lot size, tick size, freeze quantity, price band, which product types a segment allows. Ignore one and the order is rejected.
- The chart lies to you. The RSI on your charting site and the RSI in your Python script are two different implementations, so the signal you see is not always the signal you trade.
The usual answer is a Python script on a VPS and a lot of hope. The other answer is a hosted platform that hides everything behind a black box. I wanted neither. The goal for nalgo is simple to say: no hassle for the user, and no black box in the engine. You bring a broker account and an idea. The platform handles the sessions, the sockets, the calendar, the contract rules and the math, and it runs your idea on a professional-grade, open-source trading engine.
Why NautilusTrader, and why without Python
NautilusTrader describes itself as a "production-grade Rust-native trading engine with deterministic event-driven architecture". It has around 29.8k stars on GitHub, nanosecond-resolution timestamps, fixed-point prices and quantities, and one property that matters more than the rest: the same strategy and execution code runs across backtest and live systems. What you test is what you trade.
Most people use Nautilus from Python, but the project now supports a pure-Rust path as a first-class option. In its own words, you can "write actors, strategies, run backtests, and trade live without Python", and "this path requires no Python runtime". The crates are published on crates.io.
nalgo takes that path all the way. The backend is a Rust workspace built directly on the Nautilus Rust crates. That buys a few things a Python platform cannot:
- One language from tick to order. No interpreter between a price update and a decision, no serialization hop between a Python layer and a Rust core, no GIL.
- The compiler checks the whole path. A broker payload, a candle, a strategy rule and an order are all typed Rust values. A whole class of "worked in testing, crashed at 11:02" bugs cannot compile.
- Small, boring deployables. Each service is one compiled binary in a minimal distroless container image.
There is one thing Nautilus does not have: India. Its official integrations cover Binance, Bybit, Interactive Brokers, Databento, Hyperliquid and more, but no Dhan, Zerodha, Upstox, NSE or BSE. So the core of nalgo is the bridge. A broker's live feed comes in from your own account, gets normalized once, and is handed to Nautilus as market data. Nautilus provides the event loop, the order lifecycle, the rate limits and the matching engine. nalgo provides India.
The shape of the system
The backend is three Rust binaries and nothing else:
- The API serves REST and WebSocket traffic to the apps. Its OpenAPI document is generated from the code itself, so the 237 documented paths cannot drift from what the server actually does.
- The worker runs everything on a clock: renewing broker sessions before the market opens, loading the full instrument master every morning, refreshing calendars and contract terms, and reconciling orders with the broker every 30 seconds.
- The engine host runs deployments. Every running strategy gets its own isolated NautilusTrader node, and one host runs many of them side by side.
They coordinate without a separate message broker - no Kafka, no Celery, no queue cluster to babysit. If an engine host goes away, another host can pick up its strategies cleanly, and a strategy that keeps failing is retried with backoff and then parked as failed instead of looping forever. When a strategy comes back after a restart, it resumes from its saved state instead of running its start logic again.
Bring your own broker, keep your own data
nalgo never sells you a data feed. Charts, quotes, option chains and strategy signals all come from your own broker connection, the one you already pay for.
- One connection per account, shared by everything you open. Every chart, every tab, the live Greeks and every strategy you deploy on that account share the same upstream connection, so you stay inside the broker's socket and instrument limits however many screens you have open.
- Sessions renew themselves. The daily token problem from the top of this post is the platform's job, not yours. Where the broker allows it, your session is renewed before the open, and live feeds move to the new token before the old one expires.
- Credentials are treated like money. Broker secrets are encrypted at rest with AES-256-GCM under keys that rotate, are never written to logs, and are never returned by the API - not even to you.
- Brokers are plugins. Every broker implements one contract: how to log in, what history and feed limits it has, how it places and cancels orders, how its kill switch works. The connect form you see in the app is generated from that description. Dhan is the first plugin, and Zerodha, Upstox and Groww are new plugins, not rewrites.
If you read my F&O fair value engine post, you know I have spent a lot of time inside Dhan's APIs. nalgo is where that knowledge turned into a product anyone can use.
A strategy language that speaks Indian F&O
Strategies in nalgo are written in a small language that reads like English. Here is a trimmed version of one of the built-in templates, a 09:20 short straddle on NIFTY:
strategy "Short straddle 09:20"
capital 300000
product intraday
input size = 1 min 1 max 20
input leg_stop = 30% min 5% max 200%
instrument nifty = "NIFTY-INDEX.NSE"
option ce = nifty expiry weekly 0 strike atm call
option pe = nifty expiry weekly 0 strike atm put
schedule
skip expiry_day of nifty
square_off 15:15
end
risk
max_loss_day 6000
lock_profit 2000 after 3000
end
on time 09:20
sell ce size lots market as ce_leg group straddle
stop_loss leg_stop
sell pe size lots market as pe_leg group straddle
stop_loss leg_stop
end
on exit ce_leg reason stop
modify pe_leg
stop_loss at entry_price(pe_leg)
end
There is no glue code in there. You name an underlying, and options are picked by rule - at the money, N strikes in or out of the money, by delta or by premium, on this week's or this month's expiry. Legs can be grouped and stopped together in rupees. The schedule knows about expiry days and square-off times, and a daily risk block caps the loss and locks in profit.
The language is deliberately strict, because a strategy that does something surprising costs real money:
- Units are type-checked. A percentage and a plain number are different types, so
30%and30cannot be mixed up. - Missing data never trades. A value that is not available yet (an indicator still warming up) can never trigger an order.
- No look-ahead, no unbounded loops, no recursion. Every strategy finishes every evaluation, and every evaluation sees only the past.
- Hard limits. Source size, rule count, program size and orders per evaluation are all capped.
Writing one is closer to filling in a form than programming:
- Start from a template. There are 12 of them, from an EMA crossover with an ATR stop to an iron condor, momentum rotation and a pairs z-score trade.
- Get checked as you type. Errors point at the exact line and column, and a mistyped symbol gets a "did you mean" from the full instrument list.
- Press Explain. The strategy is read back to you in plain English, so you can confirm it does what you think it does.
- Preview it on real candles, with every trade marked on the chart. It is labelled honestly as a logic check with idealized fills, not a backtest.
- Save, then deploy. Every save is an immutable version, and a deployment is pinned to the exact version you approved.
A drag-and-drop builder is on the way. The language and its tree form already convert both ways, so the builder and the text editor will edit the same strategy.
One indicator engine, from your chart to the order
This is the part I am proudest of. Remember the chart that lies? In nalgo, indicators written in the strategy language run through one Rust engine in two places:
In the browser, the engine is a 232 KB (gzipped) WebAssembly module running in a Web Worker, so the page never stutters while it computes. On every tick, only the bar that is still forming is recomputed. When a strategy uses a custom indicator, the strategy version stores that exact indicator version, so the line on your chart and the number your strategy acts on come from the same code.
It is also fast. Measured during development:
| Workload | Time |
|---|---|
| EMA 9 + RSI 14 + SuperTrend over 5,000 bars | 1.75 ms |
| The same three over 50,000 bars | 9.4 ms |
| The same three over 200,000 bars | 35.3 ms |
| Two indicators on a live 5,000-bar chart, per update (median, worker time) | 0.6 ms |
| The same, full round trip to the chart (median) | 3.8 ms |
| First load, including compiling the WebAssembly | 96 ms |
Bring your TradingView indicators with you
Most traders already have Pine Script indicators they trust. nalgo can import them: paste a Pine v5 or v6 indicator, and a translator written in Rust turns it into the strategy language. It never runs your script as code, and the page that runs indicators still blocks JavaScript eval - WebAssembly is the only thing allowed to execute.
To keep the translation honest, it is tested against PineTS, an independent open-source Pine engine:
- 38 outputs from 27 functions match PineTS to 6 decimal places on 3,000 real RELIANCE 5-minute prices.
- A corpus of 30 Pine scripts written for this build must all translate, pass the checker, and match where they translate fully.
- The fixtures caught a real bug. Parabolic SAR reversals were off; they now follow TradingView's behavior.
On the same bars, PineTS was 30 to 100 times slower than the Rust engine. There are limits, and they are stated up front: Pine strategy() scripts, drawing objects (lines, labels, boxes, tables) and indicators that read other symbols are not supported yet. Anything the translator cannot handle comes back with its line and column and stays in the text as a comment, instead of being silently dropped.
The terminal: TanStack Start, open-source charts, and a budget
The web app is built on TanStack Start - Router, Query, Store, Form, Table and Virtual - in strict TypeScript. Candles are drawn by KLineChart, an open-source charting engine, and line charts (P&L, open interest, the IV smile, payoff curves) by uPlot.
Live data is engineered so the screen keeps up without melting your laptop. Each tab holds one WebSocket. Ticks land in a store at most once per animation frame, only the forming candle is redrawn, and long tables like 200-level market depth are virtualized so only the visible rows exist.
What is in the terminal:
- Charts with 24 built-in indicators plus your own, 12 drawing tools, session breaks and closing-auction bands, and working orders and positions drawn as draggable lines. Layouts and drawings are saved to your account, not just the browser.
- A live option chain with streamed Greeks. They use Black-Scholes for index and stock options and Black-76 for options on futures, with a forward implied from put-call parity per expiry and an ATM strike that does not flicker with every tick.
- Orders, in testing now: lots or units, tick rounding and price-band checks, plus sliced, bracket, GTT and conditional orders, a margin calculator and a kill switch that also cancels orders held at the broker.
- Portfolio: positions, holdings and funds with live P&L, across every connected account.
- Market panels: a ticker tape, gainers, losers and most active across NIFTY 500, and an index heat map.
- Search across about 180,000 instruments with Ctrl+K.
Every byte is budgeted. The landing page stays under 151 KB gzipped and the signed-in terminal shell under 251 KB, and a test fails the build if either grows past its budget. Heavy pieces - charts, the indicator engine, the strategy editor - load only when you open them.
The terminal already works on a phone: a bottom tab bar, an order ticket that slides up as a sheet, and a full-screen mode for iPhone Safari. A native mobile app is coming soon.
Speed, measured not promised
Every number below was measured against a live Dhan account, on a development build, with requests sent back to back. The first request goes to the broker. Every repeat is served by nalgo's shared cache, and a second API process serves it too without calling the broker again.
| Request | First (goes to the broker) | Repeat (served by nalgo) |
|---|---|---|
| Quote for one instrument | 1.26-1.43 s | 12-24 ms |
| NIFTY option chain with live Greeks | about 1.34 s | 62-69 ms |
| Broker option chain | about 3.4 s | 23-27 ms |
| Positions | about 270 ms | 13-17 ms |
| Funds | about 260 ms | 10-12 ms |
A few more from the build logs:
- Movers across NIFTY 500: the first scan was 13.4 s before a rewrite. It is now 1.25 s, and 30-80 ms on repeat.
- The instrument master: every morning, 204,649 rows are read and 180,447 tradable instruments loaded in 53 seconds. A "did you mean" suggestion across all of them takes 6 ms.
- The database: with 1 million orders and 666,660 fills loaded, every hot order query runs in 0.12-0.78 ms. Every query is hand-written SQL, and every one is checked with
EXPLAIN. - The live feed: 10 minutes on one socket in market hours delivered 5,999 NIFTY updates with no disconnects and a longest gap of 0.17 s, and a separate 40-minute run had no drops at all.
Order placement and paper trading are still in testing, so their speed numbers are yet to come. I will publish them once testing wraps up.
Nautilus itself is a big part of why the engine side is fast. Its core is Rust, its prices are fixed-point integers, and the project benchmarks its order matching and message bus.
Paper trading that behaves like the market
The paper trading engine is built on the backend and I am testing it now; its screens in the web app are coming next. A deployment is paper trading on live data - forward testing, not a replay. Your strategy runs inside its own NautilusTrader node, fed by your broker's live market data, and its orders are filled by Nautilus's own matching engine against live market depth.
What makes it more than a toy simulator is the India-specific layer around it:
- Same risk checks as real orders. Every order a strategy produces goes through exactly the same validation as an order you place by hand: instrument, lot size, tick size, freeze quantity, price band, product type, and whether the market is open right now.
- Real costs. Indian charges and margin requirements are applied to every fill, so paper P&L is not fantasy P&L.
- Rate limited. Each strategy is capped at 10 orders a second.
- Calendar aware. Holidays, special sessions, the closing auction and MCX hours are all known. Intraday positions are squared off before the close, DAY orders expire, and contracts that expire are settled.
- Restart safe. A strategy's state is saved continuously, so a restart resumes it from that state instead of starting over.
Paper trading is the right first step for a platform like this. It proves the strategy, the data path and the engine on live markets before a single real rupee is involved.
Built like it handles money
Because it will. A few of the rules the codebase lives by, enforced by tooling rather than good intentions:
unsafecode is denied across the workspace, andunwrap,expectandpanicare lint errors outside tests.- No ORM. Every query is hand-written, parameterized SQL, and every row a user owns carries their user ID, which every query filters on.
- Tests never touch a real broker. Broker HTTP and WebSocket traffic is mocked, so the test suite can run anywhere.
- Every capability is reachable through the documented API, and every admin-relevant state has an admin screen and an audit trail.
- Every feature starts as a written plan, and every defect found along the way is written down and tracked until it is fixed.
Some numbers on the build so far, from 27 September to 9 October 2026:
| Commits | 799 in 13 days |
| Rust | about 217,000 lines across 32 workspace members |
| Rust tests | 1,722, of which 669 run against a real PostgreSQL |
| TypeScript | about 128,500 hand-written lines in two apps and shared packages |
| Web test files | 247, including 45 Playwright end-to-end suites |
| API | 237 paths, documented with OpenAPI generated from the code |
| Strategy language | 162 functions, 31 indicator templates, 12 strategy templates |
| Written plans | 56 |
What is still on the list
nalgo is young and changing every day. In rough order:
- Paper trading in the web app. Deployments with live P&L, orders, fills and an event log per strategy. The engine behind it is built and in testing.
- Live execution, in testing now. Strategy orders go through the same broker plugin and the same risk checks as manual ones, and the speed numbers for live orders will come with it.
- Backtests on NautilusTrader's backtest engine, over cached candles and expired option data.
- More brokers. Zerodha, Upstox and Groww as plugins.
- A visual strategy builder on top of the same strategy tree the text editor uses.
- The native mobile app.
- Fundamentals and corporate events next to the chart.
- A final name. nalgo is what it is called while I build it.
Conclusion
The best algo trading platform for most people is the one where the strategy is the only thing they have to think about. Getting there takes a lot of unglamorous engineering: sessions that renew themselves, sockets that are shared and recovered, a calendar that knows about auctions, risk checks that never get skipped, and an indicator engine that gives the chart and the strategy the same answer. Building all of it in one language, on an engine as serious as NautilusTrader, is what makes it fast enough and dependable enough to trust with real money.
The hard part of retail algo trading is not the strategy - it is the plumbing around it. Put a real event-driven engine at the core, keep the whole backend in one compiled language, run the same indicator code on the chart and in the engine, and push every India-specific rule (sessions, lots, bands, auctions, expiries) into the platform. Then the user only has to bring an idea and a broker account.
References
- NautilusTrader on GitHub - the trading engine at the core of nalgo
- NautilusTrader: Rust - the pure-Rust path, without a Python runtime
- NautilusTrader integrations - the official venue and data adapters
- TanStack Start - the web framework behind the terminal
- KLineChart - the open-source candlestick chart engine
- uPlot - the line charts for P&L, open interest, IV smile and payoff
- PineTS - the independent Pine engine used to check indicator math
- Building a Real-Time F&O Fair Value Engine - my earlier work on Dhan, Black-Scholes and live depth