YAML Reference

This page documents the fields the Strategy Lab accepts in each YAML section, what each field does, and the shape of the strategy model those fields create.

Written By Axiom Admin

Last updated 1 day ago

YAML Reference

This page documents the fields the Strategy Lab accepts in each YAML section, what each field does, and the shape of the strategy model those fields create.

The important shift is this: setups, entries, take profits, and stop losses are all named units of work. Setups decide when a trading context is valid. Entries put capital into the market. Take profits and stop losses work against the current position for that direction. They are not tied to an entry ID anymore. They are tied by setup ownership, gate conditions, trigger logic, and the state tokens generated by every named unit.

For expression syntax, see Expression Reference. For built-in and generated token names, see Default Tokens. For diagnostic messages and error codes, see Diagnostics & Error Codes.

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.

Example
- setup_name: TREND_FILTER setup_active_when: PRICE_CLOSE > EMA_200 setup_cancel_when: PRICE_CLOSE < EMA_200 - setup_name: PULLBACK_WINDOW setup_active_when: PRICE_CLOSE > EMA_200 && RSI_K < 45 setup_cancel_when: PRICE_CLOSE < EMA_200

Indentation matters. Tabs are normalized to spaces, but two-space indentation is still the cleanest habit.

Colons separate keys from values. setup_name: TREND_FILTER is a key-value pair.

Comments start at #. The parser strips everything from # to the end of the line. Avoid # inside expression values.

Expression fields can span multiple lines. Continuation lines must be indented deeper than the field key:

Example
- entry_name: COMPLEX_ENTRY entry_trigger_when: PRICE_CLOSE > EMA_50 && RISING(EMA_50, 3) && VOLUME > VOLUME[1] * 1.5

The engine joins those continuation lines into one expression before compiling it.


Sections

Long and short strategies are configured in separate input areas. Each direction has four section types.

Section

Input field

What it defines

Setups

Long Setups / Short Setups

Market regimes or context windows that gate entries and exits

Entries

Long Entries / Short Entries

Order submission logic for getting into the position

Take Profits

Long Take Profits / Short Take Profits

Profit-taking exit units against the current position

Stop Losses

Long Stop Losses / Short Stop Losses

Protective exit units against the current position

You can leave a section empty. If an entry does not name a setup, it belongs to GLOBAL, which is always available. Exits also default to GLOBAL, but in complex strategies it is usually better to name the setup explicitly so the YAML reads like the trade you meant to build.


Names And State Tokens

Every unit must have a unique name after token sanitization:

Unit

Name field

Longhand state tokens

Shorthand aliases

Setup

setup_name

<NAME>_INACTIVE, <NAME>_CONFIRMING, <NAME>_ACTIVE

<NAME>INACT, <NAME>CONF, <NAME>ACT

Entry

entry_name

<NAME>_INACTIVE, <NAME>_CONFIRMING, <NAME>_WORKING, <NAME>_ACTIVE

<NAME>INACT, <NAME>CONF, <NAME>WORK, <NAME>ACT

Take profit

take_profit_name

<NAME>_INACTIVE, <NAME>_CONFIRMING, <NAME>_WORKING, <NAME>_ACTIVE

<NAME>INACT, <NAME>CONF, <NAME>WORK, <NAME>ACT

Stop loss

stop_loss_name

<NAME>_INACTIVE, <NAME>_CONFIRMING, <NAME>_WORKING, <NAME>_ACTIVE

<NAME>INACT, <NAME>CONF, <NAME>WORK, <NAME>ACT

Names are also used for order identity where the engine needs an order ID. That means entry_name is not just a label. It is the thing the engine uses to name the entry order and generate state tokens.

Avoid names that collapse into the same token after sanitization. First TP, FIRST_TP, and first-tp are too close for comfort. If two names produce the same token base, the strategy raises a diagnostic error.

The shared lifecycle is deliberately plain. CONFIRMING means the unit's condition is true but its confirmation count is still running. WORKING only applies to entries and exits that have submitted a resting order that has not filled yet. ACTIVE means the unit has completed the job it exists to do in the current lifecycle: a setup has opened its trading context, an entry has filled, or an exit has executed. The shorthand aliases mean the same thing as the longhand tokens; they are just more compact.


Setups

