A Day in Paper Trading: Running a C++ Trading Stack, and 15 Lessons

What does it actually take to run an algorithmic trading stack for one day? We walk through Kestrel's daily paper-trading routine, from the morning script to the ordered shutdown, then recap the design lessons of the whole 26-episode course.

Intro

A Day in the Life

A trading system is not only code. It is also a routine: what runs at nine in the morning, what must be stopped first at night, and what must never be started by a script. Today is the last episode of the series, and we will follow one paper trading day of Kestrel from start to finish. Then we will look back at the whole course and pull out the lessons.

  • One trading day
  • Several cooperating processes
  • Then the whole course

Where We Left Off

In the previous episode we stacked ten layers of live trading safety, each one assuming the others might fail. Those layers protect the order path. This episode is about the human and scripted procedure around them: the daily operating routine, and why its order matters. We stay in paper mode, so no real orders leave the machine.

  • Episode 25: ten safety layers
  • Today: the operating procedure

The Plan for Today

Here is the plan. First the morning script, then the generator that writes the day's configuration. Third, the script that starts and stops every process, including the stop ordering, which is the critical part. Fourth, the data jobs that keep downloads away from market hours. Finally, one slide for each lesson of the course, and an honest status report.

  • Morning script
  • Config generation
  • Start and stop order
  • Fifteen lessons

The Clock

The 24-Hour IST Clock

Let us draw the day as a clock in Indian Standard Time. Remember from episode 3 that IST is a fixed offset of five hours thirty minutes from UTC, with no daylight saving, so these times never shift. The clock has one ring of twenty-four hours, and we will place the day's events on it.

  • IST is UTC plus 05:30
  • No daylight saving

Events Around the Clock

At six thirty the daily broker token expires, so a fresh login is needed each day. At eight fifty-five the data blackout begins, which we will explain later. At nine the stack starts, and at nine fifteen the market opens. These four marks are all clustered in the morning, which is why the morning script exists.

  • 06:30 token expiry
  • 08:55 blackout start
  • 09:00 start
  • 09:15 open

The Rest of the Day

At three fifteen in the afternoon, the configured square-off time, open positions are closed. The market closes at three thirty, and at three forty-five bulk downloads are allowed again. Notice that square-off comes fifteen minutes before the close, leaving room for orders to actually fill. Between nine and three thirty, the stack must simply stay up and stay calm.

  • 15:15 square-off
  • 15:30 close
  • 15:45 downloads resume

The morning script

morning.sh: Inputs

The morning script is tools slash paper slash morning dot sh, and you run it before nine o'clock IST. It takes three settings: TARGET_DAY, the day you want to trade; START_HHMM, which defaults to zero nine zero zero; and DEADLINE_HHMM, which defaults to eleven thirty. The first thing it does is sleep until nine IST of the target day, so you can launch it the evening before.

  • TARGET_DAY
  • START_HHMM 0900
  • DEADLINE_HHMM 1130

Waiting for the Operator

Next comes the one step a script cannot do for you: the daily FYERS login. The operator logs in by hand, and the script loops, running kestrel_history with the fyers-check flag every sixty seconds until the login is valid. If the deadline of eleven thirty arrives first, the script gives up rather than guessing. This is the fail closed idea in miniature: no valid login, no trading stack.

  • kestrel_history --fyers-check
  • Every 60 seconds
  • Give up at the deadline

Config, Then a Late-Start Check

Once the login is confirmed, the script runs build_day_configs dot py, which we look at next. Then it asks one question: is it already later than nine sixteen? If so, this is a late start, and the strategies would wake up after the open with no recent bars in their warmup.

  • build_day_configs.py
  • After 09:16: late start

Gentle Backfill

On a late start the script backfills today's one-minute bars so that warmup covers the open. It does this deliberately slowly, with FYERS_MAX_PER_SEC set to one and FYERS_MAX_PER_MIN set to thirty. The reason is that the same broker rate budget will soon be needed by the live stack, and a greedy backfill would eat into it. Slow and complete beats fast and rate limited.

  • Backfill today's 1-minute bars
  • FYERS_MAX_PER_SEC=1
  • FYERS_MAX_PER_MIN=30

Start, Wait, Status

Finally the script calls md_paper dot sh start, waits sixty seconds for everything to settle, and prints the status. That last step matters, because a morning script that starts things and says nothing leaves the operator guessing. The operator can glance at the status output and see immediately whether the day began healthily.

  • md_paper.sh start
  • Wait 60 seconds
  • Print status

