agentleFS
NT-NinjaTraderNT-NinjaTrader/mcp-skills/skills/scale-manager/SKILL.md

scale-manager

Skill8 starsChanged 4 months agoApache-2.0View on GitHub

Scales into or out of an existing futures position. Actions include add to winner (pyramid), take partial at 1R, and move stop to breakeven. Actions also include trail stop, close on reversal, and ladder an entry across a price band. Computes weighted cost basis, before/after dollar risk, R-multiples, and P&L impact. Proposes the exact modify_order / place_order / close_position payloads for the user to approve. Never executes. Use when the user asks to "scale out", "scale in", "take partial", "add to winner", "pyramid", "trim", "add more", "move stop to breakeven", "trail stop", "ladder entry", "split the order", or "close half". For INITIAL entry sizing use pretrade-risk; for live-position monitoring use position-watchdog.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

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

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

    If netPos == 0 and the action is scale_in/out, defer to pretrade-risk.

    line 55
  2. Distinctive:

    After approval, the user runs one pre-flight and one order per leg:

    line 147

≈ “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

scale-manager

Purpose

Turn "take partial off here" / "add on this break" / "trail the stop" into correct math and approved order payloads. This skill is a sibling to pretrade-risk (which handles the initial entry) and position-watchdog (which monitors a live position). This skill owns all in-flight position adjustments.

Environment routing