Setups define when a trading window opens. They do not submit orders. They decide whether the entries and exits that belong to them are allowed to evaluate.

Setup Fields

Field

Required

Type

Default

What it does

setup_name

Yes

Text

None

Unique setup name. Generates setup state tokens and can be referenced by entries and exits.

setup_gate_condition

No

Boolean expression

true

Prerequisite that must pass before activation can begin.

setup_active_when

Yes

Boolean expression

None

Main activation condition.

setup_confirm_type

No

BAR_COUNT or NUM_TICKS

BAR_COUNT

How activation confirmation is measured.

setup_confirm_count

No

Integer >= 0

0

Bars or ticks required before confirmation.

setup_cancel_when

Required if no reset

Boolean expression

None

Cancels the setup when true.

setup_cancel_confirm_type

No

BAR_COUNT or NUM_TICKS

BAR_COUNT

How cancel confirmation is measured.

setup_cancel_confirm_count

No

Integer >= 0

0

Bars or ticks required before cancel.

setup_close_on_cancel

No

Boolean

false

When true, the engine closes the position when this setup is cancelled.

setup_cooldown_bars

No

Integer >= 0

0

Bars to wait after cancel/reset before activation can restart.

setup_max_entries_per_activation

No

Integer

None

Caps entry fills during one activation window.

setup_reset_when

Required if no cancel

Boolean expression

None

Hard reset that clears counters and confirmation progress.

At least one of setup_cancel_when or setup_reset_when must be present. Without one of them, the setup has no defined way to leave its active cycle.

Minimal Setup

Example
- setup_name: TREND_FILTER setup_active_when: PRICE_CLOSE > EMA_200 setup_cancel_when: PRICE_CLOSE < EMA_200

Full Setup

Example
- setup_name: TREND_FILTER setup_gate_condition: TIMEFRAME_IS_INTRADAY setup_active_when: PRICE_CLOSE > EMA_200 && RISING(EMA_200, 3) 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: 3

Entries

Entries define when and how capital enters the market. Each entry belongs to a setup, either explicitly through entry_belongs_to_setup or implicitly through GLOBAL.

Entry Fields

Field

Required

Type

Default

What it does

entry_name

Yes

Text

None

Unique entry name. Generates state tokens and becomes the order ID basis.

entry_belongs_to_setup

No

Text

GLOBAL

Setup this entry belongs to. Must match a setup_name unless using GLOBAL.

entry_gate_condition

No

Boolean expression

true

Optional entry-specific prerequisite. Use it to narrow when the trigger is allowed to matter.

entry_trigger_when

Yes

Boolean expression

None

Primary entry trigger.

entry_confirm_type

No

BAR_COUNT or NUM_TICKS

BAR_COUNT

How entry confirmation is measured.

entry_confirm_count

No

Integer >= 0

0

Bars or ticks required before order submission.

entry_order_type

Yes

MARKET, LIMIT, STOP, STOPLIMIT

None

Entry order type.

entry_allocation_percent

Yes

Number

None

Share of the Properties tab default position size. Entry allocations in a direction cannot total more than 100%.

entry_lock_prices

No

Boolean

false

Latches limit/stop prices when the entry first triggers.

entry_limit_price

Depends

Numeric expression

None

Required for LIMIT and STOPLIMIT entries.

entry_stop_price

Depends

Numeric expression

None

Required for STOP and STOPLIMIT entries.

entry_oca_group

No

Text

None

Optional one-cancels-all group name for entry orders.

entry_oca_type

No

CANCEL, REDUCE, NONE

CANCEL when group is present

OCA behavior used with entry_oca_group. Has no practical effect without a group.

entry_expire_after_bars

No

Integer

None

Cancels an unfilled non-market order after this many bars.

entry_cancel_when

No

Boolean expression

None

Cancels a working, unfilled order when true.

entry_one_shot

No

Boolean

true

When true, fires once per setup activation.

entry_pyramiding_max_adds

No

Integer

None

Additional fills allowed when entry_one_shot is false.

Entry Sizing

entry_allocation_percent splits the strategy's configured position size. If the Properties tab says the strategy uses 10% of equity and the entry allocation is 50, that entry receives 5% of equity.

