Andrea Cimitan’s Opening Range Breakout Strategy: Rules, Settings & Backtest (NQ)

By PickMyTrade

Andrea Cimitan calls the opening range breakout his “go-to” starting strategy, in his own words, on record, in a two-hour podcast interview. He also says that trading it without his order-flow overlay leaves money on the table. This guide covers both: his published rules for the base ORB setup, the Pine Script implementation we built and back-tested on NQ futures, and how to automate it with PickMyTrade.

Andrea Cimitan is not affiliated with PickMyTrade. This guide summarizes his publicly stated rules from interviews and his own teaching material, and documents an independent Pine Script implementation and backtest of the base layer he describes.

Who Is Andrea Cimitan?

Andrea Cimitan, known online as Andrea Cimi, is an Italian order-flow trader based in the UAE with roughly 250,000 YouTube subscribers across English, Italian, and Spanish channels. He co-founded the order-flow platform DeepCharts alongside fellow trader Fabio Valentini, runs a trading school called Morpheus Education, and is launching a macro fund, Palinuro Capital. His framework is “Liquidity Auction Theory,” taught across a 17-lesson Complete Order Flow Masterclass on Chart Academy.

Note: there is an unrelated software developer also named Andrea Cimitan, known in Ubuntu/GNOME circles for desktop theming work. Different person entirely.

Andrea Cimitan’s Trading Rules (From Public Interviews)

As described by Cimitan in interviews and his own teaching material, not trading advice:

  • Start simple: the opening range breakout is his recommended entry system for beginners: “the go-to,” in his words
  • Build the opening range from the first N minutes of the regular cash session (9:30 AM–4:00 PM Eastern)
  • Wait for a candle to close beyond the range, not just wick through it
  • Enter in the breakout direction once that close confirms
  • Stop and target are structure-relative: stop on the opposite side of the range
  • Two-attempts rule: a setup often gets stopped once or twice before it works, so risk budget for one idea splits across two attempts, not one
  • Layer in order flow (“big bubbles,” a live filter on large executed trades) for higher-conviction entries; without it, in his words, “you’re leaving money on the table”
  • Timeframe stack: daily for bias, 5-minute for structure, 1-minute for entry timing, with a 90-day composite volume profile behind the daily read

What Is Liquidity Auction Theory?

Cimitan’s framework treats the market as a continuous auction between balance (value) and imbalance (trend). Price either gets rejected outside an established value area (a reversal signal) or gets accepted beyond it, confirming continuation. He reads this with order flow: volume profile to see where value has built up, and a live large-trade filter to see who’s actually pressing the market at that level.

The “big bubbles” concept is specific: on his charts, a bubble marks an individual executed trade above a size threshold (he uses 150+ contracts on the S&P 500). A large bubble printing on a candle’s body signals aggressive follow-through: enter. The same size trade printing on a candle’s wick signals absorption, a resting order soaking up aggression, and means stand aside.

The Order-Flow Layer: Why the Base ORB Isn’t the Whole Story

This is the layer that can’t be coded in Pine Script, and Cimitan says so himself. His large-trade filter needs individual order-execution data: tick-by-tick trade prints with size, which standard OHLC candles and TradingView’s aggregated volume simply don’t carry. Retail platforms show you what happened to the bar; they don’t show you the individual prints that built it.

That’s the same limitation the Fabio Valentini order-flow approximation on this blog runs into, and it’s worth being direct about here too: the opening range breakout below is the mechanical, codeable base layer Cimitan teaches beginners to start with. The order-flow confirmation on top of it is his stated edge, and it stays manual: a chart-reading skill, not a script input.

The Opening Range Breakout: How the Script Works

The base layer, exactly as published:

  1. Build an opening range from the first N minutes of the regular session (9:30 AM–4:00 PM ET)
  2. Wait for a candle close beyond the range (not a wick)
  3. Enter in the breakout direction
  4. Stop on the opposite side of the opening range
  5. Target set as a configurable R-multiple
  6. Maximum two attempts per direction per day
  7. Flat before the close, no overnight risk

Which Ruleset Are We Testing?

Cimitan has described this setup across several videos and course material spanning about nine months, and the specifics (range length, direction, target) shift slightly between them. Rather than pick one silently, the script ships with four selectable presets built from his own material:

VariantRangeDirectionStopTarget
A30 minLong onlyUnder breakout candleVaries
B30 min or 15 minBothOpposite side (assumed)1:1 or 1:0.5
C15 minBothOpposite side of the range1:1 to 1:2
D30 minBothWhole range / mid-range~1:2