Demo (simulation) and live are two separate MCP servers. Account names are unique to one server. Once a workflow resolves an account on a server, every downstream call must go through that same server. This includes my_portfolio, market_snapshot, place_order, create_alert, history tools, etc. Cross-routing fails or hits the wrong environment.

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.

  • my_portfolio — current netPos, netPrice, and working orders (the source of bracket stop/target prices). Prune with fields=["positions[].symbol","positions[].netPos","positions[].netPrice","workingOrders[]"].
  • order_details — event/fill history for one known orderId.
  • market_snapshot — lastPrice, tickSize, valuePerPoint. Prune with fields=["snapshots[].symbol","snapshots[].lastPrice","snapshots[].tickSize","snapshots[].valuePerPoint"].
  • estimate_order — final feasibility gate for scale-ins (the server's pre-trade risk check)
  • risk_settings — daily-loss budget, for the cross-check in Step 4
  • Final execution paths (user approves): modify_order, place_order, close_position

Skills consumed

  • market-context — ATR for band spacing, regime for pyramid-eligibility
  • pretrade-risk — pending-qty rule for scale-ins (included-in-estimate)

Workflow

1. Classify the intent

User phrasingAction
"take partial", "trim 50%", "half off"scale_math.py --action partial_exit --pct 0.5
"scale out", "close 2 of 4"scale_math.py --action scale_out
"add to winner", "pyramid", "add more"scale_math.py --action scale_in
"move stop to breakeven"modify_order on bracket stop leg
"trail stop to X"modify_order on bracket stop leg
"ladder into 3 at 7148–7142"ladder.py --mode even

The full pattern library, with preconditions and narrations, lives in references/scale-patterns.md.

2. Gather current state

my_portfolio           # netPos, netPrice, workingOrders[] (bracket stop/target prices)
market_snapshot(...)   # lastPrice, tickSize, valuePerPoint

If netPos == 0 and the action is scale_in/out, defer to pretrade-risk. This is an initial entry, not a scale.

3. Compute the scale math

Save the script's JSON input to a file and pass its path with --file. Never re-type or inline a large JSON payload into the command.

For scale-in / scale-out / partial-exit:

python3 scripts/scale_math.py --file position_state.json --action <scale_in|scale_out|partial_exit>

The caller maps input fields from the MCP response's camelCase into the script's own JSON contract. Fields: direction, current_qty, current_basis, stop_price, current_mark (from lastPrice), value_per_point (from valuePerPoint), tick_size (from tickSize), plus action_qty and action_price (or --pct for partial_exit).

Output fields:

  • basis_after — new weighted cost basis (scale_in only; scale_out leaves the basis unchanged on the remainder)
  • dollar_risk_before_action / dollar_risk_after_action — critical for scale-in. A scale-in typically RAISES dollar risk, because the combined qty × (new_basis − stop) exceeds the original risk.
  • R_before / R_after at the current mark
  • realized_dollars — money booked on a scale_out (0 for scale_in)

For ladder entry:

python3 scripts/ladder.py --file anchor_state.json --mode <even|atr|custom> --legs N ...

Returns per-leg price + qty + weight, combined weighted basis, and best/worst-case fill scenarios.

4. Surface the dollar and R impact to the user

Three must-haves in the narration:

  1. Dollar realized (for exits) or dollar risk change (for adds).
  2. R before vs after — did the trade get easier or harder to manage?
  3. Compliance with the daily-loss budget (cross-check against risk_settings.dailyLossAutoLiq for scale-ins that expand risk).

5. Build the MCP payload (for user approval)

Never call modify_order, place_order, or close_position from this skill. This step writes payload text only. Show the plan and the exact payloads, then wait for user approval. The user submits every call in this step. So every block below describes the user's approved sequence, not an action this skill takes.

See references/scale-patterns.md § "Converting output to MCP payloads".

Scale out — close_position always closes the full position. It takes no quantity parameter. A partial exit needs a separate market order for the offset quantity. It also needs a resize of BOTH remaining bracket legs to match — never the target leg alone. The server does not link the exit order and the two bracket legs together. A stop that keeps the ORIGINAL quantity over-protects the smaller remaining position. Worse, a same-quantity stop can flip the trade to the opposite side if it fills. Example: close 2 of a long 4, and leave a same-quantity Sell Stop for 4. If that stop triggers, the trader now holds a short 2, not a flat position. A same-quantity target carries the mirror risk — a full fill flips the position too.

place_order(action=<opposing side>, orderType=Market, quantity=<off_qty>, symbol=<sym>, timeInForce=<Day|GTC|IOC|FOK|GTD>)

The user waits for the exit fill to confirm. The user then pulls my_portfolio again, and checks the new netPos against remaining_qty. The plan needs both leg IDs from workingOrders[] (see the "Stop move" step below for the filter). When the server sets bracket.parentId or bracket.ocoId, use it to confirm the pair.

modify_order(orderId=<bracket_stop_leg_id>, quantity=<remaining_qty>)
modify_order(orderId=<bracket_target_leg_id>, quantity=<remaining_qty>)

remaining_qty is the current quantity on either leg minus off_qty.

If a resize call fails, the position now carries a mis-sized leg. The caller can also skip the resize. In either case, do not treat the scale as done. Tell the user which leg still carries the ORIGINAL quantity. Propose the resize again first, before any other change to the position.

Scale in — the place_order payload for the add:

place_order(
  action=<Buy|Sell>,                       # same side as current direction
  orderType=<Market|Limit>,
  quantity=<add_qty>,
  price=<add_price>,                       # for Limit
  symbol=<sym>,
  timeInForce=<Day|GTC|IOC|FOK|GTD>,
)

For limit scale-ins, consider the pending-qty rule. The server-side pre-trade risk check includes all open, filled, and pending qty when it rates the order. If you chain multiple scale-ins as limits, the SECOND order's feasibility check includes the FIRST's pending qty. See pretrade-risk/references/risk-rules.md for details.

Stop move (breakeven / trail):

modify_order(orderId=<bracket_stop_leg_id>, stopPrice=<new>)

Find the stop leg id in my_portfolio's workingOrders[] — filter by symbol, an opposing action, and orderType: Stop|StopLimit. Find the target leg the same way, with orderType: Limit and price set instead of stopPrice. When bracket.parentId or bracket.ocoId is present, use it to confirm the two legs share one entry. The scale-out resize above needs both leg IDs — reuse this same filter for that step.

modify_order.stopPrice is an absolute price, in contract-native units — the same convention as scale_math.py's output. This is asymmetric with place_order.brackets[].stopLoss, which is a signed delta from entry (see pretrade-risk/SKILL.md §4a). Pass the new absolute stop price straight through. Do not convert it to an offset.

No server-side pre-flight exists for modify_order — estimate_order covers new orders only; it takes no orderId parameter. So validate the proposed stop yourself, before you show the payload:

  • Long position: the new stop must sit below the current mark. It must also stay on the safe side of any breakeven cross. A breakeven move that lands at or just past entry is fine. A trail that crosses through the current mark flattens the market position.
  • Short position: mirror this — the new stop must sit above the current mark.

Wrong-side stops trigger immediately on submission with no warning.

Ladder entry — one order per leg:

After approval, the user runs one pre-flight and one order per leg:

for leg in legs:
  # Pre-flight each leg — the server's pre-trade risk check counts
  # already-pending working orders from prior legs in this loop.
  estimate_order(
    account=acct, symbol=sym, action=..., quantity=leg.qty,
    orderType=Limit, price=leg.price
  )
  place_order(
    action=..., orderType=Limit, quantity=leg.qty, price=leg.price,
    timeInForce=<Day|GTC|IOC|FOK|GTD>,
  )

Each placed leg becomes pending qty for the next leg's pre-trade check. See pretrade-risk/references/risk-rules.md § pending-qty rule. A scale-in with its own bracket follows the offset rule from pretrade-risk/SKILL.md §4a — place_order.brackets[].profitTarget and .stopLoss carry a sign. They are deltas, not absolute prices.

6. Final feasibility check

For any scale-in that expands qty (a single add or each ladder leg), end with estimate_order on the proposed payload. It surfaces the authoritative pre-trade risk check result. If feasible: false, report the reason and do not submit.

estimate_order does NOT cover modify_order. The LLM must sanity-check stop-move proposals against the side-of-current-mark rule in Step 5's "Stop move" subsection. There is no server-side dry-run for modifies.

7. Emit the plan and payloads; wait for user approval

This restates the gate at the top of Step 5. Never call modify_order, place_order, or close_position from this skill. Always show the plan and the exact payloads, then stop. The user submits the approved calls.

Output idioms

Classic partial at 1R:

"Long 4 ES @ 7150, mark 7168 (2R). Propose: close 2 at market — realizes $1,800, leaves 2 at the same stop price 7141 ($900 at risk). After the fill confirms, resize BOTH remaining legs to quantity 2: place_order(action=\"Sell\", orderType=\"Market\", quantity=2, symbol=\"ESU6\"), then modify_order(orderId=<stop_leg>, quantity=2) and modify_order(orderId=<target_leg>, quantity=2). Approve?"

Pyramid with risk flag:

"Add 2 ES @ 7168 → new basis 7156, dollar risk at stop 7141 jumps from $1,800 to $4,500 (2.5× current). Options: (a) Approve as-is (accepts higher risk). (b) Tighten stop to 7155 simultaneously → risk stays $300. (c) Treat as a separate trade with its own tighter stop. estimate_order says feasible with margin headroom."

Ladder entry:

"3-leg ladder 7148 / 7145 / 7142 (6pt band, ≈0.75×ATR). Qty 1/1/1. If only the top leg fills, basis $7148 (1 contract, lightly sized). If all fill, avg basis $7145 across 3 contracts. Combined risk at stop 7140 = $450 (anchor only) to $750 (all fill). Payloads: 3× place_order(orderType=Limit, quantity=1, price=...)."

Design constraints

  • Never executes. Produces plans and payloads. Even after the user approves, the user triggers the MCP call, not the skill.
  • Dollar-risk-aware. Scale-ins typically grow dollar risk. Always surface the before/after delta so the user decides eyes-open.
  • Tick-snapped. ladder.py snaps leg prices to the symbol's tick grid. place_order rejects bad prices anyway, but the snap keeps the output clean.
  • Server-authoritative. estimate_order is the last gate on scale-ins. If it says no, the skill reports that and stops.

Disambiguation

  • vs pretrade-risk: pretrade handles the initial entry (netPos = 0). scale-manager handles netPos ≠ 0 adjustments. Always check netPos first and route accordingly.
  • vs position-watchdog: watchdog reports health (P&L, R, distance to stop, flags) informationally. scale-manager produces executable plans. Watchdog can PROPOSE a scale via its alert hook; scale-manager validates and composes the payload.
  • vs close_position MCP directly: close_position always closes the full position — it takes no quantity parameter. For a literal "close half the ES position", route through this skill's partial-exit pattern (Step 5) instead. Use close_position directly only when the user wants the whole position flat.

Explicit non-goals

  • No execution. The MCP order tools stay in the user's approval loop.
  • No indicator-driven triggers. This skill proposes a scale when the user asks. It does not watch the market and auto-propose. (Alert-based monitoring is alerts-composer + position-watchdog.)
  • No cross-account rebalancing. Scales apply to ONE symbol on ONE account.
  • No pyramid recursion. The math supports nested scale-ins, but the narrations cover only one add at a time. Ask the user explicitly before you compound them.

Resource layout

  • scripts/scale_math.py — scale-in / scale-out / partial-exit math. Stdin JSON for position state and action params. Actions: --action scale_in|scale_out|partial_exit.
  • scripts/ladder.py — ladder entry splits. Modes: even, atr, custom. Weighting: equal, front, back, custom. Integer-quantity allocation uses the largest-remainder method, so the total exactly matches the input total_qty.
  • references/scale-patterns.md — 7 named patterns: partial at 1R, runner, pyramid, and ladder mean-reversion. It also covers ladder breakout retest, pre-event scale-out, and full exit on reversal. The file also has preconditions, narrations, and the MCP-payload translation table. Load it when you pick a pattern or build the MCP payload.

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.