Stop-Loss & Take-Profit
Automatic client-side exits to protect positions
Prediction markets don't give you a native stop order. Polymarket's CLOB and Kalshi both let you place limit and market orders, but neither will automatically close a position when the price moves against you. If your YES contract drops from 0.60 to 0.20 while you're asleep, nobody is watching it but you. Predite's **Stop-Loss & Take-Profit** layer fills that gap with synthetic, client-side exit rules that monitor your open positions and fire a close order when your trigger is hit.
This works on both **paper positions** and **live bot positions**, and it's built specifically to protect you against the thing that hurts most in low-liquidity prediction markets: **gap risk**.
## What This Feature Does
A stop-loss order is a rule attached to one open position. You define a price (or a percentage move from entry), and Predite watches the market until that level is touched. When it is, the position is closed automatically and logged.
Predite supports three trigger kinds:
- **Stop-loss** β closes the position when the price of the side you hold falls to or below your trigger. This caps your downside.
- β’**Take-profit** β closes the position when the price of the side you hold rises to or above your trigger. This locks in gains so a winner doesn't round-trip back to break-even.
- β’**Time-stop** β closes the position at a fixed timestamp regardless of price. Useful for event-driven trades where you only want exposure through a known window (an earnings print, a debate, a Fed decision) and want out afterward whatever happens.
Every order is **side-aware**. Predite knows whether you're long YES or long NO and evaluates the trigger against the correct leg. Polymarket quotes YES and NO as a complementary pair (NO price = 1 β YES price), so if you hold NO at 0.30 and set a stop at 0.20, Predite tracks the NO leg (`1 β yesPrice`) and fires when *your* effective price hits 0.20 β not when the YES quote does. You always reason in terms of the contract you actually own.
## Why It Matters: Gap Risk in Thin Markets
Most prediction markets are thin. A market that trades a few thousand dollars a day can have a wide spread and a shallow book. When news breaks, the order book doesn't slide smoothly from 0.55 to 0.45 β it **gaps**. The best bid vanishes, and the next resting bid might be 15 cents lower. By the time you notice, you've already crossed the level where you wanted out.
A stop-loss won't magically get you filled at your exact trigger in a gapping market β no stop on any venue can do that. What it does is guarantee that the moment Predite observes price at or through your level, it submits a close instead of waiting for you to wake up and react. In practice that's the difference between exiting near your plan and exiting at whatever's left after a cascade. For event-driven trades, the time-stop is often the cleaner tool: it doesn't care about a momentary wick, it just removes exposure once your thesis window has closed.
This is also why we treat take-profit as a first-class trigger. In thin markets a position can spike on a single large order and then mean-revert within minutes. A take-profit lets you harvest that spike instead of watching it evaporate.
## How Monitoring Works: Client-Side + Cron
Predite monitors your exits in **two layers**, and understanding both tells you exactly what to rely on.
### Layer 1 β Client-side (browser)
While you have the dashboard open, the **Positions** view polls live prices and evaluates your active triggers in the browser in near-real-time. You'll see the distance-to-trigger update continuously and get an instant in-app toast the moment a level is touched. This layer is responsive and great while you're actively trading, but it only runs when a tab is open.
### Layer 2 β Server-side cron (the durable layer)
The layer that actually protects you when you're away is the **server cron**. A scheduled job (`/api/cron/check-stop-losses`) runs **every 2 minutes**, 24/7, independent of any browser. On each run it:
1. Loads every order with `status = 'active'`. 2. Groups them by market and fetches current prices from the Polymarket Gamma API in batches (so 40 orders on the same market cost one price lookup, not 40). 3. Evaluates each trigger against the live price (or, for time-stops, against the clock). 4. For any order that fires, it **atomically claims** the order (flips it to `triggered` only if it's still `active`), then submits the close.
Because the cron is the source of truth, **you do not need to keep a tab open** for your stops to work. The client-side layer is a convenience for instant feedback; the cron is the guarantee.
The 2-minute cadence is the practical resolution of the system. Stops are evaluated on a polling interval, not tick-by-tick, so in a violent gap your real exit can be a couple of minutes and several cents past your trigger. Set levels with that headroom in mind rather than placing a stop one cent below the current price.
## Paper vs Live Behavior
The same rules apply to both modes, but what happens on a trigger differs.
### Paper positions
For a paper position, a triggered exit closes the position **inside Predite's simulator**. The cron marks the position closed at the observed exit price, computes realized P&L from your entry, share count, and direction, and writes it to your paper history. Nothing touches a real venue. This is the ideal place to **rehearse your exit discipline** β see how a 20% stop would have played out across a week of trades before risking capital. Paper stop-loss is included from the **Starter** plan up.
### Live positions (bot)
For a live position, a triggered exit submits a **real close order on the Polymarket CLOB** through your connected wallet, handled by the bot execution engine on its next pass. The fill is a real market action subject to real liquidity and the spread, and your live P&L and trade journal update accordingly.
> **Plan summary:** Paper stop-loss & take-profit β Starter, Pro, Bot. Live stop-loss & take-profit on real positions β Bot only.
## Two Ways to Set Exits
There are two complementary entry points, depending on whether you trade manually or with a bot.
### A. Per-position orders (manual)
Attach an explicit order to a single open position from the **Positions** panel. You pick the trigger kind and the **price** (a value between 0 and 1, matching how the market quotes). This is the most precise method β you're naming an exact level.
To add a per-position stop:
1. Open **Dashboard β Positions** (paper or live) and find the open position. 2. Click **Add exit** on that row. 3. Choose **Stop-loss**, **Take-profit**, or **Time-stop**. 4. For stop-loss/take-profit, enter the **trigger price** for the side you hold (e.g. 0.20). For a time-stop, pick the **expiry time**. 5. Confirm. The order appears as `active` with a live distance-to-trigger readout.
You can stack a stop-loss and a take-profit on the same position to create a bracket β exit on either side, whichever comes first.
### B. Percentage defaults (bots)
When you build or edit a bot, you set **`stop_loss_pct`** and **`take_profit_pct`** in the strategy config. These are percentage moves measured from each position's entry price, applied automatically to **every** position the bot opens β so you don't hand-place a stop per trade. The bot engine checks these exit conditions on each run as part of `execute-bots`, and closes any position whose P&L crosses the threshold (exit reason recorded as `stop_loss` or `take_profit`).
If you don't set them, bots use sensible defaults: **30% stop-loss** and **50% take-profit**. These are starting points, not recommendations β tune them per strategy and validate with **[Backtesting](/docs/backtesting)** before going live.
The two systems coexist. A bot's percentage rules cover the whole portfolio automatically; a per-position order lets you override or add a tighter, hand-set level on a specific trade you care about.
## Step-by-Step: Your First Protected Trade
1. Open a position β paper from the **EV Scanner**, or live via a bot. 2. Go to **Positions** and click **Add exit** on that position. 3. Set a **stop-loss** a sensible distance below your entry (give it room for the spread and the 2-minute cadence). 4. Optionally add a **take-profit** above entry to lock gains. 5. Confirm. Watch the live distance-to-trigger; the cron now guards the position around the clock. 6. When a trigger fires, you get a notification and the position shows as closed with realized P&L.
## Tips & Gotchas
- **Don't set stops inside the spread.** In a thin market with a 0.55/0.62 spread, a stop at 0.60 may trigger on normal quote noise. Place levels outside the spread and the 2-minute resolution.
- β’**Mind the side.** Always set the trigger in terms of the leg you hold. If you're long NO, your stop is on the NO price, and Predite handles the YESβNO conversion for you.
- β’**Stops are not guaranteed fills.** In a gap your real exit can be worse than the trigger. Size positions assuming the stop is a backstop, not a precise floor.
- β’**Triggers are idempotent.** A fired order is claimed atomically before the close runs, so overlapping cron runs can't double-close a position.
- β’**Cancel is a soft-cancel.** Removing an order sets it to `cancelled` and keeps it in history for auditing β your triggered/cancelled record stays intact for the **[Trade Journal](/docs/trade-journal)**.
- β’**Closing a position manually** leaves its orders orphaned; the cron skips an already-closed position and won't error, but tidy up active orders to keep the panel clean.
- β’**A time-stop ignores price** β it fires purely on the clock. Pair it with a stop-loss when you want both a price floor and a hard exit time.
## How It Connects to the Rest of Predite
Stop-loss sits in the middle of your workflow. Use the **[EV Scanner](/docs/ev-scanner)** and **[AI Probability](/docs/ai-probability)** to find an edge, the **[Kelly Calculator](/docs/kelly-calculator)** to size it, and a stop-loss to bound the downside on the trade you just sized. For large entries, combine stops with **[TWAP Orders](/docs/twap-orders)** so you both scale in gently and have a defined exit. Every fired exit flows into your **[Trade Journal](/docs/trade-journal)** and **[Portfolio](/docs/portfolio)** P&L, and your bot strategies in **[Bot Strategies](/docs/bot-strategies)** carry their own percentage-based stops on every position they open.
## Related Docs
- [Paper Trading](/docs/paper-trading)
- β’[Bot Strategies](/docs/bot-strategies)
- β’[TWAP Orders](/docs/twap-orders)
- β’[Trade Journal](/docs/trade-journal)