The backtest below runs Variant C, his English-course version and the most fully specified of the four.

Risk Management Rules

  • Risk per trade: 0.20% of equity (his own stated figure for a live prop-account context)
  • Target: 2R by default (configurable: he also states “1:2 is more than enough” while elsewhere rejecting fixed R:R minimums in favor of balancing win rate against reward)
  • Two attempts per direction per day
  • Flat-before-close window: 15:55–16:00 ET, no overnight positions

Backtest Results (NQ1!, 11 Months)

Setup: NQ1! (CME E-mini Nasdaq-100 futures), 15-minute chart, regular session only, Variant C, stop on the opposite side of the range, target at 2R, risk 0.20% of equity per trade, $150,000 starting capital, $2.50 per-contract commission, 1 tick of slippage, 10x day-trading margin.

NQ1! chart showing the Andrea Cimitan opening range breakout strategy entries, exits, and opening range lines
MetricValue
PeriodOct 1, 2025 – Sep 3, 2026 (~11 months)
Total trades334 (171 long, 163 short)
Win rate48.8% overall (52.1% long, 45.4% short)
Profit factor1.083 overall (1.002 long, 1.155 short)
Net profit+$35,737.50 (+23.83% on $150k)
Sharpe ratio0.293
Sortino ratio0.606
Max drawdown25.98% (intrabar)
Buy-and-hold NQ, same period+61.75%
Strategy Tester performance tab showing cumulative PnL versus buy-and-hold for the Andrea Cimitan ORB strategy

Nearly all of the base layer’s edge came from the short side (profit factor 1.155); the long side is close to flat (1.002). That’s consistent with what Cimitan says about the base setup: it’s the layer to start with, not the finished edge. The order-flow confirmation on top is what he says the setup is actually missing without it.

Note on faithfulness: this run used a 15-minute chart. Variant C’s own definition calls for a 15-minute range confirmed by a 5-minute closing candle; a 15-minute chart has no 5-minute bar to check against, so the confirmation here is coarser than his stated trigger. A 5-minute re-run is the more exact reproduction and isn’t reflected in the numbers above.

What Pine Script Can’t Replicate

Two real implementation issues came up building this, and one of them is worth flagging for anyone backtesting futures strategies in Pine Script.

Compile error: a history-reference ternary passed a series boolean into a function expecting a number. Fixed with an explicit bar-index guard.

Silent zero-trade bug: Pine Script v6 defaults margin_long/margin_short to 100, meaning no leverage. The broker emulator then requires the full notional value of a futures contract in capital before placing an order. NQ around 29,000 with a $20/point value carries roughly $580,000 notional per contract. Against $150,000 initial capital, every order was silently rejected. No error, no warning, across every variant and timeframe tested. Fixed by setting margin_long/margin_short to 10 (day-trading margin, appropriate since the strategy is always flat before the close).

TradingView Properties tab confirming 10x long and short leverage, $2.50 commission, and $150,000 starting capital

Settings Quick Reference

Andrea Cimitan Strategy [PickMyTrade] script defaults:

SettingDefaultWhat it does
Session timezoneAmerica/New_YorkRTH session anchor
RTH cash session09:30–16:00Session window for the opening range
Published ORB variantC (15m)Selects which of his four rulesets to run
Opening range length15 or 30 min (variant-dependent)Range-building window
Breakout confirmationClose beyond rangeNot a wick-through
Max attempts per direction/day2His stated two-attempts rule
Stop placementOpposite side of rangeStructure-relative stop
Target (R multiple)2Configurable
Risk per trade0.20% of equityPosition sizing input
Flat-before-close window15:55–16:00No overnight risk

Automate It With PickMyTrade

The base layer is fully mechanical, with defined entry, stop, and target rules, so it automates the same way any rule-based Pine Script strategy does.

The script emits a ready-to-send PickMyTrade JSON payload in alert_message. Set your token and broker symbol, connect the webhook, and orders route straight to your account (Tradovate, Interactive Brokers, TradeStation, Rithmic, TradeLocker, ProjectX/prop-firm platforms, Binance, Bybit). See how TradingView-to-broker automation works.

The order-flow confirmation layer Cimitan says is the real edge stays manual. Pine Script alerts have no access to the trade-level execution data it depends on.

Get the Full Script

