agentleFS
NT-NinjaTraderNT-NinjaTrader/mcp-skills/skills/event-watch/SKILL.md

event-watch

Skill8 starsChanged 4 months agoApache-2.0View on GitHub

Covers a high-volatility economic event calendar — FOMC, CPI, NFP, EIA, and OPEC. Also covers earnings-season awareness and session-boundary context — globex open, NY cash open, settlement, and EIA release windows. Reports upcoming events and filters them by the user's current positions. Explains a move after it happens (for example, "ES +24pts in 8min matches the hot CPI print"). Computes historical reaction-size magnitudes from prior releases. Proposes reaction-window bracket alerts via alerts-composer. It is strictly reactive, with no timer-based push. Use when the user asks "what's coming up", "economic calendar", "why did it move", "NY cash open", or "session open". Also use when the user names a specific event — CPI, FOMC, NFP, EIA, OPEC, or earnings.

The file

We split this skill into the rules it gives an agent

9 rules. About 0 are common, 2 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Every event you report must appear in the economic_calendar payload (after importance_filter.py).

    line 41
  2. Distinctive:

    Never invent numbers: Do not add any consensus, prior, actual, or rate level that is not in the payload.

    line 44
  3. Very specific:

    Day placement is mechanical: Place each event on the day its own date timestamp shows.

    line 45
  4. Very specific:

    If the response has hasMore: true, page with offset and run the filter over each page before you answer.

    line 66
  5. Very specific:

    All values are in raw points.

    line 110
  6. Distinctive:

    When the user's question falls near a high-vol boundary (NY cash open, EIA release, FOMC statement, etc.), surface the context:

    line 120
  7. Very specific:

    When the user holds a position exposed to a known-risk event, propose a reaction-window bracket alert.

    line 129
  8. Very specific:

    Use mean_abs_move from reaction_size.py as the per-side magnitude, or bump it by 1.5× for a "meaningful surprise" threshold.

    line 135
  9. Very specific:

    No third-party calendar scraping: Only the internal economic_calendar / earnings_calendar tools.

    line 165

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

event-watch

Purpose

Give the user volatility-event context on demand. Three things:

  1. Pre-event awareness on ask ("what's on the calendar tomorrow?")
  2. Historical reaction-size context ("how much does ES usually move on CPI?")
  3. Post-event attribution on ask ("why did it just spike?")

It also recognizes session boundaries: NY cash open, EIA release window, FOMC press conference. Those drive volatility even without an explicit event.

Environment routing

Calendars and event data only — no account binding. A sibling skill's account resolution might already pin the session to demo (simulation) or live. If so, stay on that same MCP server.

MCP tools used

Tool names below are bare. The NinjaTrader MCP server provides them. Your client adds its own prefix. See AGENTS.md at the repo root.

  • economic_calendar — upcoming releases with date, eventName, importance (1–5), actual, consensus, prior. These field names come from an external, unversioned passthrough API. Verify them against a live call — the MCP server's own schema does not guarantee them.
  • earnings_calendar — equity-index context
  • market_history — bar windows around past releases for reaction-size math
  • my_portfolio — dollar exposure in current positions. Prune with fields=["positions[].symbol","positions[].netPos","positions[].openPnL"].
  • market_snapshot — gives the current price when you propose bracket alerts. Prune with fields=["snapshots[].symbol","snapshots[].lastPrice","snapshots[].tickSize"].

Explicitly not allowed: third-party commercial calendar sites (investing.com, forexfactory, tradingeconomics) — TOS-restricted and redundant with data the server already exposes.

Design constraint — strictly reactive

Phrase outputs as "you asked near X", never "X is about to happen" (that would imply a timer this skill does not have). Proactive pushes belong on the MCP's SSE channel, not in a skill.

Grounding rules — the calendar is the tool output, nothing else

Every event you report must appear in the economic_calendar payload (after importance_filter.py). These rules are absolute:

  • Never add an event from memory, even one that "should" happen this week. If it is not in the tool output, it does not go in the answer.
  • Never invent numbers. Do not add any consensus, prior, actual, or rate level that is not in the payload. If a field does not appear in the payload, leave it out. Never estimate it.
  • Day placement is mechanical. Place each event on the day its own date timestamp shows. When you convert time zones, convert each event and re-bucket its day from the converted time. Never group events by the day the market "usually" releases them.
  • Disclose partial data. Say so if you only see or page through part of the payload. The list may be incomplete. An honest gap beats a filled one.

Workflow

1. Pre-event on ask — "what's coming up?" / "what's on the calendar?"

economic_calendar(fromDate=<today ISO-8601>, toDate=<today+3d ISO-8601>)
my_portfolio(fields=["positions[].symbol","positions[].netPos","positions[].openPnL"])

Call my_portfolio once for each account name you already know from an earlier tool call in this session. The tool requires an account argument — a call without one fails. If you do not know an account name yet, ask the user for one before you call my_portfolio. Never pass a guessed account name, like Sim101. The server rejects it.

Expect an oversized result. A multi-day calendar window often exceeds the inline tool-result cap. When that happens, your client saves the JSON to a file and returns the path instead of the payload. That file is the input to importance_filter.py — pass the saved path with --file. Do not explore the file with ad-hoc jq queries or reassemble the calendar yourself. The filter script is the only sanctioned reader. Never re-type or inline a large JSON payload into the command.

python3 scripts/importance_filter.py --file <saved-tool-result-path> \
    --products ES MNQ CL --min-importance 3

If the response has hasMore: true, page with offset and run the filter over each page before you answer. Otherwise, say the list covers only the first page.

