Signal Generator
Type:
signal_generator• Category:flow• Tags:signals,trading,strategy,conditions,backtest
Description
Generate trading signals based on configurable conditions
Parameters
| Name | Type | Description | Required | Default |
|---|---|---|---|---|
data | string | OHLC/indicator data from upstream worker | yes | |
time_field | string | Timestamp field name in your data | no | "datetime" |
long_conditions | array | Conditions to open long position. Each condition: {left, operator, right} | no | [] |
long_logic | string | How to combine long conditions | no | "AND" |
short_conditions | array | Conditions to open short position | no | [] |
short_logic | string | How to combine short conditions | no | "AND" |
close_mode | string | When to generate close signals: reverse (on opposite entry), conditions (explicit only), both, or none (rely on backtest SL/TP) | no | "reverse" |
close_long_conditions | array | Conditions to close long position (used when close_mode is 'conditions' or 'both') | no | [] |
close_long_logic | string | How to combine close long conditions | no | "AND" |
close_short_conditions | array | Conditions to close short position (used when close_mode is 'conditions' or 'both') | no | [] |
close_short_logic | string | How to combine close short conditions | no | "AND" |
signal_mode | string | How to handle repeated signals: 'first' (only when condition becomes true), 'every' (on each bar condition is true), 'cooldown' (with minimum gap) | no | "first" |
cooldown_bars | number | Minimum bars between signals | no | 0 |
cooldown_seconds | number | Minimum seconds between signals | no | 0 |
allow_pyramiding | boolean | Allow multiple entries in same direction | no | false |
Help
📊 Signal Generator
Generate trading signals from your data based on customizable conditions.
Connect the output directly to the backtest_strategy worker.
🎯 Quick Start
Simplest Example - Buy when RSI < 30
{
"data": "{{workers[0].results}}",
"long_conditions": [
{"left": "rsi", "operator": "<", "right": "30"}
]
}
Buy and Sell Signals
{
"data": "{{workers[0].results}}",
"long_conditions": [
{"left": "rsi", "operator": "crosses_above", "right": "30"}
],
"short_conditions": [
{"left": "rsi", "operator": "crosses_below", "right": "70"}
]
}
⚡ Key Features
| Feature | Description |
|---|---|
| Flexible Conditions | Compare any fields with 15+ operators |
| Cross Detection | Detect when values cross above/below each other |
| Nested AND/OR Logic | Complex conditions like (A AND B) OR (C AND D) |
| Close Modes | Control when positions are closed (4 modes) |
| Field Expressions | Math on fields: high - low, close + 10 |
| Percentage Functions | pct_change(close), pct(close, open) for % calculations |
| Previous Bar Access | Reference previous values with field[-1] |
| Signal Filtering | Avoid duplicates with first or cooldown modes |
| String/Text Operators | Filter by symbol, news, patterns |
🎯 Signal Mode (Avoiding Duplicates)
The signal_mode parameter controls how repeated signals are handled:
| Mode | Description | Use Case |
|---|---|---|
first | (Default) Only signal when condition BECOMES true | Avoid duplicates - most common |
every | Signal on every bar the condition is true | Testing, specific strategies |
cooldown | Require minimum gap between signals | Fine-tuned signal frequency |
Example: The Problem
With condition close > 4000:
- every mode: Generates signal on EVERY bar where close > 4000 (many duplicates!)
- first mode: Only generates signal on the FIRST bar where close > 4000
first mode (Recommended)
{
"signal_mode": "first",
"long_conditions": [{"left": "close", "operator": ">", "right": "4000"}]
}
Signal only when price CROSSES above 4000, not while it stays above.
cooldown mode
{
"signal_mode": "cooldown",
"cooldown_bars": 10,
"long_conditions": [{"left": "close", "operator": ">", "right": "4000"}]
}
After a signal, wait at least 10 bars before allowing another.
{
"signal_mode": "cooldown",
"cooldown_seconds": 3600,
"long_conditions": [{"left": "rsi", "operator": "<", "right": "30"}]
}
After a signal, wait at least 1 hour (3600 seconds) before allowing another.
📥 Inputs
Data
Connect OHLC data with indicators from upstream workers. Example data row:
{
"time": 1700000000,
"open": 100, "high": 105, "low": 99, "close": 104,
"rsi": 72, "sma_20": 101, "sma_50": 98
}
🔧 Condition Format
Each condition is an object with:
{
"left": "field or expression",
"operator": "comparison operator",
"right": "value, field, or expression"
}
Supported Operators
Numeric Operators
| Operator | Description | Example |
|---|---|---|
> | Greater than | rsi > 70 |
>= | Greater or equal | close >= sma_20 |
< | Less than | rsi < 30 |
<= | Less or equal | close <= sma_50 |
== | Equal | direction == 1 |
!= | Not equal | trend != 0 |
Crossing Operators
| Operator | Description | Example |
|---|---|---|
crosses_above | Crosses from below to above | rsi crosses_above 30 |
crosses_below | Crosses from above to below | rsi crosses_below 70 |
String/Text Operators
| Operator | Description | Example |
|---|---|---|
contains | Text contains substring (case-insensitive) | symbol contains "USD" |
not_contains | Text does not contain substring | news not_contains "bearish" |
starts_with | Text starts with prefix | ticker starts_with "BTC" |
ends_with | Text ends with suffix | pair ends_with "USDT" |
matches | Regex pattern match | description matches "bull.*pattern" |
is_empty | Field is empty or null | notes is_empty "" |
is_not_empty | Field has value | signal is_not_empty "" |
Value Types
| Type | Example | Description |
|---|---|---|
| Number | 70 | Static number |
| Field | sma_20 | Field from data |
| Field Math | high - low | Math between two fields |
| Expression | sma_20 + 2 | Field with number math |
| Previous | close[-1] | Previous bar's value |
| Previous Math | close[-1] - close | Compare previous to current |
| Text | "USD" | Literal text string |
| Percent Change | pct_change(close) | % change from previous bar |
| Percent Function | pct(close, open) | % difference: (a-b)/b×100 |
📈 Percentage Change Functions
pct_change(field)
Returns the percentage change of a field from the previous bar.
Formula: (current - previous) / previous × 100
Signal when price rises 3% or more from previous bar:
{"left": "pct_change(close)", "operator": ">=", "right": "3"}
Signal when price drops 5% or more:
{"left": "pct_change(close)", "operator": "<=", "right": "-5"}
Signal on any big move (up or down 2%+):
{"left": "abs_pct_change(close)", "operator": ">=", "right": "2"}
abs_pct_change(field)
Returns the absolute percentage change (always positive). Use when you care about the size of the move, not the direction.
Signal when volume changes by 50% or more (up or down):
{"left": "abs_pct_change(volume)", "operator": ">=", "right": "50"}
pct(a, b)
Returns percentage difference between any two values.
Formula: (a - b) / b × 100
Signal when close is 2% above open (within same bar):
{"left": "pct(close, open)", "operator": ">=", "right": "2"}
Signal when current high is 1% above previous high:
{"left": "pct(high, high[-1])", "operator": ">=", "right": "1"}
Signal when RSI increased by 10% from previous bar:
{"left": "pct(rsi, rsi[-1])", "operator": ">=", "right": "10"}
Complete Example: 3% Price Spike Entry
{
"long_conditions": [
{"left": "pct_change(close)", "operator": ">=", "right": "3"},
{"left": "volume", "operator": ">", "right": "volume[-1]"}
],
"long_logic": "AND",
"signal_mode": "first"
}
Long signal when price jumps 3%+ with increasing volume.
Complete Example: Volatility Breakout
{
"long_conditions": [
{"left": "abs_pct_change(close)", "operator": ">=", "right": "2"},
{"left": "close", "operator": ">", "right": "open"}
],
"long_logic": "AND",
"short_conditions": [
{"left": "abs_pct_change(close)", "operator": ">=", "right": "2"},
{"left": "close", "operator": "<", "right": "open"}
],
"short_logic": "AND"
}
Trade big moves (2%+) in direction of the candle.
🔢 Math Expressions
You can use math operators in both left and right values.
Supported Operators
| Operator | Example | Description |
|---|---|---|
+ | close + 10 | Addition |
- | high - low | Subtraction |
* | atr * 2 | Multiplication |
/ | close / 100 | Division |
Multiply Field by Number
{"left": "volume", "operator": ">", "right": "avg_volume * 2"}
Signal when volume is greater than 2× average volume.
Multiply Two Fields
{"left": "close * volume", "operator": ">", "right": "1000000"}
Signal when price × volume exceeds 1 million (dollar volume).
ATR-Based Threshold
{"left": "close", "operator": ">", "right": "close[-1] + atr * 2"}
Signal when price breaks 2×ATR above previous close.
Percentage of Price (Division)
{"left": "high - low", "operator": ">", "right": "close / 100"}
Signal when candle range is more than 1% of price.
Previous Bar with Multiplier
{"left": "close", "operator": ">", "right": "close[-1] * 1.03"}
Signal when close is 3% above previous close.
Volume Spike Detection
{
"long_conditions": [
{"left": "volume", "operator": ">", "right": "volume[-1] * 3"},
{"left": "close", "operator": ">", "right": "open"}
],
"long_logic": "AND"
}
Signal on 3× volume spike with bullish candle.
Bollinger Band Width
{"left": "bb_upper - bb_lower", "operator": ">", "right": "close * 0.04"}
Signal when Bollinger Band width exceeds 4% of price.
📝 String/Text Condition Examples
Filter by Symbol
{"left": "symbol", "operator": "contains", "right": "BTC"}
Signal only when symbol contains "BTC".
Exclude Specific Pairs
{"left": "pair", "operator": "not_contains", "right": "JPY"}
Signal when pair does NOT contain "JPY".
Signal Type Filter
{"left": "signal_type", "operator": "==", "right": "buy"}
Signal when signal_type equals "buy".
Pattern in News/Description
{"left": "headline", "operator": "matches", "right": "bull|bullish|surge"}
Signal when headline matches any of the patterns (regex).
Non-Empty Confirmation
{"left": "confirmation_signal", "operator": "is_not_empty", "right": ""}
Signal only when confirmation_signal field has a value.
📊 Multi-Column Expressions
Candle Size (Pips/Points)
{"left": "high - low", "operator": ">", "right": "0.0020"}
Signal when candle is larger than 20 pips.
Up Candle (Bullish)
{"left": "close - open", "operator": ">", "right": "0"}
Signal when candle closes higher than it opened.
Down Candle (Bearish)
{"left": "close - open", "operator": "<", "right": "0"}
Signal when candle closes lower than it opened.
Gap Up
{"left": "open", "operator": ">", "right": "high[-1]"}
Signal when current open is above previous high.
Higher High
{"left": "high", "operator": ">", "right": "high[-1]"}
Signal when current high exceeds previous high.
Current Up + Previous Down (Reversal Pattern)
Use nested AND group:
{
"long_conditions": [
{
"logic": "AND",
"conditions": [
{"left": "close - open", "operator": ">", "right": "0"},
{"left": "close[-1] - open[-1]", "operator": "<", "right": "0"}
]
}
]
}
Signal when current candle is up AND previous was down.
Candle Body vs Wick Ratio
{"left": "close - open", "operator": ">", "right": "high - low * 0.6"}
Note: For complex expressions, consider pre-calculating in upstream worker.
🔀 AND/OR Logic
Simple AND (all conditions must be true)
{
"long_conditions": [
{"left": "rsi", "operator": "<", "right": "30"},
{"left": "close", "operator": ">", "right": "sma_200"}
],
"long_logic": "AND"
}
Result: Long signal when rsi < 30 AND close > sma_200
Simple OR (any condition can be true)
{
"long_conditions": [
{"left": "rsi", "operator": "<", "right": "30"},
{"left": "close", "operator": "<=", "right": "bb_lower"}
],
"long_logic": "OR"
}
Result: Long signal when rsi < 30 OR close <= bb_lower
Nested Groups (complex logic)
For (A AND B) OR (C AND D):
{
"long_conditions": [
{
"logic": "AND",
"conditions": [
{"left": "rsi", "operator": "<", "right": "30"},
{"left": "macd", "operator": ">", "right": "0"}
]
},
{
"logic": "AND",
"conditions": [
{"left": "close", "operator": ">", "right": "sma_50"},
{"left": "volume", "operator": ">", "right": "avg_volume"}
]
}
],
"long_logic": "OR"
}
Result: (rsi < 30 AND macd > 0) OR (close > sma_50 AND volume > avg_volume)
🚪 Close Signal Modes
The close_mode parameter controls when close signals are generated:
| Mode | Description |
|---|---|
reverse | (Default) Close when opposite entry signal occurs |
conditions | Close only when explicit close conditions are met |
both | Close on reverse signal OR when close conditions are met |
none | Never generate close signals (rely on backtest SL/TP/time exits) |
Examples
Mode: reverse (default)
- Long signal triggers → enters long
- Short signal triggers → closes long, enters short
- No explicit close signal needed
Mode: conditions
- Long signal triggers → enters long
- Short signal triggers → enters short (no close of long!)
- Only closes when
close_long_conditionsare met
Mode: both
- Closes on reverse signal OR when conditions are met
- Most flexible option
Mode: none
- Never generates close signals
- Useful when you want backtest_strategy to handle all exits via:
- Stop loss / Take profit
- Trailing stop
- Time-based exits (max_hold_duration, close_at_time)
📝 Strategy Examples
RSI Mean Reversion
{
"long_conditions": [
{"left": "rsi", "operator": "crosses_above", "right": "30"}
],
"short_conditions": [
{"left": "rsi", "operator": "crosses_below", "right": "70"}
],
"close_mode": "reverse"
}
Moving Average Crossover with Exit Conditions
{
"long_conditions": [
{"left": "sma_20", "operator": "crosses_above", "right": "sma_50"}
],
"close_long_conditions": [
{"left": "sma_20", "operator": "crosses_below", "right": "sma_50"}
],
"short_conditions": [
{"left": "sma_20", "operator": "crosses_below", "right": "sma_50"}
],
"close_short_conditions": [
{"left": "sma_20", "operator": "crosses_above", "right": "sma_50"}
],
"close_mode": "conditions"
}
Breakout with Volume Confirmation
{
"long_conditions": [
{"left": "close", "operator": ">", "right": "high[-1]"},
{"left": "volume", "operator": ">", "right": "avg_volume * 1.5"}
],
"long_logic": "AND",
"close_mode": "none"
}
Uses backtest SL/TP for exits.
Complex Multi-Condition Entry
{
"long_conditions": [
{
"logic": "AND",
"conditions": [
{"left": "rsi", "operator": "<", "right": "40"},
{"left": "macd_histogram", "operator": ">", "right": "0"}
]
},
{
"logic": "AND",
"conditions": [
{"left": "close", "operator": ">", "right": "sma_200"},
{"left": "adx", "operator": ">", "right": "25"}
]
}
],
"long_logic": "OR"
}
Enters long when: (RSI < 40 AND MACD > 0) OR (Price > SMA200 AND ADX > 25)
Candle Size Filter (20+ Pips)
{
"long_conditions": [
{"left": "high - low", "operator": ">", "right": "0.0020"},
{"left": "close - open", "operator": ">", "right": "0"}
],
"long_logic": "AND"
}
Long signal when candle is bullish AND larger than 20 pips.
Bullish Reversal (Up After Down)
{
"long_conditions": [
{
"logic": "AND",
"conditions": [
{"left": "close - open", "operator": ">", "right": "0"},
{"left": "close[-1] - open[-1]", "operator": "<", "right": "0"}
]
}
]
}
Long signal when current candle is UP and previous candle was DOWN.
Bearish Reversal (Down After Up)
{
"short_conditions": [
{
"logic": "AND",
"conditions": [
{"left": "close - open", "operator": "<", "right": "0"},
{"left": "close[-1] - open[-1]", "operator": ">", "right": "0"}
]
}
]
}
Short signal when current candle is DOWN and previous candle was UP.
Higher High Breakout
{
"long_conditions": [
{"left": "high", "operator": ">", "right": "high[-1]"},
{"left": "close", "operator": ">", "right": "open"}
],
"long_logic": "AND"
}
Long when making higher high with bullish close.
Gap Up Entry
{
"long_conditions": [
{"left": "open", "operator": ">", "right": "high[-1]"}
]
}
Long signal when price gaps up above previous high.
Two Consecutive Up Candles
{
"long_conditions": [
{"left": "close - open", "operator": ">", "right": "0"},
{"left": "close[-1] - open[-1]", "operator": ">", "right": "0"}
],
"long_logic": "AND"
}
Long signal when both current and previous candle are bullish.
🔗 Connection to Backtest
[Data Source] → [Indicators] → [Signal Generator] → [Backtest Strategy]
↓
{signals: [...]}
In backtest worker, set:
signals: {{workers[X].signals}}
📤 Output
signals
Array of signal objects:
[
{"time": 1700000000, "action": "long"},
{"time": 1700003600, "action": "close"},
{"time": 1700007200, "action": "short"}
]
summary
Statistics about generated signals:
{
"total_signals": 150,
"long_signals": 50,
"short_signals": 50,
"close_signals": 50,
"data_rows": 1000
}
🔧 Complete Parameters Reference
📥 Input Data
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
data | array | ✅ Yes | - | OHLC/indicator data from upstream worker. Use {{workers[0].results}} |
time_field | string | No | datetime | Timestamp field name. Dropdown shows available fields |
📈 Entry Conditions (Long)
| Parameter | Type | Default | Description |
|---|---|---|---|
long_conditions | array | [] | Conditions to open long position |
long_logic | string | AND | How to combine: AND (all must be true) or OR (any can be true) |
📉 Entry Conditions (Short)
| Parameter | Type | Default | Description |
|---|---|---|---|
short_conditions | array | [] | Conditions to open short position |
short_logic | string | AND | How to combine: AND or OR |
🚪 Exit Conditions
| Parameter | Type | Default | Description |
|---|---|---|---|
close_mode | string | reverse | When to close positions (see modes below) |
close_long_conditions | array | [] | Conditions to close long (when close_mode is conditions or both) |
close_short_conditions | array | [] | Conditions to close short (when close_mode is conditions or both) |
close_long_logic | string | AND | Logic for close long conditions |
close_short_logic | string | AND | Logic for close short conditions |
Close Mode Options
| Mode | Description | Use Case |
|---|---|---|
reverse | (Default) Close when opposite signal occurs | Most common, simple strategies |
conditions | Close ONLY when explicit close conditions met | Separate entry/exit logic |
both | Close on reverse OR when conditions met | Maximum flexibility |
none | Never generate close signals | Use backtest SL/TP/trailing |
🎯 Signal Filtering
| Parameter | Type | Default | Description |
|---|---|---|---|
signal_mode | string | first | How to handle repeated signals |
cooldown_bars | number | 0 | Min bars between signals (cooldown mode only) |
cooldown_seconds | number | 0 | Min seconds between signals (cooldown mode only) |
allow_pyramiding | boolean | false | Allow multiple entries in same direction |
Signal Mode Options
| Mode | Description | Use Case |
|---|---|---|
first | (Default) Only signal when condition BECOMES true | Prevents duplicates, most common |
every | Signal every bar condition is true | Testing, accumulation strategies |
cooldown | Require minimum gap between signals | Fine-tuned frequency control |
📖 Real-World Strategy Examples
1️⃣ RSI Oversold/Overbought
Buy when RSI crosses above 30, sell when crosses below 70:
{
"long_conditions": [
{"left": "rsi", "operator": "crosses_above", "right": "30"}
],
"short_conditions": [
{"left": "rsi", "operator": "crosses_below", "right": "70"}
],
"close_mode": "reverse"
}
2️⃣ Moving Average Crossover
Classic golden/death cross strategy:
{
"long_conditions": [
{"left": "sma_20", "operator": "crosses_above", "right": "sma_50"}
],
"short_conditions": [
{"left": "sma_20", "operator": "crosses_below", "right": "sma_50"}
],
"close_mode": "reverse"
}
3️⃣ Breakout with Volume Confirmation
Enter on breakout with high volume, let backtest handle exits:
{
"long_conditions": [
{"left": "close", "operator": ">", "right": "high[-1]"},
{"left": "volume", "operator": ">", "right": "volume_sma_20"}
],
"long_logic": "AND",
"close_mode": "none"
}
4️⃣ Multi-Timeframe Trend Following
Long when price above both 20 and 200 SMA:
{
"long_conditions": [
{"left": "close", "operator": ">", "right": "sma_20"},
{"left": "close", "operator": ">", "right": "sma_200"}
],
"long_logic": "AND",
"short_conditions": [
{"left": "close", "operator": "<", "right": "sma_20"},
{"left": "close", "operator": "<", "right": "sma_200"}
],
"short_logic": "AND"
}
5️⃣ Bollinger Band Mean Reversion
Enter at bands, exit at middle:
{
"long_conditions": [
{"left": "close", "operator": "<=", "right": "bb_lower"}
],
"close_long_conditions": [
{"left": "close", "operator": ">=", "right": "bb_middle"}
],
"short_conditions": [
{"left": "close", "operator": ">=", "right": "bb_upper"}
],
"close_short_conditions": [
{"left": "close", "operator": "<=", "right": "bb_middle"}
],
"close_mode": "conditions"
}
6️⃣ Complex Multi-Condition (Nested AND/OR)
Long when: (RSI < 40 AND MACD > 0) OR (Price > SMA200 AND ADX > 25)
{
"long_conditions": [
{
"logic": "AND",
"conditions": [
{"left": "rsi", "operator": "<", "right": "40"},
{"left": "macd", "operator": ">", "right": "0"}
]
},
{
"logic": "AND",
"conditions": [
{"left": "close", "operator": ">", "right": "sma_200"},
{"left": "adx", "operator": ">", "right": "25"}
]
}
],
"long_logic": "OR"
}
7️⃣ Candle Pattern - Bullish Engulfing
Current up candle larger than previous down candle:
{
"long_conditions": [
{
"logic": "AND",
"conditions": [
{"left": "close - open", "operator": ">", "right": "0"},
{"left": "close[-1] - open[-1]", "operator": "<", "right": "0"},
{"left": "close - open", "operator": ">", "right": "open[-1] - close[-1]"}
]
}
]
}
8️⃣ Gap Trading
Enter on gap up, exit on gap down:
{
"long_conditions": [
{"left": "open", "operator": ">", "right": "high[-1]"}
],
"close_long_conditions": [
{"left": "open", "operator": "<", "right": "low[-1]"}
],
"close_mode": "conditions"
}
9️⃣ Minimum Candle Size (Pips Filter)
Only trade candles larger than 20 pips:
{
"long_conditions": [
{"left": "high - low", "operator": ">", "right": "0.0020"},
{"left": "close - open", "operator": ">", "right": "0"}
],
"long_logic": "AND",
"short_conditions": [
{"left": "high - low", "operator": ">", "right": "0.0020"},
{"left": "close - open", "operator": "<", "right": "0"}
],
"short_logic": "AND"
}
🔟 Symbol/Text Filter
Only trade BTC pairs with bullish signal:
{
"long_conditions": [
{"left": "symbol", "operator": "contains", "right": "BTC"},
{"left": "signal_type", "operator": "==", "right": "bullish"}
],
"long_logic": "AND"
}
1️⃣1️⃣ News Headline Filter
Trade on specific news patterns:
{
"long_conditions": [
{"left": "headline", "operator": "matches", "right": "surge|rally|bullish"},
{"left": "sentiment", "operator": ">", "right": "0.5"}
],
"long_logic": "AND",
"short_conditions": [
{"left": "headline", "operator": "matches", "right": "crash|plunge|bearish"},
{"left": "sentiment", "operator": "<", "right": "-0.5"}
],
"short_logic": "AND"
}
1️⃣2️⃣ Cooldown - Max 1 Signal per Hour
Limit signal frequency:
{
"signal_mode": "cooldown",
"cooldown_seconds": 3600,
"long_conditions": [
{"left": "rsi", "operator": "<", "right": "30"}
]
}
1️⃣3️⃣ Cooldown - Max 1 Signal per 10 Bars
{
"signal_mode": "cooldown",
"cooldown_bars": 10,
"long_conditions": [
{"left": "close", "operator": ">", "right": "sma_20"}
]
}
1️⃣4️⃣ Higher Highs and Higher Lows
Trend continuation:
{
"long_conditions": [
{"left": "high", "operator": ">", "right": "high[-1]"},
{"left": "low", "operator": ">", "right": "low[-1]"}
],
"long_logic": "AND",
"short_conditions": [
{"left": "high", "operator": "<", "right": "high[-1]"},
{"left": "low", "operator": "<", "right": "low[-1]"}
],
"short_logic": "AND"
}
1️⃣5️⃣ Pyramiding - Multiple Entries
Allow adding to winning positions:
{
"allow_pyramiding": true,
"signal_mode": "cooldown",
"cooldown_bars": 5,
"long_conditions": [
{"left": "close", "operator": ">", "right": "sma_20"}
]
}
💡 Tips & Best Practices
1. Use signal_mode: first (Default)
Prevents duplicate signals when conditions stay true for multiple bars.
2. Pre-calculate Complex Indicators
For complex expressions, calculate them in an upstream worker:
- Bad:
{"left": "(close - sma_20) / atr", "operator": ">", "right": "2"} - Good: Calculate
zscorein indicator worker, then{"left": "zscore", "operator": ">", "right": "2"}
3. Start Simple
Begin with one or two conditions, test, then add complexity.
4. Check Output
Use the summary output to verify signal counts make sense.
5. Use close_mode: none with Backtest
When using backtest_strategy with SL/TP, set close_mode: none to avoid conflicting exit signals.
6. crosses_above vs >
>signals every bar where condition is truecrosses_abovesignals only on the bar where it BECOMES true
❓ Troubleshooting
No signals generated?
- Check
time_fieldmatches your data (datetime, time, date, timestamp) - Verify condition field names exist in your data
- Check operator is appropriate for data type
- Try
signal_mode: everytemporarily to see if conditions ever match
Too many signals?
- Use
signal_mode: first(default) orcooldown - Add more restrictive conditions
- Use
crosses_above/crosses_belowinstead of>/>=/<</<=
Signals not closing?
- Check
close_modeis set correctly - If using
conditions, verify close conditions are defined - Try
close_mode: bothfor maximum flexibility