The complete Andrea Cimitan Strategy [PickMyTrade] script, including all four ruleset presets, the risk-sizing engine, and the PickMyTrade webhook integration, is available in our Discord community, along with scripts for other traders we’ve covered the same way: Fabio Valentini’s order-flow scalper, Patrick Nill’s strategy, the TJR Trades indicator, Zanco’s ICT strategy, and JadeCap’s ICT strategy.

FAQ

What is Andrea Cimitan’s trading strategy?

He names the opening range breakout as his recommended starting system for beginners, layered with an order-flow confirmation (“big bubbles,” a live filter on large executed trades) that he says is the actual edge on top of it.

Does the opening range breakout work as Cimitan describes it?

Tested as a standalone base layer on NQ futures over 11 months: profit factor 1.083, with almost all of the edge on the short side and the long side close to flat. Consistent with Cimitan’s own framing of it as a starting layer, not the finished edge.

Is there one official version of the Cimitan ORB?

He’s described it slightly differently across several videos and course material. Our script ships all four variants as selectable presets rather than picking one silently.

What indicators does Andrea Cimitan use?

Order-flow tools rather than lagging indicators: a live large-trade filter (“big bubbles”), volume profile, and a 90-day composite for daily bias, all part of his Liquidity Auction Theory framework.

Can this strategy be automated?

Yes. The base ORB layer is mechanical and automates like any rule-based Pine Script strategy via PickMyTrade. The order-flow confirmation layer stays manual; it depends on trade-level data Pine Script alerts don’t have access to.

What is DeepCharts?

The order-flow platform Cimitan co-founded with Fabio Valentini, used for the large-trade filtering, absorption reads, and opening-range tools referenced in his teaching material.

The Complete Pine Script

The full, unedited Andrea Cimitan Strategy [PickMyTrade] script, exactly as backtested above, sourced rules and ASSUMED inputs clearly separated in the comments. Paste it directly into the TradingView Pine Editor.

//@version=6

// =============================================================================
//  OPENING RANGE BREAKOUT - Andrea Cimitan ("Andrea Cimi") DOCUMENTED BASE LAYER
// =============================================================================
//
//  WHAT THIS IS
//  ------------
//  A faithful Pine implementation of the one mechanical strategy Andrea Cimitan
//  publicly and repeatedly names as his recommended starting system, using only
//  rules he has stated in his own words. Nothing here is inferred, optimised or
//  invented to improve results.
//
//  HIS WORDS (Words of Rizdom podcast, ~2h07m, video znSRU984kc8):
//    "start with something simple. The opening range breakout is, in my opinion,
//     the go-to. It was developed by a trader called Toby Crabel in the 1990s ...
//     on the S&P 500 and the NASDAQ ... it is one of the most consistent edges of
//     the last 20 years that retail can implement."
//    "Gap fill, ORB. That's it."
//    "candlesticks, volume profile, and bubbles. It doesn't need to be [more]."
//
//  WHAT IS DELIBERATELY MISSING - READ THIS
//  ----------------------------------------
//  Cimitan's actual edge is ORDER FLOW layered ON TOP of this base. He is explicit
//  that the ORB alone is the beginner layer and that big-trade "bubbles" are the
//  add-on: "if you're an ORB trader and you're not using big bubbles on your
//  chart, you're leaving [money] on the table."
//
//  Pine Script CANNOT reproduce that layer. It has no trade-level prints, no
//  bid/ask footprint, no DOM/Level 2, no market-by-order data. Specifically absent:
//    - big-trade bubbles (his ES filter: single trades of >= 150 contracts)
//    - his master entry trigger: a bubble on the candle BODY = enter,
//      a bubble on the WICK = absorption = do not enter
//    - absorption walls (~5-10 ticks of passive size on M5)
//    - icebergs, spoofing, book sweeping, speed of tape
//    - his stop-run scalp (ES only, London session only, pure order-book)
//    - his options / dealer-gamma book
//  None of these are approximated here. A proxy would be my invention rather than
//  his method, so the order-flow layer is reported as ABSENT instead of faked.
//
//  THERE IS NO SINGLE CANONICAL CIMITAN ORB - READ BEFORE TRADING
//  --------------------------------------------------------------
//  A full sweep of his own published sources found that EVERY parameter a coder
//  must fix takes at least two different values across four videos he authored
//  within roughly nine months:
//    A  3Zs52kfCwiU (EN)          30m range, LONG ONLY, stop under the breakout
//                                 candle, R:R stated three contradictory ways in
//                                 consecutive sentences - NOT reliable
//    B  AUVg0-Gdd8M / t3KcM6r_1ZA 30m range at 1:1, or 15m range at 1:0.5,
//       (IT / ES shorts)          Nasdaq, 2% risk per trade
//    C  KfjjHv7DB8o + cWb6wvd9nn0 15m range off the 9:30 open, trigger = a 5m
//       (EN course / IT)          candle closing outside, LONG AND SHORT, stop
//                                 beyond the OTHER side of the range, 1:1 to 1:2
//    D  EtQv0IF0QmU (IT short)    30m range, both directions, stop = the whole
//                                 range or roughly mid-range, ~1:2
//  Pick one on the "Published ORB variant" input. Anyone coding "Andrea Cimi's
//  ORB" is choosing one of four incompatible published versions and must say
//  which. Blending them produces a strategy he never published.
//
//  Reward-to-risk carries a second, separate contradiction: "1:2 is more than
//  enough" in one source, versus an explicit rejection of fixed R:R minimums
//  elsewhere (WR = 1 / (1 + R) couples win rate and reward).
//
//  Risk per trade likewise has four scoped values - 0.20% (discretionary order
//  flow on a prop challenge), 0.4-0.5% (generic prop guidance), 2% (the
//  MECHANICAL ORB plan, i.e. this script), ~5% (a small first tranche).
//
//  ANYTHING MARKED "ASSUMED" IS NOT HIS RULE
//  -----------------------------------------
//  Inputs prefixed ASSUMED are parameters he references qualitatively but never
//  quantifies. Per the no-invention rule they all ship DISABLED or neutral.
//  Enabling one means trading your assumption, not his documented method.
//
//  NON-REPAINTING
//  --------------
//  No request.security() calls at all, therefore no lookahead and no future leak.
//  The opening range is built from confirmed intraday bars on the chart. Signals
//  are evaluated on bar close and fill at the next bar's open (Pine default, with
//  calc_on_every_tick = false), which is the realistic outcome for a market order
//  sent at the close of the breakout candle. Historical and realtime match.
//
//  PUBLICATION CAUTION
//  -------------------
//  This names a real third party, and the quoted claims ("most consistent edge of
//  the last 20 years", Sharpe outperformance) are HIS claims about the general ORB
//  concept, not results produced by this script. Do not restate them as expected
//  performance anywhere in a published description.
// =============================================================================

