Week 07 · Build Your Own Automated Options Trading System

Telegram — your bot's voice,
wired before money moves.

Your bot cannot tap your shoulder. Telegram is the tap. Wire it before you place a single real order — never after.

Week 7 of 12
Four severity levels
Entry · exit · end-of-day pings
This week, in one glance

Same five beats. New topic.

1
Idea
Your bot cannot tap your shoulder. Telegram is the tap. Wire it before Week 9.
2
Outcome
Four message types working. You know what each looks like at 3 AM.
3
Vocabulary
bot token · chat ID · severity (info/warn/error/critical) · dedupe key · retry policy
4
Hands-on
Bootstrap a Telegram bot. Wire your Week-6 strategy to ping at entry, exit, end-of-day.
5
War story
Every routine adjustment buzzed the phone. Operator muted the bot. A real emergency got muted too.
1 · The idea

Logs are for evenings. Telegram is for now.

What you want — a quiet, useful feed

Trading-info bot · today
09:15 Strategy started · NIFTY · 3 lots planned just now
09:25 ENTRY CE · 24800 · ₹68 · 1 lot 3m ago
11:30 EXIT CE · ₹42 · +₹1,300 2h ago
15:14 Squareoff complete · no residuals just now

What you must also wire — the panic line

Trading-info bot · just now
CRITICAL · Position open at broker without SL · NIFTY 24800 PE qty=195
ERROR · SL placement failed after 3 retries · check broker
WARN · Margin shortfall · skipping tranche 3
Routine events log silently. Real problems light up your phone. Keep the channels separate or both stop working.
Four severity levels — what each one means

Pick the right rung for the right event.

INFO
Routine. Things going as planned.
Strategy started · tranche 1 fired · day-end summary
WARN
Something unusual, but the strategy can handle it.
Tranche skipped (low margin) · WebSocket reconnected · partial fill
ERROR
Action failed. Strategy is degraded but not dangerous.
Order rejected · 3 retries exhausted · API timeout on read
CRITICAL
Money is at risk right now. Human action required.
Position open with no SL · duplicate fill detected · broker unreachable
If every entry is "critical," none of them are. Severity is a budget — spend it carefully.
2 · By the end of this week

Four message types. Working. Tested.

You have your own Telegram bot — created via @BotFather — with a saved bot_token and the chat_id for your own chat.
A send_alert(text, severity) function works from Python on your cloud server. Calling it with each of the four severities lands a message on your phone.
Your Week-6 strategy emits three pings: at entry, at exit, at end-of-day. All INFO. None of them buzz on silent mode.
You can read the bot's output at 3 AM in the dark and instantly tell: is anything wrong?
By Sunday, the channel should feel boring. Boring is the goal — Week 9's first live order will break that calm exactly once.
3 · New vocabulary

Five words. Use them this week.

bot token
The long secret string Telegram gives you for a new bot. Lets your code post messages as the bot.
7234567:AAH…
chat ID
The numeric ID of the chat the bot should post into. Yours is the chat you start with the bot.
123456789
severity
The four-rung ladder: info, warn, error, critical. Decides how loud the alert is.
info · warn · error · critical
dedupe key
A string that says "this is the same alert as before." Stops the bot spamming the same message 500 times.
sl_failed:NIFTY:24800CE
retry policy
What the alert function does if Telegram is briefly down. Try again, but not forever, and never block the strategy.
3 retries, 1s back-off
Two of these — dedupe key and retry policy — are the difference between "useful" and "spam machine."
4 · The hands-on bit — your task

Make the bot. Wire three pings.

What to do this week (90 min, once)

  1. Create the bot. Open Telegram. Message @BotFather. Type /newbot. Name it (e.g. Trading-info). Save the bot_token it gives you.
  2. Find your chat ID. Start a chat with your new bot. Send any message. Then call https://api.telegram.org/bot<TOKEN>/getUpdates in the browser. Your chat_id is in the JSON.
  3. Add both to .env on your cloud server. Never to code. Never to a commit.
  4. Write alerts.py with a send_alert(text, severity) function. Ask Claude to scaffold it with a 3-retry/1s back-off policy.
  5. Wire the three pings. In your Week-6 strategy.py: send an INFO at startup, at every entry decision, and one summary at end-of-day.
  6. Test all four severities. Send one of each from a Python REPL. Check your phone for each. Note how each one feels.
No live trading yet. The point this week is the channel — not the orders. Wire it first.
5 · A real war story

Every routine adjustment buzzed the phone. So the operator muted it.

Every SL move, every partial fill, every minor reconnection was a CRITICAL. The phone buzzed 80 times a day. The operator hit "mute notifications for 8 hours." That afternoon, a real emergency fired — naked position, no SL — and the alert sat silent. Found out at end-of-day. Real money damage.

Before — alert spam

Trading-info · today (muted)
CRITICAL · SL moved up by ₹2
CRITICAL · partial fill 130/195
CRITICAL · WebSocket reconnected
CRITICAL · SL moved up by ₹1
CRITICAL · 80 more like this …
CRITICAL · POSITION OPEN, NO SL · NIFTY ← missed

After — calibrated severity

Trading-info · today
INFO · SL moved · routine
INFO · partial fill 130/195 (within budget)
INFO · WebSocket reconnected
CRITICAL · POSITION OPEN, NO SL · NIFTY 24800 PE · you'll see this one
5b · A second war story · 2026-05-19

The exit was skipped on purpose. The verifier didn't get the memo — and screamed.

Expiry day. A short call had decayed to LTP = ₹0.05. The squareoff code intentionally skipped closing it — paying brokerage to buy back ₹0.05 options is worse than letting them expire worthless. Sound logic. But the same script ran a defence-in-depth residual check right after: re-query the broker, alert on anything still open. That check had no idea about the skip — saw a residual short, fired three CRITICAL alerts in a row for the same expected, intentional position.

