Teaching Examples
This page gives you four complete long-side strategy configurations, from simple to complex. They are not trade recommendations. They are bench tests you can paste, run, question, and take apart until the Strategy Lab...
Written By Axiom Admin
Last updated 1 day ago
Teaching Examples
This page gives you four complete long-side strategy configurations, from simple to complex. They are not trade recommendations. They are bench tests you can paste, run, question, and take apart until the Strategy Lab starts to feel less like a form and more like a machine you understand.
Each example has multiple YAML blocks. Paste each block into the matching Strategy Lab input section: Long Setups into Long Setups, Long Entries into Long Entries, Long Take Profits into Long Take Profits, and Long Stop Losses into Long Stop Losses.
These examples are written to paste cleanly when the required custom tokens are connected. That matters because the Strategy Lab now warns when a token is unavailable during warm-up. A setup gate does not automatically protect every other field. If an entry gate, trigger, take profit, or stop references a warming token, that field needs its own NZ, SAFE_DIV, or warm-up guard.
That is not busywork. It is the difference between "this rule is intentionally quiet until the data exists" and "this rule accidentally depended on a value that was not there yet."
Use the token tables before you paste the YAML. Connect each custom token to the matching indicator plot first, then paste each block into its matching Strategy Lab section. If the diagnostics table names a token after that, check the token binding before rewriting the strategy.
Read the fallbacks literally. NZ(RSI_K, 50) means "treat missing RSI as neutral." NZ(EMA_20, PRICE_CLOSE) means "do not create an artificial EMA signal before the EMA exists." SAFE_DIV(x, y, fallback) means "if the denominator is missing or zero, use the fallback instead of poisoning the whole expression."
Read gates and triggers as two different questions.
A gate condition answers: "Is this unit even allowed to think yet?" Use gates to link one unit of work to another unit's state. A setup can expose
L_INT_UPTREND_ACTIVE. An entry can exposeL_EXT_PULLBACK_PRIME_ACTIVE. The position exposesPOSITION_ACTIVEandPOSITION_REMAINING_PERCENT. Those belong in gates when they are eligibility rules.A trigger condition answers: "Now that this unit is eligible, what makes it do its job?" Put the actual entry signal, exit signal, breakout, cross, or failure condition there.
If a take profit should only exist after a certain entry has filled, put that entry's active token in
take_profit_gate_condition, then put the actual profit-taking event intake_profit_trigger_when.If a resting limit target or stop should be submitted as soon as the gate is true, use
TRUEas the trigger. That is not a shortcut. It means, "No extra event is needed after eligibility; place the working order."
Do not optimize these examples on the first pass. First prove that the structure behaves. Then change one thing at a time. A strategy you cannot explain is not a strategy yet; it is just YAML with confidence painted on top.
For the complete field list, see YAML Reference. For tokens, see Default Tokens. For expression syntax and safe math patterns, see Expression Reference.
Beginner - Single Crossover With Fixed Exits
What this teaches: one entry, one take profit, one stop loss, no named setup, and the simplest warm-up-safe custom token pattern.
The Trading Idea
Enter long when price crosses above a 50 EMA. Once the position is open, place one fixed profit target and one fixed stop. Nothing here is trying to be clever. That is the point. This is the smallest useful Strategy Lab shape: one way in, two ways out.
The Strategy Lab Idea
There is no setup in this example, so the entry belongs to the global strategy context. The entry creates the position. The take profit and stop loss do not belong to the entry directly; they link to the overall position with POSITION_ACTIVE.
That is the first mental model to get right: entries build exposure, exits reduce or close whatever exposure exists.
Custom tokens needed:
The EMA is wrapped with NZ(EMA_50, PRICE_CLOSE). On the first bars of a chart, the EMA may not exist yet. Falling back to current price keeps the crossover quiet until the EMA is usable.
Why The YAML Looks Like This
entry_namegives this unit its identity. If you later inspect generated state tokens or order names, this is the name you should recognize.entry_trigger_whenis the actual entry moment. The market order is not submitted until the crossover becomes true.take_profit_gate_condition: POSITION_ACTIVEandstop_loss_gate_condition: POSITION_ACTIVElink those exits to the open position. The exits do not even try to work while there is nothing to manage.take_profit_trigger_when: TRUEandstop_loss_trigger_when: TRUEmean the working target and stop should be submitted as soon as the position link is valid.NZ(EMA_50, PRICE_CLOSE)prevents a warm-up warning and avoids inventing a signal before the EMA exists.POSITION_AVERAGE_PRICEmakes the exits calculate from the filled position price, not from the current candle.take_profit_lock_prices: trueandstop_loss_lock_prices: truefreeze the target and stop when the exit order is created. Without locking, dynamic prices can keep moving as the chart updates.
Long Entries
Example- entry_name: L_BEG_EMA_CROSS
entry_trigger_when: CROSS_OVER(PRICE_CLOSE, NZ(EMA_50, PRICE_CLOSE))
entry_order_type: MARKET
entry_allocation_percent: 100Long Take Profits
Example- take_profit_name: L_BEG_TP_FIXED
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: 100Long Stop Losses
Example- stop_loss_name: L_BEG_SL_FIXED
stop_loss_gate_condition: POSITION_ACTIVE
stop_loss_trigger_when: TRUE
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVERAGE_PRICE * 0.98
stop_loss_lock_prices: true
stop_loss_allocation_percent: 100What To Verify
Direction is Long Only. This proves you are testing the same side as the YAML.
Schema summary shows 1 long entry, 1 long take profit, and 1 long stop loss. This proves the YAML was parsed into the expected units.
The diagnostics table stays clean when
EMA_50is connected. This proves the token binding and warm-up fallback are working.Trades appear near EMA crossovers. This proves the entry trigger is doing the thing you asked it to do.
The trade list shows exits near the fixed 3% target or 2% stop. This proves the exits are watching the open position.
If It Does Not Behave
If the diagnostics table names
EMA_50, check the custom token binding first. Do not rewrite the YAML until the token is actually connected.If there are no trades, zoom out and check whether price actually crossed above the EMA during the tested range.
If entries happen but exits do not, make sure the take profit YAML went into Long Take Profits and the stop YAML went into Long Stop Losses.
Try One Controlled Change
Change the take profit from 1.03 to 1.015. Do not change anything else. Run it again and confirm that exits move closer. This is how you learn the lab without losing the thread.
Intermediate - Trend Setup With Scale-Out
What this teaches: named setup, setup confirmation, setup-owned entry and exits, partial take profit, and break-even stop gating.
The Trading Idea
Only buy pullbacks when the broader trend is already up. The 200 EMA defines the trend. RSI defines the pullback. The 20 EMA gives the re-entry trigger. Once the trade is open, take half off at the first target, then let the rest try for a larger target with a break-even stop underneath it.
This is a common trader thought: "I want to be paid quickly, then remove some risk and see if the rest can run."
The Strategy Lab Idea
The setup is the regime filter. It answers, "Are we even allowed to think long yet?" The entry belongs to that setup, so it should not fire while the setup is inactive. The exits also belong to the setup, but they still manage the overall open position.
The important teaching point is the scale-out. The first take profit closes 50%. After that happens, POSITION_REMAINING_PERCENT should drop to 50 or lower. That one position token becomes a gate: it turns off the wider initial stop and turns on the break-even stop.
Custom tokens needed:
Notice that the setup, entry gate, and entry trigger each protect their own warming tokens. The setup's BAR_INDEX > 200 gate is useful, but the entry still needs to handle RSI_K and EMA_20 directly because diagnostics read each expression field on its own.
Why The YAML Looks Like This
setup_gate_condition: BAR_INDEX > 200keeps the setup quiet until the 200 EMA has had enough chart history to mean something.setup_active_whenandsetup_cancel_whenboth wrapEMA_200anyway. The gate is for trading logic; the fallback is for clean diagnostics.setup_confirm_count: 3requires the trend condition to hold for three bars before the setup becomes active. One candle does not get to decide the whole regime.entry_belongs_to_setup: L_INT_UPTRENDlinks the entry to the setup state. The entry can still have its own gate and trigger, but it is not floating loose.NZ(RSI_K, 50)treats missing RSI as neutral. Neutral RSI is not below 40, so it will not accidentally approve a pullback during warm-up.The first take profit links to
POSITION_ACTIVE, then usesTRUEas the trigger because a resting limit target should be placed as soon as a position exists.The final take profit links to
POSITION_REMAINING_PERCENT <= 50, then usesTRUEas the trigger because it is another resting limit target.The two stops are not ranked by priority. They are separated by gates. Before the half take profit, the initial stop is eligible. After the half take profit, the break-even stop is eligible.
Long Setups
Example- setup_name: L_INT_UPTREND
setup_gate_condition: BAR_INDEX > 200
setup_active_when: PRICE_CLOSE > NZ(EMA_200, PRICE_CLOSE)
setup_confirm_count: 3
setup_cancel_when: PRICE_CLOSE < NZ(EMA_200, PRICE_CLOSE)
setup_cancel_confirm_count: 2
setup_cooldown_bars: 5Long Entries
Example- entry_name: L_INT_PULLBACK
entry_belongs_to_setup: L_INT_UPTREND
entry_gate_condition:
BAR_INDEX > 200
&& NZ(RSI_K, 50) < 40
entry_trigger_when: CROSS_OVER(PRICE_CLOSE, NZ(EMA_20, PRICE_CLOSE))
entry_confirm_count: 1
entry_order_type: MARKET
entry_allocation_percent: 100Long Take Profits
Example- take_profit_name: L_INT_TP_HALF
take_profit_belongs_to_setup: L_INT_UPTREND
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: 50
- take_profit_name: L_INT_TP_FINAL
take_profit_belongs_to_setup: L_INT_UPTREND
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.06
take_profit_lock_prices: true
take_profit_allocation_percent: 100Long Stop Losses
Example- stop_loss_name: L_INT_SL_INITIAL
stop_loss_belongs_to_setup: L_INT_UPTREND
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 * 0.97
stop_loss_lock_prices: true
stop_loss_allocation_percent: 100
- stop_loss_name: L_INT_SL_BREAK_EVEN
stop_loss_belongs_to_setup: L_INT_UPTREND
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: 100What To Verify
L_INT_UPTREND_ACTIVEbecomes true only after three bars above the 200 EMA. This proves setup confirmation is working.The entry does not fire before the setup is active. This proves
entry_belongs_to_setupis doing real work.The diagnostics table stays clean when
EMA_200,EMA_20, andRSI_Kare connected. This proves each expression field is handling its own warm-up.The first TP closes about half the position. This proves exit allocation is acting against the current position.
After the half TP fills,
POSITION_REMAINING_PERCENTdrops and the break-even stop becomes eligible.The old wider stop is gated off after the scale-out. You should not have both stop styles logically active for the same remaining position.
If It Does Not Behave
If the setup never activates, check
EMA_200first, then check whether price actually stays above it for three bars.If the entry never fires, check
RSI_K < 40and the crossover separately. A valid uptrend with no pullback is not a broken strategy.If the break-even stop never becomes eligible, the half take profit probably did not fill. Watch
POSITION_REMAINING_PERCENTbefore blaming the stop.If you see a warm-up warning, read the named token. A setup gate elsewhere does not protect an entry field that references an unguarded token.
Try One Controlled Change
Change NZ(RSI_K, 50) < 40 to NZ(RSI_K, 50) < 50. That should allow more pullbacks through the gate. If trade frequency does not change at all, the RSI gate probably was not the limiting factor.
Advanced - Competing Entries With Shared Exits
What this teaches: multiple setups, entry OCA, state-token gates, alternative full exits, no entry-ID targeting, and warm-up-safe shared logic.
The Trading Idea
Trade only when the larger trend is bullish and volatility is expanding. Once that context exists, allow two different entry tactics to compete: a Bollinger-band bounce and a breakout. They are different paths into the same long exposure, not separate strategy accounts.
After entry, manage the open position with shared exits. One exit is an ATR-based target. Another exit is an RSI fade while already profitable. The stop can either be ATR-based or immediate if the macro setup fails.
The Strategy Lab Idea
This is where the "one pot of money" model starts to matter. The two entries can compete through an OCA group, but the exits do not need to know which entry won. They are independent units watching the overall position.
The volatility setup is also important. No entry belongs to L_ADV_VOL_EXPANSION. It is being used as a gate condition through its generated state token, L_ADV_VOL_EXPANSION_ACTIVE. That is a clean pattern: one setup can describe context without directly owning an entry.
Custom tokens needed:
This example has more moving parts, so every field that touches a warming token owns its fallback. The macro setup protects EMAs, volatility rules protect ATR ratios, and entry triggers protect Bollinger and historical-high references.
Why The YAML Looks Like This
L_ADV_MACRO_TRENDowns the actual trade idea. Entries and exits belong to it because losing the macro trend should matter to the whole position.L_ADV_VOL_EXPANSIONis a context switch. It does not own trades; it creates a state token that entries can consult.Entry gates link each entry to setup state. Entry triggers hold the actual entry events.
Exit gates link each exit to position or setup state. Exit triggers hold the actual exit event, or
TRUEwhen the unit should place a resting order immediately after the gate is true.entry_oca_group: L_ADV_PRIMARYandentry_oca_type: CANCELtell the two primary entries to compete. If one entry gets submitted, the other should not also become a duplicate expression of the same idea.The two entries allocate 50% each, so combined entry exposure stays within the 100% cap.
The take profits both allocate 100%, but they are not promising to exit 200% of the position. They are alternative full exits against whatever position remains when one of them triggers.
NZ(ATR_14, MIN_TICK)keeps dynamic target and stop prices usable during diagnostics without inventing a large ATR value.The breakout trigger uses
BAR_INDEX > 20andNZ(HIGHEST(...), PRICE_HIGH)because historical lookbacks need enough chart history before they can answer honestly.
Long Setups
Example- setup_name: L_ADV_MACRO_TREND
setup_gate_condition: BAR_INDEX > 200
setup_active_when:
PRICE_CLOSE > NZ(EMA_200, PRICE_CLOSE)
&& NZ(EMA_50, PRICE_CLOSE) > NZ(EMA_200, PRICE_CLOSE)
setup_confirm_count: 5
setup_cancel_when:
PRICE_CLOSE < NZ(EMA_200, PRICE_CLOSE)
&& NZ(EMA_50, PRICE_CLOSE) < NZ(EMA_200, PRICE_CLOSE)
setup_cancel_confirm_count: 3
setup_close_on_cancel: true
setup_cooldown_bars: 10
- setup_name: L_ADV_VOL_EXPANSION
setup_gate_condition: BAR_INDEX > 20
setup_active_when:
SAFE_DIV(NZ(ATR_14, 0), NZ(ATR_14[20], 1), 0) > 1.20
setup_confirm_count: 2
setup_cancel_when:
SAFE_DIV(NZ(ATR_14, 0), NZ(ATR_14[20], 1), 1) < 0.80Long Entries
Example- entry_name: L_ADV_BB_BOUNCE
entry_belongs_to_setup: L_ADV_MACRO_TREND
entry_gate_condition:
L_ADV_VOL_EXPANSION_ACTIVE
&& NZ(RSI_K, 50) < 35
entry_trigger_when: CROSS_OVER(PRICE_CLOSE, NZ(BB_LOWER, PRICE_CLOSE))
entry_order_type: MARKET
entry_allocation_percent: 50
entry_oca_group: L_ADV_PRIMARY
entry_oca_type: CANCEL
- entry_name: L_ADV_BREAKOUT
entry_belongs_to_setup: L_ADV_MACRO_TREND
entry_gate_condition:
L_ADV_VOL_EXPANSION_ACTIVE
&& NZ(RSI_K, 50) > 50
entry_trigger_when:
BAR_INDEX > 20
&& PRICE_HIGH > NZ(HIGHEST(PRICE_HIGH[1], 20), PRICE_HIGH)
entry_order_type: MARKET
entry_allocation_percent: 50
entry_oca_group: L_ADV_PRIMARY
entry_oca_type: CANCELLong Take Profits
Example- take_profit_name: L_ADV_TP_ATR_TARGET
take_profit_belongs_to_setup: L_ADV_MACRO_TREND
take_profit_gate_condition: POSITION_ACTIVE
take_profit_trigger_when: TRUE
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVERAGE_PRICE + NZ(ATR_14, MIN_TICK) * 2
take_profit_lock_prices: true
take_profit_allocation_percent: 100
- take_profit_name: L_ADV_TP_RSI_FADE
take_profit_belongs_to_setup: L_ADV_MACRO_TREND
take_profit_gate_condition:
POSITION_ACTIVE
&& POSITION_PROFIT_PERCENT > 2
take_profit_trigger_when: CROSS_UNDER(NZ(RSI_K, 50), 65)
take_profit_order_type: MARKET
take_profit_allocation_percent: 100Long Stop Losses
Example- stop_loss_name: L_ADV_SL_ATR
stop_loss_belongs_to_setup: L_ADV_MACRO_TREND
stop_loss_gate_condition: POSITION_ACTIVE
stop_loss_trigger_when: TRUE
stop_loss_order_type: STOP
stop_loss_stop_price: POSITION_AVERAGE_PRICE - NZ(ATR_14, MIN_TICK) * 1.5
stop_loss_lock_prices: true
stop_loss_allocation_percent: 100
- stop_loss_name: L_ADV_SL_SETUP_FAIL
stop_loss_belongs_to_setup: L_ADV_MACRO_TREND
stop_loss_gate_condition: POSITION_ACTIVE
stop_loss_trigger_when:
!L_ADV_MACRO_TREND_ACTIVE
stop_loss_order_type: MARKET
stop_loss_allocation_percent: 100What To Verify
L_ADV_MACRO_TREND_ACTIVEandL_ADV_VOL_EXPANSION_ACTIVEcan be true or false independently. This proves the context setup is not secretly owning the trade.The two entries share
L_ADV_PRIMARY, so they compete. This proves entry OCA is controlling entry alternatives.Entry order names are based on
entry_name. This proves the strategy is using named units, not removed entry-ID targeting.No exit uses entry-ID targeting. This proves exits are managing the position, not one specific entry label.
Both take profits are 100% exits, but they are alternatives against the same remaining position.
The setup-failure stop exits the position if the macro setup is lost.
The diagnostics table stays clean while the example still uses custom tokens and historical lookbacks.
If It Does Not Behave
If neither entry fires, check whether both setups are active at the same time. A trend without volatility expansion should stay quiet here.
If only one entry style ever appears, that may be normal. OCA competition means one tactic can dominate on a given market and timeframe.
If you see an allocation diagnostic, check only the entries. Exit allocations are allowed to be alternative full exits, but entry allocations cannot exceed 100% combined.
If the ATR target or stop looks too close, check whether
ATR_14is connected. The fallback isMIN_TICK, which is intentionally tiny.
Try One Controlled Change
Change entry_oca_type: CANCEL to entry_oca_type: REDUCE on both entries and compare behavior. Do not keep that change blindly. The point is to see how OCA changes the order relationship, not to assume one mode is better.
Extreme - Regime Engine With Dynamic Risk
What this teaches: multiple cooperating setups, safe historical math, add-on entries, partial exits, break-even transition, time-based escape, and expression diagnostics coverage.
The Trading Idea
Build a long-only regime engine. The strategy wants a bullish trend, acceptable volatility, and acceptable volume before it allows primary entries. It can enter through a pullback or a momentum breakout. If the position starts working, it can add on. Then it scales out, protects the remainder, and has several ways to abandon the trade if the story changes.
This is not "better" because it is bigger. It is bigger because it is trying to model more decisions a trader might normally hold in their head.
The Strategy Lab Idea
This example treats setups, entries, take profits, and stop losses as separate units of work against one overall position. Some units create context. Some create exposure. Some reduce exposure. Some close it entirely.
The important thing to watch is not just whether trades happen. Watch why they become eligible. A complex strategy that trades but cannot explain itself is not advanced; it is just noisy.
Custom tokens needed:
This is the stress test. It uses several custom tokens, historical lookbacks, generated state tokens, and alternative exits. The YAML is deliberately defensive so the diagnostic table teaches you about real problems instead of yelling about normal warm-up behavior.
Why The YAML Looks Like This
L_EXT_REGIME_BULLis the main authority. Entries and exits belong to this setup because the bullish regime is the reason the strategy is allowed to be long.L_EXT_VOL_OKandL_EXT_VOLUME_OKare permission layers. They do not own trades; they expose state tokens that entries can require.The two prime entries share
L_EXT_PRIMARY, so the pullback and momentum tactics compete instead of stacking blindly.The add-on entry does not share that OCA group. It has a different job: add only after the position is already profitable and volatility is still acceptable.
Entry allocations total 100% across the three entry units: 40 + 40 + 20. That respects the entry allocation cap while still allowing different ways to deploy the same capital pool.
The first take profit exits 50%. Its gate links it to a profitable active position; its trigger is
TRUEbecause the limit order should be placed immediately once that link is valid.The runner take profit and break-even stop both depend on
POSITION_REMAINING_PERCENT <= 50, so they only become logical after the scale-out.The time escape watches generated entry state tokens with
BARS_SINCE(...). It is asking, "Has one of these entry units been active long enough, and has price lost the 20 EMA while the trade is still profitable?"The strategy uses
NZ,SAFE_DIV, and same-fieldBAR_INDEXguards because this example intentionally touches historical values, token warm-up, and ratios. The diagnostics table should be reserved for real mistakes, not predictable early-chart emptiness.
Long Setups
Example- setup_name: L_EXT_REGIME_BULL
setup_gate_condition:
BAR_INDEX > 200
&& TIMEFRAME_IS_INTRADAY
setup_active_when:
PRICE_CLOSE > NZ(EMA_200, PRICE_CLOSE)
&& NZ(EMA_50, PRICE_CLOSE) > NZ(EMA_200, PRICE_CLOSE)
&& NZ(EMA_20, PRICE_CLOSE) > NZ(EMA_50, PRICE_CLOSE)
setup_confirm_count: 5
setup_cancel_when:
NZ(EMA_20, PRICE_CLOSE) < NZ(EMA_50, PRICE_CLOSE)
&& NZ(EMA_50, PRICE_CLOSE) < NZ(EMA_200, PRICE_CLOSE)
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: L_EXT_VOL_OK
setup_gate_condition: BAR_INDEX > 20
setup_active_when:
SAFE_DIV(NZ(ATR_14, 0), NZ(ATR_14[10], 1), 0) > 1.10
&& SAFE_DIV(NZ(ATR_14, 0), NZ(ATR_14[10], 1), 0) < 3.00
setup_confirm_count: 2
setup_cancel_when:
SAFE_DIV(NZ(ATR_14, 0), NZ(ATR_14[10], 1), 1) < 0.80
|| SAFE_DIV(NZ(ATR_14, 0), NZ(ATR_14[10], 1), 1) > 3.00
- setup_name: L_EXT_VOLUME_OK
setup_gate_condition: BAR_INDEX > 20
setup_active_when:
SAFE_DIV(VOLUME, NZ(VOLUME_SMA, VOLUME), 0) > 1.20
setup_confirm_count: 1
setup_cancel_when:
SAFE_DIV(VOLUME, NZ(VOLUME_SMA, VOLUME), 1) < 0.50
setup_cooldown_bars: 3Long Entries
Example- entry_name: L_EXT_PULLBACK_PRIME
entry_belongs_to_setup: L_EXT_REGIME_BULL
entry_gate_condition:
L_EXT_VOL_OK_ACTIVE
&& L_EXT_VOLUME_OK_ACTIVE
&& NZ(RSI_K, 50) < 40
&& STRATEGY_OPEN_TRADES < 3
entry_trigger_when:
CROSS_OVER(PRICE_CLOSE, NZ(EMA_20, PRICE_CLOSE))
&& PRICE_CLOSE > NZ(EMA_50, PRICE_CLOSE)
entry_confirm_count: 1
entry_order_type: MARKET
entry_allocation_percent: 40
entry_oca_group: L_EXT_PRIMARY
entry_oca_type: CANCEL
- entry_name: L_EXT_MOMENTUM_PRIME
entry_belongs_to_setup: L_EXT_REGIME_BULL
entry_gate_condition:
L_EXT_VOL_OK_ACTIVE
&& L_EXT_VOLUME_OK_ACTIVE
&& NZ(RSI_K, 50) > 55
&& NZ(RSI_K, 50) < 75
&& STRATEGY_OPEN_TRADES < 3
entry_trigger_when:
BAR_INDEX > 15
&& PRICE_HIGH > NZ(HIGHEST(PRICE_HIGH[1], 15), PRICE_HIGH)
&& SAFE_DIV(VOLUME, NZ(VOLUME_SMA, VOLUME), 0) > 1.50
entry_order_type: MARKET
entry_allocation_percent: 40
entry_oca_group: L_EXT_PRIMARY
entry_oca_type: CANCEL
- entry_name: L_EXT_ADD_ON_STRENGTH
entry_belongs_to_setup: L_EXT_REGIME_BULL
entry_gate_condition:
POSITION_ACTIVE
&& POSITION_PROFIT_PERCENT > 1.5
&& L_EXT_VOL_OK_ACTIVE
entry_trigger_when:
CROSS_OVER(PRICE_CLOSE, NZ(EMA_20, PRICE_CLOSE))
&& NZ(RSI_K, 50) > 40
&& NZ(RSI_K, 50) < 65
entry_order_type: MARKET
entry_allocation_percent: 20
entry_one_shot: false
entry_pyramiding_max_adds: 2Long Take Profits
Example- take_profit_name: L_EXT_TP_SCALE_HALF
take_profit_belongs_to_setup: L_EXT_REGIME_BULL
take_profit_gate_condition:
POSITION_ACTIVE
&& POSITION_PROFIT_PERCENT > 1
take_profit_trigger_when: TRUE
take_profit_order_type: LIMIT
take_profit_limit_price: POSITION_AVERAGE_PRICE + NZ(ATR_14, MIN_TICK) * 2
take_profit_lock_prices: true
take_profit_allocation_percent: 50
- take_profit_name: L_EXT_TP_RUNNER_RSI
take_profit_belongs_to_setup: L_EXT_REGIME_BULL
take_profit_gate_condition:
POSITION_ACTIVE
&& POSITION_REMAINING_PERCENT <= 50
&& POSITION_PROFIT_PERCENT > 3
take_profit_trigger_when: CROSS_UNDER(NZ(RSI_K, 50), 65)
take_profit_order_type: MARKET
take_profit_allocation_percent: 100
- take_profit_name: L_EXT_TP_TIME_ESCAPE
take_profit_belongs_to_setup: L_EXT_REGIME_BULL
take_profit_gate_condition:
POSITION_ACTIVE
&& POSITION_PROFIT_PERCENT > 0
&& BAR_INDEX > 1
&& (
BARS_SINCE(L_EXT_PULLBACK_PRIME_ACTIVE && !L_EXT_PULLBACK_PRIME_ACTIVE[1]) > 60
|| BARS_SINCE(L_EXT_MOMENTUM_PRIME_ACTIVE && !L_EXT_MOMENTUM_PRIME_ACTIVE[1]) > 60
|| BARS_SINCE(L_EXT_ADD_ON_STRENGTH_ACTIVE && !L_EXT_ADD_ON_STRENGTH_ACTIVE[1]) > 60
)
take_profit_trigger_when: PRICE_CLOSE < NZ(EMA_20, PRICE_CLOSE)
take_profit_order_type: MARKET
take_profit_allocation_percent: 100Long Stop Losses
Example- stop_loss_name: L_EXT_SL_INITIAL
stop_loss_belongs_to_setup: L_EXT_REGIME_BULL
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 - NZ(ATR_14, MIN_TICK) * 2.5
stop_loss_lock_prices: true
stop_loss_allocation_percent: 100
- stop_loss_name: L_EXT_SL_BREAK_EVEN
stop_loss_belongs_to_setup: L_EXT_REGIME_BULL
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
- stop_loss_name: L_EXT_SL_REGIME_FAIL
stop_loss_belongs_to_setup: L_EXT_REGIME_BULL
stop_loss_gate_condition: POSITION_ACTIVE
stop_loss_trigger_when:
!L_EXT_REGIME_BULL_ACTIVE
|| !L_EXT_VOL_OK_ACTIVE
stop_loss_order_type: MARKET
stop_loss_allocation_percent: 100What To Verify
No warm-up warnings appear when the required custom tokens are connected because warming values are guarded in the same fields that use them.
L_EXT_REGIME_BULL_ACTIVE,L_EXT_VOL_OK_ACTIVE, andL_EXT_VOLUME_OK_ACTIVEmove independently. This proves each setup is carrying a separate job.Entry allocations stay within the 100% cap: 40 + 40 + 20.
The two prime entries compete through
L_EXT_PRIMARY. This proves the primary tactics are alternatives, not duplicate exposure.The add-on entry only becomes eligible when the position is already profitable.
The first TP reduces the position; the runner TP and break-even stop depend on
POSITION_REMAINING_PERCENT.The time escape only exits profitable positions after one of the entries has been active for a while and price loses the 20 EMA.
Multiple 100% exits are present, but they are alternative full exits against the current remaining position.
If It Does Not Behave
If the strategy barely trades, check the setup state tokens first. Three cooperating setups can easily become too strict together.
If the add-on never appears, check
POSITION_PROFIT_PERCENT > 1.5andL_EXT_VOL_OK_ACTIVE. The add-on is intentionally not a first entry.If the break-even stop appears too early, inspect whether the 50% scale-out filled and whether
POSITION_REMAINING_PERCENTactually dropped.If the time escape never fires, remember that it requires profit, an active-position history condition, and price below the 20 EMA.
If the diagnostics table is noisy, do not wave it off. This example is written defensively. A warning usually means a token binding, field edit, or copied block is wrong.
Try One Controlled Change
Disable L_EXT_VOLUME_OK_ACTIVE from the two prime entry gates and run the same chart again. You should see whether volume was acting as a meaningful filter or just making the strategy quieter. Put it back before testing anything else.
Building From Here
Start simple, then add one unit at a time. After each addition:
Check the diagnostics table.
Check the schema summary.
Watch generated state tokens.
Confirm the trade list matches the story you think the YAML is telling.
Run slippage sensitivity before believing the equity curve.
Complexity is not the goal. Clarity is. Complexity is only useful when you can still explain what each unit is supposed to do and how you would know if it failed.