strategy(
     title                = "ORB Base Layer - Cimitan documented rules",
     shorttitle           = "ORB-BASE",
     overlay              = true,
     initial_capital      = 150000,
     currency             = currency.USD,
     default_qty_type     = strategy.fixed,
     default_qty_value    = 1,
     pyramiding           = 0,
     calc_on_every_tick   = false,
     calc_on_order_fills  = false,
     commission_type      = strategy.commission.cash_per_contract,
     commission_value     = 2.50,
     slippage             = 1,
     margin_long          = 10,
     margin_short         = 10,
     max_labels_count     = 200,
     max_lines_count      = 200)
// ENGINEERING FIX, not a Cimitan rule: Pine v6 defaults margin_long/margin_short to
// 100 (no leverage), meaning the broker emulator requires the FULL notional value of
// a futures contract as capital before it will place an order. NQ at ~29,000 with a
// $20 point value has a notional of ~$580,000 per contract - far above the
// initial_capital above, so every single order was being silently rejected with no
// error and no warning. This is why the strategy showed zero trades across every
// variant, every timeframe, and every date range tested. margin_long/margin_short
// = 10 approximates realistic intraday day-trading margin (a small percentage of
// notional, not the full amount), which is appropriate since this strategy is
// flat before the close and never holds overnight.

// -----------------------------------------------------------------------------
// INPUTS
// -----------------------------------------------------------------------------
string G_SESS = "1 - Session (EXPLICIT)"
string G_RNG  = "2 - Opening range (EXPLICIT)"
string G_ENT  = "3 - Entry (EXPLICIT)"
string G_EXT  = "4 - Stop and target"
string G_RSK  = "5 - Risk (EXPLICIT)"
string G_ASM  = "6 - ASSUMED - not his stated rules"
string G_ALR  = "7 - PickMyTrade webhook"
string G_VIS  = "8 - Visuals"

tzInput = input.string("America/New_York", "Session timezone", group = G_SESS,
     tooltip = "An explicit timezone is mandatory. Pine defaults session strings to the EXCHANGE clock, which for CME futures is Chicago, not New York. Cimitan states the cash session in EST.")

