FNOTrader Algo — Help
A no-code builder for F&O algos. Author multi-leg strategies, backtest them against minute-bar history, and ship the exact same recipe to live trading through your broker. This page documents every feature in the builder, the backtest engine, and the live runtime — with worked examples for each.
Welcome
The execution engine is a standalone Go service that runs configurable multi-leg F&O strategies on your behalf. It pairs three pieces:
- A visual builder (this UI) where you describe a strategy as a recipe — no programming required.
- A backtest engine that replays the recipe against last year of minute-bar history (CE/PE OHLC + IV + OI per ATM±10 strike).
- A live runtime that ships the exact same recipe to your broker — Kite/Dhan/paper — and supervises the trade end-to-end.
Trader's mental model
WHEN some condition is true on these WATCH instruments, FIRE these legs, MONITOR them under these stop/target rules, and EXIT when this other condition is true (or at square-off time).
Builder is laid out the same way: Step 1–2 define your universe, Step 3 defines triggers, Step 4–5 define legs and risk, Step 6 defines how orders go out.
Five-minute quick-start
- Open the builder and pick a Template in Step 1 — e.g. Short Straddle. It seeds the legs for you.
- Skip straight to Step 6 → press ▶ Run Backtest. You'll get a full report in 10–20 seconds covering the last month.
- Tweak the SL/TG in Step 4 → re-run. Compare results in the Backtest History tab.
- Press 💾 Save Strategy. The recipe is now reusable in live trading too.
- From the home screen, attach the saved strategy to a Broker Account and press ▶ Start.
Colors & conventions
Badges: BACKTEST works in backtest, LIVE works in live trading, BETA accepted but not fully wired, TODO deferred.
Step 1 · Strategy identity
Three fields define what the strategy is and where it trades.
| Field | What it does |
|---|---|
| Strategy Name | Free-form label — appears in the Strategies tab, save modal, and backtest history. Autofill is disabled so the browser doesn't accidentally fill your login email here. |
| Symbol | The instrument the strategy trades. Searchable dropdown of every F&O index (NIFTY / BANKNIFTY / FINNIFTY / MIDCPNIFTY / SENSEX / BANKEX) plus every F&O stock. The chosen symbol drives ATM-strike resolution, lot-size lookup, and weekly-vs-monthly expiry eligibility. |
| Template | Pre-built recipes you can use as a starting point:
short_straddle, iron_condor,
BTST, STBT,
rolling_straddle, rolling_strangle, or
custom (blank slate). Picking one seeds Steps 4–6. |
Step 2 · Instruments to Watch
The "vocabulary" your conditions can use. Anything you name here is
readable in Step 3 conditions via ALIAS.METRIC.
Scope dropdown
| Scope | What it resolves to | Example alias |
|---|---|---|
| Spot | Underlying spot index/stock | NIFTY.CLOSE |
| Option | One specific strike + CE/PE | OPT_ATM_CE.LTP, OPT_OTM2_PE.IV |
| ATM Straddle | Sum of ATM CE + ATM PE LTPs | ATM_STRADDLE.LTP |
| Strangle | Sum of OTMn CE + OTMn PE LTPs | OTM2_STRANGLE.LTP |
| Custom Combiner | Arbitrary linear combination of legs (synthetic) | MY_SYNTH.LTP |
Per-row fields
- Alias — what you'll type in Step-3 expressions. Auto-populates
from Scope but is fully editable. Keep it descriptive
(
OPT_ATM_CEnotfoo). - Timeframe — bucket size for indicator aggregation
(1m / 3m / 5m / 15m / 30m / 1h / 1d). Drives
EMA,RSIetc. on that alias. A 5m TF meansOPT_ATM_CE.EMA(10)reads the 10-bar EMA of 5-min candles, not 10 raw minutes. - Symbol / Expiry / Strike Distance — adapt to the chosen scope.
Add Scope = Option, Alias = OPT_ATM_CE, Option Type = CE, Distance = ATM, TF = 5m. Now in Step 3A you can write:
OPT_ATM_CE.CLOSE > OPT_ATM_CE.EMA(10)
Entry only when ATM CE breaks above its own 10-bar (5m) EMA.
Step 3A · Entry conditions
Multi-row builder. Each row is one boolean clause; rows combine with AND
or OR (your choice). The full expression is evaluated every bar (or
throttled — see Check Frequency) and the
strategy enters on the first true.
Per-row fields
| Field | Purpose |
|---|---|
| Symbol | Step-1 instrument the metric reads from. Defaults to the strategy underlying. |
| Metric | Indicator to evaluate. 40+ choices — see catalog. |
| Metric args | Inline numeric inputs for parameters (e.g. EMA period, MACD fast/slow). All values are user-editable. |
| Operator | How LHS is compared (full list below). |
| RHS | Either a literal value or another metric. Toggle with the value/metric pill. |
Operator catalog
| Operator | Fires when… |
|---|---|
greater_than / less_than | Plain numeric comparison. |
above / below | LHS above/below a price reference (e.g. above_VWAP). |
crossing | LHS crosses RHS in either direction this bar. |
crossing_up / crossing_down | LHS crosses RHS from below / above this bar. |
moving_up / moving_down | LHS strictly increasing / decreasing N bars in a row. |
inside_channel / outside_channel | LHS is between (or outside) two RHS values. |
entering_channel / exiting_channel | Entered / left the channel this bar. |
new_day_high / new_day_low | LHS prints a fresh intraday extreme. |
range_breakout_up / _down / _either | LHS breaks above/below/either side of the opening-range high/low. Window is user-editable (Start–End times). |
Combine mode
Toggle AND (all rows must fire) or OR (any one). Rows cannot mix AND/OR within one block — for that, save two strategies and cascade them via On-Hit actions.
Check Frequency
How often the expression is evaluated:
tick— every market tick (live) / every minute-bar (backtest).every X-min bar close— only when minute-of-day mod X == 0 (e.g. 5 = 09:20, 09:25, …).
Step 3B · Exit conditions
Same builder as 3A but evaluated after entry. If any exit row fires (when combine = OR) or all exit rows fire (combine = AND), the engine flattens every open leg at next bar's open.
Exit conditions compose with the per-leg SL/TG (Step 4) and Combined SL/TG (Step 5). Whichever triggers first wins — they're not mutually exclusive.
Step 3C · BTST / STBT mode
Buy-Today-Sell-Tomorrow / Sell-Today-Buy-Tomorrow. Two time pickers:
Start Time (today's entry window) and Exit Time (next
trading day's square-off). When both are set, the engine flips
overnight_hold = true and the strategy is held across the
EOD square-off boundary. Entry/Exit conditions 3A/3B remain available
but optional.
Step 4 · Strategy Legs
Table of legs the strategy fires. One row per leg.
Main-row columns
| Col | What it does |
|---|---|
| Idle | Leg is deferred — won't fire at entry. Activated only by another leg's execute_other_leg action. |
| Hedge | Marks a protective BUY leg. Excluded from Move-SL-to-Cost and exits last on flatten. |
| Side | BUY / SELL |
| Fut/Opt | OPT (default) or FUT. FUT hides Type/Strike-Selection cells. |
| Type | CE or PE |
| Strike Selection | How the strike is picked — see below. |
| Strike Value | Adapts to the selection mode. |
| Expiry | Relative (Current Weekly / Next Weekly / Current Monthly / Next Monthly) or Absolute date. |
| Qty (lots) | Multiplied by lot_size at order time. |
| ⚙ Settings | Expands the advanced 4-tab panel. |
Strike Selection modes
| Mode | Behaviour | Backtest support |
|---|---|---|
| Distance | ATM / OTM1–15 / ITM1–15 strike steps from ATM. Most common. | ATM±10 — deeper strikes clamp to boundary with a warning. |
| Absolute | Exact strike number (e.g. 24500). | LIVE — backtest clamps to nearest archived strike with a warning. |
| Premium | Engine picks the strike whose LTP is closest to a target ₹ value. | LIVE — backtest clamp warning. |
| Delta | Target |delta| (e.g. 0.30 for ~30-delta). | LIVE — backtest clamp warning. |
| Straddle Width | Strike whose premium is N% (or N×) of the ATM straddle premium. | LIVE |
| Underlying Price | Signed % offset from spot — e.g. +0.5% on NIFTY=24000 → strike ≈ 24120. | LIVE |
Advanced (⚙) — tabbed panel
Tab 1 · Wait & Trade
Delay this leg's entry until its premium crosses a trigger price. Useful for buying weakness or selling strength after the basket has already fired.
- SL Wait (sec) — extra delay before arming SL after fill.
- Wait & Trade Trigger — value + unit
(
ptsabsolute /pts_relrelative to LTP at entry /%).
Tab 2 · Stoploss (SL1+)
| SL Type | Meaning |
|---|---|
pct | % of entry premium (e.g. 30 = 30%). |
points | Flat ₹ move from entry (e.g. 15 = ₹15 swing). |
pnl | Per-leg ₹ loss (qty-aware). |
underlying_move / _up / _down | SL trips when spot moves N points or N% in the chosen direction. |
delta | SL trips when the leg's |delta| crosses a threshold. |
atr | SL = entry ± N × ATR(period). ATR source is a Step-1 watch instrument. |
Per-rung fields: SL Qty (% or lots), On-Hit action, Check Frequency. Add SL2 / SL3 rungs for laddered exits.
On-Hit action catalog
| Action | Effect |
|---|---|
just exit | Close the leg, do nothing else (default). |
keep_leg_running | Don't close — mark SL fired but continue holding. Useful for ladder rungs that change behaviour without flat-flat. |
re_execute_N_times | Close, then re-fire the same leg up to N times. Each re-entry counts. |
close_leg_id | Also close another leg by ID (e.g. spread partner). |
enter_leg_id | Fire a leg marked Idle. |
move_sl_to_cost | Move every other leg's SL to its entry price (lock breakeven). |
add_qty_pct | Scale up the leg by N% (martingale-style). |
execute_other_leg | Trigger another leg with optional delay (live engine cascade). |
execute_other_strategy | Launch a separate saved strategy. |
Tab 3 · Target (TGT1+)
Same structure as SL. Target Types include all SL types plus
r_multiple (risk-reward — target distance = N × stop distance).
Tab 4 · Per-leg Trailing
- Trail Trigger — profit ₹ threshold that arms the trail.
- Trail Step — every N₹ further profit, ratchet the stop up.
- Trail Lock — minimum ₹ locked in once trail is armed.
- Check Frequency — tick / xm_close.
Step 5 · Strategy Risk Settings (Combined)
Same shape as the per-leg advanced panel but at the basket level. Four tabs: Wait & Trade, Stoploss, Target, Trailing.
Combined SL/TG fires when the basket-level MTM (sum of all open-leg PnLs) crosses a ₹ or % threshold. On hit, the action choices include:
just exit— flatten all legs.close_current_strategy— explicit version of above.close_and_re_enter_strategy— flatten, then re-fire after a configured delay (capped by NTimes).close_all_losing/close_all_profitable— partial flatten.close_all_ce_buys/_ce_sells/_pe_buys/_pe_sells— close by option-type + side.move_sl_to_cost_profitable_legs— lock breakeven on the winners.execute_other_leg/execute_other_strategy— cascade.
Step 6 · Execution Settings
| Field | What it does |
|---|---|
| Legs Execution | parallel (all at once), sequential (fire next after prev fills), buy_first (BUYs in parallel, then SELLs after delay). |
| Hold Sell Sec | Delay between BUY batch and SELL batch in buy_first mode. Used to lock hedges before opening short exposure. |
| If Leg Fails | cancel_all / keep_placed / retry_failed (with Max Retries). |
| Spike Protect % | Skip entry if spread > %. |
| Spread Limit % | Reject any leg whose bid/ask spread exceeds %. |
| Premium Gap % | Reject if leg LTP gapped > % from prev close. |
| Slippage % | Cap acceptable slippage at fill. |
| Run On Days | Mon–Sun checkboxes. Strategy is paused on un-checked days. |
| DTE Filter | Only enter when days-to-expiry matches the chosen set (discrete: pick 0,1,2…) or range (e.g. 3–7). Basis = weekly or monthly cycle. |
| Max Lots | Hard cap on total lot count across all legs. |
| Exposure (₹) | Auto-size qty from capital — engine divides this by margin/lot to compute lots. |
| Order Type | MKT / LMT / LMT-BUF (limit with N% buffer off LTP). |
| Product | NRML (carry) / MIS (intraday). |
| Send to Telegram | Mirror lifecycle events to your bot. |
Step 7 · Summary & Save
A single-page English-prose recap of everything you've configured. Refresh it (↻) any time. Then ▶ Start Strategy (live), 💾 Save Strategy (reusable recipe), or Export JSON / Import JSON (share/version).
Expression language
Conditions internally compile to a small expression language. The builder writes it for you, but you can also type it directly into the Preview box (advanced).
Operators & precedence
| Class | Operators | Notes |
|---|---|---|
| Boolean | AND OR NOT | Case-insensitive; standard precedence (NOT > AND > OR). |
| Comparison | > < >= <= == != | Pair LHS metric to RHS value/metric. |
| Arithmetic | + - * / | Standard math precedence. Use parentheses freely. |
| Grouping | ( ) | Override precedence. |
Symbol resolution
Three styles, all interchangeable:
NIFTY.CLOSE— bare underlying token. Recognised symbols: NIFTY, BANKNIFTY, FINNIFTY, MIDCPNIFTY, SENSEX, BANKEX.ATM_CE.IV,OTM2_PE.OI,ITM3_CE.DELTA— relative option symbols. Strike-offset computed automatically; CE/PE explicit.LEG1.CLOSE,LEG2.IV— refers to leg #1, #2, … of this strategy.ALIAS.METRIC— any alias you defined in Step 2.
Special identifiers
| Token | Value |
|---|---|
TIME | Current bar in HHMM (e.g. TIME >= 0930). |
PREV_CLOSE | Yesterday's last bar close — persists across overnight gap. |
LAST_TICK | Tick-level LTP (not candle-level). Useful for sub-second alerts in live. |
Multi-instrument (Phase 4.6)
You can reference foreign underlyings in the same expression. Common use: trade NIFTY only when the broader market (SENSEX) also agrees.
// NIFTY straddle, only when SENSEX is trending up
TIME >= 0920 AND SENSEX.CLOSE > SENSEX.EMA(10)
Backtest data: only NIFTY and SENSEX have archived spot bars today. BANKNIFTY / FINNIFTY references compile fine but produce a warning + read as 0 (so the gate effectively never fires). Live trading is unaffected — all 6 indices stream.
Arithmetic between metrics
The evaluator supports full arithmetic between metric reads. Strike-wise PCR is the canonical example:
// Strike-wise PCR > 1.5 (puts dominate at ATM = bearish hedging)
ATM_PE.OI / ATM_CE.OI > 1.5
// Straddle premium relative to spot > 1.5%
(ATM_CE.LTP + ATM_PE.LTP) / NIFTY.CLOSE * 100 > 1.5
// Credit-spread net premium > ₹50
LEG1.LTP - LEG2.LTP > 50
Every condition row in Steps 3A/3B has an optional arithmetic
combinator between the primary metric and the operator — a small
dropdown reading — by default. Pick +, −,
×, or ÷ and a second
[Symbol] + [Metric] + [args] block appears, so you
can build composite LHS expressions like
ATM_PE.OI ÷ ATM_CE.OI > 1.5 entirely from dropdowns. The
Preview textarea is still available for power users who want to type
longer compound expressions directly.
Metrics & indicator catalog
Every metric below works on any symbol — spot, option, alias.
Price & structural
| Metric | Returns | Example |
|---|---|---|
LTP | Last traded price | OPT_ATM_CE.LTP > 200 |
OPEN / HIGH / LOW / CLOSE | Current bar's OHLC | NIFTY.CLOSE > NIFTY.OPEN |
DAY_HIGH / DAY_LOW | Intraday extreme | NIFTY.CLOSE >= NIFTY.DAY_HIGH |
PREV_CLOSE | Yesterday's last close | NIFTY.CLOSE > PREV_CLOSE |
VWAP | Volume-weighted avg price (day-anchored) | NIFTY.CLOSE > NIFTY.VWAP |
SMA(N) | Simple moving avg over N bars | NIFTY.CLOSE > NIFTY.SMA(20) |
EMA(N) | Exponential MA | NIFTY.CLOSE > NIFTY.EMA(10) |
WMA(N) | Weighted MA | NIFTY.WMA(14) |
SAR(step, max) | Parabolic SAR (defaults 0.02, 0.2) | NIFTY.CLOSE > NIFTY.SAR(0.02, 0.2) |
Momentum
| Metric | Returns | Example |
|---|---|---|
RSI(N) | Wilder RSI (0–100) | NIFTY.RSI(14) < 30 |
ROC(N) | Rate of change (%) over N bars | NIFTY.ROC(5) > 0.5 |
MACD(fast, slow) | MACD line | NIFTY.MACD(12, 26) > 0 |
MACD_SIGNAL(f, s, sig) | Signal line | NIFTY.MACD(12,26) > NIFTY.MACD_SIGNAL(12,26,9) |
MACD_HIST(...) | Histogram (MACD − signal) | NIFTY.MACD_HIST(12,26,9) > 0 |
STOCH_K(N) / STOCH_D(N, d) | Stochastic %K / %D | NIFTY.STOCH_K(14) > 80 |
ADX(N) | Average Directional Index | NIFTY.ADX(14) > 25 |
CCI(N) | Commodity Channel Index | NIFTY.CCI(20) > 100 |
WILLR(N) | Williams %R (−100..0) | NIFTY.WILLR(14) > -20 |
Volatility & channels
| Metric | Returns | Example |
|---|---|---|
ATR(N) | Avg True Range | NIFTY.ATR(14) > 100 |
BB_UPPER(N, σ) | Bollinger upper band | NIFTY.CLOSE > NIFTY.BB_UPPER(20, 2) |
BB_MIDDLE(N) | BB middle (SMA(N)) | NIFTY.BB_MIDDLE(20) |
BB_LOWER(N, σ) | BB lower band | NIFTY.CLOSE < NIFTY.BB_LOWER(20, 2) |
SUPERTREND(N, mult) | Supertrend value | NIFTY.CLOSE > NIFTY.SUPERTREND(10, 3) |
Volume / OI / CDV
| Metric | Returns | Example |
|---|---|---|
VOLUME | Bar volume | OPT_ATM_CE.VOLUME > 100000 |
OBV | On-Balance Volume | NIFTY.OBV > 0 |
OI | Open interest (options only) | ATM_PE.OI / ATM_CE.OI > 1.5 |
CDV | Cumulative delta volume (signed) | NIFTY.CDV > 0 |
BUILDUP | OI buildup tag (long/short addition/unwinding) | OPT_ATM_CE.BUILDUP == 1 |
Option Greeks
Computed via Black-Scholes (Hull 11e) at risk-free rate 6.5%. Returned per option symbol; backtest computes on-the-fly from (spot, strike, IV, DTE).
| Metric | Returns | Example |
|---|---|---|
IV | Implied volatility (%) | ATM_CE.IV > 25 |
DELTA | Price sensitivity to spot | OPT_ATM_CE.DELTA > 0.4 |
GAMMA | Δ sensitivity to spot | ATM_CE.GAMMA > 0.001 |
THETA | Per-day time decay (₹) | OPT_ATM_CE.THETA < -50 |
VEGA | Per-1%-IV sensitivity (₹) | ATM_CE.VEGA > 20 |
Pivots, CPR, Camarilla
| Metric | Returns |
|---|---|
PIVOT_P, PIVOT_R1..R3, PIVOT_S1..S3 | Standard floor pivots |
CPR_PIVOT, CPR_TC, CPR_BC, CPR_WIDTH | Central Pivot Range bands |
FIB_P, FIB_R1..R3, FIB_S1..S3 | Fibonacci pivots |
CAM_H1..H4, CAM_L1..L4 | Camarilla bands |
TIME & PREV_CLOSE
// Window-only entry
TIME >= 0925 AND TIME < 1100
// Gap-up open
NIFTY.OPEN > PREV_CLOSE * 1.005
Backtest engine
Replays your saved strategy against minute-bar history from
dhan_backtest.db (29.4M option rows, spot bars per index,
ATM±10 strike coverage with full OHLC + IV + OI). Hit
▶ Run Backtest on any saved strategy; reports are persisted to
Backtest History.
What's loaded
- Spot bars for the primary underlying (NIFTY / SENSEX) + every foreign underlying referenced in expressions (Phase 4.6).
- Option bars (CE/PE OHLC + IV + OI) for the strike offsets the
strategy needs — folded from per-leg Distance + any
ATM_CE/OTM2_PEtokens in the entry/exit expressions. - day_meta (ATM, expiry flags, DTE) per session.
On-the-fly Greeks
The archive carries OHLC + IV + OI but not Δ Γ Θ Vega. The engine computes them per-minute from (spot, strike, IV, DTE) via Black-Scholes. Theta ticks down throughout the day as DTE shrinks. Verified by 7 unit tests including ATM sanity, deep ITM/OTM bounds, Γ-peak-at-ATM, vega-peak-at-ATM, garbage-input guards, and put-call parity at 1e-9 precision.
Multi-instrument
Expression tokens like SENSEX.RSI(14) in a NIFTY backtest
transparently load SENSEX spot bars in lock-step. Unsupported foreign
underlyings (BANKNIFTY, FINNIFTY, MIDCPNIFTY, BANKEX) surface a clear
Warnings entry instead of silently zeroing — see
multi-instrument.
No-lookahead-bias
Common backtester bug: signal fires at bar X's close and "fills" at bar X's open. That's physically impossible — the open already happened 60s before the close existed — and inflates results.
This engine enforces a 1-bar defer: indicator signal at bar X → fill at bar X+1's OPEN. The rule applies to entry, exit_condition, per-leg SL/TG, AND combined SL/TG.
Pure-TIME strategies (no bar data read) still fill same-bar — no lookahead since no bar was consulted to decide.
Friction model
Two knobs in the Run-Backtest dialog:
- cost_inr_per_leg — flat ₹ deducted per round-trip (brokerage + STT + exchange + GST + stamp). Typical ₹50–80 for NIFTY.
- slippage_pct — adverse fill at entry and exit. SELL at mid×(1−slip%) on entry, mid×(1+slip%) on exit; BUY direction reverses. You pay both sides.
The report has 3 tabs: Plain, Costs only, +Slippage — so you can see the friction sensitivity instantly.
Check Frequency throttle
Honored independently per surface: entry expression, exit expression,
per-leg SL1/SL2/TGT1/TGT2/Trail, and combined SL/TG/Trail.
shouldCheckThisMinute() handles three modes:
tick— every minute bar.every_xm— N-min interval from StartHHMM.xm_close— minute-of-day grid (MM mod N == 0).
Use this to model "evaluate SL only on 5-min close" or "Combined SL every minute, per-leg SL every 5 minutes" mixtures.
Strike clamp at ATM±10
The archive only has ATM±10 strike data. Out-of-range legs are clamped to the boundary (with a warning) — never silently skipped. Live trading uses the exact strike you specified.
You'll also see a clamp notification toast in the Builder when:
- You pick a Distance outside ATM±10 (OTM12, ITM15, etc.).
- You pick any dynamic mode (Premium / Delta / Absolute / Straddle / UndPrice) — since the resolved strike is unknown at build time.
Report & History
Every backtest produces:
- Daily P&L list with trade-by-trade detail, ATM, skip reasons.
- Headline stats — total PnL, win rate, day count, best/worst day, max drawdown, avg daily.
- Monthly calendar — hedge-fund-style P&L heat-map.
- Equity curve + running drawdown chart (TradingView Lightweight Charts).
- Strategy rules header — exact entry/exit/SL/TG echoed back.
- Warnings panel — strike clamps, unsupported metrics, missing data.
Every run is persisted to Backtest History — sort by PnL, win rate, sharpe.
Live trading · broker adapters
| Adapter | Status | Use case |
|---|---|---|
| stub | READY | No real orders. Lifecycle / smoke tests. |
| paper | READY | Fills at current LTP from quote feed. Realistic dry-run with live data. |
| kite | WIRED | Zerodha — adapter scaffold in place. |
| dhan | WIRED | Dhan — adapter scaffold in place. |
Strategy lifecycle
- Start — registry spawns a supervised goroutine for the strategy.
- Wait for entry — evaluates entry condition every tick (or per check_freq) until firing.
- Resolve strikes — uses the per-leg strike-selection mode (Distance / Premium / Delta / OI-based / etc.).
- Fire legs — atomically, per execution-mode (parallel / sequential / buy-first).
- Monitor — quote feed per leg → per-leg SL/TG → combined SL/TG → trail SL — all gated by their own check_freq.
- Exit — on SL/TG hit, exit-condition fire, sqoff time, or kill-switch.
- Settle — records realised P&L, updates daily-loss counters, marks strategy complete.
Leg execution modes
parallel— all legs fired concurrently (default).sequential— wait for leg N to fill before firing leg N+1.buy_first— all BUY legs in parallel; wait HoldSellSec; then all SELL legs. Locks hedges before opening short exposure.
Fail policies when any leg fails to fill:
cancel_all— square off any filled legs and abort.keep_placed— proceed with the partial basket.retry_failed— retry up to MaxRetries before falling back to cancel_all.
On-Hit actions
Fire on SL or TGT events at the leg level (Step 4 → SL/TGT tabs) or the basket level (Step 5 → Combined SL/TGT). See the Step 4 action catalog for per-leg; basket-level actions are listed in Step 5. All actions can chain and most carry a delay parameter for staged behaviour.
Hedges & Move-SL-to-Cost
- IsHedge flag (checkbox on a leg) — that leg is excluded from Move-SL-to-Cost and is exited last when flatting the basket. Use on BUY legs that protect a SELL.
- Move-SL-to-Cost (Combined SL action) — once profitable legs cross a threshold, move every other (non-hedge) leg's SL to its entry price. Locks breakeven on the open legs.
Risk gate
| Setting | Effect |
|---|---|
| Max Daily Loss | Kill switch — once realised P&L for the day drops below this, no new entries fire (across all strategies). Resets at IST midnight. |
| Max Daily Trades | Cap on entry count per day. |
Webhook entry (OnSignal)
Get a private token from the Webhook page. POST to
/api/webhook/signal/{token} with no body — the token is
the auth. The configured saved-strategy fires immediately. Useful for
TradingView / Python alerts / external scanners.
curl -X POST https://your-engine/api/webhook/signal/AbC123xyz
Telegram notifications
Tick Send to Telegram in Step 6 to mirror every lifecycle event
to your bot — entry fills, SL/TG hits, leg closes, re-entries,
auto-hedge applied. Configure bot_token + chat_id
in config.yml. Buffered, non-blocking, Markdown-formatted.
Strategy recipes
Twelve worked examples covering the breadth of features. Each is a complete spec you can paste into the builder.
R1 · Short Straddle Beginner
TIME >= 0920SELL CE · ATM · 1 lot · SL 30% · TG 50%
R2 · Iron Condor with hedges Beginner
TIME >= 0920SELL CE ATM · SL 30% · TG 50%
BUY PE OTM3 · Hedge ✓
BUY CE OTM3 · Hedge ✓
R3 · EMA-crossover long CE Beginner
TIME >= 0925 AND OPT_ATM_CE.CLOSE > OPT_ATM_CE.EMA(10)R4 · Range Breakout strangle Intermediate
NIFTY.CLOSE range_breakout_either (window 09:15–10:00)R5 · PCR-gated straddle Intermediate
Row 2: ATM_PE · OI · ÷ · ATM_CE · OI · > · 1.5 (use the arithmetic ÷ between the two metrics)
Compiled:
TIME >= 0930 AND (ATM_PE.OI / ATM_CE.OI) > 1.5
R6 · IV-filtered iron fly Intermediate
TIME >= 0920 AND ATM_CE.IV > 18R7 · BTST overnight strangle Intermediate
R8 · Cross-index gate Advanced
TIME >= 0920 AND SENSEX.CLOSE > SENSEX.EMA(10)R9 · Delta-gated CE seller Advanced
TIME >= 0920 AND ATM_CE.DELTA > 0.4 AND ATM_CE.DELTA < 0.6R10 · Multi-level SL ladder Advanced
just exit · check freq tickmove_sl_to_cost on remaining · check freq 5m closeR11 · Combined SL kill-switch + re-enter Advanced
close_and_re_enter_strategy · delay 300s · NTimes 2R12 · 5m TF indicator + 1m execution Advanced
OPT_ATM_CE.CLOSE > OPT_ATM_CE.EMA(10)Known limits
- Backtest strike range — ATM±10 only. Beyond that, legs clamp with a warning. Live trading unaffected.
- Backtest spot underlyings — only NIFTY and SENSEX have archived spot bars. BANKNIFTY / FINNIFTY / MIDCPNIFTY / BANKEX references warn and read 0.
- Multi-component synthetic instruments (custom combiners) are accepted by the live engine but the backtest currently skips them with a warning.
- Premium / Delta / Absolute / OI-based strike resolution is deferred in backtest — those modes resolve to the clamp boundary with a warning. Live trading resolves dynamically as designed.
- Gap-up / Gap-down gates, auto-hedge logic, re-execute-N-times are accepted in params but the live engine evaluation is partial — they're flagged BETA.
- Kite / Dhan adapters are scaffolded but not yet production-tested. Use paper or stub for go-live testing.
Glossary
| Term | Meaning |
|---|---|
| ATM | At-the-money. Strike closest to current spot. |
| ATM±N | N strike steps away from ATM (typically 50pt for NIFTY, 100pt for BANKNIFTY). |
| OTM | Out-of-the-money. CE strike > spot, or PE strike < spot. |
| ITM | In-the-money. Opposite of OTM. |
| DTE | Days to expiry. |
| MTM | Mark-to-market — current unrealised P&L. |
| NRML | Carry-forward (overnight) product. |
| MIS | Intraday product — must square off by 15:25 IST. |
| PCR | Put-Call Ratio. OI(PE) / OI(CE) — at a strike or aggregated. |
| IV | Implied Volatility (%). |
| VWAP | Volume-Weighted Average Price (day-anchored). |
| Lookahead bias | Backtester bug where a signal fills at a price that didn't yet exist when the signal computed. |
| Combined SL/TG | Basket-level stop/target on the sum of all open-leg PnLs. |
| Move-SL-to-Cost | Action that moves every other leg's stop to its entry price (lock breakeven). |
| BTST / STBT | Buy-Today-Sell-Tomorrow / Sell-Today-Buy-Tomorrow — overnight hold. |
| Hedge leg | A BUY leg flagged to cap basket loss; excluded from Move-SL-to-Cost; exits last. |
| Idle leg | Leg that doesn't fire at entry — activated only by another leg's execute_other_leg action. |
FAQ
Why are my backtest trades different from yesterday's run?
Most likely you tweaked something in the Builder, or the engine received a lookahead-bias fix / Greeks fix / TF-fix in a recent release. If the recipe is unchanged and pre-dates a fix, results should diverge — the older results were quietly wrong.
My strategy never enters in backtest. Why?
Check the Warnings panel of the report. Common reasons:
- Foreign underlying referenced but unarchived (e.g. BANKNIFTY).
- Out-of-archive strike (Distance > ATM±10 or Premium/Delta/etc. resolving outside).
- Entry condition that depends on an indicator that hasn't warmed up
yet — e.g.
EMA(200)with only ~50 bars in history.
Why is my entry timing one bar later than my signal?
That's the lookahead-bias guard working as intended — see No-lookahead-bias. Pure-TIME entries don't defer; only indicator-driven entries do.
How do I compute strike-wise PCR?
Pick the primary metric (e.g. ATM_PE · OI), then choose
÷ from the arithmetic-combinator dropdown in the same row,
then pick the second metric (ATM_CE · OI). Set the operator
to greater than and the RHS value to 1.5. The
Preview compiles to (ATM_PE.OI / ATM_CE.OI) > 1.5 and the
backtest/live engine evaluates it natively — no special PCR metric needed
because the same UI supports any ratio / sum / difference / product of two
metrics.
What's the difference between "tick" and "xm_close" check freq?
tick evaluates every minute bar. xm_close only
evaluates on bars whose minute-of-day mod X is zero — so 5m_close fires
at 09:20, 09:25, 09:30, … and ignores the bars between. Use xm_close
to model "candle-close confirmation" entry/exit logic.