Guides / Cookbooks
Cookbooks · Signals: rules plus forecasts · Advanced · about 12 min
Gap-fill playbook to your order system
Send your own opening-gap numbers, ask whether the gap fills today or within five sessions, and route the answer to one of three playbooks in your order system.
- A webhook connection named
my-oms(see Send decisions to your own system). - Your own pre-market or opening numbers for the gap.
When to use it
You trade opening gaps and want one decision per gap: fade it intraday, hold for a fill over a few sessions, or stand aside. The gap numbers come from your own feed at the open, so they go in
state.context; the server does not fill them.The request
A real gap: AAPL gaps with the whole market: AAPL 2026-07-23 -1.3%. The three actions are exclusive:
swing_fillrequires that today's fill is unlikely, andelsefires only when nothing else did.{ "model": "ora-fin1", "state": { "symbol": "AAPL", "as_of": "2026-07-23", "context": { "gap_pct": -0.01278, "gap_dir": -1, "gap_atr": -0.51892, "gap_vs_typical": 3.66191, "gap_outside_range_atr": 0.20111, "earnings_day": 0, "earnings_next_5d": 0, "market_gap_pct": -0.01076, "gap_vs_market": -0.00202, "prior_return_1d": -0.00565, "prior_return_5d": -0.00492, "prior_return_20d": 0.10733, "prior_rsi_14": 62.55, "prior_dist_sma_20": 0.05104, "prior_dist_sma_50": 0.06889, "prior_dist_high_20": -0.02716, "prior_dist_low_20": 0.19048, "prior_close_location": 0.45053, "prior_volume_ratio": 0.59052, "volatility_20d": 0.37453, "atr_pct": 0.02462, "dollar_volume_log": 10.295, "beta_1y": 0.84395, "market_volatility_20d": 0.10645, "sym_gap_fill_rate": 0.24, "sym_gap_fill_rate_dir": 0.26, "sym_gap_fill_5d_rate": 0.58, "sym_gap_go_rate": 0.48, "sym_gaps_1y": 34 } }, "questions": { "fill_today": { "type": "yes_no", "instructions": "Will the gap fill today?" }, "fill_5d": { "type": "yes_no", "instructions": "Will the gap fill within 5 sessions?" } }, "actions": [ { "id": "fade_today", "when": "fill_today >= 0.6", "do": "webhook", "connection": "my-oms", "body": { "symbol": "{{symbol}}", "playbook": "gap_fade_intraday", "p_fill_today": "{{fill_today}}", "gap_pct": "{{state.context.gap_pct}}", "as_of": "{{as_of}}" } }, { "id": "swing_fill", "when": "fill_today < 0.6 and fill_5d >= 0.6", "do": "webhook", "connection": "my-oms", "body": { "symbol": "{{symbol}}", "playbook": "gap_fill_swing", "p_fill_5d": "{{fill_5d}}", "gap_pct": "{{state.context.gap_pct}}", "as_of": "{{as_of}}" } }, { "id": "stand_aside", "when": "else", "do": "slack", "connection": "trading-desk", "message": "{{symbol}} gap {{as_of}}: no fill edge (today {{fill_today|pct}}, 5 sessions {{fill_5d|pct}}). Standing aside." } ], "dry_run": true }Open this in the PlaygroundThe real response
{ "model": "ora-fin1", "answers": { "fill_today": { "type": "yes_no", "yes_no": 0.431 }, "fill_5d": { "type": "yes_no", "yes_no": 0.801 } }, "usage": { "input_tokens": 734, "output_tokens": 8 }, "version": "ora-fin-0.1.1", "actions": [ { "id": "fade_today", "fired": false, "status": "skipped" }, { "id": "swing_fill", "fired": true, "status": "dry_run", "do": "webhook", "connection": "my-oms", "preview": { "body": { "symbol": "AAPL", "playbook": "gap_fill_swing", "p_fill_5d": 0.801, "gap_pct": -0.01278, "as_of": "2026-07-23" } } }, { "id": "stand_aside", "fired": false, "status": "skipped" } ] }fill_today0.431 is under the line,fill_5d0.801 is well over it, soswing_fillfired and the preview is the exact body your system would receive. Numbers stay numbers:"{{fill_5d}}"arrives as0.801.What happened afterwards, from the example's recorded outcome: the gap did not fill that day, and did fill within five sessions. One case is an illustration, not evidence; the Gap fill examples carry several more with outcomes.
The code
Requires curl 7.76+. Save as run.sh, then: bash run.shcurl -sS https://oramodel.com/v1/systemone \ -H "Authorization: Bearer $JEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "ora-fin1", "state": { "symbol": "AAPL", "as_of": "2026-07-23", "context": { "gap_pct": -0.01278, "gap_dir": -1, "gap_atr": -0.51892, "gap_vs_typical": 3.66191, "gap_outside_range_atr": 0.20111, "earnings_day": 0, "earnings_next_5d": 0, "market_gap_pct": -0.01076, "gap_vs_market": -0.00202, "prior_return_1d": -0.00565, "prior_return_5d": -0.00492, "prior_return_20d": 0.10733, "prior_rsi_14": 62.55, "prior_dist_sma_20": 0.05104, "prior_dist_sma_50": 0.06889, "prior_dist_high_20": -0.02716, "prior_dist_low_20": 0.19048, "prior_close_location": 0.45053, "prior_volume_ratio": 0.59052, "volatility_20d": 0.37453, "atr_pct": 0.02462, "dollar_volume_log": 10.295, "beta_1y": 0.84395, "market_volatility_20d": 0.10645, "sym_gap_fill_rate": 0.24, "sym_gap_fill_rate_dir": 0.26, "sym_gap_fill_5d_rate": 0.58, "sym_gap_go_rate": 0.48, "sym_gaps_1y": 34 } }, "questions": { "fill_today": { "type": "yes_no", "instructions": "Will the gap fill today?" }, "fill_5d": { "type": "yes_no", "instructions": "Will the gap fill within 5 sessions?" } }, "actions": [ { "id": "fade_today", "when": "fill_today >= 0.6", "do": "webhook", "connection": "my-oms", "body": { "symbol": "{{symbol}}", "playbook": "gap_fade_intraday", "p_fill_today": "{{fill_today}}", "gap_pct": "{{state.context.gap_pct}}", "as_of": "{{as_of}}" } }, { "id": "swing_fill", "when": "fill_today < 0.6 and fill_5d >= 0.6", "do": "webhook", "connection": "my-oms", "body": { "symbol": "{{symbol}}", "playbook": "gap_fill_swing", "p_fill_5d": "{{fill_5d}}", "gap_pct": "{{state.context.gap_pct}}", "as_of": "{{as_of}}" } }, { "id": "stand_aside", "when": "else", "do": "slack", "connection": "trading-desk", "message": "{{symbol}} gap {{as_of}}: no fill edge (today {{fill_today|pct}}, 5 sessions {{fill_5d|pct}}). Standing aside." } ], "dry_run": true }'Act on it
On the receiving side, verify
X-Jev-Signature, ignore repeatedX-Jev-Deliveryids, reply 2xx within 5 seconds, then map the playbook to an order template:PLAYBOOKS = { "gap_fade_intraday": lambda m: stage_order(m["symbol"], tif="day", note="fade"), "gap_fill_swing": lambda m: stage_order(m["symbol"], tif="gtc", target="prior_close", max_days=5), } def on_delivery(msg): # after the signature check PLAYBOOKS[msg["playbook"]](msg) # staged for a person or your risk checks, not sent blindTest with
"dry_run": trueuntil the bodies look right, then sendfalse.Variations
- Different lines per gap size: put
gap_pctin the rule, e.g.fill_today >= 0.55for small gaps in a separate action. - Add
Is this a gap-and-go day rather than a fade?as a third question and skip fades when it is high. - Send the stand-aside branch to Slack so the desk sees every gap, traded or not (it does in this request).
- Different lines per gap size: put
Information, not investment advice. Every number on this page is a real response for the session shown; answers change with each session.