Cival Pattern Lab — Reading the Indicator

Pattern Lab is a research instrument. On every closed bar it asks one question: did the rule you chose match? If it did, it marks the bar, simulates the trade that would have been taken at the next bar's open, follows that simulated trade bar by bar to its stop, target or time limit, and adds the result to a scoreboard that is split into train, validation and test periods. The point is to find out whether a rule survives costs and unseen data before you risk money on it.

Everything below is taken from the shipped plugin (v1.0.0). Defaults are the ones the indicator starts with.

1. What is drawn on the chart

Element Where Meaning
▲ in the Bull color (default green #3CB371) just below the signal bar's low The rule matched on a closed bar with a long hypothesis.
▼ in the Bear color (default red #FF6347) just above the signal bar's high The rule matched with a short hypothesis.
Label LAB <Pattern>, for example LAB DeltaReversal to the right of the arrow Which rule matched. Hidden when bars are narrower than Minimum bar spacing for signal labels (pixels) (default 6) or when it would overlap another label (Avoid overlapping labels, default on). Labels are hidden, never moved. The arrow always stays.
Information panel top-left of the chart, 50 px below the top edge Rule, simulation settings and the results scoreboard (section 8).

There are no zones, lines or volume bubbles. Settings for those (Maximum visible zones, Show touched levels, Show bubble volume numbers, Bubble number color, Compact volume numbers) have no effect in this product.

An arrow is drawn for every match, including a match that happens while a simulated trade is already open. Only one simulated position is allowed at a time, so the number of arrows is usually larger than the number of trades in the scoreboard (in the demo: 111 arrows, 78 completed trades and 1 pending, section 11).

Nothing is drawn on the forming bar. A bar is judged when it has closed; the arrow appears when the next bar starts.

2. Gates every pattern must pass

Let b be the bar that just closed, p the bar before it, and prior the Prior lookback bars (default 20) bars before b.

Gate Rule
Enough history At least max(3, Prior lookback bars + 1) closed bars have been processed.
Footprint present and complete b and every bar in prior have footprint rows, and the bid+ask total of those rows is within 1% of the candle's volume. One incomplete bar silences the rule until it leaves the lookback window.
Non-degenerate bar High is above Low and the volume is above zero.
No gaps The last max(lookback + 1, 5) bars (or the sequence length for CandleSequence) have consecutive bar numbers. A missing bar from the data provider silences the rule for a while.
Volume Volume of b is at least the mean volume of prior times Volume / prior mean (default 1; 0 switches this gate off).
Delta size |delta| / volume × 100 of b is at least Minimum absolute delta % (default 20; 0 switches this gate off).

Volume here is bid plus ask volume from the footprint. Delta is ask volume minus bid volume (aggressive buying minus aggressive selling). Close location is (Close − Low) / (High − Low): 0 means the bar closed on its low, 1 on its high. The 0.65 close-location threshold below is fixed in the plugin; it is not a setting.

3. The six patterns

After the gates, exactly one of these conditions decides the side: +1 is a long hypothesis, −1 a short hypothesis.

Pattern Long (+1) Short (−1)
Engulfing b closed up, p closed down, b opened at or below p's close and closed at or above p's open (b's body covers p's body). Mirror image: b down, p up, b opened at or above p's close and closed at or below p's open.
DeltaReversal (default) p's delta was negative, b's delta is positive, b closed above p's close, and b's close location is at least 0.65 (top 35% of its range). p's delta was positive, b's delta is negative, b closed below p's close, and b's close location is at most 0.35.
Absorption b's delta is negative (net aggressive selling) but b closed in the top 35% of its range (close location ≥ 0.65). b's delta is positive but b closed in the bottom 35% (close location ≤ 0.35).
BreakoutRetest Let H be the highest high of the prior bars excluding p. p closed above H, b traded back down to H or lower (Low ≤ H), b closed above H, and b's delta is positive. Let L be the lowest low of the same bars. p closed below L, b traded back up to L or higher, b closed below L, and b's delta is negative.
ReversalFiveBar Closes of the last five bars c0…c4 (c4 is b): c0 > c1 > c2 < c3 < c4 and b's delta is positive. c0 < c1 < c2 > c3 > c4 and b's delta is negative.
CandleSequence The last N bars match the Custom sequence (U up / D down / N doji) string, U = close above open, D = close below open, N = close equal to open. N is the length of the string (2 to 20 characters). Default DDDUU. The side is the Custom sequence side (+1 / −1) setting (default +1; 0 or positive means +1). Same, with side −1.

Notes that matter when you interpret a match:

4. From signal to simulated trade

  1. Signal bar. The bar that matches is marked. It is closed; nothing about it will change.
  2. Entry. The simulated trade enters at the open of the next bar. It is never filled inside the signal bar: a signal on bar 10 cannot enter at bar 10's own open or at any earlier price, so the first possible entry is the open of bar 11.
  3. Levels. Stop distance = Stop distance (ticks) × tick size (default 20 ticks). Target distance = stop distance × Target / stop multiple (default 2). For a long, the stop is below the entry and the target above; for a short the reverse.
  4. Checked on every bar from the entry bar on (the entry bar counts as bar 1):
Condition on the bar Exit price Reason shown in the CSV
The bar opened at or beyond the stop (a gap through the stop; cannot happen on the entry bar) the bar's open (can be worse than the stop) Stop gap
The bar opened at or beyond the target the target price (the extra gap profit is not credited) Target gap
The bar's range reached the stop the stop price Stop
The bar's range reached the target the target price Target
The count of bars since entry reached Maximum holding bars (default 20) and neither level was reached the bar's close Time
  1. Both levels inside one bar. Intrabar order is unknown, so the Lab always assumes the stop was hit first and counts the trade as Ambiguous.
  2. Net result = side × (exit − entry) − Round-trip costs in price units (default 0). Results are in price units (for a BTC perpetual quoted in dollars: dollars per 1 BTC), not in ticks and not in your account currency.
  3. One position at a time. While a simulated trade is open, further matches are marked with an arrow but do not become trades.
  4. Censored. If the indicator skips a bar while a trade is open (a hole in the data), that trade is dropped and counted as censored; it is not guessed.
  5. Pending. A trade that has not finished at the end of the loaded history is counted as pending and is not added to the statistics.

MAE / MFE. Maximum adverse and favorable excursion are measured from the entry using the full high-low range of each bar, including the bar where the trade exits. Because the real order of highs and lows inside a bar is unknown, they are bounds, not exact excursions. They appear only in the CSV (mae_bound, mfe_bound).

5. Holdout periods: train, validation, test

Set Validation begins (chart time) and Untouched test begins (chart time) to split the history by date. A trade belongs to a period according to when it was known to have finished:

Period A trade is counted when
Train its exit time is before the Validation date
Validation its entry time is on or after the Validation date and its exit time is before the Test date (if a Test date is set)
Test its entry time is on or after the Test date
boundary-excluded (CSV only) it entered before a boundary and exited at or after it. It is in no period, so no result leaks across a boundary.

The exit time the Lab uses is the open time of the bar after the exit bar, the earliest moment the result could be known. A trade that exits on the last bar before a boundary is therefore treated as crossing it.

ATAS may display an unset date as 01/01/0001 00:00:00; that means not set. The dates must be in chronological order. If the Test date is set but not later than the Validation date (or Validation is not set), the panel prints INVALID: test must follow validation and no new signals are marked or simulated until the dates are fixed.

Until the dates are set, the panel prints Set holdout dates before judging results, Validation not configured and Test not configured. If you set only Validation, everything after it is Validation. Tip: leave the Test date empty while you explore, so that the Test: line cannot tempt you (see 04-Trading-Playbook.md).

6. The panel, line by line

The panel has nine lines. By default only the first three are visible; untick Compact panel (title + two lines) (group Information panel) to see all of them. When an export error occurs, a line with the error is inserted as line 2.

# Text (example from the demo) What it means
1 Cival Pattern Lab — simulation Title (gold).
2 DeltaReversal; V≥1× Δ≥20% Active pattern, the Volume / prior mean gate (V) and the Minimum absolute delta % gate (Δ).
3 Next bar open; stop 100t / 2R Entry rule, stop in ticks (t) and target multiple (R).
4 All n=78 PF=0.61 DD=2931 All completed trades: count, profit factor, maximum drawdown in price units. PF=n/a when there are no losing trades (including when there are no trades at all).
5 Train: n=24 WR=41.7% E=-12.6667 Count, win rate, expectancy (average net per trade, price units) for the train period. Replaced by Set holdout dates before judging results if no Validation date.
6 Validation: n=27 WR=25.9% E=-46.2222 The same for validation. Replaced by Validation not configured.
7 Test: n=27 WR=29.6% E=-35.1111 The same for the test period. Replaced by Test not configured.
8 Ambiguous=0; censored=0; pending=1 Trades where stop and target were both inside one bar; trades dropped for missing bars; simulated trades still open.
9 MAE/MFE: full-bar bounds; stop-first Reminder of the two modelling assumptions. Reads INVALID: test must follow validation when the dates are wrong.

How the numbers are computed

Number Definition
n Completed trades in the group.
WR Trades with net result above zero ÷ n × 100.
E Mean net result per trade after costs, in price units.
PF Sum of positive net results ÷ sum of absolute negative net results. Below 1 means the group lost money after costs.
DD Largest fall of cumulative net result from a previous peak, trades ordered by exit bar, price units. Shown for All only.

A group with only a handful of trades produces numbers that are anecdotes, not evidence. The demo's 24 to 27 trades per period are already on the small side.

7. CSV exports

Set CSV export folder (blank disables) to write four files. Use a different folder for each chart or timeframe, because a second instance writing to the same folder overwrites the files.

File Written Columns
PatternLab-trades.csv when history finishes calculating, then whenever trades or bars are added live signal_bar, entry_bar, exit_bar, entry_time, exit_time, partition, side, entry, exit, net_price_units, mae_bound, mfe_bound, ambiguous, reason
PatternLab-bars.csv same bar, time, open, high, low, close, volume, delta, poc, complete
PatternLab-signals.csv when history finishes calculating and whenever a new signal appears live time, available_time, bar, price, side, kind, label, volume
PatternLab-zones.csv together with the signals file available_bar, low, high, poc, side, label, state, touched_bar, invalidated_bar (header only: Pattern Lab creates no zones)

Column notes:

8. Alerts

Alerts on closed signal / level touch (default off) plays the Alert sound (default alert1) when a bar closes with a match, with the text Cival LAB <Pattern>: <price>. In Pattern Lab an alert means "the rule matched on the bar that just closed". It is an observation for research or replay, not an instruction. Recalculating the history does not fire alerts for old signals.

9. Display and session settings

Setting (group) Effect in Pattern Lab
Show information panel (Appearance), default on Shows or hides the panel. Hiding the panel or the labels does not remove the underlying events or the CSV rows.
Panel top offset (pixels), Panel width (pixels) Position/width of the panel. The offset only applies when Automatic panel placement is off; width is limited to 220–700 px and to the chart width.
Automatic panel placement, Panel font size (10–22, default 13), Compact panel (Information panel) Stacks the panels of several Cival indicators in a column; font size; the three-line limit described above.
Show labels, Minimum bar spacing for signal labels, Avoid overlapping labels, Bull color, Bear color (Appearance) Marker labels and colors.
Maximum bars back (Performance), default 10,000 Only the latest N bars are processed. The indicator keeps at most the 500 most recent signals in memory and 10,000 trades.
Compact display (full detail must be off), Full analysis detail (00 Chart clarity), default on/on In the default state Pattern Lab draws normally. If Full analysis detail is off while Compact display is on, Pattern Lab hides its own markers and panel.
No effect here: Session start, Session timezone, Initial balance minutes, Show readiness/status panel, Maximum visible zones, Show touched levels, Show bubble volume numbers, Bubble number color, Compact volume numbers Pattern Lab does not use sessions, zones or bubbles.

Setting changes that alter the calculation (pattern, filters, stop, target, holding bars, costs, dates, Maximum bars back) recalculate the whole history. Each change is another trial of the rule, which matters for honest testing (see the playbook).

10. History revisions and what "closed bar" means here

Signals are decided only from bars that have closed; nothing is looked up from the future. However, Pattern Lab recalculates its entire history whenever you change a calculation setting and whenever the data provider revises an already-processed closed bar. Marks and statistics can therefore change after a recalculation. That is a property of the data and of your settings, not a live "repaint". Source corrections, a different history prefix (loading more or fewer bars), changes to any calculation setting and a change of timeframe can all legitimately recalculate the results, so a screenshot taken today may not match a chart opened next week. Panning, zooming or moving the cursor changes only what is drawn, never the underlying closed-bar results.

11. Worked example — real numbers from the demo

Source. The store demo: Hyperliquid BTC perpetual, 5-minute bars (tick size 1.0) built from trades recorded by the Cival order-flow recorder, 17–21 October 2026, 1,380 closed bars (about 4.8 days). It was produced by the shipped plugin. Settings: DeltaReversal with the default gates (volume ≥ 1× the prior-20-bar mean, |delta| ≥ 20%), Stop distance (ticks) 100, Target / stop multiple 2, Maximum holding bars 24, Round-trip costs in price units 24 (about 0.03% of price), Validation begins 19 Oct 00:00, Test begins 20 Oct 12:00. Raw output and settings file: demo\out\pattern-lab.json, demo\settings\pattern-lab.json.

A trade that worked. The 5-minute bar opening 15:45 UTC on 17 October (open 81,434, high 81,434, low 81,372, close 81,374) traded 137.0149 BTC against a prior-20-bar mean of about 22.0 BTC (6.2×). Its delta was −106.0531, or −77.4% of its volume. The previous bar had delta +7.3557 and closed at 81,435. So: previous delta positive, this delta negative, close below the previous close, and the close at the very bottom of the range (close location 0.03, far under the 0.35 limit). The Lab marked ▼ at 81,434 (the bar's high). The simulated short entered at the next open, 81,374; stop 100 units higher at 81,474; target 200 units lower at 81,174. It exited at the target on the 16:55 bar: gross +200, minus the 24 cost = +176.

A trade that did not. The 18:40 bar (high 81,529, low 81,501, close 81,507) traded 103.5589 BTC (about 2.2× its prior mean) with delta −77.3548 (−74.7%) after a previous bar with delta +5.7342. The Lab marked ▼, entered at the next open 81,507, and the 19:40 bar's high reached the stop at 81,607: gross −100, minus 24 = −124.

The scoreboard (panel values; the profit-factor column for the partitions is computed from the trade list in the same raw output using the panel's own formula):

Group Trades Wins Win rate Expectancy per trade Profit factor
All 78 25 32.1% −32.05 0.61
Train 24 10 41.7% −12.67 0.82
Validation 27 7 25.9% −46.22 0.50
Test 27 8 29.6% −35.11 0.60

Other numbers from the same run: maximum drawdown 2,931 price units; net result over all 78 trades −2,500 price units; 52 stops, 22 targets and 4 time exits; 0 ambiguous bars; 0 censored; 1 pending; 111 arrows in total.

The arithmetic of why. With a 100-unit stop and a 24-unit cost, a stop-out loses 124 and a target wins 176. Ignoring time exits, that needs about 41.3% winners just to break even (124 ÷ 300). The rule won 32.1% overall. Even the train period, which came closest at 41.7%, still had negative expectancy.

Verdict. This rule lost money after costs in all three periods, including the test period it never saw. It is a rule to reject, and finding that out cost nothing. This is one rule on one market over a short sample, so the honest reading is "no evidence of an edge here", not "this pattern can never work". It also shows the correct response: do not go back and tune the test period away (see 04-Trading-Playbook.md).

12. What Pattern Lab can and cannot know

It can It cannot
Apply a precisely defined rule to every closed bar of your loaded history Know that a rule will work on future data
Charge a fixed cost per round trip, assume entry at the next open and stop-first inside a bar Model real slippage, queue position, partial fills, latency, funding or margin
Keep results out of a period when a trade crosses a boundary Stop you from peeking at the Test line and tuning on it
Report win rate, expectancy, profit factor, drawdown and ambiguity counts Give a confidence interval, or tell you whether a sample is large enough
Export trades and bar features for your own analysis Know where other participants' orders, stops or positions are
Show results in price units Convert to your contract size or currency; do that yourself

Unavailable data is not a measured zero: with no footprint rows, too little history or a rule that never matched, the panel simply shows no signals. That says nothing about whether the rule works.

Every change to a setting after you have seen a result is another trial. Many parameter trials create selection bias: with enough trials, some rule will look good by chance. A zero-cost default is not realistic performance, and open simulations are never silently completed. Pattern Lab has no way to count your trials for you; keep your own log.