Day configs

build_day_configs.py

build_day_configs dot py writes the day's configuration. It reads the last closes from the history store we built in episode 4, then generates nine day groups on control ports eighty eighty-one through eighty eighty-nine. We will not explain the strategies here; that belongs to the separate strategies playlist. We only care about the plumbing.

  • Reads last closes from the store
  • Nine groups
  • Ports 8081 to 8089

Three Files per Group

Each group gets the three-file run config from episode 3. Strategy dot json says mode paper, sends the log to run directory slash run dot log, and carries risk, costs, and the square-off time of fifteen fifteen. Alpha dot json carries the previous day's parameters forward. Data dot json lists instruments, the market-data socket, a twenty-day warmup read from the store, and the order-service socket.

  • strategy.json
  • alpha.json
  • data.json

Option Chains Around Spot

For option instruments, the generator reads the symbol master and builds chains around the spot price, using the last close as its anchor. It skips any expiry that is less than sixty minutes away. An expiry that close is about to be settled, as we saw in episode 6, and subscribing to a chain that is about to disappear only adds noise and risk.

  • Symbol master
  • Strikes around spot
  • Skip expiries under 60 minutes

Validate Every File

Generating files is not enough, so each one is checked with kestrel_config validate. If a file is malformed, the problem shows up in the morning script, before any process starts, rather than in the middle of the session. A bad config is a cheap error at nine in the morning and an expensive one at ten past eleven.

  • kestrel_config validate
  • Each file checked
  • Bad config never starts

Start and stop

Start Order

Now md_paper dot sh. It starts the market-data service first and waits up to thirty seconds for md dot sock to appear. Then the order service, again waiting for its socket. Then the portal and the UI, and finally one trader per eligible group. Each process only starts once the things it depends on are actually listening.

  • md, then orders
  • portal and UI
  • one trader per group

Who Gets Started

Not every group is started. Only groups whose mode is paper and whose orders type is service get a trader. Live groups are never started by this script; they are always started by hand. A script that can start live trading at nine in the morning, unattended, is a script that will eventually do it on a day you did not intend.

  • mode is paper
  • orders type is service
  • Live: always by hand

Other Commands

The script has two more commands. Restart GROUP bounces a single trader without touching the rest. Status prints process ids, then the market-data service's api status, then the order service's api sessions list. Because the traders hold only a shadow book, as we saw in episode 24, restarting one is safe: the order service still owns the truth.

  • restart GROUP
  • status
  • pids, md status, orders sessions

Stop in Reverse

Stopping is where the order matters most. The stop command runs in reverse. Traders go first, then the order service, and only then market data, the portal and the UI. Here is the simplified sequence as pseudo-steps, since the real scripts contain no comments.

  • Traders first
  • Orders second
  • Then md, portal, UI

The Stop Ordering (Simplified)

Step one: stop traders, send SIGINT, wait thirty seconds, then send TERM if they are still alive. Step two: stop the order service, with a one hundred twenty second grace period for end-of-day files and archives. Step three: stop market data, the portal and the UI. This is simplified pseudo-code, not the verbatim script.

  • step 1: traders, SIGINT, 30 s, TERM
  • step 2: orders, 120 s grace
  • step 3: md, portal, UI

Why Traders Go First

Why this order? A trader that receives SIGINT shuts down cleanly and says bye to the order service, which lets the service close that session properly. Only then does the order service write its end-of-day files and run archives, and that can take time, hence the one hundred twenty second grace. If you stop the order service first, the traders lose their counterpart mid-conversation, and the archive may record a messy day.

  • Traders say bye
  • Orders then flush files
  • Orders last would lose the session

Data jobs and pitfalls

Keep Bulk Downloads Out

The data jobs follow a blackout window from eight fifty-five to fifteen forty-five IST. Bulk history downloads simply refuse to run during market hours. The broker's rate budget is shared, as we discussed in episode 22, and a large download in the middle of the session could starve the live market-data and order calls that actually matter.

  • Blackout 08:55 to 15:45 IST
  • Protects the live rate budget

The F&O Ban List

Another data job fetches the F and O ban list, the list of derivatives underlyings where new positions are restricted. That file feeds the foBan risk policy from episode 8. The point is that a risk check is only as good as its data, so refreshing that data is part of the daily routine, not an afterthought.

  • Fetched by a data job
  • Feeds the foBan risk policy