rthInput = input.session("0930-1600", "RTH cash session", group = G_SESS,
     tooltip = "EXPLICIT. Cimitan: cash session / RTH 9:30 EST to 16:00 EST. He describes the intraday volume shape as a heavy opening auction, heavy first hours, a midday trough, then the closing auction as the single highest-volume peak of the session.")

orbVariantInput = input.string("C - 15m range, 5m close trigger, both directions, 1:2", "Published ORB variant", options = ["A - 30m range, LONG ONLY, stop under breakout candle", "B - 30m range 1:1 (or 15m 1:0.5), 2% risk", "C - 15m range, 5m close trigger, both directions, 1:2", "D - 30m range, both directions, stop = range or mid, 1:2", "Custom - use the manual inputs below"], group = G_RNG,
     tooltip = "THERE IS NO SINGLE CANONICAL CIMITAN ORB. Across four sources he authored within about nine months, the range length, permitted direction, stop anchor and target each take at least two different values. Rather than silently blending them, pick the published variant you intend to trade. A = EN video 3Zs52kfCwiU (its stated R:R is self-contradictory within one paragraph and is NOT reliable; 1.0 is used as a placeholder). B = IT/ES shorts AUVg0-Gdd8M / t3KcM6r_1ZA, which also state 2% risk per trade. C = EN course KfjjHv7DB8o + IT cWb6wvd9nn0, run this one on a 5-minute chart. D = IT short EtQv0IF0QmU. Selecting anything other than Custom OVERRIDES the manual range / direction / stop / target inputs below.")

orLenInput = input.string("30", "Opening range length (minutes)", options = ["15", "30", "60"], group = G_RNG,
     tooltip = "EXPLICIT. His in-house IVB model offers 15 / 30 / 60 minutes and the DeepCharts team recommends 30. This also satisfies his separate rules of never trading the first 5 minutes and typically starting only after the first 30.")

requireBodyInput = input.bool(true, "Breakout candle must CLOSE beyond the range", group = G_ENT,
     tooltip = "EXPLICIT, quoted as 'the official rules of the IVB model': the breakout candle must close with a BODY beyond the opening range, not merely wick through it. Disabling this reverts to a naive wick-touch breakout, which is NOT his rule.")

allowLongInput  = input.bool(true, "Allow longs",  group = G_ENT)
allowShortInput = input.bool(true, "Allow shorts", group = G_ENT)

maxAttemptsInput = input.int(2, "Max attempts per direction per day", minval = 1, maxval = 5, group = G_ENT,
     tooltip = "EXPLICIT 'two attempts' rule: he always gives a setup two tries, because being stopped out once or twice by stop runs before it works is normal. Total risk for the idea is therefore split across two separate trades.")

stopModeInput = input.string("Opposite side of opening range", "Stop placement",
     options = ["Opposite side of opening range", "Opening range midline", "Breakout candle"], group = G_EXT,
     tooltip = "EXPLICIT but not numerically pinned. For the breakout setup he states the stop goes 'below the breakout structure'. The opening range IS that structure, so its opposite side is the faithful default. His IVB tool also plots a Mid line, offered here as the tighter alternative.")

rMultipleInput = input.float(2.0, "Target (R multiple)", minval = 0.5, maxval = 10.0, step = 0.5, group = G_EXT,
     tooltip = "CONFLICTED EVIDENCE - see the header. Reading A: '1:2 risk to reward is more than enough' for the ORB continuation, which is this default. Reading B: he explicitly rejects fixed R:R minimums because WR = 1/(1+R) couples win rate and reward. He also mentions deliberately backtesting at a pessimistic 1:1 to prove an edge survives.")

useRiskSizingInput = input.bool(true, "Size position from stop distance", group = G_RSK,
     tooltip = "EXPLICIT method: fixed-money risk with the contract count derived automatically from the stop distance, never from a profit goal.")

riskPctInput = input.float(0.20, "Risk per trade (% of equity)", minval = 0.01, maxval = 30.0, step = 0.01, group = G_RSK,
     tooltip = "EXPLICIT: 0.20% of account on average during his 150k prop-firm challenge, the only concrete personally-used figure in the corpus. He also states that 'anything above 30% risk is gamble on a small account', which is the hard cap on this input.")

minStopTicksInput = input.int(4, "SAFETY - minimum stop distance (ticks)", minval = 1, group = G_RSK,
     tooltip = "NOT one of his rules - an engineering guard. Variant A anchors the stop to the breakout candle, so a very small candle yields a near-zero risk distance and therefore an absurd contract count. Trades whose stop is tighter than this are skipped.")

