Workflows
This page walks through four complete strategy configurations — from simple to complex — using only default tokens and custom tokens you connect from standard indicators. Each example includes all required YAML fields...
Written By Axiom Admin
Last updated About 1 month ago
Workflows
This page walks through four complete strategy configurations — from simple to complex — using only default tokens and custom tokens you connect from standard indicators. Each example includes all required YAML fields and can be pasted directly into the strategy inputs (assuming the listed custom tokens are connected). None of them are trading recommendations. They are teaching tools designed to show how the YAML and expression system work together at increasing levels of depth.
Start at the level that matches where you are. If you are new to the tool, start with Beginner and work forward. Each level builds on the concepts from the previous one.
For the complete list of available tokens, see Default Tokens. For expression syntax, see Expression Reference. For every YAML field and its purpose, see YAML Reference.
Beginner — Single crossover with fixed exits
What this teaches: The simplest possible working strategy. One entry, one take profit, one stop loss. No setups (uses GLOBAL). Market orders only. This is your first honest run — the goal is to confirm the engine is reading your rules, not to produce a profitable backtest.
Custom tokens needed:
Long Entries
Example- entry_name: EMA_CROSS_LONG
entry_gate_condition: PRICE_CLOSE > 0
entry_trigger_when: CROSSOVER(PRICE_CLOSE, EMA_50)
entry_order_type: MARKET
entry_allocation_percent: 100Long Take Profits
Example- take_profit_name: TP_FIXED
take_profit_gate_condition: PRICE_CLOSE > 0
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE * 1.03
take_profit_lock_prices: trueLong Stop Losses
Example- stop_loss_name: SL_FIXED
stop_loss_gate_condition: PRICE_CLOSE > 0
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE * 0.98
stop_loss_lock_prices: trueWhat is happening
The entry fires when price crosses above the 50 EMA. The gate is always-true (PRICE_CLOSE > 0), which satisfies the required field without adding a real filter. It belongs to GLOBAL (no belongs_to_setup), so it evaluates every bar without any setup gating. The allocation is 100% — the full Properties tab default position size. One-shot is the default, so it fires once and then waits for a position cycle reset before it can fire again.
The take profit places a limit order at 3% above the average entry price. The stop loss places a stop order at 2% below entry. Both prices are latched — they are calculated once when the orders are placed and held constant.
This produces a 1.5:1 reward-to-risk ratio (3% target vs. 2% stop). That ratio is a design choice — it means the strategy can be profitable with a win rate below 50% if the winners are consistently larger than the losers. Whether that holds depends entirely on the market and the EMA's ability to identify favorable crossover points.
What to verify
Set direction to Long Only and check the consent box.
Enable the schema summary table. You should see: 0 setups, 1 entry, 1 take profit, 1 stop loss under Long.
Enable expression diagnostics. Look for
EMA_CROSS_LONGtrigger showing EVAL status.Check the trade list. Trades should appear with entries at crossover points and exits at the TP or SL level.
Run the slippage sensitivity test (0, 5, 10, 15 ticks). If the strategy is only profitable at 0 slippage, the edge is in the fill model, not in the rules.
What to explore next
Change the EMA period (swap
EMA_50for a different indicator) and observe how trade frequency and win rate change.Adjust the TP and SL percentages. A tighter stop (1%) with a wider target (5%) changes the character of the strategy entirely.
Add a volume condition to the entry trigger:
CROSSOVER(PRICE_CLOSE, EMA_50) && VOLUME > VOLUME[1].
Intermediate — Trend-gated entries with scaled exits
What this teaches: Named setups with confirmation. Entry gating on a confirmed regime. A two-leg take profit ladder. Entry-level confirmation. This is where the tool starts showing its depth.
Custom tokens needed:
Long Setups
Example- setup_name: UPTREND
setup_gate_condition: BAR_INDEX > 200
setup_active_when: PRICE_CLOSE > EMA_200
setup_confirm_count: 3
setup_cancel_when: PRICE_CLOSE < EMA_200
setup_cancel_confirm_count: 2
setup_cooldown_bars: 5Long Entries
Example- entry_name: PULLBACK_ENTRY
entry_belongs_to_setup: UPTREND
entry_gate_condition: RSI_K < 40
entry_trigger_when: CROSSOVER(PRICE_CLOSE, EMA_20)
entry_confirm_count: 1
entry_order_type: MARKET
entry_allocation_percent: 100Long Take Profits
Example- take_profit_name: TP_PARTIAL
take_profit_belongs_to_setup: UPTREND
take_profit_gate_condition: POSITION_PROFIT_PERCENT > 1
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE * 1.03
take_profit_lock_prices: true
take_profit_allocation_percent: 50
- take_profit_name: TP_RUNNER
take_profit_belongs_to_setup: UPTREND
take_profit_gate_condition: POSITION_PROFIT_PERCENT > 2
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE * 1.06
take_profit_lock_prices: true
take_profit_allocation_percent: 50Long Stop Losses
Example- stop_loss_name: SL_INITIAL
stop_loss_belongs_to_setup: UPTREND
stop_loss_gate_condition: PRICE_CLOSE > 0
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE * 0.97
stop_loss_lock_prices: trueWhat is happening
The setup creates a trading window called UPTREND. It requires price to hold above the 200 EMA for 3 consecutive bars before confirming. The gate condition BAR_INDEX > 200 prevents evaluation on the first 200 bars, giving the EMA enough history to warm up. When price drops below the 200 EMA for 2 bars, the setup cancels and enters a 5-bar cooldown.
The entry only evaluates when UPTREND is CONFIRMED. Within that window, it waits for RSI to pull back below 40 (gate), then triggers on a crossover above the 20 EMA with 1-bar confirmation. Allocation is 100% — the full Properties default position size. This is a classic pullback entry: enter the trend after a dip, not at the first sign of strength.
The exits form a two-leg ladder. TP_PARTIAL closes 50% of the position at 3% profit. TP_RUNNER closes the remaining 50% at 6% profit. Both use gate_condition to require the position to be in profit before their orders activate. The stop loss sits at 3% below entry. All exits set belongs_to_setup: UPTREND so they target only entries from this setup.
The combined exit profile: risk 3% to make 3% on half and 6% on the other half. The blended TP is 4.5%. The reward-to-risk is 1.5:1 on the blended profile.
What to verify
Schema summary should show: 1 setup, 1 entry, 2 take profits, 1 stop loss under Long.
Expression diagnostics should show UPTREND-related conditions. Watch for the setup state tokens:
UPTREND_INACTIVE,UPTREND_ACTIVE,UPTREND_CONFIRMED.Scroll to a bar where the 200 EMA is trending up. Confirm the setup reaches CONFIRMED after 3 bars above the EMA.
Find a pullback where RSI drops below 40 and then price crosses back above the 20 EMA. That should be an entry point.
Check the trade list: partial exits at 3% and runner exits at 6% (or stop exits at 3% for losing trades).
The key concept
The setup separates "is the environment right?" from "should I enter now?" This is the most important structural lesson in the tool. Without the setup, the pullback entry would fire in downtrends, sideways markets, and during the first 200 bars when the EMA has not stabilized. The setup filters all of that away, leaving only entries in confirmed uptrends after pullbacks.
Advanced — Multi-setup, multi-entry with OCA groups
What this teaches: Multiple setups running simultaneously. Two alternative entry strategies in an OCA group (first one wins). Entry pyramiding. Exit targeting by entry ID. Setup cross-referencing in entry gates.
Custom tokens needed:
Long Setups
Example- setup_name: MACRO_TREND
setup_gate_condition: BAR_INDEX > 200
setup_active_when:
PRICE_CLOSE > EMA_200
&& EMA_50 > EMA_200
setup_confirm_count: 5
setup_cancel_when:
PRICE_CLOSE < EMA_200
&& EMA_50 < EMA_200
setup_cancel_confirm_count: 3
setup_close_on_cancel: true
setup_cooldown_bars: 10
- setup_name: VOLATILITY_EXPANSION
setup_active_when:
ATR_14 > ATR_14[20] * 1.2
setup_confirm_count: 2
setup_cancel_when:
ATR_14 < ATR_14[20] * 0.8Long Entries
Example- entry_name: BB_BOUNCE
entry_belongs_to_setup: MACRO_TREND
entry_gate_condition:
VOLATILITY_EXPANSION_CONFIRMED
&& RSI_K < 35
entry_trigger_when: CROSSOVER(PRICE_CLOSE, BB_LOWER)
entry_order_type: MARKET
entry_allocation_percent: 40
entry_id: MEAN_REVERT
entry_oca_group: PRIMARY_ENTRY
- entry_name: BREAKOUT_LONG
entry_belongs_to_setup: MACRO_TREND
entry_gate_condition:
VOLATILITY_EXPANSION_CONFIRMED
&& RSI_K > 50
entry_trigger_when:
PRICE_HIGH > HIGHEST(PRICE_HIGH[1], 20)
entry_order_type: MARKET
entry_allocation_percent: 40
entry_id: BREAKOUT
entry_oca_group: PRIMARY_ENTRY
- entry_name: CONTINUATION_ADD
entry_belongs_to_setup: MACRO_TREND
entry_gate_condition:
POSITION_ACTIVE
&& POSITION_PROFIT_PERCENT > 1
entry_trigger_when: CROSSOVER(PRICE_CLOSE, EMA_50)
entry_order_type: MARKET
entry_allocation_percent: 20
entry_one_shot: false
entry_pyramiding_max_adds: 2
entry_id: CONTINUATIONLong Take Profits
Example- take_profit_name: TP_MEAN_REVERT
take_profit_belongs_to_setup: MACRO_TREND
take_profit_from_entry_id: MEAN_REVERT
take_profit_gate_condition: PRICE_CLOSE > 0
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE + ATR_14 * 2
take_profit_lock_prices: true
take_profit_allocation_percent: 100
- take_profit_name: TP_BREAKOUT_PARTIAL
take_profit_belongs_to_setup: MACRO_TREND
take_profit_from_entry_id: BREAKOUT
take_profit_gate_condition: POSITION_PROFIT_PERCENT > 2
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE + ATR_14 * 3
take_profit_lock_prices: true
take_profit_allocation_percent: 60
- take_profit_name: TP_BREAKOUT_RUNNER
take_profit_belongs_to_setup: MACRO_TREND
take_profit_from_entry_id: BREAKOUT
take_profit_gate_condition: POSITION_PROFIT_PERCENT > 3
take_profit_trigger_when: CROSSUNDER(RSI_K, 65)
take_profit_order_type: MARKET
take_profit_allocation_percent: 40
- take_profit_name: TP_CONTINUATION
take_profit_belongs_to_setup: MACRO_TREND
take_profit_from_entry_id: CONTINUATION
take_profit_gate_condition: PRICE_CLOSE > 0
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE + ATR_14 * 1.5
take_profit_lock_prices: trueLong Stop Losses
Example- stop_loss_name: SL_MEAN_REVERT
stop_loss_belongs_to_setup: MACRO_TREND
stop_loss_from_entry_id: MEAN_REVERT
stop_loss_gate_condition: PRICE_CLOSE > 0
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE - ATR_14 * 1.5
stop_loss_lock_prices: true
- stop_loss_name: SL_BREAKOUT
stop_loss_belongs_to_setup: MACRO_TREND
stop_loss_from_entry_id: BREAKOUT
stop_loss_gate_condition: PRICE_CLOSE > 0
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE - ATR_14 * 2
stop_loss_lock_prices: true
- stop_loss_name: SL_CONTINUATION
stop_loss_belongs_to_setup: MACRO_TREND
stop_loss_from_entry_id: CONTINUATION
stop_loss_gate_condition: PRICE_CLOSE > 0
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE - ATR_14 * 1
stop_loss_lock_prices: trueWhat is happening
Two setups run independently. MACRO_TREND confirms when price and the 50 EMA are both above the 200 EMA for 5 bars — a strong structural uptrend. VOLATILITY_EXPANSION confirms when ATR is 20% above its 20-bar average — the market is active enough to trade.
Three entries serve different purposes:
BB_BOUNCE is a mean-reversion entry: buy the Bollinger Band lower touch when RSI is oversold and volatility is expanding. This is a counter-move entry within the trend.
BREAKOUT_LONG is a momentum entry: buy the 20-bar high breakout when RSI confirms strength and volatility is expanding. This is a with-trend continuation.
Both share the OCA group
PRIMARY_ENTRY, which means whichever fires first cancels the other. You get one or the other on any given setup activation, not both. This prevents conflicting entries.CONTINUATION_ADD is a pyramid entry that only fires when a position is already open and profitable. It allows up to 2 additional adds at smaller size (20% vs. 40% of the default position size) on EMA crossovers. It is not in the OCA group — it works alongside whichever primary entry won.
All three entry allocations sum to 100% (40% + 40% + 20%), which is required by the validator. Since the OCA entries are mutually exclusive, at most 40% + 20% of the default position size is used in practice (the primary entry plus potential adds).
Targeted exits are the key structural feature. Each entry group has its own exit logic:
The mean-reversion entry gets a tight 2 ATR TP (it is a counter-move, so expectations are modest) and a 1.5 ATR stop.
The breakout entry gets a wider 3 ATR TP in two legs (60/40 split) and a 2 ATR stop (breakouts need room).
The continuation adds get a 1.5 ATR TP and a tight 1 ATR stop (smaller size, tighter control).
The key concept
This strategy demonstrates separation of concerns. Each entry type has different market assumptions, different sizing, and different exit profiles. The OCA group prevents conflicting entries. The from_entry_id fields route exits to the correct trades. The setup cross-reference (VOLATILITY_EXPANSION_CONFIRMED in the entry gates) creates a composite regime requirement without combining everything into one giant setup.
Extreme — Full-spectrum regime engine with dynamic risk
What this teaches: Multiple cooperating setups with cross-references. Conditional stop tightening based on position performance. Time-based exit management. Cancel conditions on exits. Setup-level entry caps. The full depth of what the YAML/expression combination can express.
Custom tokens needed:
Long Setups
Example- setup_name: REGIME_BULL
setup_gate_condition:
BAR_INDEX > 200
&& TF_ISDAILY
setup_active_when:
PRICE_CLOSE > EMA_200
&& EMA_50 > EMA_200
&& EMA_20 > EMA_50
setup_confirm_count: 5
setup_cancel_when:
EMA_20 < EMA_50
&& EMA_50 < EMA_200
setup_cancel_confirm_count: 3
setup_close_on_cancel: true
setup_cooldown_bars: 15
setup_max_entries_per_activation: 5
setup_reset_when:
STRATEGY_MAX_DRAWDOWN_PERCENT > 15
- setup_name: VOLATILITY_REGIME
setup_active_when:
ATR_14 > ATR_14[10] * 1.1
&& ATR_14 < ATR_14[10] * 3.0
setup_confirm_count: 2
setup_cancel_when:
ATR_14 < ATR_14[10] * 0.8
|| ATR_14 > ATR_14[10] * 3.0
- setup_name: VOLUME_REGIME
setup_active_when:
VOLUME > VOLUME_SMA * 1.2
setup_confirm_count: 1
setup_cancel_when:
VOLUME < VOLUME_SMA * 0.5
setup_cooldown_bars: 3Long Entries
Example- entry_name: PULLBACK_PRIME
entry_belongs_to_setup: REGIME_BULL
entry_gate_condition:
VOLATILITY_REGIME_CONFIRMED
&& VOLUME_REGIME_CONFIRMED
&& RSI_K < 40
&& STRATEGY_OPENTRADES < 3
entry_trigger_when:
CROSSOVER(PRICE_CLOSE, EMA_20)
&& PRICE_CLOSE > EMA_50
entry_confirm_count: 1
entry_order_type: MARKET
entry_allocation_percent: 40
entry_id: PRIME_GROUP
entry_oca_group: ALPHA_ENTRY
- entry_name: MOMENTUM_PRIME
entry_belongs_to_setup: REGIME_BULL
entry_gate_condition:
VOLATILITY_REGIME_CONFIRMED
&& VOLUME_REGIME_CONFIRMED
&& RSI_K > 55
&& RSI_K < 75
&& STRATEGY_OPENTRADES < 3
entry_trigger_when:
PRICE_HIGH > HIGHEST(PRICE_HIGH[1], 15)
&& VOLUME > VOLUME_SMA * 1.5
entry_order_type: MARKET
entry_allocation_percent: 40
entry_id: PRIME_GROUP
entry_oca_group: ALPHA_ENTRY
- entry_name: ADD_ON_STRENGTH
entry_belongs_to_setup: REGIME_BULL
entry_gate_condition:
POSITION_ACTIVE
&& POSITION_PROFIT_PERCENT > 1.5
&& VOLATILITY_REGIME_CONFIRMED
entry_trigger_when:
CROSSOVER(PRICE_CLOSE, EMA_20)
&& RSI_K > 40
&& RSI_K < 65
entry_order_type: MARKET
entry_allocation_percent: 20
entry_one_shot: false
entry_pyramiding_max_adds: 2
entry_id: ADD_GROUPLong Take Profits
Example- take_profit_name: TP_PRIME_QUICK
take_profit_belongs_to_setup: REGIME_BULL
take_profit_from_entry_id: PRIME_GROUP
take_profit_gate_condition: POSITION_PROFIT_PERCENT > 1
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE + ATR_14 * 2
take_profit_lock_prices: true
take_profit_allocation_percent: 30
- take_profit_name: TP_PRIME_TARGET
take_profit_belongs_to_setup: REGIME_BULL
take_profit_from_entry_id: PRIME_GROUP
take_profit_gate_condition: POSITION_PROFIT_PERCENT > 2
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE + ATR_14 * 4
take_profit_lock_prices: true
take_profit_allocation_percent: 40
- take_profit_name: TP_PRIME_RUNNER
take_profit_belongs_to_setup: REGIME_BULL
take_profit_from_entry_id: PRIME_GROUP
take_profit_gate_condition: POSITION_PROFIT_PERCENT > 3
take_profit_trigger_when: CROSSUNDER(RSI_K, 65)
take_profit_order_type: MARKET
take_profit_allocation_percent: 30
- take_profit_name: TP_ADD_QUICK
take_profit_belongs_to_setup: REGIME_BULL
take_profit_from_entry_id: ADD_GROUP
take_profit_gate_condition: PRICE_CLOSE > 0
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE + ATR_14 * 1.5
take_profit_lock_prices: true
take_profit_allocation_percent: 100Long Stop Losses
Example- stop_loss_name: SL_INITIAL
stop_loss_belongs_to_setup: REGIME_BULL
stop_loss_from_entry_id: PRIME_GROUP
stop_loss_gate_condition:
POSITION_PROFIT_PERCENT < 2
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE - ATR_14 * 2.5
stop_loss_lock_prices: true
stop_loss_allocation_percent: 100
- stop_loss_name: SL_TIGHTENED
stop_loss_belongs_to_setup: REGIME_BULL
stop_loss_from_entry_id: PRIME_GROUP
stop_loss_gate_condition:
POSITION_PROFIT_PERCENT >= 2
stop_loss_trigger_when: TRUE
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE - ATR_14 * 1
stop_loss_lock_prices: true
stop_loss_cancel_when:
POSITION_PROFIT_PERCENT < 2
stop_loss_allocation_percent: 100
- stop_loss_name: SL_ADD
stop_loss_belongs_to_setup: REGIME_BULL
stop_loss_from_entry_id: ADD_GROUP
stop_loss_gate_condition: PRICE_CLOSE > 0
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE - ATR_14 * 1
stop_loss_lock_prices: trueWhat is happening
Three setups create a layered regime filter:
REGIME_BULL is the structural trend filter — all three EMAs stacked bullish, with a hard reset if strategy drawdown exceeds 15%. The reset is a circuit breaker at the setup level: if the strategy is losing badly, clear all state and start fresh after cooldown. Entry cap of 5 per activation prevents over-trading within a single trend window. The gate requires a daily timeframe — this strategy is not designed for intraday.
VOLATILITY_REGIME confirms that ATR is between 1.1x and 3.0x its recent average. Too low means no movement. Too high means chaos. The sweet spot is elevated but not extreme volatility.
VOLUME_REGIME confirms above-average participation. Volume 20% above its moving average suggests real interest.
The entries require all three setups to be confirmed (REGIME_BULL via belongs_to_setup, the other two via gate cross-references). This means the strategy only enters when structure, volatility, and volume are all aligned.
PULLBACK_PRIME and MOMENTUM_PRIME are alternative entries in an OCA group — whichever fires first, the other cancels. One buys pullbacks (RSI oversold + EMA cross), the other buys breakouts (new highs on volume). Each allocates 40% of the Properties default position size.
ADD_ON_STRENGTH adds to winners: only fires when position is already profitable, allows 2 adds at 20% each. All three entries sum to 100% (40% + 40% + 20%) as required. Since the OCA entries are mutually exclusive, effective allocation is at most 40% (prime) + 20% + 20% = 80% of the default position size across all fills.
The exits demonstrate dynamic stop management:
SL_INITIAL is the wide stop — 2.5 ATR below entry. It is gated on
POSITION_PROFIT_PERCENT < 2, meaning it only applies while the open position is still below a 2% unrealized gain.SL_TIGHTENED replaces it once the open position reaches 2% unrealized profit (gated on
>= 2). It tightens to 1 ATR below entry. Thecancel_whencondition hands control back to the wider stop if open profit drops back below that threshold.This creates a graduated stop based on current open profit: wider protection early, tighter protection once the trade is working.
The three-leg TP on the prime entry scales out systematically: 30% at 2 ATR, 40% at 4 ATR, and the final 30% on an RSI signal (market order when RSI drops from above 65). The runner leg is not a fixed price — it is a conditional exit that waits for momentum to fade. This is how you let winners run without a fixed target.
The key concepts
Setup cross-referencing — Entry gates check
VOLATILITY_REGIME_CONFIRMED && VOLUME_REGIME_CONFIRMED. The setups run independently, but entries require all of them. This is modular regime composition.
Strategy-aware logic —
STRATEGY_OPENTRADES < 3in the entry gates caps total exposure.STRATEGY_MAX_DRAWDOWN_PERCENT > 15as a setup reset creates a portfolio-level circuit breaker.
Position-aware exits — Stop tightening based on
POSITION_PROFIT_PERCENTcreates adaptive risk management. The stop is not fixed — it responds to how the open trade is performing right now.
Conditional runners — The final TP leg uses a market order triggered by RSI rather than a fixed price. This is the difference between a static exit ladder and a dynamic one.
Entry caps —
setup_max_entries_per_activation: 5prevents the strategy from over-committing within a single trend window, even if conditions keep firing.
The honest warning
This configuration has many moving parts. Each interaction point — three setups cross-referencing each other, OCA groups, pyramiding, conditional stop tightening, graduated TPs — is a place where behavior can surprise you. Do not deploy something this complex without:
Running the schema summary to confirm all items parsed correctly.
Enabling expression diagnostics and verifying each setup's state transitions.
Walking through individual trades in the trade list to confirm entries and exits are targeting correctly.
Running the slippage sensitivity test.
Testing on at least two different time windows.
Complexity is earned through understanding. If you cannot explain what every field in this configuration does and why it is set to that value, simplify until you can.
Building from here
These four examples demonstrate a progression from a single-condition entry to a full regime engine. The distance between them is not just more YAML — it is more understanding of what the tool can express and what the backtest can honestly evaluate.
A few principles for building your own:
Start simple. Every strategy should begin as a Beginner-level configuration. Get the core thesis working before adding complexity.
Add one thing at a time. Each new setup, entry, or exit should be tested in isolation before combining it with existing logic. Use the schema summary and expression diagnostics after every change.
Name everything clearly. Token-safe, descriptive names make diagnostics readable.
TREND_PULLBACK_LONGis better thanE1. You will thank yourself when debugging.Test the failure modes. The backtesting checklist in Operating Checklist applies at every level. Slippage sensitivity, trade count, regime dependence — check them all.
Read the diagnostics, not just the equity curve. The equity curve is the summary. The diagnostics are the evidence. When the summary surprises you, the evidence will tell you why.
For the full build-test-iterate discipline, see Operating Checklist. For what can go wrong and how to diagnose it, see Troubleshooting.