All entry allocations in the same direction can total any value up to 100%. A single-entry strategy can use entry_allocation_percent: 100 for the full configured size, or a smaller value for reduced exposure. A two-leg ladder might use 50 and 50 for full deployment, or 25 and 25 for half of the configured size.

If the total is below 100, the unused share of the configured position size simply stays out of the market. That is valid and often useful when you want a smaller deployment without changing the Properties tab.

Entry OCA

Entry OCA is for orders that are competing to enter the position.

Example
- entry_name: BREAKOUT_LONG entry_belongs_to_setup: TREND_FILTER entry_gate_condition: PRICE_CLOSE > EMA_200 entry_trigger_when: PRICE_CLOSE > PRICE_HIGH[1] entry_order_type: STOP entry_stop_price: PRICE_HIGH[1] + MIN_TICK entry_allocation_percent: 50 entry_oca_group: LONG_ENTRY_COMPETE entry_oca_type: CANCEL - entry_name: PULLBACK_LONG entry_belongs_to_setup: TREND_FILTER entry_gate_condition: PRICE_CLOSE > EMA_200 entry_trigger_when: PRICE_CLOSE < EMA_20 entry_order_type: LIMIT entry_limit_price: EMA_20 entry_allocation_percent: 50 entry_oca_group: LONG_ENTRY_COMPETE entry_oca_type: CANCEL

Use CANCEL when one filled entry should cancel its peers. In a breakout-versus-pullback group, this is usually the plainest behavior: once one entry fills, the remaining sibling orders are cancelled.

Use REDUCE when sibling orders share one intended size pool and you want fills in one order to shrink the remaining sibling quantities instead of cancelling them outright. If one order fills 40% of the planned size, the remaining orders in that OCA group are reduced by that filled quantity. This can be useful for advanced staged entry plans, but it is easier to misread because an order can still exist after a sibling fill while its remaining quantity has changed.

Use NONE when you want the group field effectively disabled.

Minimal Entry

Example
- entry_name: EMA_CROSS_OVER entry_trigger_when: CROSS_OVER(PRICE_CLOSE, EMA_50) entry_order_type: MARKET entry_allocation_percent: 100

Take Profits

Take profits are independent exit units against the current position for that direction. They do not point at entry IDs. If you need a TP to apply only after a specific entry or setup, use take_profit_belongs_to_setup, state tokens, and gate/trigger logic.

Take Profit Fields

Field

Required

Type

Default

What it does

take_profit_name

Yes

Text

None

Unique take-profit name. Generates state tokens.

take_profit_belongs_to_setup

No

Text

GLOBAL

Setup context for this TP.

take_profit_gate_condition

No

Boolean expression

true

Eligibility link before the TP can evaluate. Use it for position, setup, or entry-state requirements.

take_profit_trigger_when

Yes

Boolean expression

None

Primary TP trigger.

take_profit_confirm_type

No

BAR_COUNT or NUM_TICKS

BAR_COUNT

How TP confirmation is measured.

take_profit_confirm_count

No

Integer >= 0

0

Bars or ticks required before submission.

take_profit_order_type

No

MARKET, LIMIT, STOP, STOPLIMIT

LIMIT

TP order type.

take_profit_allocation_percent

No, but recommended

Number

100

Percentage of the current remaining position this unit attempts to close. Set it explicitly so the exit's intent is visible.

take_profit_lock_prices

No

Boolean

false

Latches limit/stop prices when the TP first triggers.

take_profit_limit_price

Depends

Numeric expression

None

Required for LIMIT and STOPLIMIT TPs.

take_profit_stop_price

Depends

Numeric expression

None

Required for STOP and STOPLIMIT TPs.

take_profit_cancel_when

No

Boolean expression

None

Cancels a working TP when true. Has no practical effect on market exits.

Multiple Full-Exit Take Profits

Because take profits are independent units, more than one TP can use take_profit_allocation_percent: 100. That does not mean you are trying to exit 300% of the position. It means each TP is an alternative full-exit condition. The engine submits exits against the current remaining position and uses reduce-style OCA behavior for exit orders.