minOneContractInput = input.bool(true, "Allow a minimum of 1 contract", group = G_RSK,
     tooltip = "When the risk budget computes to less than one contract, take one anyway. This EXCEEDS the configured risk percentage. On full-size ES (50 USD per point) a 0.20% budget rarely funds a contract; micros (MES/MNQ) size correctly. Disable to skip such trades instead.")

useBEInput = input.bool(false, "ASSUMED - move stop to breakeven", group = G_ASM,
     tooltip = "He says he is willing to move to breakeven 'after the ORB body-close confirmation' and at 'a defined intermediate level', but never states which level. The trigger below is therefore an assumption. OFF by default.")
beTriggerRInput = input.float(1.0, "ASSUMED - breakeven trigger (R)", minval = 0.1, step = 0.1, group = G_ASM)

useTrailInput = input.bool(false, "ASSUMED - trailing stop", group = G_ASM,
     tooltip = "He states trailing 'works well on the NASDAQ but NOT on the ES', and separately that he trails more aggressively as price approaches the target. No distances are ever published. OFF by default. Enabling it on ES contradicts him.")
trailPointsInput = input.int(40, "ASSUMED - trail activation (ticks)", minval = 1, group = G_ASM)
trailOffsetInput = input.int(20, "ASSUMED - trail offset (ticks)",     minval = 1, group = G_ASM)

maxDailyLossInput = input.float(0.0, "ASSUMED - daily loss circuit breaker (% equity, 0 = off)",
     minval = 0.0, maxval = 30.0, step = 0.1, group = G_ASM,
     tooltip = "He explicitly advocates a platform-enforced daily risk budget / circuit breaker rather than discretion, and outsourcing risk enforcement entirely. He never publishes the number. 0 = off.")

flatSessInput = input.session("1555-1600", "ASSUMED - flat-before-close window", group = G_ASM,
     tooltip = "Not holding an intraday futures position overnight is standard practice, but the exact cutoff minute is this script's choice, not his rule. He notes the closing auction is the highest-volume event of the session.")

emitJsonInput = input.bool(true, "Emit PickMyTrade JSON in alert_message", group = G_ALR)
pmtTokenInput = input.string("YOUR_TOKEN_HERE", "PickMyTrade token", group = G_ALR,
     tooltip = "Copy the exact token from your PickMyTrade dashboard, and verify the final payload against the JSON your dashboard generates before going live.")
pmtSymbolInput  = input.string("NQ", "Broker symbol", group = G_ALR)
pmtAccountInput = input.string("", "Account id (optional)", group = G_ALR)

showRangeInput  = input.bool(true, "Show opening range",        group = G_VIS)
showLevelsInput = input.bool(true, "Show stop / target",        group = G_VIS)
shadeORInput    = input.bool(true, "Shade range build window",  group = G_VIS)

// -----------------------------------------------------------------------------
// GUARDS
// -----------------------------------------------------------------------------
// ---- resolve the selected published variant ---------------------------------
int    effOrMin = int(nz(str.tonumber(orLenInput), 30))
bool   effLong  = allowLongInput
bool   effShort = allowShortInput
string effStop  = stopModeInput
float  effR     = rMultipleInput

if str.startswith(orbVariantInput, "A")
    effOrMin := 30
    effLong  := true
    effShort := false
    effStop  := "Breakout candle"
    effR     := 1.0
else if str.startswith(orbVariantInput, "B")
    effOrMin := 30
    effLong  := true
    effShort := true
    effStop  := "Opposite side of opening range"
    effR     := 1.0
else if str.startswith(orbVariantInput, "C")
    effOrMin := 15
    effLong  := true
    effShort := true
    effStop  := "Opposite side of opening range"
    effR     := 2.0
else if str.startswith(orbVariantInput, "D")
    effOrMin := 30
    effLong  := true
    effShort := true
    effStop  := "Opening range midline"
    effR     := 2.0

if timeframe.isdwm
    runtime.error("Intraday chart required: this strategy builds an opening range from intraday bars.")

if timeframe.in_seconds() > effOrMin * 60
    runtime.error("Chart timeframe exceeds the opening range length. Use " + str.tostring(effOrMin) + " minutes or lower. He charts the 5-minute for structure and the 1-minute for entry timing.")

