Paper trading only. This skill must never execute against a live brokerage endpoint. If live credentials or a live base URL are detected at any point, stop immediately and request explicit human confirmation before proceeding.
This skill defines the complete behavioral, governance, and execution spec for an OpenClaw agent running the Perfect Storm (PS+/PS−) options strategy.
The agent's mandate in one sentence:
Trade only when setup quality, market regime, liquidity, and risk conditions all align strongly enough to justify premium risk. "No trade" is a valid— often preferred—output.
The agent produces one of five symbolic states per scan cycle per symbol:
StateMeaningIGNOREFails pre-filter; stop evaluating this symbolWATCHLISTInteresting but not yet ready; monitor next cycleARM_ENTRYSetup is forming; prepare contract selection and sizeENTERAll gates pass; submit limit orderEXITExisting position must be reduced or closed now
FilePurposereferences/AGENTS.mdFull strategy rulebook: universe, setup definitions, indicator stack, sizing/exit logic, journaling schemareferences/risk_config.yamlHard limits: account config, per-trade risk, daily/weekly drawdown caps, option filtersscripts/alpaca.mjsMinimal Alpaca REST helper for account state, positions, orders
Always load references/risk_config.yaml at agent startup. If the file is
missing or unreadable, halt and request it before doing anything else.
Execute these phases in strict order. Any gate failure returns the symbol to
IGNORE or SKIP and logs the reason.
text
1. Load risk_config.yaml — halt if missing
2. Confirm APCA_API_BASE_URL == https://paper-api.alpaca.markets — halt if live
3. Fetch account state via scripts/alpaca.mjs account
4. Compute current portfolio heat (open positions × notional risk)
5. Check daily/weekly loss counters — halt new entries if limits hit
6. Confirm data feeds are live and spread data is fresh (< 60s)
If any safety check fails → set agent_state = HALTED, log reason, do not
scan.
Classify the broad market environment using SPY/QQQ as primary proxies:
RegimeSignal CharacteristicsAllowed BiasTRENDING_BULLPrice > 20/50/200 EMA stack; ADX > 20; shallow pullbacksPS+ calls preferredTRENDING_BEARPrice < EMA stack; ADX > 20; weak bouncesPS− puts preferredCHOPPrice whipping around EMAs; ADX < 20; no follow-throughReduce size 50%; raise confidence threshold to exceptional_score``SHOCKVIX spike > 25%; spreads blown out; correlation breakdownHalt new entries
Default rule: If regime cannot be clearly classified → CHOP.
In CHOP or SHOCK, only enter if confidence_score >= exceptional_score from
risk_config.yaml (default 85).
Start from the approved universe in references/AGENTS.md. For each symbol apply:
text
✓ Underlying price >= min_stock_price (config)
✓ Avg daily share volume >= min_avg_daily_share_volume (config)
✓ ATR% >= min_atr_percent (config)
✓ Relative volume >= min_relative_volume (config)
✗ Earnings within avoid_earnings_days_before days → SKIP
✗ Macro event within avoid_macro_minutes_before minutes → SKIP
✗ Abnormal spread expansion detected → SKIP
Rank survivors by setup readiness, cap at max_symbols_ranked_per_cycle.
Score one point per condition met. Maximum 10 points.
Raw ScoreNormalized (×10)Action< 7< 70SKIP7–870–80WATCHLIST or ENTER at reduced size8–980–90ENTER at standard size9–1090–100ENTER at full size (still within hard limits)
text
DTE: preferred_dte_min (7) to preferred_dte_max (21)
0-DTE only if allow_0dte: true in config (default false)
Delta: delta_min (0.35) to delta_max (0.60) for standard directional trades
Tighter end (0.45–0.65) for strong trend-continuation setups
Day-trade / fast scalp: 0.25–0.45 only if spread/fill quality excellent
OI: >= min_open_interest (config)
Volume: >= min_option_volume (config)
Spread: bid-ask spread as % of mid <= max_bid_ask_spread_percent (config)
When multiple contracts qualify, rank by:
Reject if option premium is so low that one tick is > 5% of premium (lottery contract risk).
Use fixed-fraction risk logic:
text
max_risk_dollars = account_equity × (max_risk_per_trade_percent / 100)
contracts_raw = floor(max_risk_dollars / (premium_per_contract × 100))
contracts = min(contracts_raw, max_contracts_derived_from_position_pct)
Adjustments:
chop_size_multiplier (0.5)reduced_size_multiplier (0.5) once
reduce_size_after_consecutive_losses threshold is hitIf contracts < 1 after adjustments → SKIP (minimum size violates risk rules).
Also check:
max_open_positions not exceededmax_positions_per_symbol not exceededportfolio_heat > max_portfolio_heat_percenttext
Order type: LIMIT (always)
Limit price: mid-price of bid-ask at evaluation time, or slight edge inside mid
Chase guard: if current ask has moved > do_not_chase_percent (3%) above
entry plan → cancel and re-evaluate
Fill timeout: cancel_if_not_filled_seconds (45)
Never submit a market order for options. Never re-chase a missed fill blindly.
Choose the tightest applicable stop:
max_option_premium_loss_percent (35%) of entry premiumtime_stop_minutes_intraday
(45 min) → exitend_of_day_flatten_intraday: true → close all intraday
positions before session endPartial exit and runner logic per config:
text
At R×1.0 → sell scale_out_fractions[0] (50%) of position
At R×2.0 → sell scale_out_fractions[1] (30%) of position
Remaining (20%) = runner — move stop to break-even at R×1.0
Only allow runner in TRENDING_BULL or TRENDING_BEAR regime, never in CHOP.
Exit fully on any of:
avoid_macro_minutes_before)Do not convert an options trade into an "investment."
Map the 10-point raw checklist score to 0–100 (multiply by 10), then apply qualitative adjustments:
FactorAdjustmentStrong multi-timeframe agreement (3 TFs aligned)+5Clean S/R confluence at entry+5IV context favorable (IV not historically extreme for long premium)+3Recent symbol behavior cooperative (not whippy last 3 sessions)+3Spread exceptionally tight (< 3%)+2Event risk within 3 days−10Higher and execution TF in direct conflict−15ADX < 15 (very weak trend)−10Spread > 6% of mid−8
Cap at 100. Below min_score_to_trade (70) → SKIP.
ConditionActionEarnings within avoid_earnings_days_before (2) daysBlock new entries on that symbolFOMC / CPI / NFP within avoid_macro_minutes_before (30) minBlock ALL new entriesUnscheduled high-impact headline (spreads blow out > 20%)Halt new entries, tighten existing stopsAlready in position as event approachesReduce size, tighten stop, or exit per config
Check after every fill and before every new entry:
text
daily_realized_loss >= max_daily_loss_percent (4%) → HALT all new entries
consecutive_losses >= max_consecutive_losses (3) → HALT all new entries
portfolio_heat >= max_portfolio_heat_percent (8%) → no new entries
slippage on last trade > max_slippage_percent (5%) → flag; raise fill threshold
Halt conditions are sticky for the session. Manual reset required.
Every symbol evaluated in a cycle must produce a structured decision object:
json
{
"timestamp": "ISO-8601",
"action": "ENTER | HOLD | EXIT | SKIP | WATCHLIST",
"symbol": "AAPL",
"direction": "bullish | bearish",
"setup_type": "PS+ | PS-",
"confidence_score": 82,
"regime": "TRENDING_BULL | TRENDING_BEAR | CHOP | SHOCK",
"thesis": "Brief narrative: what pattern, why now, what invalidates",
"contract_candidate": {
"expiration": "YYYY-MM-DD",
"strike": 185.0,
"type": "call | put",
"dte": 14,
"delta": 0.48,
"open_interest": 4200,
"volume": 850,
"bid": 2.15,
"ask": 2.25,
"spread_pct": 4.5,
"iv": 0.32
},
"entry_plan": {
"limit_price": 2.20,
"entry_window_minutes": 15
},
"stop_plan": {
"underlying_invalidation": 182.50,
"premium_stop_pct": 35,
"time_stop_minutes": 45
},
"target_plan": {
"r1_price": 3.08,
"r2_price": 4.40,
"runner_stop": "break_even_after_r1"
},
"position_size": {
"contracts": 2,
"total_premium_at_risk": 440,
"pct_of_account": 0.44
},
"risk_checks_passed": true,
"blockers": [],
"journal_note": "Setup quality A. Clean bounce off VWAP+50EMA confluence. PPO improving. ADX 24 with +DI crossing. Room to prior day high ~4.5R. No events next 4 days."
}
If action == SKIP, still populate confidence_score, regime, blockers,
and journal_note. Logged skips are required for strategy improvement.
Log every evaluation, including skips. Required fields per log entry:
Also log:
Use scripts/alpaca.mjs for all broker interaction.
bash
APCA_API_KEY_ID=<your_paper_key>
APCA_API_SECRET_KEY=<your_paper_secret>
APCA_API_BASE_URL=https://paper-api.alpaca.markets
bash
# Health check and account state
node skills/perfect-storm-options-trader/scripts/alpaca.mjs account
# Current open positions
node skills/perfect-storm-options-trader/scripts/alpaca.mjs positions
# Open orders
node skills/perfect-storm-options-trader/scripts/alpaca.mjs orders --status open
# Place a limit order (options use OCC symbol format)
node skills/perfect-storm-options-trader/scripts/alpaca.mjs order:place \
--symbol AAPL250117C00185000 \
--qty 2 \
--side buy \
--type limit \
--time_in_force day \
--limit_price 2.20
# Cancel an order
node skills/perfect-storm-options-trader/scripts/alpaca.mjs order:cancel --id <order_id>
text
AAPL 250117 C 00185000
ROOT YYMMDD P/C 8-digit strike (×1000, zero-padded)
Example: AAPL call, Jan 17 2025, $185 strike = AAPL250117C00185000
text
✓ BASE_URL contains "paper-api" — never "api.alpaca.markets"
✓ account.status == "ACTIVE"
✓ account.trading_blocked == false
✓ Buying power sufficient for order
✓ Position limit not exceeded (check open positions count)
✓ Order is LIMIT type
✓ client_order_id set to trace order in journal
risk_config.yaml without exception.risk_config.yaml rules without explicit human instructionWhen rules or conditions conflict, resolve in this order:
Before entering any long premium trade, evaluate whether implied volatility makes the option attractively priced:
text
IV Rank (IVR) = (current IV − 52w low IV) / (52w high IV − 52w low IV)
IVR < 30 → premium is relatively cheap → favorable for long premium
IVR 30–60 → neutral; ensure setup quality is strong (score ≥ 75)
IVR > 60 → premium is expensive → require score ≥ 85 or skip
A great chart pattern with expensive premium is still a risky trade. Log IV context in every trade journal entry.
Do not allow correlated positions to compound hidden directional risk:
max_portfolio_heat_percent / 2 per directionWhen in doubt, the tighter constraint applies.
Any change to thresholds, filters, or exit logic must:
risk_config.yamlNo live-forward parameter changes mid-session.
This is the prioritized starting universe for each scan cycle. Symbols are grouped by category and annotated with their primary trading characteristics. The agent must still apply all liquidity, spread, and event-risk filters — this list is a starting point, not a guaranteed tradeable set.
Rank and trim to max_symbols_ranked_per_cycle (default 10) each cycle based on
relative volume, ATR%, and setup readiness score.
TickerWhy It's On The ListNVDAHighest beta AI play; massive options volume; PS setups are clean and fastAAPLDeepest options chain in the market; spreads excellent; smooth trend behaviorMSFTStrong institutional trend structure; reliable EMA respect; liquid chainAMZNCloud + consumer composite; strong trending periods; liquid weekliesMETAHigh ATR%; clean breakout/breakdown patterns; active options marketGOOGLStable large-cap with periodic high-momentum setups; good chain depth
TickerWhy It's On The ListAMDCorrelated to NVDA but more volatile; excellent PS setups during momentum runsSMCIExtremely high ATR%; fast-moving; use reduced size; spreads can widen — filter strictlySNOWGrowth-tech with high relative moves; strong trend-or-nothing behavior
TickerWhy It's On The ListTSLAHigh retail + institutional interest; large ATR%; frequent PS+ and PS− setupsCOINCrypto-correlated; explosive directional moves; requires strict spread filterPLTRStrong narrative-driven momentum; clean structure on daily and 30m charts
TickerWhy It's On The ListJPMLiquid large-cap; sector proxy; good for regime-aligned put setups during stressGSHigh price / active options; strong directional bias during macro movesBACRate-sensitive; use for macro-driven setups around FOMC; very liquid chain
TickerWhy It's On The ListWMTLow beta; use for isolated PS setups when broad market is choppyKOStable trend structure; good for low-volatility swing setupsPEPSimilar profile to KO; use to diversify away from tech concentration
TickerWhy It's On The ListXOMMacro/oil-driven; useful hedge when tech is choppy; active options chainCVXSimilar to XOM; use for sector-divergence setups or energy trend trades
TickerWhy It's On The ListSPYPrimary regime proxy; also tradeable directly for broad-market PS setupsQQQTech-heavy regime proxy; use when NASDAQ is the dominant trend driverIWMSmall-cap risk-on/risk-off signal; divergence from SPY/QQQ is informative
Note: SPY, QQQ, and IWM are listed in
risk_config.yamlandAGENTS.mdas core ETFs. They count toward the 20-symbol scan universe but are evaluated first as regime filters before being considered as trade candidates.
Score each symbol 0–3 on each factor, sum, and take the top max_symbols_ranked_per_cycle:
Factor0123Relative volume vs 10-day avg< 0.8×0.8–1.2×1.2–2.0×> 2.0×ATR% (intraday)< 1.5%1.5–2.5%2.5–4.0%> 4.0%Setup confluence score (pre-screen)< 5050–6565–80> 80Options chain quality (spread + OI)PoorAcceptableGoodExcellent
Ties broken by options chain quality, then alphabetically.