YAML Reference
This page documents every field the engine accepts in each YAML section, what each field does, and why you would use it. If you want to understand how the pieces interact — how setups gate entries, how exits target en...
Written By Axiom Admin
Last updated About 1 month ago
YAML Reference
This page documents every field the engine accepts in each YAML section, what each field does, and why you would use it. If you want to understand how the pieces interact — how setups gate entries, how exits target entry groups, how the state machine flows — read Rules & Risk first. This page is the field-level reference. It tells you what you can write. Rules & Risk tells you what it means.
For the expression syntax used in condition and price fields, see Expression Reference. For the list of token names you can reference, see Default Tokens.
When examples use names like EMA_200, EMA_20, RSI_K, or ATR_14, assume those are custom tokens you connected from indicators on your chart. They are not built in.
YAML structure basics
Each YAML section is a list of items. Each item starts with a dash (-) at the root indent level, followed by key-value fields indented beneath it. The dash is required — it tells the parser where one item ends and the next begins.
Example- setup_name: MY_SETUP
setup_active_when: PRICE_CLOSE > EMA_200
setup_confirm_count: 3
- setup_name: ANOTHER_SETUP
setup_active_when: VOLUME > 1000000Indentation matters. Fields must be indented consistently under their item dash. The parser uses indentation to determine which fields belong to which item. Tabs are automatically normalized to two spaces, so tabs will not cause parse errors — but using spaces explicitly is still recommended for consistency. Two-space indentation is conventional.
Colons separate keys from values. setup_name: MY_SETUP is a key-value pair. The space after the colon is not strictly required (the parser trims whitespace from both key and value), but including it is conventional and improves readability.
Comments. Lines containing # are stripped from that character onward. This applies blindly — the parser does not distinguish between # in a comment and # inside a value. Avoid using # in expression strings.
Expression fields can span multiple lines. If an expression is complex, you can continue it on the next line with additional indentation:
Example- entry_name: COMPLEX_ENTRY
entry_trigger_when:
PRICE_CLOSE > EMA_50
&& RSI_K < 30
&& VOLUME > VOLUME[1] * 1.5The parser collects continuation lines (indented deeper than the field key) and joins them into a single expression string. This is purely for readability — the engine sees one expression.
The four sections
Your strategy is defined across four section types per direction. Long and short are independent — you write them in separate input fields.
Each section is pasted into its corresponding text area in the Inputs tab. You can leave any section empty. A strategy with only entries and no setups will use the implicit GLOBAL setup (always confirmed). A strategy with entries but no exits will rely on direction reversals or manual close logic.
Setups section
Setups define when a trading window opens. They do not submit orders — they control whether entries belonging to them are allowed to evaluate. Think of a setup as a regime filter: "the market is in a state where my thesis applies."
Every named setup follows the state machine described in Rules & Risk: INACTIVE → CONFIRMING → CONFIRMED. Entries only fire when their owning setup is CONFIRMED.
Setup fields
\* At least one of setup_cancel_when or setup_reset_when must be provided. You need not provide both, but one of them is required. Without either, the engine has no way to exit the setup, and validation will reject the YAML.
Why you would use each field
setup_gate_condition — Use this for slow-moving, broad filters. A 200-bar EMA direction, a volatility regime check, a session time window. The gate must be true before the activation expression is even considered. This separates "the environment is right" (gate) from "the specific trigger fired" (activation).
setup_confirm_count — Use this when your activation condition is noisy. A single bar above the EMA is a spike. Three consecutive bars above the EMA is a trend establishing. Confirmation turns a momentary signal into a persistent one. Start with small counts (2–3 bars) and increase only if you are filtering too few false activations.
setup_cancel_when — Use this to close the trading window when the regime changes. If your setup activates on an uptrend and you want to deactivate when the trend breaks, the cancel expression defines that break. At least one of setup_cancel_when or setup_reset_when must be present — the engine requires a defined exit path for every setup.
setup_close_on_cancel — Use this when a regime change means existing positions are no longer valid. If the setup represents "we are in an uptrend" and the uptrend breaks, you may want to not only stop new entries but also close any open trades that were entered under the uptrend assumption.
setup_cooldown_bars — Use this to prevent whipsawing. After a cancel, the setup must wait before re-activating. This is useful when the activation and cancel conditions are close together — without cooldown, the setup can oscillate between CONFIRMED and INACTIVE on every bar, producing chaotic entry behavior.
setup_max_entries_per_activation — Use this to limit how many times you enter during a single setup window. If your setup represents a daily trading window and you only want two entries per day, set this to 2. The cap resets when the setup re-activates after a cancel or reset.
Minimal setup example
Example- setup_name: TREND_FILTER
setup_active_when: PRICE_CLOSE > EMA_200
setup_cancel_when: PRICE_CLOSE < EMA_200This creates a setup that reaches CONFIRMED whenever price is above the 200 EMA (assuming EMA_200 is a custom token), and cancels when price drops below. No confirmation delay, no cooldown. Entries belonging to TREND_FILTER can evaluate on any bar where price is above the EMA.
Full setup example
Example- setup_name: TREND_FILTER
setup_gate_condition: TF_ISDAILY
setup_active_when: PRICE_CLOSE > EMA_200
setup_confirm_type: BAR_COUNT
setup_confirm_count: 3
setup_cancel_when: PRICE_CLOSE < EMA_200
setup_cancel_confirm_count: 2
setup_close_on_cancel: true
setup_cooldown_bars: 5
setup_max_entries_per_activation: 3This setup only evaluates on daily charts (gate), activates when price holds above the 200 EMA for 3 consecutive bars, cancels when price holds below for 2 bars (closing all positions on cancel), waits 5 bars before re-activating, and allows up to 3 entries per activation window.
Entries section
Entries define when and how to submit orders. Each entry belongs to a setup (explicitly via entry_belongs_to_setup, or implicitly to GLOBAL if not specified).
Entry fields
Entry sizing: how allocation works
entry_allocation_percent does not set a percentage of equity directly. It sets a percentage of the Properties tab default position size. The engine computes entry quantity as:
quantity = default_entry_qty(price) * (entry_allocation_percent / 100)Where default_entry_qty comes from TradingView's Properties tab (e.g., "10% of equity" or a fixed contract count).
If your Properties tab says "10% of equity" and you set entry_allocation_percent: 50, the entry gets 50% of 10% = 5% of equity. If you set entry_allocation_percent: 100, the entry gets the full 10%.
All entry allocation percentages in a direction must sum to 100%. If you have one entry, set it to 100. If you have two entries that should split the position equally, set each to 50. If the total deviates from 100% by more than 0.5%, the engine raises a validation error and the strategy will not run.
Why you would use each field
entry_belongs_to_setup — This is how you connect entries to regime filters. Without it, entries evaluate every bar regardless of market conditions. With it, entries only evaluate when the named setup is CONFIRMED. If you defined setups but forgot to set this field, your entries are ignoring your setups entirely.
entry_gate_condition — This field is required. Use it for entry-specific prerequisites that are separate from the setup's gate. The setup gate might say "the market is trending." The entry gate might say "and RSI is not overbought." Both must pass. If you want the gate to always pass, write PRICE_CLOSE > 0.
entry_order_type — This field is required. MARKET orders execute at the next bar's open. LIMIT orders specify a price and wait. STOP orders trigger when price reaches a level. STOPLIMIT combines both. Limit and stop orders interact with expiration, the bar magnifier, and the fill assumption settings in ways that can surprise you.
entry_lock_prices — Use this when you want the limit or stop price to be calculated once and then held. Without latching, a limit price expression like PRICE_CLOSE - 50 * MINTICK recalculates every bar, which means the order target drifts with the market. Latching freezes it at the value calculated when the trigger first fired.
entry_oca_group — Use this when you have alternative entry strategies and want whichever triggers first. Two entries in the same OCA group mean: "I want either this entry or that entry, but not both."
entry_one_shot — The default true means the entry fires once per setup activation and then stops. Set to false for pyramiding — adding to a winning position. Pyramiding interacts with the Properties tab pyramiding limit: even if your entry allows multiple adds, the global limit caps the total concurrent trades.
Minimal entry example
Example- entry_name: EMA_CROSSOVER
entry_gate_condition: PRICE_CLOSE > 0
entry_trigger_when: CROSSOVER(PRICE_CLOSE, EMA_50)
entry_order_type: MARKET
entry_allocation_percent: 100A market order entry on GLOBAL (no setup), triggered when price crosses above the 50 EMA. Gate is always-true. Allocation is 100% of the Properties tab default position size. One-shot by default — fires once and stops.
Full entry example
Example- entry_name: PULLBACK_LONG
entry_belongs_to_setup: TREND_FILTER
entry_gate_condition: RSI_K < 40
entry_trigger_when: CROSSOVER(PRICE_CLOSE, EMA_20)
entry_confirm_count: 1
entry_order_type: LIMIT
entry_limit_price: PRICE_CLOSE - (10 * MINTICK)
entry_lock_prices: true
entry_allocation_percent: 100
entry_id: PULLBACK_GROUP
entry_expire_after_bars: 5
entry_cancel_when: PRICE_CLOSE < PRICE_LOW[3]
entry_one_shot: false
entry_pyramiding_max_adds: 2This entry belongs to the TREND_FILTER setup, waits for RSI to be below 40 (gate), triggers on an EMA crossover with 1-bar confirmation, submits a limit order 10 ticks below the current close (latched), uses the full Properties default position size, allows up to 3 total fills (1 + 2 adds), expires unfilled orders after 5 bars, and cancels the pending order if price breaks below the 3-bar low.
Take profits section
Take profits define profit-taking exits. They target open trades from specific entries (via from_entry_id) or from all entries in the same setup.
Take profit fields
Why you would use each field
take_profit_allocation_percent — This controls how much of the position the TP closes. Two TPs at 50% each close the entire position in two legs. Three TPs at 33% each close it in three legs. If total allocation exceeds 100%, all TPs are scaled down proportionally. This is how you build exit ladders.
take_profit_trigger_when — Use this when the TP should only activate under certain conditions. A TP gated on POSITION_PROFIT_PERCENT > 2 and triggered when CROSSUNDER(RSI_K, 70) means: "take profit when RSI starts dropping from overbought, but only after the position is at least 2% in profit."
take_profit_lock_prices — Use this for fixed target TPs. A TP with a limit price of POSITION_AVG_PRICE * 1.05 and lock_prices: true sets the target at 5% above entry and holds it. Without latching, the target would recalculate if the average entry price changes (from pyramiding adds, for example).
take_profit_from_entry_id — Use this when different entries need different exit logic. Your pullback entry might have a tighter TP than your breakout entry. Give them different entry_id values and target each TP at the appropriate group.
Exit targeting scope
How an exit selects which entry groups it applies to depends on two fields:
If
from_entry_idis set, the exit only applies to the entry group with thatentry_id. This is the most specific targeting.
If
from_entry_idis omitted and the exit belongs to a named setup (not GLOBAL), the exit applies to all entries in that same setup.
If
from_entry_idis omitted and the exit belongs to GLOBAL (either explicitly or by default becausebelongs_to_setupwas omitted), the exit applies to every entry group in the direction. This is the broadest scope and is often not what you want for complex strategies.
If you have multiple setups with different entries, always set belongs_to_setup or from_entry_id on your exits to avoid unintended cross-targeting.
Minimal take profit example
Example- take_profit_name: TP_1
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: trueA limit order at 3% above entry, price latched on first evaluation. Gate is always-true. Closes 100% of the position (default). Because belongs_to_setup is omitted, this exit attaches to GLOBAL and targets all entry groups.
Scaled take profit example
Example- take_profit_name: TP_1
take_profit_gate_condition: PRICE_CLOSE > 0
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE * 1.02
take_profit_lock_prices: true
take_profit_allocation_percent: 50
- take_profit_name: TP_2
take_profit_gate_condition: PRICE_CLOSE > 0
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVG_PRICE * 1.05
take_profit_lock_prices: true
take_profit_allocation_percent: 50Two TPs that together close the full position: half at 2% profit, the other half at 5%.
Stop losses section
Stop losses define protective exits. The field structure mirrors take profits with a different prefix.
Stop loss fields
Why you would use each field
stop_loss_stop_price — This is the most important field. A stop loss without a price expression is a market exit that fires when the trigger is true. A stop loss with a stop price is a standing order that executes when price reaches the level. The difference is timing: a market stop fires on the next bar after the trigger. A stop-order stop fires intra-bar when price touches the level.
stop_loss_lock_prices — Almost always true for stop losses. You want the stop level set once, based on where you entered, and held. A stop at POSITION_AVG_PRICE - ATR_14 * 2 with latching freezes the stop at 2 ATR below entry and does not drift as ATR changes. Without latching, the stop recalculates every bar, which can widen or tighten your risk in ways you did not intend.
stop_loss_trigger_when — Use this for conditional stops. A stop that should only activate after the position is already working: POSITION_PROFIT_PERCENT > 1. Or a stop that should only arm after price re-enters a certain zone. This lets you build graduated protection logic without forcing every stop to be live from the first bar.
Minimal stop loss example
Example- stop_loss_name: SL_1
stop_loss_gate_condition: PRICE_CLOSE > 0
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVG_PRICE - (200 * MINTICK)
stop_loss_lock_prices: trueA stop order 200 ticks below entry, latched. Gate is always-true. Closes the full position.
Field defaults summary
When you omit optional fields, the engine applies these defaults. Note that several fields are required and have no default — omitting them causes a validation error.
Understanding defaults and required fields is essential for debugging. If the strategy shows a validation error on load, check that all required fields are present. When behavior surprises you, check whether a default is doing something you did not expect — especially one_shot: true (entries fire once), allocation_percent: 100 on exits (closes everything), and belongs_to_setup defaulting to GLOBAL on exits (targets all entry groups).
Common YAML mistakes
See Troubleshooting for the complete diagnostic workflow when your YAML is not behaving as expected.