Use cases · Builders
Quant developer: 20 ways to use Ora
Wires exact rules and forecasts into pipelines, tests and order systems. Each example is a complete, runnable request with the real answers it returned (32 requests, captured 2026-10-31), what they mean and, where it fits, the action it would send.
ora-fin-0.1.1. Another model changes the request JSON and the Playground link; run it there to see its answers.Rule functions and facts used by this player (64)
sma 8ref 7offset 6avg 5ema 3abs 3atr 3crossup 2wma 2adx 2highest 2log 2sqrt 2std 2zscore 2rsi 2sum 2mean 2crossdown 1diminus 1diplus 1linreg 1median 1gap_down 1gap_up 1inside_bar 1marubozu 1outside_bar 1spinning_top 1cum 1rec 1rma 1macd 1macdsignal 1cci 1stochd 1stochk 1willr 1days_since_earnings 1days_to_earnings 1last_earnings_move 1next_report_amc 1barssince 1highestbars 1lowestbars 1bblower 1between 1iif 1sign 1greatest 1hammer 1hanging_man 1inverted_hammer 1least 1hl2 1hlc3 1ohlc4 1tr 1swinghigh 1swinglow 1lowest 1max 1obv 1percentrank 1
Examples 1–10 of 20 · page 1 of 2
Quant developer · example 1
Unit-test a moving-average signal on SPY against the rule engine
Before shipping a crossover signal in a pipeline, compare the in-house computation with Ora's exact rules for the same session.
- StateSPY
- Questions4 asked
- Answersreal, captured
- Actions1 rule · dry run
State
{"symbol":"SPY"} The server fills in the latest completed session.
Questions
cross_50 | rule | crossup(C, sma(C, 50))Crossed above the 50-day today |
ema_wma | rule | wma(C, 10) > ema(C, 30)10-day weighted average above the 30-day EMA |
sma50_up | rule | sma(C, 50) > ref(sma(C, 50), -10)The 50-day average is rising |
dn_cross | rule | crossdown(sma(C, 20), sma(C, 50))20-day average crossed under the 50-day today |
Answers
| Question | Answer | Reading |
|---|---|---|
cross_50Crossed above the 50-day today | 0.05 | false |
ema_wma10-day weighted average above the 30-day EMA | 0.3059 | false |
sma50_upThe 50-day average is rising | 0.2481 | false |
dn_cross20-day average crossed under the 50-day today | 0.05 | false |
Actions
Rules on the answers decide what to send.
cross_50 >= 0→Webhookci-results{
"suite": "signal_parity",
"symbol": "SPY",
"as_of": "2026-10-30",
"cross_50d": 0.05,
"wma_over_ema": 0.3059,
"sma50_rising": 0.2481,
"cross_20_50_down": 0.05
}What it means
For SPY on the session of 2026-10-30: Not true: Crossed above the 50-day today; 10-day weighted average above the 30-day EMA; The 50-day average is rising; 20-day average crossed under the 50-day today. Fired: test_result (Webhook → ci-results).
Each answer carries the rule that was evaluated, so a test can assert the in-house flag matches the rule's yes or no for the same as_of date.
Request JSON
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "SPY"
},
"questions": {
"cross_50": {
"type": "yes_no",
"ask": "crossup(C, sma(C, 50))"
},
"ema_wma": {
"type": "yes_no",
"ask": "wma(C, 10) > ema(C, 30)"
},
"sma50_up": {
"type": "yes_no",
"ask": "sma(C, 50) > ref(sma(C, 50), -10)"
},
"dn_cross": {
"type": "yes_no",
"ask": "crossdown(sma(C, 20), sma(C, 50))"
}
},
"actions": [
{
"id": "test_result",
"when": "cross_50 >= 0",
"do": "webhook",
"connection": "ci-results",
"body": {
"suite": "signal_parity",
"symbol": "{{symbol}}",
"as_of": "{{as_of}}",
"cross_50d": "{{cross_50}}",
"wma_over_ema": "{{ema_wma}}",
"sma50_rising": "{{sma50_up}}",
"cross_20_50_down": "{{dn_cross}}"
}
}
],
"dry_run": true
}Response JSON (SPY, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"cross_50": {
"yes_no": 0.05,
"rule": "crossup(C, sma(C, 50))",
"basis": "rule"
},
"ema_wma": {
"yes_no": 0.3059,
"rule": "wma(C, 10) > ema(C, 30)",
"basis": "rule"
},
"sma50_up": {
"yes_no": 0.2481,
"rule": "sma(C, 50) > ref(sma(C, 50), -10)",
"basis": "rule"
},
"dn_cross": {
"yes_no": 0.05,
"rule": "crossdown(sma(C, 20), sma(C, 50))",
"basis": "rule"
}
},
"context": {
"symbol": "SPY",
"as_of": "2026-10-30"
},
"actions": [
{
"id": "test_result",
"fired": true,
"status": "dry_run",
"do": "webhook",
"connection": "ci-results",
"preview": {
"body": {
"suite": "signal_parity",
"symbol": "SPY",
"as_of": "2026-10-30",
"cross_50d": 0.05,
"wma_over_ema": 0.3059,
"sma50_rising": 0.2481,
"cross_20_50_down": 0.05
}
}
}
]
}Quant developer · example 2
Send a QQQ breakout signal to the order service as typed JSON
A breakout rule plus a volume rule plus the one-week forecast decide whether a signed webhook carries an entry signal to the order management service.
- StateQQQ
- Questions4 asked
- Answersreal, captured
- Actions2 rules · dry run
State
{"symbol":"QQQ"} The server fills in the latest completed session.
Questions
breakout | rule | C > highest(C, 20)20-day closing breakout |
volume | rule | V > 2 * ref(avg(V, 20), -1)Volume more than twice the previous 20-day average |
adx | rule | adx(14) > 25Trending (ADX above 25) |
up_week | forecast | Will the stock be higher in a week? Higher in a week |
Answers
| Question | Answer | Reading |
|---|---|---|
breakout20-day closing breakout | 0.0537 | false |
volumeVolume more than twice the previous 20-day average | 0.766 | true |
adxTrending (ADX above 25) | 0.6956 | true |
up_weekHigher in a week | 0.561 | 56% · close to even |
Actions
Rules on the answers decide what to send.
breakout >= 0.6 and volume >= 0.6 and up_week >= 0.55→Webhookoms-signalselse→Webhookoms-signals{
"symbol": "QQQ",
"signal": "none",
"p_breakout": 0.0537,
"as_of": "2026-10-30"
}What it means
For QQQ on the session of 2026-10-30: True now: Volume more than twice the previous 20-day average; Trending (ADX above 25). Not true: 20-day closing breakout. Forecasts: Higher in a week 56%. Fired: no_signal (Webhook → oms-signals).
The order service receives exactly one body per run, either an entry or an explicit none, so downstream code never has to infer silence.
Request JSON
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "QQQ"
},
"questions": {
"breakout": {
"type": "yes_no",
"ask": "C > highest(C, 20)"
},
"volume": {
"type": "yes_no",
"ask": "V > 2 * ref(avg(V, 20), -1)"
},
"adx": {
"type": "yes_no",
"ask": "adx(14) > 25"
},
"up_week": {
"type": "yes_no",
"instructions": "Will the stock be higher in a week?"
}
},
"actions": [
{
"id": "entry",
"when": "breakout >= 0.6 and volume >= 0.6 and up_week >= 0.55",
"do": "webhook",
"connection": "oms-signals",
"body": {
"symbol": "{{symbol}}",
"signal": "breakout_long",
"p_breakout": "{{breakout}}",
"p_volume": "{{volume}}",
"p_trend": "{{adx}}",
"p_up_week": "{{up_week}}",
"as_of": "{{as_of}}"
}
},
{
"id": "no_signal",
"when": "else",
"do": "webhook",
"connection": "oms-signals",
"body": {
"symbol": "{{symbol}}",
"signal": "none",
"p_breakout": "{{breakout}}",
"as_of": "{{as_of}}"
}
}
],
"dry_run": true
}Response JSON (QQQ, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"breakout": {
"yes_no": 0.0537,
"rule": "C > highest(C, 20)",
"basis": "rule"
},
"volume": {
"yes_no": 0.766,
"rule": "V > 2 * ref(avg(V, 20), -1)",
"basis": "rule"
},
"adx": {
"yes_no": 0.6956,
"rule": "adx(14) > 25",
"basis": "rule"
},
"up_week": {
"yes_no": 0.561
}
},
"context": {
"symbol": "QQQ",
"as_of": "2026-10-30"
},
"actions": [
{
"id": "entry",
"fired": false,
"status": "skipped"
},
{
"id": "no_signal",
"fired": true,
"status": "dry_run",
"do": "webhook",
"connection": "oms-signals",
"preview": {
"body": {
"symbol": "QQQ",
"signal": "none",
"p_breakout": 0.0537,
"as_of": "2026-10-30"
}
}
}
]
}Quant developer · example 3
Build a regime feature vector for AAPL from exact rules
Turn trend, volatility and momentum states into binary features for a model, each computed by the rule engine rather than reimplemented.
- StateAAPL
- Questions6 asked
- Answersreal, captured
- Actions1 rule · dry run
State
{"symbol":"AAPL"} The server fills in the latest completed session.
Questions
trend | rule | adx(14) > 20 and diplus(14) > diminus(14)Trending up (ADX over 20 and +DI over −DI) |
linreg_up | rule | linreg(C, 20) > ref(linreg(C, 20), -5)20-day regression line higher than a week ago |
vol_regime | rule | std(log(C / C[-1]), 20) * sqrt(252) > 0.4Annualized 20-day volatility above 40% |
zs | rule | zscore(C, 50) > 1close more than 1 standard deviation above its 50-day mean |
median_vol | rule | V > 2 * median(V, 20)volume over twice its 20-day median |
drop5 | forecast | Will it drop at least 5% at some point in the next month? A 5% drawdown within a month |
Answers
| Question | Answer | Reading |
|---|---|---|
trendTrending up (ADX over 20 and +DI over −DI) | 0.2895 | false |
linreg_up20-day regression line higher than a week ago | 0.6301 | true |
vol_regimeAnnualized 20-day volatility above 40% | 0.0537 | false |
zsclose more than 1 standard deviation above its 50-day mean | 0.5609 | on the line (true) |
median_volvolume over twice its 20-day median | 0.2151 | false |
drop5A 5% drawdown within a month | 0.365 | 37% · unlikely |
Actions
Rules on the answers decide what to send.
trend >= 0→Webhookfeature-store{
"entity": "AAPL",
"as_of": "2026-10-30",
"adx_uptrend": 0.2895,
"linreg_up": 0.6301,
"hv_over_40": 0.0537,
"zscore_over_1": 0.5609,
"volume_over_2x_median": 0.2151,
"p_drop5": 0.365
}What it means
For AAPL on the session of 2026-10-30: True now: 20-day regression line higher than a week ago. Not true: Trending up (ADX over 20 and +DI over −DI); Annualized 20-day volatility above 40%; volume over twice its 20-day median. On the line: close more than 1 standard deviation above its 50-day mean. Forecasts: A 5% drawdown within a month 37%. Fired: features (Webhook → feature-store).
Rule answers near one or zero become clean binary features; the forecast column stays a probability and is stored as such.
Request JSON
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "AAPL"
},
"questions": {
"trend": {
"type": "yes_no",
"ask": "adx(14) > 20 and diplus(14) > diminus(14)"
},
"linreg_up": {
"type": "yes_no",
"ask": "linreg(C, 20) > ref(linreg(C, 20), -5)"
},
"vol_regime": {
"type": "yes_no",
"ask": "std(log(C / C[-1]), 20) * sqrt(252) > 0.4"
},
"zs": {
"type": "yes_no",
"ask": "zscore(C, 50) > 1"
},
"median_vol": {
"type": "yes_no",
"ask": "V > 2 * median(V, 20)"
},
"drop5": {
"type": "yes_no",
"instructions": "Will it drop at least 5% at some point in the next month?"
}
},
"actions": [
{
"id": "features",
"when": "trend >= 0",
"do": "webhook",
"connection": "feature-store",
"body": {
"entity": "{{symbol}}",
"as_of": "{{as_of}}",
"adx_uptrend": "{{trend}}",
"linreg_up": "{{linreg_up}}",
"hv_over_40": "{{vol_regime}}",
"zscore_over_1": "{{zs}}",
"volume_over_2x_median": "{{median_vol}}",
"p_drop5": "{{drop5}}"
}
}
],
"dry_run": true
}Response JSON (AAPL, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"trend": {
"yes_no": 0.2895,
"rule": "adx(14) > 20 and diplus(14) > diminus(14)",
"basis": "rule"
},
"linreg_up": {
"yes_no": 0.6301,
"rule": "linreg(C, 20) > ref(linreg(C, 20), -5)",
"basis": "rule"
},
"vol_regime": {
"yes_no": 0.0537,
"rule": "std(log(C / C[-1]), 20) * sqrt(252) > 0.4",
"basis": "rule"
},
"zs": {
"yes_no": 0.5609,
"rule": "zscore(C, 50) > 1",
"basis": "rule"
},
"median_vol": {
"yes_no": 0.2151,
"rule": "V > 2 * median(V, 20)",
"basis": "rule"
},
"drop5": {
"yes_no": 0.365
}
},
"context": {
"symbol": "AAPL",
"as_of": "2026-10-30"
},
"actions": [
{
"id": "features",
"fired": true,
"status": "dry_run",
"do": "webhook",
"connection": "feature-store",
"preview": {
"body": {
"entity": "AAPL",
"as_of": "2026-10-30",
"adx_uptrend": 0.2895,
"linreg_up": 0.6301,
"hv_over_40": 0.0537,
"zscore_over_1": 0.5609,
"volume_over_2x_median": 0.2151,
"p_drop5": 0.365
}
}
}
]
}adx diminus diplus linreg log median offset ref sqrt std zscore
Quant developer · example 4
Scan a five-name tech universe for oversold-in-uptrend setups
Run the same rule set over a small universe in parallel and rank by the drawdown forecast.
- State5 symbols
- Questions4 asked
- Answersreal, captured
- Actions1 rule · dry run
State
{"symbol":"AAPL"} then MSFT, NVDA, AMD, ORCL, one request each. The server fills in the latest completed session.
Questions
setup | rule | (C > sma(C, 200) and rsi(C, 14) < 40) or (C < sma(C, 200) and rsi(C, 14) < 25)Oversold, with the line set by the trend |
rsi2 | rule | rsi(C, 2) < 10Two-day RSI under 10 |
above_200 | rule | C > sma(C, 200) * 1.10More than 10% above the 200-day |
drop5 | forecast | Will it drop at least 5% at some point in the next month? A 5% drawdown within a month |
Answers
| Symbol | setuprule | rsi2rule | above_200rule | drop5forecast | Fired |
|---|---|---|---|---|---|
AAPL | 0.0634 | 0.1464 | 0.934 | 0.365 | none |
MSFT | 0.1064 | 0.5812 | 0.9431 | 0.422 | none |
NVDA | 0.5455 | 0.591 | 0.06 | 0.523 | none |
AMD | 0.5217 | 0.4518 | 0.8701 | 0.763 | none |
ORCL | 0.0537 | 0.2388 | 0.0537 | 0.653 | none |
true false not known for rules; forecasts are odds. Hover a column for its question.
Actions
Rules on the answers decide what to send. Each symbol runs its own request, so each one can fire.
setup >= 0.6 and drop5 < 0.5→Slackquant-devWhat it means
Session of 2026-10-30, 5 symbols: Oversold, with the line set by the trend: true for none of 5. Two-day RSI under 10: true for none of 5. More than 10% above the 200-day: true for AAPL, MSFT, AMD of 5. Highest odds for “A 5% drawdown within a month”: AMD at 76%. candidate fired for none.
One request per symbol with identical keys makes the results a table; filter on the setup rule and sort by the drawdown odds.
Request JSON (AAPL; the others differ only in the symbol)
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "AAPL"
},
"questions": {
"setup": {
"type": "yes_no",
"ask": "(C > sma(C, 200) and rsi(C, 14) < 40) or (C < sma(C, 200) and rsi(C, 14) < 25)"
},
"rsi2": {
"type": "yes_no",
"ask": "rsi(C, 2) < 10"
},
"above_200": {
"type": "yes_no",
"ask": "C > sma(C, 200) * 1.10"
},
"drop5": {
"type": "yes_no",
"instructions": "Will it drop at least 5% at some point in the next month?"
}
},
"actions": [
{
"id": "candidate",
"when": "setup >= 0.6 and drop5 < 0.5",
"do": "slack",
"connection": "quant-dev",
"message": "{{symbol}} ({{as_of}}): oversold-in-regime setup ({{setup|pct}}), RSI(2) {{rsi2|pct}}, 5% drawdown odds {{drop5|pct}}."
}
],
"dry_run": true
}Response JSON (AAPL, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"setup": {
"yes_no": 0.0634,
"rule": "(C > sma(C, 200) and rsi(C, 14) < 40) or (C < sma(C, 200) and rsi(C, 14) < 25)",
"basis": "rule"
},
"rsi2": {
"yes_no": 0.1464,
"rule": "rsi(C, 2) < 10",
"basis": "rule"
},
"above_200": {
"yes_no": 0.934,
"rule": "C > sma(C, 200) * 1.10",
"basis": "rule"
},
"drop5": {
"yes_no": 0.365
}
},
"context": {
"symbol": "AAPL",
"as_of": "2026-10-30"
},
"actions": [
{
"id": "candidate",
"fired": false,
"status": "skipped"
}
]
}Quant developer · example 5
Regression-test candlestick detectors on TSLA
Check that a home-grown candlestick detector agrees with Ora's pattern functions on the latest bar.
- StateTSLA
- Questions6 asked
- Answersreal, captured
- Actionsnone
State
{"symbol":"TSLA"} The server fills in the latest completed session.
Questions
marubozu | rule | marubozu()marubozu candle: Body at least 90% of the range: almost no wicks. |
spinning | rule | spinning_top()spinning top candle: Small body (10–30% of range) with wicks of at least a quarter of the range on both sides. |
outside | rule | outside_bar()outside bar candle: Today's high above yesterday's and low below it. |
inside | rule | inside_bar()inside bar candle: Today's high and low are inside yesterday's (equal counts). |
gap_up | rule | gap_up()gap up candle: Today's whole range is above yesterday's high: an unfilled gap up. |
gap_down | rule | gap_down()gap down candle: Today's whole range is below yesterday's low. |
Answers
| Question | Answer | Reading |
|---|---|---|
marubozumarubozu candle: Body at least 90% of the range: almost no wicks. | 0.0551 | false |
spinningspinning top candle: Small body (10–30% of range) with wicks of at least a quarter of the range on both sides. | 0.2832 | false |
outsideoutside bar candle: Today's high above yesterday's and low below it. | 0.3172 | false |
insideinside bar candle: Today's high and low are inside yesterday's (equal counts). | 0.0795 | false |
gap_upgap up candle: Today's whole range is above yesterday's high: an unfilled gap up. | 0.0577 | false |
gap_downgap down candle: Today's whole range is below yesterday's low. | 0.2768 | false |
What it means
For TSLA on the session of 2026-10-30: Not true: marubozu candle: Body at least 90% of the range: almost no wicks.; spinning top candle: Small body (10–30% of range) with wicks of at least a quarter of the range on both sides.; outside bar candle: Today's high above yesterday's and low below it.; inside bar candle: Today's high and low are inside yesterday's (equal counts).; gap up candle: Today's whole range is above yesterday's high: an unfilled gap up.; gap down candle: Today's whole range is below yesterday's low..
A pattern answer is an exact rule on one bar; disagreement with the in-house detector points at a definition difference worth documenting.
Request JSON
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "TSLA"
},
"questions": {
"marubozu": {
"type": "yes_no",
"ask": "marubozu()"
},
"spinning": {
"type": "yes_no",
"ask": "spinning_top()"
},
"outside": {
"type": "yes_no",
"ask": "outside_bar()"
},
"inside": {
"type": "yes_no",
"ask": "inside_bar()"
},
"gap_up": {
"type": "yes_no",
"ask": "gap_up()"
},
"gap_down": {
"type": "yes_no",
"ask": "gap_down()"
}
}
}Response JSON (TSLA, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"marubozu": {
"yes_no": 0.0551,
"rule": "marubozu()",
"basis": "rule"
},
"spinning": {
"yes_no": 0.2832,
"rule": "spinning_top()",
"basis": "rule"
},
"outside": {
"yes_no": 0.3172,
"rule": "outside_bar()",
"basis": "rule"
},
"inside": {
"yes_no": 0.0795,
"rule": "inside_bar()",
"basis": "rule"
},
"gap_up": {
"yes_no": 0.0577,
"rule": "gap_up()",
"basis": "rule"
},
"gap_down": {
"yes_no": 0.2768,
"rule": "gap_down()",
"basis": "rule"
}
},
"context": {
"symbol": "TSLA",
"as_of": "2026-10-30"
}
}gap_down gap_up inside_bar marubozu outside_bar spinning_top
Quant developer · example 6
Compare a custom recursive smoother with built-in averages on MSFT
Prototype an exponential smoother with rec() and check it against ema and rma before porting it to production code.
- StateMSFT
- Questions4 asked
- Answersreal, captured
- Actionsnone
State
{"symbol":"MSFT"} The server fills in the latest completed session.
Questions
rec_above | rule | C > rec(C, self + 0.1 * (C - self))close above a recursive smoother with alpha one tenth |
ema_above | rule | C > ema(C, 19)close above the 19-day EMA |
rma_above | rule | C > rma(C, 10)close above the 10-day Wilder average |
cum_up | rule | cum(C > C[-1]) > cum(C < C[-1])more up days than down days in the whole history |
Answers
| Question | Answer | Reading |
|---|---|---|
rec_aboveclose above a recursive smoother with alpha one tenth | 0.3041 | false |
ema_aboveclose above the 19-day EMA | 0.3041 | false |
rma_aboveclose above the 10-day Wilder average | 0.3041 | false |
cum_upmore up days than down days in the whole history | 0.9463 | true |
What it means
For MSFT on the session of 2026-10-30: True now: more up days than down days in the whole history. Not true: close above a recursive smoother with alpha one tenth; close above the 19-day EMA; close above the 10-day Wilder average.
A smoother with alpha one tenth should agree with the 19-day EMA most days; a disagreement on this session is a test case to keep.
Request JSON
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "MSFT"
},
"questions": {
"rec_above": {
"type": "yes_no",
"ask": "C > rec(C, self + 0.1 * (C - self))"
},
"ema_above": {
"type": "yes_no",
"ask": "C > ema(C, 19)"
},
"rma_above": {
"type": "yes_no",
"ask": "C > rma(C, 10)"
},
"cum_up": {
"type": "yes_no",
"ask": "cum(C > C[-1]) > cum(C < C[-1])"
}
}
}Response JSON (MSFT, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"rec_above": {
"yes_no": 0.3041,
"rule": "C > rec(C, self + 0.1 * (C - self))",
"basis": "rule"
},
"ema_above": {
"yes_no": 0.3041,
"rule": "C > ema(C, 19)",
"basis": "rule"
},
"rma_above": {
"yes_no": 0.3041,
"rule": "C > rma(C, 10)",
"basis": "rule"
},
"cum_up": {
"yes_no": 0.9463,
"rule": "cum(C > C[-1]) > cum(C < C[-1])",
"basis": "rule"
}
},
"context": {
"symbol": "MSFT",
"as_of": "2026-10-30"
}
}Quant developer · example 7
Nightly signal snapshot for the index ETFs, posted to a data lake hook
After every close, compute the same four signals for the index ETFs and post each row to an ingestion webhook.
- ScheduleMon–Fri at 16:45 ET
- State4 symbols
- Questions4 asked
- Answersreal, captured
- Actions1 rule · dry run
State
{"symbol":"SPY"} then QQQ, IWM, DIA, one request each. The server fills in the latest completed session.
Questions
trend | rule | C > sma(C, 50)Above the 50-day average |
momentum | rule | macd(C) > macdsignal(C)MACD above its signal line |
breadth_proxy | rule | sum(C > C[-1], 10) >= 6Up on at least six of the last ten days |
up_week | forecast | Will the stock be higher in a week? Higher in a week |
Answers
| Symbol | trendrule | momentumrule | breadth_proxyrule | up_weekforecast | Fired |
|---|---|---|---|---|---|
SPY | 0.1128 | 0.1658 | 0.55 | 0.598 | row |
QQQ | 0.0653 | 0.1238 | 0.2018 | 0.561 | row |
IWM | 0.2176 | 0.9247 | 0.9174 | 0.526 | row |
DIA | 0.2849 | 0.6182 | 0.55 | 0.567 | row |
true false not known for rules; forecasts are odds. Hover a column for its question.
Actions
Rules on the answers decide what to send. Each symbol runs its own request, so each one can fire.
trend >= 0→Webhooklake-ingest{
"table": "ora_signals",
"symbol": "SPY",
"as_of": "2026-10-30",
"trend": 0.1128,
"momentum": 0.1658,
"mostly_up": 0.55,
"p_up_week": 0.598
}{
"table": "ora_signals",
"symbol": "QQQ",
"as_of": "2026-10-30",
"trend": 0.0653,
"momentum": 0.1238,
"mostly_up": 0.2018,
"p_up_week": 0.561
}{
"table": "ora_signals",
"symbol": "IWM",
"as_of": "2026-10-30",
"trend": 0.2176,
"momentum": 0.9247,
"mostly_up": 0.9174,
"p_up_week": 0.526
}{
"table": "ora_signals",
"symbol": "DIA",
"as_of": "2026-10-30",
"trend": 0.2849,
"momentum": 0.6182,
"mostly_up": 0.55,
"p_up_week": 0.567
}What it means
Session of 2026-10-30, 4 symbols: Above the 50-day average: true for none of 4. MACD above its signal line: true for IWM, DIA of 4. Up on at least six of the last ten days: true for IWM of 4. Highest odds for “Higher in a week”: SPY at 60%. row fired for SPY, QQQ, IWM, DIA.
The always-true condition makes every symbol post a row, so the table has one record per symbol per session for later research.
As a scheduled workflow (Mon–Fri at 16:45 ET)
Create it under Workflows in the console: it runs these questions for every symbol on the schedule and fires the actions per symbol. The answers above are what one run returned.
{
"name": "Nightly signal snapshot for the index ETFs, posted to a data lake hook",
"symbols": "SPY QQQ IWM DIA",
"days": [
1,
2,
3,
4,
5
],
"at_time": "16:45",
"model": "ora-fin-0.1.1",
"questions": {
"trend": {
"type": "yes_no",
"ask": "C > sma(C, 50)"
},
"momentum": {
"type": "yes_no",
"ask": "macd(C) > macdsignal(C)"
},
"breadth_proxy": {
"type": "yes_no",
"ask": "sum(C > C[-1], 10) >= 6"
},
"up_week": {
"type": "yes_no",
"instructions": "Will the stock be higher in a week?"
}
},
"actions": [
{
"id": "row",
"when": "trend >= 0",
"do": "webhook",
"connection": "lake-ingest",
"body": {
"table": "ora_signals",
"symbol": "{{symbol}}",
"as_of": "{{as_of}}",
"trend": "{{trend}}",
"momentum": "{{momentum}}",
"mostly_up": "{{breadth_proxy}}",
"p_up_week": "{{up_week}}"
}
}
]
}Request JSON (SPY; the others differ only in the symbol)
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "SPY"
},
"questions": {
"trend": {
"type": "yes_no",
"ask": "C > sma(C, 50)"
},
"momentum": {
"type": "yes_no",
"ask": "macd(C) > macdsignal(C)"
},
"breadth_proxy": {
"type": "yes_no",
"ask": "sum(C > C[-1], 10) >= 6"
},
"up_week": {
"type": "yes_no",
"instructions": "Will the stock be higher in a week?"
}
},
"actions": [
{
"id": "row",
"when": "trend >= 0",
"do": "webhook",
"connection": "lake-ingest",
"body": {
"table": "ora_signals",
"symbol": "{{symbol}}",
"as_of": "{{as_of}}",
"trend": "{{trend}}",
"momentum": "{{momentum}}",
"mostly_up": "{{breadth_proxy}}",
"p_up_week": "{{up_week}}"
}
}
],
"dry_run": true
}Response JSON (SPY, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"trend": {
"yes_no": 0.1128,
"rule": "C > sma(C, 50)",
"basis": "rule"
},
"momentum": {
"yes_no": 0.1658,
"rule": "macd(C) > macdsignal(C)",
"basis": "rule"
},
"breadth_proxy": {
"yes_no": 0.55,
"rule": "sum(C > C[-1], 10) >= 6",
"basis": "rule"
},
"up_week": {
"yes_no": 0.598
}
},
"context": {
"symbol": "SPY",
"as_of": "2026-10-30"
},
"actions": [
{
"id": "row",
"fired": true,
"status": "dry_run",
"do": "webhook",
"connection": "lake-ingest",
"preview": {
"body": {
"table": "ora_signals",
"symbol": "SPY",
"as_of": "2026-10-30",
"trend": 0.1128,
"momentum": 0.1658,
"mostly_up": 0.55,
"p_up_week": 0.598
}
}
}
]
}Quant developer · example 8
Stochastic %K and %D states for AMD as model inputs
Feed oscillator states into a classifier without writing an oscillator library.
- StateAMD
- Questions5 asked
- Answersreal, captured
- Actionsnone
State
{"symbol":"AMD"} The server fills in the latest completed session.
Questions
k_over_d | rule | stochk(14) > stochd(14)stochastic %K above %D |
k_low | rule | stochk(14) < 20Stochastic %K under 20 |
willr | rule | willr(14) > -20Williams %R above −20 |
cci | rule | cci(20) > 100CCI above 100 |
up_tomorrow | forecast | Will the stock be up tomorrow? Up tomorrow |
Answers
| Question | Answer | Reading |
|---|---|---|
k_over_dstochastic %K above %D | 0.3746 | false |
k_lowStochastic %K under 20 | 0.1754 | false |
willrWilliams %R above −20 | 0.0666 | false |
cciCCI above 100 | 0.0724 | false |
up_tomorrowUp tomorrow | 0.528 | 53% · close to even |
What it means
For AMD on the session of 2026-10-30: Not true: stochastic %K above %D; Stochastic %K under 20; Williams %R above −20; CCI above 100. Forecasts: Up tomorrow 53%.
Oscillator states come back as exact rules; the next-day forecast is the label the classifier is compared with.
Request JSON
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "AMD"
},
"questions": {
"k_over_d": {
"type": "yes_no",
"ask": "stochk(14) > stochd(14)"
},
"k_low": {
"type": "yes_no",
"ask": "stochk(14) < 20"
},
"willr": {
"type": "yes_no",
"ask": "willr(14) > -20"
},
"cci": {
"type": "yes_no",
"ask": "cci(20) > 100"
},
"up_tomorrow": {
"type": "yes_no",
"instructions": "Will the stock be up tomorrow?"
}
}
}Response JSON (AMD, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"k_over_d": {
"yes_no": 0.3746,
"rule": "stochk(14) > stochd(14)",
"basis": "rule"
},
"k_low": {
"yes_no": 0.1754,
"rule": "stochk(14) < 20",
"basis": "rule"
},
"willr": {
"yes_no": 0.0666,
"rule": "willr(14) > -20",
"basis": "rule"
},
"cci": {
"yes_no": 0.0724,
"rule": "cci(20) > 100",
"basis": "rule"
},
"up_tomorrow": {
"yes_no": 0.528
}
},
"context": {
"symbol": "AMD",
"as_of": "2026-10-30"
}
}Quant developer · example 9
Earnings blackout flag for NVDA in a trading pipeline
Block new entries when a report is close, using the earnings calendar facts instead of a separate data feed.
- StateNVDA
- Questions4 asked
- Answersreal, captured
- Actions2 rules · dry run
State
{"symbol":"NVDA"} The server fills in the latest completed session.
Questions
earn_soon | rule | days_to_earnings <= 7earnings within 7 days |
just_reported | rule | days_since_earnings <= 5Reported in the last 5 days |
amc | English → rule | Does the stock report after the close next time? |
big_mover | rule | abs(last_earnings_move) > 5Last earnings move bigger than 5% |
Answers
| Question | Answer | Reading |
|---|---|---|
earn_soonearnings within 7 days | 0.0537 | false |
just_reportedReported in the last 5 days | 0.0537 | false |
amcDoes the stock report after the close next time compiled to next_report_amc > 0.5 | 0.8591 | true |
big_moverLast earnings move bigger than 5% | 0.9463 | true |
Actions
Rules on the answers decide what to send.
earn_soon >= 0.6→Webhookrisk-gateelse→Webhookrisk-gate{
"symbol": "NVDA",
"gate": "clear",
"as_of": "2026-10-30"
}What it means
For NVDA on the session of 2026-10-30: True now: Does the stock report after the close next time; Last earnings move bigger than 5%. Not true: earnings within 7 days; Reported in the last 5 days. Fired: clear (Webhook → risk-gate).
The gate service gets a blackout or a clear for each symbol; strategies read the gate rather than the calendar.
Request JSON
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "NVDA"
},
"questions": {
"earn_soon": {
"type": "yes_no",
"ask": "days_to_earnings <= 7"
},
"just_reported": {
"type": "yes_no",
"ask": "days_since_earnings <= 5"
},
"amc": {
"type": "yes_no",
"instructions": "Does the stock report after the close next time?"
},
"big_mover": {
"type": "yes_no",
"ask": "abs(last_earnings_move) > 5"
}
},
"actions": [
{
"id": "blackout",
"when": "earn_soon >= 0.6",
"do": "webhook",
"connection": "risk-gate",
"body": {
"symbol": "{{symbol}}",
"gate": "earnings_blackout",
"p_earn_soon": "{{earn_soon}}",
"p_big_mover": "{{big_mover}}",
"as_of": "{{as_of}}"
}
},
{
"id": "clear",
"when": "else",
"do": "webhook",
"connection": "risk-gate",
"body": {
"symbol": "{{symbol}}",
"gate": "clear",
"as_of": "{{as_of}}"
}
}
],
"dry_run": true
}Response JSON (NVDA, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"earn_soon": {
"yes_no": 0.0537,
"rule": "days_to_earnings <= 7",
"basis": "rule"
},
"just_reported": {
"yes_no": 0.0537,
"rule": "days_since_earnings <= 5",
"basis": "rule"
},
"amc": {
"yes_no": 0.8591,
"rule": "next_report_amc > 0.5",
"basis": "pattern"
},
"big_mover": {
"yes_no": 0.9463,
"rule": "abs(last_earnings_move) > 5",
"basis": "rule"
}
},
"context": {
"symbol": "NVDA",
"as_of": "2026-10-30"
},
"actions": [
{
"id": "blackout",
"fired": false,
"status": "skipped"
},
{
"id": "clear",
"fired": true,
"status": "dry_run",
"do": "webhook",
"connection": "risk-gate",
"preview": {
"body": {
"symbol": "NVDA",
"gate": "clear",
"as_of": "2026-10-30"
}
}
}
]
}abs days_since_earnings days_to_earnings last_earnings_move next_report_amc
Quant developer · example 10
How long since GE last broke out? Timing features with barssince
Measure time-since-event features (breakout, 52-week high, volume spike) for a holding-period model.
- StateGE
- Questions4 asked
- Answersreal, captured
- Actionsnone
State
{"symbol":"GE"} The server fills in the latest completed session.
Questions
quiet | rule | barssince(C > highest(C, 20)) > 30No 20-day breakout for 30 sessions |
recent_high | rule | highestbars(H, 50) <= 5the 50-day high was set in the last 5 sessions |
old_low | rule | lowestbars(L, 50) >= 30the 50-day low is at least 30 sessions old |
since_spike | rule | barssince(V > 2 * avg(V, 20)) < 10a volume spike within the last 10 sessions |
Answers
| Question | Answer | Reading |
|---|---|---|
quietNo 20-day breakout for 30 sessions | 0.9237 | true |
recent_highthe 50-day high was set in the last 5 sessions | 0.0563 | false |
old_lowthe 50-day low is at least 30 sessions old | 0.1019 | false |
since_spikea volume spike within the last 10 sessions | 0.534 | on the line (true) |
What it means
For GE on the session of 2026-10-30: True now: No 20-day breakout for 30 sessions. Not true: the 50-day high was set in the last 5 sessions; the 50-day low is at least 30 sessions old. On the line: a volume spike within the last 10 sessions.
Bar-count rules turn event timing into features; a recent high with an old low describes a stock trending away from its base.
Request JSON
{
"model": "ora-fin-0.1.1",
"state": {
"symbol": "GE"
},
"questions": {
"quiet": {
"type": "yes_no",
"ask": "barssince(C > highest(C, 20)) > 30"
},
"recent_high": {
"type": "yes_no",
"ask": "highestbars(H, 50) <= 5"
},
"old_low": {
"type": "yes_no",
"ask": "lowestbars(L, 50) >= 30"
},
"since_spike": {
"type": "yes_no",
"ask": "barssince(V > 2 * avg(V, 20)) < 10"
}
}
}Response JSON (GE, real)
{
"model": "ora-fin-0.1.1",
"answers": {
"quiet": {
"yes_no": 0.9237,
"rule": "barssince(C > highest(C, 20)) > 30",
"basis": "rule"
},
"recent_high": {
"yes_no": 0.0563,
"rule": "highestbars(H, 50) <= 5",
"basis": "rule"
},
"old_low": {
"yes_no": 0.1019,
"rule": "lowestbars(L, 50) >= 30",
"basis": "rule"
},
"since_spike": {
"yes_no": 0.534,
"rule": "barssince(V > 2 * avg(V, 20)) < 10",
"basis": "rule"
}
},
"context": {
"symbol": "GE",
"as_of": "2026-10-30"
}
}Information, not investment advice. Rules answer from the latest completed daily session; forecasts are probabilities. Actions ran as dry runs: nothing was sent. More in Builders: Fintech app builder, Robo-advisor, Broker app, Algo / bot developer, Data vendor / platform, Trading educator / newsletter.