Example
- take_profit_name: TP_RSI_REVERSAL take_profit_belongs_to_setup: TREND_FILTER take_profit_gate_condition: POSITION_ACTIVE take_profit_trigger_when: CROSS_UNDER(RSI_K, 70) take_profit_order_type: MARKET take_profit_allocation_percent: 100 - take_profit_name: TP_FIXED_TARGET take_profit_belongs_to_setup: TREND_FILTER take_profit_gate_condition: POSITION_ACTIVE take_profit_trigger_when: TRUE take_profit_order_type: LIMIT take_profit_limit_price: POSITION_AVERAGE_PRICE * 1.03 take_profit_lock_prices: true take_profit_allocation_percent: 100

Scaling Out

Use allocations below 100 when you want actual legs.

Example
- take_profit_name: TP_HALF take_profit_belongs_to_setup: TREND_FILTER take_profit_gate_condition: POSITION_ACTIVE take_profit_trigger_when: TRUE take_profit_order_type: LIMIT take_profit_limit_price: POSITION_AVERAGE_PRICE * 1.02 take_profit_lock_prices: true take_profit_allocation_percent: 50 - take_profit_name: TP_FINAL take_profit_belongs_to_setup: TREND_FILTER take_profit_gate_condition: POSITION_ACTIVE && POSITION_REMAINING_PERCENT <= 50 take_profit_trigger_when: TRUE take_profit_order_type: LIMIT take_profit_limit_price: POSITION_AVERAGE_PRICE * 1.05 take_profit_lock_prices: true take_profit_allocation_percent: 100

Stop Losses

Stop losses are also independent exit units against the current position. They can be full-position alternatives, partial protective legs, break-even stops, invalidation stops, or emergency market exits.

Stop Loss Fields

Field

Required

Type

Default

What it does

stop_loss_name

Yes

Text

None

Unique stop-loss name. Generates state tokens.

stop_loss_belongs_to_setup

No

Text

GLOBAL

Setup context for this SL.

stop_loss_gate_condition

No

Boolean expression

true

Eligibility link before the SL can evaluate. Use it for position, setup, or entry-state requirements.

stop_loss_trigger_when

Yes

Boolean expression

None

Primary SL trigger.

stop_loss_confirm_type

No

BAR_COUNT or NUM_TICKS

BAR_COUNT

How SL confirmation is measured.

stop_loss_confirm_count

No

Integer >= 0

0

Bars or ticks required before submission.

stop_loss_order_type

No

MARKET, LIMIT, STOP, STOPLIMIT

STOP

SL order type.

stop_loss_allocation_percent

No, but recommended

Number

100

Percentage of the current remaining position this unit attempts to close. Set it explicitly so the stop's intent is visible.

stop_loss_lock_prices

No

Boolean

false

Latches limit/stop prices when the SL first triggers.

stop_loss_stop_price

Depends

Numeric expression

None

Required for STOP and STOPLIMIT SLs.

stop_loss_limit_price

Depends

Numeric expression

None

Required for LIMIT and STOPLIMIT SLs.

stop_loss_cancel_when

No

Boolean expression

None

Cancels a working SL when true. Has no practical effect on market exits.

Full Stop Alternatives

Multiple stop losses can each use stop_loss_allocation_percent: 100 when they represent alternative ways the same position can be invalidated.

Example
- stop_loss_name: SL_STRUCTURE_BREAK stop_loss_belongs_to_setup: TREND_FILTER stop_loss_gate_condition: POSITION_ACTIVE stop_loss_trigger_when: TRUE stop_loss_order_type: STOP stop_loss_stop_price: LOWEST(PRICE_LOW, 10) stop_loss_lock_prices: false stop_loss_allocation_percent: 100 - stop_loss_name: SL_MOMENTUM_FAIL stop_loss_belongs_to_setup: TREND_FILTER stop_loss_gate_condition: POSITION_ACTIVE stop_loss_trigger_when: CROSS_UNDER(MOMENTUM_SCORE, 0) stop_loss_order_type: MARKET stop_loss_allocation_percent: 100

Break-Even After First Profit

You do not need a special "TP filled" field to move a stop. Use remaining-position tokens as the eligibility gate, then let stop_loss_trigger_when: TRUE arm the working stop as soon as the gate is valid.