// -----------------------------------------------------------------------------
// SESSION AND OPENING RANGE
// -----------------------------------------------------------------------------
bool inRTH      = not na(time(timeframe.period, rthInput, tzInput))
bool prevInRTH  = bar_index > 0 ? inRTH[1] : false
bool newSession = inRTH and not prevInRTH
bool inFlatWin  = not na(time(timeframe.period, flatSessInput, tzInput))

var float orHigh        = na
var float orLow         = na
var int   orStartMs     = na
var bool  orDone        = false
var int   longAttempts  = 0
var int   shortAttempts = 0
var bool  dayBlocked    = false
var float dayOpenEquity = na

if newSession
    orHigh        := high
    orLow         := low
    orStartMs     := time
    orDone        := false
    longAttempts  := 0
    shortAttempts := 0
    dayBlocked    := false
    dayOpenEquity := strategy.equity
else if inRTH and not na(orStartMs)
    if time < orStartMs + effOrMin * 60 * 1000
        orHigh := math.max(nz(orHigh, high), high)
        orLow  := math.min(nz(orLow,  low),  low)
    else
        orDone := true

bool  building = inRTH and not na(orStartMs) and not orDone
float orMid    = (orHigh + orLow) / 2.0

if maxDailyLossInput > 0 and inRTH and not na(dayOpenEquity)
    if strategy.equity <= dayOpenEquity * (1.0 - maxDailyLossInput / 100.0)
        dayBlocked := true

// -----------------------------------------------------------------------------
// SIGNALS
// -----------------------------------------------------------------------------
bool rangeValid = orDone and not na(orHigh) and not na(orLow) and orHigh > orLow

bool breakUp   = rangeValid and (requireBodyInput ? close > orHigh : high > orHigh)
bool breakDown = rangeValid and (requireBodyInput ? close < orLow  : low  < orLow)

float minStopDist = minStopTicksInput * syminfo.mintick

bool canTrade = inRTH and not inFlatWin and rangeValid and not dayBlocked and strategy.position_size == 0

bool longSignal  = canTrade and effLong  and breakUp   and longAttempts  < maxAttemptsInput
bool shortSignal = canTrade and effShort and breakDown and shortAttempts < maxAttemptsInput

float stopLong  = effStop == "Opening range midline" ? orMid : effStop == "Breakout candle" ? low  : orLow
float stopShort = effStop == "Opening range midline" ? orMid : effStop == "Breakout candle" ? high : orHigh

float riskLong  = close - stopLong
float riskShort = stopShort - close

// -----------------------------------------------------------------------------
// POSITION SIZING - fixed money risk, contracts derived from the stop distance
// -----------------------------------------------------------------------------
calcQty(float riskDist) =>
    float q = 1.0
    if useRiskSizingInput and riskDist > 0 and syminfo.pointvalue > 0
        float riskCash    = strategy.equity * riskPctInput / 100.0
        float perContract = riskDist * syminfo.pointvalue
        q := perContract > 0 ? riskCash / perContract : 0.0
    float floored = math.floor(q)
    float result  = floored < 1 ? (minOneContractInput ? 1.0 : 0.0) : floored
    result

// -----------------------------------------------------------------------------
// WEBHOOK PAYLOAD
// -----------------------------------------------------------------------------
pmtJson(string action, float qty, float slPrice, float tpPrice) =>
    string acct = pmtAccountInput == "" ? "" : ",\"account_id\":\"" + pmtAccountInput + "\""
    string js = "{\"symbol\":\"" + pmtSymbolInput
     + "\",\"date\":\"" + str.format_time(timenow, "yyyy-MM-dd HH:mm:ss", "UTC")
     + "\",\"data\":\"" + action
     + "\",\"quantity\":" + str.tostring(qty, "#.##")
     + ",\"price\":" + str.tostring(close, format.mintick)
     + ",\"sl\":" + str.tostring(nz(slPrice, 0), format.mintick)
     + ",\"tp\":" + str.tostring(nz(tpPrice, 0), format.mintick)
     + ",\"token\":\"" + pmtTokenInput
     + "\",\"pyramid\":false,\"reverse_order_close\":true,\"order_type\":\"MKT\"" + acct + "}"
    js

// -----------------------------------------------------------------------------
// ORDERS
// -----------------------------------------------------------------------------
var float curStop = na
var float curTP   = na
var bool  beArmed = false

if strategy.position_size == 0 and not longSignal and not shortSignal
    beArmed := false