Three Operational Pitfalls

So three pitfalls. First, stopping the order service before the traders. Second, letting bulk downloads consume the live rate budget during market hours. Third, starting live groups from a script. Each is a procedure problem rather than a code problem, and each is prevented by one small rule in the scripts we just walked through.

  • Orders stopped before traders
  • Downloads eating the rate budget
  • Live started by script

Lessons I: structure

Lessons 1 to 3

Now the lessons. One: the same engine runs in every mode, so a backtest exercises the code that will trade. Two: the dependency graph is a security boundary, so kestrel_trader contains no broker code at all. Three: single-owner threading instead of locks, so every piece of state has exactly one thread that may touch it.

  • Same engine in every mode
  • Dependency graph as boundary
  • Single-owner threading

Lessons 4 to 6

Four: deterministic ordering is proven with hashes, not assumed. Five: a pull-model venue, which fills orders only from information that has already happened, so lookahead cannot sneak in. Six: event time, not wall time, so a replay at any speed behaves the same as the real day.

  • Determinism proven by hashes
  • Pull-model venue
  • Event time, not wall time

Lessons II: safety

Lessons 7 to 9

Seven: fail closed on uncertainty, so when the system does not know, it does nothing. Eight: never retry an ambiguous order, because a timed-out request may have succeeded, as episode 23 showed. Nine: write-ahead before side effects, so the intent is on disk before anything leaves the machine.

  • Fail closed on uncertainty
  • Never retry an ambiguous order
  • Write-ahead before side effects

Lessons 10 to 12

Ten: share limits at the level the broker enforces them, so your internal accounting matches the real constraint. Eleven: encode once, fan out, so a bar is serialized one time and sent to every subscriber. Twelve: bounded queues everywhere, so a slow consumer causes a visible drop instead of silently growing memory.

  • Share limits where the broker enforces them
  • Encode once, fan out
  • Bounded queues everywhere

Lessons 13 to 15

Thirteen: atomic writes using a temporary file, fsync and rename, so a file is either the old version or the new one, never half of each. Fourteen: secrets live only in environment variables and are redacted in logs. Fifteen: reverse-engineered protocols are flagged as unverified and report themselves, which brings us to the honest status.

  • Atomic tmp, fsync, rename
  • Secrets only in env, redacted
  • Unverified protocols flagged

The Lessons Montage

Put the fifteen slides side by side and a theme appears. Most of them say the same thing in different words: assume something will fail, decide in advance what happens, and make the safe outcome the default. None of it is clever. It is mostly discipline, applied at every layer.

  • Fifteen slides
  • One theme: assume failure

Honest status

What Is Tested

Now the honest status. The offline research side is covered by golden tests and fakes, as we saw in episode 16. The paper procedure you saw today is a design for daily operation. And the FYERS binary websocket decoder was tested only against a fake server that we wrote ourselves.

  • Backtests and golden tests
  • Paper stack procedure
  • Fake-server tests

What Is Unverified

Its specification was reverse-engineered from the official SDKs, and some protocol fields are marked unverified in the code. That is why, on the first real connection, the code logs a one-time protocol facts line, so reality can be compared with the assumptions. The live order code is heavily guarded, but it should be seen as a design, not as something proven in production.

  • Protocol reverse-engineered from SDKs
  • Some fields UNVERIFIED
  • One-time protocol facts log line

Not Financial Advice

This course is educational. It is not financial advice, and nothing in it claims or implies that any strategy makes money. Any numbers shown in examples are illustrative. The goal was always to understand how a careful trading platform is built, not to promise anything about markets.

  • Educational only
  • No profit claims
  • Numbers are illustrative

Recap and goodbye

Recap of Today

To recap the day. The morning script waits for the operator's login, builds validated configs, and backfills gently if it starts late. The start script brings up md, orders, portal, UI and traders in dependency order, and live is always by hand. The stop script goes in reverse, with traders first and the order service given a long grace, and data jobs stay out of market hours.

  • morning.sh waits for login
  • Configs validated
  • Start in order, stop in reverse

The End of the Course

That is the end of the course: twenty-six episodes, from one engine in three modes to the daily routine that keeps the stack honest. The trading strategies themselves live in a separate playlist, so head there if you want the alpha logic that we deliberately left out.

  • 26 episodes
  • Strategies are a separate playlist