Example
- stop_loss_name: SL_INITIAL stop_loss_belongs_to_setup: TREND_FILTER stop_loss_gate_condition: POSITION_ACTIVE && POSITION_REMAINING_PERCENT > 50 stop_loss_trigger_when: TRUE stop_loss_order_type: STOP stop_loss_stop_price: POSITION_AVERAGE_PRICE - ATR_14 * 2 stop_loss_lock_prices: true stop_loss_allocation_percent: 100 - stop_loss_name: SL_BREAK_EVEN stop_loss_belongs_to_setup: TREND_FILTER stop_loss_gate_condition: POSITION_ACTIVE && POSITION_REMAINING_PERCENT <= 50 stop_loss_trigger_when: TRUE stop_loss_order_type: STOP stop_loss_stop_price: POSITION_AVERAGE_PRICE stop_loss_lock_prices: true stop_loss_allocation_percent: 100

Defaults And Required Fields

Omitted field

Result

entry_gate_condition, take_profit_gate_condition, stop_loss_gate_condition

Defaults to true. Gates are eligibility links and filters; triggers are the work condition after eligibility passes.

entry_trigger_when, take_profit_trigger_when, stop_loss_trigger_when

Error. Entries and exits require a trigger condition.

entry_order_type

Error. Entries require an order type.

entry_allocation_percent

Error. Entries require an allocation.

take_profit_allocation_percent, stop_loss_allocation_percent

Defaults to 100 in the current parser. Still set it explicitly so the intent is not hidden.

Both setup_cancel_when and setup_reset_when

Error. One reset path is required.

Any confirmation count

Defaults to 0.

Any confirmation type

Defaults to BAR_COUNT.

entry_one_shot

Defaults to true.

take_profit_order_type

Defaults to LIMIT.

stop_loss_order_type

Defaults to STOP.

entry_lock_prices, take_profit_lock_prices, stop_loss_lock_prices

Defaults to false.

entry_belongs_to_setup, take_profit_belongs_to_setup, stop_loss_belongs_to_setup

Defaults to GLOBAL.

entry_oca_type

Defaults to CANCEL when an OCA group is present.


Removed Or Rejected Fields

These fields are not part of the current schema:

Field

What to use instead

entry_id

Use entry_name. It is the entry order identity and state-token base.

take_profit_from_entry_id

Use take_profit_belongs_to_setup, generated state tokens, and gate/trigger logic.

stop_loss_from_entry_id

Use stop_loss_belongs_to_setup, generated state tokens, and gate/trigger logic.

from_entry_id

Same replacement: setup ownership plus gates and state tokens.

TRAIL as an exit order type

Use explicit stop logic with STOP or STOPLIMIT.

The parser reports entry_id as a removed-field diagnostic. Other stale entry-ID routing fields are not part of the current schema and may appear as unknown-field warnings. Either way, remove the old field and use the current setup ownership, state-token, and gate/trigger model. Typo fields are warnings, not silent no-ops. Read the diagnostics table before assuming the strategy is behaving as written.


Common Mistakes

Mistake

What happens

Better habit

Naming two units that sanitize to the same token base

Blocking diagnostic. The engine cannot safely generate state tokens.

Use short, unique, uppercase names like L_BREAKOUT_ENTRY and L_PULLBACK_ENTRY.

Entry allocations total more than 100% in one direction

Blocking diagnostic: YAML_ALLOCATION_TOTAL.

Keep combined entry allocations at 100% or less. Under 100% is valid when you want partial deployment.

Forgetting exit allocation

Defaults to 100, which can hide the intended size of the exit.

Always set take_profit_allocation_percent or stop_loss_allocation_percent in production YAML.

Assuming two 100% exits are invalid

They can be valid alternatives.

Use 100% for alternative full exits; use smaller numbers for true scale-out legs.

Using a lookback before enough history exists

Usually a warmup warning, sometimes a final-type error if the expression returns no usable value.

Use NZ or a warm-up gate when early bars should stay quiet. Use SAFE_DIV only when the lookback is part of a denominator.

Using only a logical guard around unsafe math

The guarded function may still be evaluated.

Put the fallback inside the calculation, not just around it.

Adding entry_oca_type without entry_oca_group

Warning. OCA type has no effect without a group.

Add a group or remove the OCA type field.

Adding cancel logic to a market exit

Warning. Market exits do not sit on the book long enough for cancel logic to matter.

Use cancel conditions on working non-market orders.

For a practical debugging flow, see Troubleshooting. For the diagnostic code map, see Diagnostics & Error Codes.