if longSignal and not na(riskLong) and riskLong >= minStopDist
    float q = calcQty(riskLong)
    if q > 0
        curStop      := stopLong
        curTP        := close + riskLong * effR
        longAttempts := longAttempts + 1
        beArmed      := false
        strategy.entry("L", strategy.long, qty = q,
             alert_message = emitJsonInput ? pmtJson("buy", q, stopLong, close + riskLong * effR) : "ORB long")

if shortSignal and not na(riskShort) and riskShort >= minStopDist
    float q = calcQty(riskShort)
    if q > 0
        curStop       := stopShort
        curTP         := close - riskShort * effR
        shortAttempts := shortAttempts + 1
        beArmed       := false
        strategy.entry("S", strategy.short, qty = q,
             alert_message = emitJsonInput ? pmtJson("sell", q, stopShort, close - riskShort * effR) : "ORB short")

// breakeven (ASSUMED, off by default)
if useBEInput and strategy.position_size != 0 and not beArmed and not na(curStop)
    float entryPx  = strategy.position_avg_price
    float initRisk = strategy.position_size > 0 ? entryPx - curStop : curStop - entryPx
    if initRisk > 0
        bool beHit = strategy.position_size > 0 ? high >= entryPx + initRisk * beTriggerRInput : low <= entryPx - initRisk * beTriggerRInput
        if beHit
            curStop := entryPx
            beArmed := true

float trailPts = useTrailInput ? trailPointsInput : na
float trailOff = useTrailInput ? trailOffsetInput : na

if strategy.position_size > 0
    strategy.exit("X-L", from_entry = "L", stop = curStop, limit = curTP,
         trail_points = trailPts, trail_offset = trailOff,
         alert_message = emitJsonInput ? pmtJson("close", math.abs(strategy.position_size), curStop, curTP) : "ORB long exit")

if strategy.position_size < 0
    strategy.exit("X-S", from_entry = "S", stop = curStop, limit = curTP,
         trail_points = trailPts, trail_offset = trailOff,
         alert_message = emitJsonInput ? pmtJson("close", math.abs(strategy.position_size), curStop, curTP) : "ORB short exit")

// flat before the close, and never hold outside the session
if strategy.position_size != 0 and (inFlatWin or not inRTH)
    strategy.close_all(comment = "EOD flat",
         alert_message = emitJsonInput ? pmtJson("close", math.abs(strategy.position_size), 0.0, 0.0) : "ORB EOD flat")

// -----------------------------------------------------------------------------
// VISUALS
// -----------------------------------------------------------------------------
color cUp  = color.new(#26A69A, 0)
color cDn  = color.new(#EF5350, 0)
color cMid = color.new(#787B86, 30)

plot(showRangeInput and inRTH and rangeValid ? orHigh : na, "OR High", color = cUp,  linewidth = 2, style = plot.style_linebr)
plot(showRangeInput and inRTH and rangeValid ? orLow  : na, "OR Low",  color = cDn,  linewidth = 2, style = plot.style_linebr)
plot(showRangeInput and inRTH and rangeValid ? orMid  : na, "OR Mid",  color = cMid, linewidth = 1, style = plot.style_linebr)

plot(showLevelsInput and strategy.position_size != 0 ? curStop : na, "Stop",   color = cDn, style = plot.style_linebr, linewidth = 1)
plot(showLevelsInput and strategy.position_size != 0 ? curTP   : na, "Target", color = cUp, style = plot.style_linebr, linewidth = 1)

bgcolor(shadeORInput and building ? color.new(#2962FF, 92) : na, title = "Range build window")
bgcolor(dayBlocked and inRTH ? color.new(#EF5350, 90) : na, title = "Daily circuit breaker tripped")

// -----------------------------------------------------------------------------
// ALERT CONDITIONS
// -----------------------------------------------------------------------------
alertcondition(longSignal,  "ORB long breakout",  "ORB base layer: body close above the opening range high.")
alertcondition(shortSignal, "ORB short breakout", "ORB base layer: body close below the opening range low.")

Educational content, not financial advice. Andrea Cimitan is not affiliated with PickMyTrade; this guide is an independent summary of his publicly stated rules and an independent Pine Script implementation and backtest. All figures are hypothetical backtest results produced with modeled commission and slippage. Past performance does not guarantee future results. Futures trading carries substantial risk of loss.

Sources

Primary: Andrea Cimitan’s own words

Platform:

Related reading:

For AI tools & developers:View Markdown →

Leave a Comment

Your email address will not be published. Required fields are marked *

error

Follow us for more insights and updates

Scroll to Top
Rated 4.6/5 by 83+ traders on Trustpilot
Markdown version
Verified by MonsterInsights