Before — verifier blind to its own skip

Trading-info · 15:14 IST · expiry day
INFO · Skipping squareoff · LTP ₹0.05 ≤ ₹0.10 · let expire
CRITICAL · POSITION STILL OPEN · NIFTY 23700 CE · qty −520
CRITICAL · RESIDUAL after squareoff · OC believed closed, broker shows open
CRITICAL · EQUITY SQUAREOFF · 1 position FAILED to close

After — skip set passed downstream

Trading-info · 15:14 IST · expiry day
INFO · Skipping squareoff · LTP ₹0.05 ≤ ₹0.10 · let expire
INFO · Expected residual (low-LTP skip) · qty −520 · letting expire worthless

The fix wasn't to silence the verifier — that would have masked real residuals tomorrow. The fix was to pass the set of intentionally-skipped instrument IDs from the squareoff step into the verifier, and treat those as expected. One field, two call sites. Real residuals still scream.

The lesson, pinned

If everything is urgent, nothing is urgent.

80+
alerts/day during the spam phase
8 hrs
muted by the operator — including the real emergency
4
severity rungs today · routine events log silently

The defence is not "send more alerts." It's calibration. Routine events go to the log file. Unusual events go to Telegram at INFO/WARN. Money-at-risk events go at CRITICAL — and only those. Add a dedupe key so the same alert never fires twice. Add a retry policy so a brief Telegram outage doesn't block the strategy. Both must exist before you go live.

The alert channel is a relationship. Spam it and the operator stops listening — usually right before they need to.
A subtler rule · 2026-05-20

Severity rides the consequence, not the event.

"Chain fetch failed" is the same event. But the severity isn't a property of the event — it's a property of what happens next. Will the strategy retry on the next tick? Or is this tranche dead for the day?

Same event · strategy retries

First Strike: chain-fetch raised. Engine retries next tick. Trigger is rolling — minutes still in budget.
→ WARN

Operator sees it in the feed at end of day, no phone buzz. If it persists, a dedupe key keeps the noise to one alert per 60 s.

Same event · tranche is dead

RSI Sniper: chain-fetch raised. Tranche marked terminal — won't fire again today. No retry window.
→ CRITICAL

A scheduled entry just evaporated. Operator must know now — manual rescue may still be possible if they catch it inside 15 minutes.

If retry is on the table, it's WARN. If retry is gone, it's CRITICAL. The event is silent on which one.
When one codebase, many strategies

Same condition → same severity. Or the operator can't trust the channel.

A real audit. Six strategies in the same repo. The holiday-file-missing check fired CRITICAL in one and WARN in another. Operator skim at 09:14 IST: same root condition, two different responses. Eventually you stop trusting the colour.

Condition
Strategy A
Strategy B
Canonical
Holiday file missing
CRITICAL
WARN
CRITICAL
Insufficient margin (skip tranche)
WARN
CRITICAL
WARN
API unreachable > 30 s
CRITICAL
CRITICAL
CRITICAL ✓
Day-end summary
INFO
INFO
INFO ✓
Spot quote unavailable
CRITICAL
(no alert)
CRITICAL
Audit periodically. The canonical column is the only one that matters — bring outliers in line.
Tags are UI · so design them like UI

Short, unique, mandatory. Every line.

When multiple strategies share one Telegram channel, the operator's eyes look for the tag first. Two-to-three letter prefixes scan in a glance; verbose ones eat the message body on mobile.

✗ Inconsistent / verbose

MCX: SL HIT CRUDEOIL 6400CE
RSI_SNIPER: T1 ENTRY: rsi=72.3 dte=0 legs=PE…
OC: T2 BOTH legs placed
(no tag) WebSocket reconnected after 3s

One verbose tag breaks the scan. One missing tag and you cannot tell which strategy fired.

✓ Uniform · two or three letters

MCX: SL HIT CRUDEOIL 6400CE
RS: T1 ENTRY: rsi=72.3 dte=0 legs=PE…
OC: T2 BOTH legs placed
DD: WebSocket reconnected after 3s

Pinned in one config field — ALERT_PREFIX. Auto-prefixed by the _alert() helper. Operator's eyes adapt in a week.

A tag is a promise. If you can't keep it short and unique, you can't ship the message either.
Process · keeping the inventory honest

A drift gate so the playbook cannot fall behind the code.

The alert inventory is a doc. Docs rot. Solution: a git pre-commit hook that refuses commits which add new send_alert() sites without updating the playbook in the same commit.

1
Detect
Hook greps the staged diff for added lines that introduce send_alert( or self._alert(.
git diff --cached -U0 | grep '^\+.*send_alert('
2
Compare
Is docs/telegram-notification-playbook.md also staged in the same commit?
git diff --cached --name-only | grep playbook.md
3
Decide
No new alerts → exit 0. New alerts + playbook → exit 0. New alerts without playbook → exit 1, commit blocked.
exit 1 # with a helpful message
✓ Pass
no new send_alert lines
✓ Pass
new alerts + playbook staged together
✗ Block
new alerts, playbook missing → commit refused
Inventory drift is invisible until something fires unexpectedly. The hook makes drift expensive at the right moment — at commit, not at 10 AM live.
Week 7 — takeaway

Wire the voice before the wallet.

A trading bot without alerts is a trading bot you can't trust at 3 AM. A trading bot with poorly-calibrated alerts is a bot you'll mute the day before it matters. Get severity right, dedupe the chatter, retry the network. Then — and only then — let money move.

End of Week 7

Next: Safety nets.

source: cowork/Course_Outline_12_Weeks · Week 7
← → navigate · F fullscreen · click to advance
1 / 11