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:
- The delta gate checks size, not direction, for Engulfing and CandleSequence. A bullish engulfing bar with a negative delta of at least 20% of its volume still passes.
- Absorption is a name for a pattern, not a measurement of absorption. It means "net aggressive flow one way, close location the other way" on one bar. The Lab does not look at what happened at individual prices. Like every family here it is an evidence-based hypothesis about one bar; it does not reveal anyone's hidden positions or orders.
- A CandleSequence with a character other than U, D, N, or a length outside 2–20, never matches and shows no warning. The panel does not print the sequence either; it only prints the pattern name.
- Require directional POC migration (default off) adds one more gate to any pattern: the POC of b (the price row with the most volume; ties go to the lower price) must be higher than p's POC for a long, lower for a short.
- The default settings (DeltaReversal, 20 bars, volume ≥ 1×, |delta| ≥ 20%) and the default
DDDUUsequence are examples, not tuned recommendations.
4. From signal to simulated trade
- Signal bar. The bar that matches is marked. It is closed; nothing about it will change.
- 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.
- 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.
- 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 |
- 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. - 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.
- One position at a time. While a simulated trade is open, further matches are marked with an arrow but do not become trades.
- 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. - Pending. A trade that has not finished at the end of the loaded history is counted as
pendingand 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:
partitionistrain,validation,testorboundary-excluded, using the rules in section 5. With no dates set every trade istrain.sideis1(long) or-1(short).ambiguousisTrueorFalse.reasonisStop,Target,Stop gap,Target gaporTime.net_price_unitsis after costs.mae_boundandmfe_boundare full-bar bounds (section 4).entry_timeis the open time of the entry bar;exit_timeis the time the result became known (open of the bar after the exit bar).bars.csv:volumeanddeltaare footprint totals (bid + ask, and ask − bid);pocis the bar's highest-volume price;completeisTrueonly when the bar's footprint rows exist and match the candle volume within 1%. Bars without a footprint show volume 0, delta 0,completeFalse. The file keeps at most Maximum bars back bars.signals.csv:timeis the signal bar's open time;available_timeis the open time of the next bar, when the signal bar's close is known;volumeis the marker size and is always 1 for Pattern Lab. Signals older than the last 1,000 retained closed bars are not written to this file.- All times are in the chart's time base, written in ISO 8601. Numbers use a dot as decimal separator.
- Files are snapshots. Changing a setting recalculates the history and rewrites them, so copy files you want to keep. After you set a folder, files may appear only when the next bar closes or when history is next recalculated; if you do not want to wait, change any calculation setting and change it back.
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.