importance_filter.py drops:

  • events with importance < --min-importance (default 3)
  • events whose name does not match a product-group keyword for the user's products (see the script's canonical map)

Output fields: kept, dropped_by_importance, dropped_by_relevance, events[] (each with matched_product_groups).

2. Reaction-size context — "how much does ES usually move on CPI?"

Gather the last N releases from economic_calendar. Use a fromDate far enough back for about 6 releases of the same type. CPI is monthly, so that is about 180 days. Then, for each release, fetch a bar window around the release time via market_history:

market_history(
  symbol="ESU6",
  barType="Minute",
  barSize=5,
  from=<release - 5min, ISO-8601>,
  to=<release + 30min, ISO-8601>
)

Structure each release + its bars into the input format:

{"events": [
  {"timestamp": "2026-01-15T13:30:00Z", "bars": [...]},
  {"timestamp": "2026-02-13T13:30:00Z", "bars": [...]},
  ...
]}

Save that as events.json and run reaction_size.py:

python3 scripts/reaction_size.py --file events.json --offset-minutes 5

Output fields:

  • samples — events that had enough bar data
  • mean_abs_move — avg |close(t+offset) − close(t0)|
  • mean_max_move_up / mean_max_move_down — directional max
  • range_mean / range_max / range_stdev — window range stats

All values are in raw points. Multiply by valuePerPoint × |netPos| for the dollar exposure.

Input fixture for shape reference: scripts/fixtures/cpi_reactions_synthetic.json.

3. Post-event attribution on ask — "why did it spike?"

Two inputs: recent price action (from market-context or market_history) + the nearest release from economic_calendar. Narrate the causal link where the timestamps line up. If no release falls within 10min, do not invent one — say "no scheduled release near the spike; could be headline-driven."

4. Session-boundary on ask

When the user's question falls near a high-vol boundary (NY cash open, EIA release, FOMC statement, etc.), surface the context:

"You asked 3 min before NY cash open — expect a vol spike and spread-widening in the first 10 min."

The boundary table lives in references/session-schedules.md — load that file and pick the nearest boundary.

5. Alert-proposal handoff

When the user holds a position exposed to a known-risk event, propose a reaction-window bracket alert. Then hand it to the user to submit via alerts-composer:

Propose: lastPrice(ESU6) > <entry + reaction_size> OR lastPrice(ESU6) < <entry - reaction_size>

Use mean_abs_move from reaction_size.py as the per-side magnitude, or bump it by 1.5× for a "meaningful surprise" threshold. Pass this expression to alerts-composer — this skill does not submit alerts.

Subjects must be unquoted. The DSL parser rejects lastPrice("ESU6"). The subject regex [\$@]?[\w\s\-\+/|]+ excludes double-quotes: the server's rule parser accepts only unquoted subject strings. alerts-composer/scripts/validate.py catches this offline before submission.

Output idioms

  • Pre-event: "CPI in 18 min (08:30 ET, consensus 0.3% m/m, prior 0.2%). Recent CPI releases moved ES by double-digit points within minutes. You're long 2 ES — run reaction_size.py for today's actual reaction range before you size a hedge or a stop. Options: flatten, hedge with MES short, or widen stops to 1.5× normal."
  • Reaction-size report: "Recent CPI releases moved ES by double-digit points in the first 5 minutes, with occasional larger outliers. Run reaction_size.py over the last N releases for the exact average, max, and spread before you size a bracket."
  • Post-event: "ES +24pts in 8min is consistent with the hotter-than- expected CPI (0.5% vs 0.3% consensus) released at 08:30 ET."
  • Session-boundary: "NY cash open in 3 min. Expect wider spreads and a vol burst in the first 10 min."

Disambiguation

  • vs market-context: market-context is intra-day analytics on one symbol (VWAP, ATR, profile). event-watch is cross-event history ("how does ES usually move on CPI?") + calendar surfacing.
  • vs position-watchdog: watchdog monitors one live position. If a known-risk event threatens that position, narrate with event-watch and propose a reaction-window alert.
  • vs pretrade-risk: pretrade-risk sizes an entry. If the entry sits near a known event, flag the event-derived volatility. Do not hard-gate the trade — the user decides.
  • vs alerts-composer: event-watch proposes an alert expression; alerts-composer constructs + submits it. One-way handoff.

Explicit non-goals

  • No proactive warnings. This skill has no timer. If the user does not ask, the skill does not act.
  • No third-party calendar scraping. Only the internal economic_calendar / earnings_calendar tools.
  • No price prediction. Reaction-size reports are historical magnitudes, not directional forecasts.
  • Not a strategy. Whether to hedge, flatten, or hold through an event is the user's decision. This skill shows magnitude and precedent.

Resource layout

  • scripts/importance_filter.py — filters the economic_calendar payload by min importance + product-group relevance. Input via stdin.
  • scripts/reaction_size.py — historical reaction-size math for a list of {event, bars} pairs. Input via stdin.
  • scripts/fixtures/ — synthetic samples for smoke-testing:
    • econ_calendar_synthetic.json — 8-event calendar for the filter
    • cpi_reactions_synthetic.json — 3 CPI releases with 5-min bars
  • references/session-schedules.md — US futures market hours + a high-vol boundary table (08:30, 09:30, 10:00, 10:30, 14:00, 14:30, 16:00 ET). Load it when a question falls near a session boundary.
  • references/event-playbooks.md — per-event narrative context (FOMC, CPI, NFP, PCE, PPI, ISM, EIA, OPEC, ECB, BOJ, earnings). Load it when you narrate the story behind one named event.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.