Install
openclaw skills install indian-stock-monitorDaily intelligent watchdog for Indian equity holdings (NSE/BSE). Silent by default — only notifies on Sev-1 critical events (governance shocks, surveillance...
openclaw skills install indian-stock-monitorAn intelligent investment-watchdog skill for Indian equities. Designed for silence by default — it only speaks up when something genuinely actionable happens to a stock you hold.
All data files for this skill live in the same directory as this SKILL.md file. Throughout this document, that directory is referred to as {SKILL_DIR}. When executing, resolve {SKILL_DIR} to the actual absolute path where you read this SKILL.md from.
Files used:
{SKILL_DIR}/portfolio.json — user's holdings, watchlist, preferences (managed by skill, never edited by hand){SKILL_DIR}/competitors.json — sector → peers mapping{SKILL_DIR}/severity-rubric.md — Sev-1/2/3 classification rules{SKILL_DIR}/sources.md — data source reference{SKILL_DIR}/state/last-run.json — persistent state (alerts already sent, results calendar, follow-ups){SKILL_DIR}/alerts/{YYYY-MM-DD}-*.md — archived alerts{SKILL_DIR}/state/portfolio-backup-{TS}.json — automatic backups before every portfolio write| User message contains... | Run |
|---|---|
portfolio.json _first_run: true flag, OR user says "set up stock monitor" / "I want to start monitoring my stocks" | Onboarding Workflow (Onboard-1) |
| "I bought ...", "I sold ...", "add ... to portfolio", "update my portfolio", "remove ...", "trim ...", "exit ...", or any image of a broker portfolio | Portfolio Update Workflow (Update-1) |
| "check my stocks", "morning brief", "anything I should know", "scan my portfolio", scheduled daily run | Daily Monitoring Workflow (Step 1) |
| Ambiguous | Ask the user which they want |
The skill's portfolio.json starts with _first_run: true and empty holdings. Detect this on first invocation. NEVER assume the user wants to skip — always offer to set up.
Greet warmly. In plain language, explain what the skill does in 3 lines:
Then ask if they'd like to set it up now.
Use AskUserQuestion (if available) OR ask in chat:
"How would you like to share your portfolio?"
- Drop a screenshot of my broker app (Zerodha Kite, Groww, Upstox, Angel One, etc.) — easiest
- Describe in text (e.g., "50 HDFC Bank at avg 1620, 10 Reliance at 2900")
- Skip for now — I'll come back later
Based on their choice, follow the same logic as the Update Workflow (Update-2 onwards).
Ask three short questions (use AskUserQuestion if available):
Save these into portfolio.json preferences block.
Offer to create a scheduled task that runs the Daily Monitoring Workflow every weekday at 8:30 AM IST. If the user agrees, use mcp__scheduled-tasks__create_scheduled_task with cron 30 8 * * 1-5 and a prompt that invokes this skill. If they want a different time, use that.
Offer: "Want me to do a quick first-look scan of your holdings now to flag anything sitting in the last 7 days?" If yes, run the Daily Monitoring Workflow once. If no, just confirm setup is done and let them go.
Set _first_run: false in portfolio.json. Save. Done.
The user does NOT edit portfolio.json by hand. You handle it. They describe changes in text OR drop a screenshot of their broker app and you parse it.
Trigger phrases (match on intent, not exact wording):
Read the image directly using vision. Extract: ticker (or company name → resolve to NSE ticker), quantity, average buy price. Note the broker if visible.
Common broker layouts:
If the screenshot is unclear or partially visible, ask the user to re-upload or fill in gaps in text. Don't guess.
CRUCIAL — full vs partial screenshot ambiguity: Before computing the diff, ASK: "Is this your complete portfolio (so I should remove anything held but not shown), or just additions/changes to layer onto your existing holdings?" Default behaviour: layer onto existing — never silently remove holdings based on absence from a screenshot.
If the screenshot looks truncated (scroll indicator visible, "+N more" text), tell the user it looks partial and ask them to scroll & re-upload.
Parse natural language:
competitors.json → ticker_to_sector. If found, use it.sector_peers for the ticker.competitors.json.sector blank.Read {SKILL_DIR}/portfolio.json. Compute proposed new state in memory.
NEVER write portfolio.json without explicit user confirmation. Show a clear diff:
Proposed portfolio update:
✱ ADD HDFCBANK qty: 50 avg: ₹1,620 sector: Private Banks
✏ UPDATE TCS qty: 30 → 10 (sold 20) avg: ₹3,450 (unchanged)
✗ REMOVE WIPRO (full exit)
Summary: +1 new holding, 1 trim, 1 exit. Net 6 holdings after.
Apply these changes? (yes / no / edit)
Wait for explicit "yes" / "confirm" / "apply". If "edit", adjust and re-show diff.
On confirmation:
portfolio.json to {SKILL_DIR}/state/portfolio-backup-{YYYY-MM-DD-HHMMSS}.json.portfolio.json preserving structure.competitors.json → ticker_to_sector.Weighted average:
new_avg = ((old_qty × old_avg) + (new_qty × new_buy_price)) / (old_qty + new_qty)
new_qty_total = old_qty + new_qty
Show the calculation in the diff.
If user states a new average explicitly ("my new avg is X"), use their number.
After write, if meaningful change (new sector entered, large addition, full exit), offer:
You are an intelligent investment advisor for Indian equities. Job: silence by default. Only ping the user when something genuinely actionable shows up. False positives erode trust faster than missed Sev-2 noise.
{SKILL_DIR}/portfolio.json. If _first_run: true OR holdings is empty, route to Onboarding Workflow instead. Do NOT silently exit.holdings.competitors.json. Build the peer set.{SKILL_DIR}/state/last-run.json for what's already been alerted.Quick web search for: US close (Dow / Nasdaq / S&P 500), GIFT Nifty / SGX Nifty, Brent crude, USD/INR, any Asian market shock.
Only flag if a global shock could directly hit a held name (crude up 5% with HPCL/BPCL → margin pressure flag; USD/INR sharp move with TCS/Infy → tailwind/headwind).
For each held ticker, run these in parallel where possible:
Search: site:nseindia.com {COMPANY_NAME} announcement last 1 day; site:bseindia.com {COMPANY_NAME} last 1 day.
Look for: results dates, board meetings, auditor changes, KMP changes, credit rating updates, pledge disclosures, SAST/PIT, litigation, plant disruptions.
{COMPANY_NAME} news filtered to last 1 day, prefer Moneycontrol / ET / Reuters / Mint / Business Standard{COMPANY_NAME} SEBI (last 7 days){COMPANY_NAME} CBI ED IT raid (last 30 days, only flag if NEW){COMPANY_NAME} downgrade (last 7 days, brokerage or rating agency)For each unique sector across holdings: did any peer announce results / guidance / material news? Did any sector regulator (RBI, USFDA, GST council, etc.) issue something? Cross-map peer concerns to held names — 2+ peer Sev-1 in 7 days = industry stress trigger.
Classify each signal against severity-rubric.md. Default to silence. Only Sev-1 surfaces.
Suppression rule: If you've already alerted on the same signal_id in the last 14 days, suppress.
Triggered when Step 3e finds new results published.
For the held stock:
Same as Step 5 but for peer results. Output: one paragraph per peer (QoQ delta + concall tone) and one sector-level read: "Industry trend looks {strong / mixed / weak / deteriorating}." Surface ONLY if it changes the read on a held stock.
Notify only if:
Otherwise — produce nothing in chat. Just update state and exit.
EXCEPTION: if user's delivery preference is daily_brief, always post a one-liner ("All clear — no Sev-1 across {N} holdings as of {time}.").
Save at {SKILL_DIR}/alerts/{YYYY-MM-DD}-alert.md AND surface in chat:
🔴 STOCK ALERT — {date}
{TICKER} — {one-line headline}
Severity: Sev-1 | Sector: {sector}
What happened: {2-3 lines, factual}
Why it matters for YOU ({horizon} holder):
- {bullet 1}
- {bullet 2}
Suggested action: {Sell / Trim / Watch closely / Hold but reassess after X}
Confidence: {High / Medium / Low}
Sources:
- [Title](URL)
- [Title](URL)
Counter-view: {one line — what could make this NOT critical}
If multiple stocks have triggers, repeat the block per ticker.
Update {SKILL_DIR}/state/last-run.json with everything you flagged AND every signal_id you considered (so suppression works).
_first_run: true or holdings empty, route to Onboarding — don't try to scan an empty portfolio.The user can also trigger ad-hoc:
In ad-hoc mode, run the same workflow but if nothing critical, give a one-line "All clear — no Sev-1 triggers across {N} holdings as of {time}." rather than total silence.