# Rulyfi Strategy Definition Format

This is the public reference for the strategy definition format used by Rulyfi's
no-code strategy builder, scanner, and backtester. A strategy is a single JSON
object that describes which indicators to compute, the entry and exit conditions,
and the execution parameters (fees, slippage, leverage, position size). The same
object shape is used everywhere in the product, so a strategy written by hand is
identical to one produced by the visual builder.

This document covers the object shape only. The backtest period (start and end
timestamps) and the choice of what to run are supplied separately at run time and
are not part of the strategy object.

> When this strategy is run through the public API's single-backtest endpoint
> (`POST /v1/backtests`), only spot markets are supported. Futures are available
> through the scanner and the visual builder.

---

## 1. Top-level object

```json
{
  "symbol": "BTCUSDT",
  "exchange": "binance",
  "timeframe": "1h",
  "direction": "long",
  "indicators": [ ... ],
  "entry_rules": { "logic": "AND", "conditions": [ ... ] },
  "exit_rules":  { "take_profit": 3, "stop_loss": 1.5, "ttl_bars": 48, "logic": "AND", "conditions": [ ... ] },
  "position":    { "leverage": 1, "size_pct": 100 },
  "costs":       { "commission_maker_pct": 0.02, "commission_taker_pct": 0.04, "slippage_pct": 0.01, "order_type": "market" }
}
```

| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
| `symbol` | string | — | 1–32 chars | Trading pair, e.g. `"BTCUSDT"`. |
| `exchange` | string (enum) | `"binance"` | see §2 | Market-data source. |
| `timeframe` | string (enum) | — | see §2 | Candle interval. |
| `direction` | string (enum) | — | `"long"` \| `"short"` | Position side the strategy takes. |
| `indicators` | array | — | max 20 items | Indicator instances (§4). |
| `entry_rules` | object | — | — | Entry logic and conditions (§5). |
| `exit_rules` | object | — | — | Exit targets and conditions (§6). |
| `position` | object | — | — | Leverage and position size (§7). |
| `costs` | object | — | — | Fees, slippage, order type (§7). |

---

## 2. Enumerations

**`direction`**: `long`, `short`.

**`timeframe`**: `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d`, `1w`.

**`exchange`** (26 supported):
`binance`, `bybit`, `okx`, `bitget`, `gate`, `kucoin`, `coinbase`, `kraken`,
`mexc`, `htx`, `bingx`, `cryptocom`, `bitstamp`, `bitfinex`, `gemini`,
`binanceus`, `whitebit`, `lbank`, `phemex`, `bitvavo`, `poloniex`, `bitkub`,
`backpack`, `hashkey`, `hyperliquid`, `dydx`.

---

## 3. Unit convention — percent notation

Every field that ends in `_pct`, plus `take_profit` and `stop_loss`, is expressed
in **percent notation**: the number *is* the percent value.

- `commission_taker_pct: 0.04` means **0.04%** (four basis points), not 4%.
- `slippage_pct: 0.01` means **0.01%** per side.
- `take_profit: 3` means close the position at **+3%**.
- `stop_loss: 1.5` means close the position at **−1.5%** (magnitude; always a positive number).

There is no separate decimal form in this format. A value of `1` in a `_pct`
field is one percent, and `100` is one hundred percent.

---

## 4. `indicators[]`

Each entry declares one indicator instance.

```json
{ "id": "rsi1", "type": "RSI", "params": { "period": 14 } }
```

| Field | Type | Constraints | Description |
|---|---|---|---|
| `id` | string | 1–64 chars, unique within the strategy | Handle used to reference this indicator's output in conditions (see §8). Any stable name works, e.g. `rsi1`, `sma_fast`, `ind0`. |
| `type` | string (enum) | one of the 103 catalog types (§9) | Selects the indicator. |
| `params` | object | keys per indicator | Parameter overrides. Any key you omit falls back to that indicator's default (see the catalog). Parameter keys are the `key` values in §9. |

Indicators with no parameters (for example `OBV`, `VWAP`, candlestick patterns)
take `params: {}` or may omit the key.

---

## 5. `entry_rules`

```json
{ "logic": "AND", "conditions": [ { "left": "rsi1.value", "op": "<", "right": 30 } ] }
```

| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
| `logic` | string (enum) | `"AND"` | `"AND"` \| `"OR"` | How the conditions combine. `AND` fires when every condition is true on the same bar; `OR` fires when any is true. |
| `conditions` | array | `[]` | max 10 items | Entry conditions (§8). |

---

## 6. `exit_rules`

A position closes on whichever exit is reached first: take-profit, stop-loss,
time limit, or a matching exit condition.

```json
{ "take_profit": 3, "stop_loss": 1.5, "ttl_bars": 48, "logic": "AND", "conditions": [], "conservative_fill": false }
```

| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
| `take_profit` | number \| null | `null` | > 0, ≤ 100 (percent) | Close at this percent gain. `null` disables. |
| `stop_loss` | number \| null | `null` | > 0, ≤ 100 (percent) | Close at this percent loss (magnitude). `null` disables. |
| `ttl_bars` | integer \| null | `null` | > 0, ≤ 10000 | Maximum bars to hold one trade; closes when exceeded even if TP/SL were not hit. `null` disables. |
| `logic` | string (enum) | `"AND"` | `"AND"` \| `"OR"` | How the exit `conditions` combine. |
| `conditions` | array | `[]` | max 10 items | Condition-based exits (§8). Empty means exits are driven only by TP/SL/TTL. |
| `auto_enabled` | boolean | `true` | — | Master switch for the automatic exits. When `false`, `take_profit`, `stop_loss`, and `ttl_bars` are all ignored. Omitting the field means `true`. |
| `cond_enabled` | boolean | `true` | — | Master switch for condition-based exits. When `false`, the exit `conditions` are ignored. Treated as `false` whenever `conditions` is empty; omitting the field means `true`. |
| `conservative_fill` | boolean | `false` | — | Resolves the tie when TP and SL are both reachable within the same bar. `false` = assume TP filled first (optimistic); `true` = assume SL filled first (pessimistic). |

At least one exit must be effective (a TP, SL, TTL, or exit condition), otherwise
positions never close.

---

## 7. `position` and `costs`

**`position`**

| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
| `leverage` | number | `1` | > 0, ≤ 125 | Leverage multiplier. |
| `size_pct` | number | `100` | 0.1–100 | Position size as a percent of capital. |
| `max_concurrent` | integer | `1` | ≥ 1 | Maximum number of positions open at the same time when the strategy is run across several symbols as a portfolio. For a single-symbol strategy this is `1`. |

**`costs`**

| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
| `commission_maker_pct` | number | `0.02` | 0–100 (percent) | Maker fee, applied to both sides when `order_type` is `limit`. |
| `commission_taker_pct` | number | `0.04` | 0–100 (percent) | Taker fee, applied to both sides when `order_type` is `market`. |
| `slippage_pct` | number | `0.01` | 0–100 (percent) | Slippage applied per side. |
| `order_type` | string (enum) | `"market"` | `"market"` \| `"limit"` | Fill model. `market` uses the taker fee; `limit` uses the maker fee. |

---

## 8. Condition grammar

A condition compares two operands with an operator:

```json
{ "left": <operand>, "op": <operator>, "right": <operand> }
```

### Operators (`op`)

| `op` | Meaning |
|---|---|
| `>` | left greater than right |
| `>=` | left greater than or equal to right |
| `<` | left less than right |
| `<=` | left less than or equal to right |
| `==` | left equal to right |
| `!=` | left not equal to right |
| `crossover` | left crosses **above** right: on the previous bar `left ≤ right`, and on the current bar `left > right` |
| `crossunder` | left crosses **below** right: on the previous bar `left ≥ right`, and on the current bar `left < right` |

### Operands (`left`, `right`)

Each operand is one of:

- **Number** — a literal constant, e.g. `30`, `0`, `-100`. (A numeric string such as `"30"` is also accepted and coerced to a number.)
- **Price field** — one of `open`, `high`, `low`, `close`, `volume`.
- **Indicator output** — the dotted string `"<indicatorId>.<output>"`, where `<indicatorId>` matches an `id` in the `indicators` array and `<output>` is one of that indicator's outputs. Every indicator exposes `value` as its primary line, so `"rsi1.value"` is the RSI line of the indicator whose id is `rsi1`. Multi-output indicators additionally expose the named series listed in the **Outputs** column of §9 — for example `"macd1.macd"`, `"macd1.signal"`, `"macd1.histogram"`, or `"bb1.upper"` and `"bb1.lower"`.

### Evaluation semantics

- A condition group is evaluated bar by bar. Entry conditions that fire on a bar open the position on the **following** bar.
- During an indicator's warm-up period its value is `NaN`; any comparison against `NaN` is false, so no signal fires until the indicator is ready.
- `crossover` and `crossunder` require a previous bar and therefore never fire on the first bar of the series.

---

## 9. Indicator catalog

103 indicators, grouped by category. The **Type** column is the value for
`indicators[].type`. The **Params** column lists each parameter's `key = default`
(and step where the builder uses a fractional step). The **Outputs** column lists
the component series that can be referenced as `<id>.<output>` in a condition;
every indicator also answers to `<id>.value` for its primary line.

<!-- BEGIN INDICATOR TABLES (generated from src/data/indicators.js + en/indicators.json) -->
### Trend

| Type | Name | Params (key = default) | Outputs | Description |
|---|---|---|---|---|
| `SMA` | Simple Moving Average | `period` = 20 | `value` | Calculates the average closing price over N periods. Smooths out price noise to show the underlying trend. |
| `EMA` | Exponential Moving Average | `period` = 20 | `value` | A moving average that gives more weight to recent prices, making it faster to react to price changes than SMA. |
| `WMA` | Weighted Moving Average | `period` = 20 | `value` | A moving average where recent prices carry more weight in a linear fashion. Reacts faster than SMA but differently from EMA. |
| `DEMA` | Double Exponential Moving Average | `period` = 20 | `value` | Reduces the lag of a standard EMA by applying exponential smoothing twice. Tracks price more closely than EMA. |
| `TEMA` | Triple Exponential Moving Average | `period` = 20 | `value` | Applies triple exponential smoothing to minimize lag even further than DEMA. Extremely responsive to price changes. |
| `HMA` | Hull Moving Average | `period` = 9 | `value` | A moving average designed to eliminate lag almost entirely while remaining smooth. Combines weighted moving averages of different lengths. |
| `KAMA` | Kaufman Adaptive Moving Average | `period` = 10<br>`fast` = 2<br>`slow` = 30 | `value` | Automatically adjusts its speed based on market noise. Moves fast in trends and slow in choppy markets. |
| `VWMA` | Volume Weighted Moving Average | `period` = 20 | `value` | A moving average that weighs prices by their trading volume. Gives more importance to price levels where heavy trading occurred. |
| `ALMA` | Arnaud Legoux Moving Average | `period` = 9<br>`offset` = 0.85 (step 0.05)<br>`sigma` = 6 | `value` | A Gaussian-weighted moving average that provides very smooth curves with minimal lag. Uses an offset and sigma parameter for fine-tuning. |
| `T3` | T3 Moving Average | `period` = 5<br>`v_factor` = 0.7 (step 0.1) | `value` | A very smooth moving average that uses multiple layers of exponential smoothing. Produces extremely clean trend signals with minimal noise. |
| `ZLEMA` | Zero-Lag Exponential Moving Average | `period` = 20 | `value` | An EMA variant that attempts to remove inherent lag by adjusting the input data. Tracks price very closely. |
| `FRAMA` | Fractal Adaptive Moving Average | `period` = 16 | `value` | Uses fractal geometry to determine how fast the moving average should adapt. Becomes responsive in trends and sluggish in consolidation. |
| `MCGINLEY_DYNAMIC` | McGinley Dynamic | `period` = 14 | `value` | A self-adjusting moving average that automatically speeds up or slows down based on market speed. Designed to avoid whipsaws. |
| `ATR` | Average True Range | `period` = 14 | `value` | Measures market volatility by calculating the average range of price movement over N periods. Higher ATR means higher volatility. |
| `SUPERTREND` | Supertrend | `period` = 10<br>`multiplier` = 3 (step 0.1) | `value`, `direction` | A trend-following indicator that plots a line above or below price based on ATR. Green means uptrend, red means downtrend. |
| `PARABOLIC_SAR` | Parabolic SAR | `af_start` = 0.02 (step 0.01)<br>`af_step` = 0.02 (step 0.01)<br>`af_max` = 0.2 (step 0.01) | `value`, `direction` | Places dots above or below price to indicate trend direction and potential reversal points. SAR stands for 'Stop and Reverse'. |
| `ICHIMOKU` | Ichimoku Cloud | `tenkan` = 9<br>`kijun` = 26<br>`senkou_b` = 52 | `tenkan`, `kijun`, `senkou_a`, `senkou_b`, `chikou` | A comprehensive indicator that shows support, resistance, trend direction, and momentum all at once using five lines and a colored cloud. |
| `AROON` | Aroon | `period` = 25 | `up`, `down`, `oscillator` | Measures how long it has been since the highest high and lowest low over N periods. Identifies whether a trend is forming or fading. |
| `ADX` | Average Directional Index | `period` = 14 | `adx`, `plus_di`, `minus_di` | Measures trend strength on a scale of 0 to 100, regardless of direction. Does not tell you if the trend is up or down, only how strong it is. |
| `VORTEX_INDICATOR` | Vortex Indicator | `period` = 14 | `plus_vi`, `minus_vi` | Identifies trend direction and trend reversals using two oscillating lines (VI+ and VI-). Based on the concept of positive and negative trend movement. |
| `LINEAR_REGRESSION` | Linear Regression | `period` = 14 | `slope`, `intercept`, `r2` | Draws a best-fit straight line through price data over N periods. Shows the statistical trend direction and expected price path. |

### Momentum

| Type | Name | Params (key = default) | Outputs | Description |
|---|---|---|---|---|
| `RSI` | Relative Strength Index | `period` = 14 | `value` | Measures the speed and magnitude of recent price changes on a 0-100 scale. Shows whether an asset is overbought or oversold. |
| `STOCHASTIC_RSI` | Stochastic RSI | `rsi_period` = 14<br>`stoch_period` = 14<br>`k_smooth` = 3<br>`d_smooth` = 3 | `k`, `d` | Applies the Stochastic formula to RSI values instead of price. More sensitive than regular RSI, providing earlier overbought/oversold signals. |
| `MACD` | MACD | `fast` = 12<br>`slow` = 26<br>`signal_period` = 9 | `macd`, `signal`, `histogram` | Shows the relationship between two EMAs (12 and 26). The MACD line, signal line, and histogram together reveal trend direction, momentum, and potential reversals. |
| `STOCHASTIC` | Stochastic Oscillator | `k_period` = 14<br>`d_period` = 3 | `k`, `d` | Compares the current closing price to the price range over N periods. Shows where the close sits relative to the recent high-low range. |
| `CCI` | Commodity Channel Index | `period` = 20 | `value` | Measures how far the current price deviates from its statistical average. Identifies cyclical price patterns and extreme conditions. |
| `WILLIAMS_R` | Williams %R | `period` = 14 | `value` | Shows where the current close is relative to the highest high over N periods. Ranges from -100 to 0, with readings near 0 being overbought. |
| `ROC` | Rate of Change | `period` = 12 | `value` | Measures the percentage change in price over N periods. A simple momentum indicator that shows how fast price is moving. |
| `MOMENTUM` | Momentum | `period` = 10 | `value` | The simplest momentum indicator: calculates the raw price difference between now and N periods ago. Positive means upward movement, negative means downward. |
| `CMO` | Chande Momentum Oscillator | `period` = 14 | `value` | Measures momentum on a scale of -100 to +100 by comparing the sum of up-day gains to down-day losses. Unsmoothed, making it very responsive. |
| `TSI` | True Strength Index | `long_period` = 25<br>`short_period` = 13<br>`signal_period` = 7 | `value`, `signal` | A double-smoothed momentum oscillator that ranges between -100 and +100. Filters out noise while showing trend direction and overbought/oversold conditions. |
| `ULTIMATE_OSCILLATOR` | Ultimate Oscillator | `p1` = 7<br>`p2` = 14<br>`p3` = 28 | `value` | Combines momentum across three different timeframes (7, 14, 28 periods) into a single oscillator. Reduces false signals by using multiple timeframes. |
| `AWESOME_OSCILLATOR` | Awesome Oscillator | `fast` = 5<br>`slow` = 34 | `value` | Shows market momentum by comparing a 5-period SMA to a 34-period SMA of the midpoint price. Displayed as a histogram that changes color. |
| `ACCELERATOR_OSCILLATOR` | Accelerator Oscillator | `fast` = 5<br>`slow` = 34<br>`smooth` = 5 | `value` | Measures the acceleration or deceleration of the current market momentum. Derived from the Awesome Oscillator minus its own SMA. |
| `PPO` | Percentage Price Oscillator | `fast` = 12<br>`slow` = 26<br>`signal_period` = 9 | `ppo`, `signal`, `histogram` | Shows the percentage difference between two EMAs. Similar to MACD but expressed as a percentage, making it easier to compare across different assets. |
| `PVO` | Percentage Volume Oscillator | `fast` = 12<br>`slow` = 26<br>`signal_period` = 9 | `pvo`, `signal`, `histogram` | Shows the percentage difference between two volume EMAs. Indicates whether volume is trending above or below its average. |
| `FISHER_TRANSFORM` | Fisher Transform | `period` = 9 | `value`, `signal` | Converts price data into a Gaussian normal distribution, making turning points sharper and easier to spot. Creates clear peak/trough signals. |
| `CONNORS_RSI` | Connors RSI | `rsi_period` = 3<br>`streak_period` = 2<br>`pct_rank_period` = 100 | `value` | Combines three components (standard RSI, streak RSI, and percentile rank) into a single oscillator. Designed to find short-term overbought/oversold extremes. |
| `RVI` | Relative Vigor Index | `period` = 10 | `value`, `signal` | Compares the closing price relative to the trading range, normalized by a moving average. Assumes prices close higher in uptrends and lower in downtrends. |
| `SQUEEZE_MOMENTUM` | Squeeze Momentum | `bb_period` = 20<br>`bb_mult` = 2 (step 0.1)<br>`kc_period` = 20<br>`kc_mult` = 1.5 (step 0.1) | `value`, `squeeze_on` | Detects when Bollinger Bands squeeze inside Keltner Channels, indicating low volatility that often precedes a big move. Combines volatility and momentum. |
| `TRIX` | TRIX | `period` = 15<br>`signal_period` = 9 | `value`, `signal` | A triple-smoothed EMA displayed as a rate of change. Filters out minor price movements to show only significant trend changes. |
| `DPO` | Detrended Price Oscillator | `period` = 20 | `value` | Removes the trend from price to show only the cyclical component. Helps identify overbought/oversold levels within cycles. |
| `KST` | Know Sure Thing | — | `value`, `signal` | Combines four smoothed rate-of-change values at different timeframes into one oscillator. Provides a comprehensive view of momentum across multiple cycles. |
| `COPPOCK_CURVE` | Coppock Curve | `wma_period` = 10<br>`long_roc` = 14<br>`short_roc` = 11 | `value` | Originally designed to identify long-term buying opportunities in stock markets. Combines two rates of change with weighted smoothing. |

### Volatility

| Type | Name | Params (key = default) | Outputs | Description |
|---|---|---|---|---|
| `TRUE_RANGE` | True Range | — | `value` | Measures the full range of price movement for each period, including any gap from the previous close. The building block for ATR. |
| `NATR` | Normalized ATR | `period` = 14 | `value` | ATR expressed as a percentage of the closing price. Allows you to compare volatility across assets with different price levels. |
| `BOLLINGER_BANDS` | Bollinger Bands | `period` = 20<br>`std_dev` = 2 (step 0.1) | `upper`, `middle`, `lower`, `pct_b`, `bandwidth` | Three bands: a middle SMA with upper and lower bands at 2 standard deviations away. Dynamically adjusts to volatility, widening in volatile markets and narrowing in calm ones. |
| `KELTNER_CHANNEL` | Keltner Channel | `period` = 20<br>`multiplier` = 2 (step 0.1) | `upper`, `middle`, `lower` | An envelope indicator using EMA as the center line and ATR for the channel width. Smoother than Bollinger Bands because it uses ATR instead of standard deviation. |
| `DONCHIAN_CHANNEL` | Donchian Channel | `period` = 20 | `upper`, `middle`, `lower` | Plots the highest high and lowest low over N periods, creating a price channel. One of the oldest and simplest breakout indicators. |
| `STD_DEV` | Standard Deviation | `period` = 20 | `value` | Measures how spread out price values are from their average. Higher values mean prices are more dispersed, indicating higher volatility. |
| `HISTORICAL_VOLATILITY` | Historical Volatility | `period` = 20 | `value` | Calculates the annualized standard deviation of logarithmic returns. Gives a percentage measure of how volatile the asset has been. |
| `CHAIKIN_VOLATILITY` | Chaikin Volatility | `ema_period` = 10<br>`change_period` = 10 | `value` | Measures the rate of change of the Average True Range. Shows whether volatility itself is increasing or decreasing. |
| `ULCER_INDEX` | Ulcer Index | `period` = 14 | `value` | Measures downside volatility and the depth and duration of price drawdowns. Higher values mean the investment is causing more 'ulcers' (stress). |
| `CHOPPINESS_INDEX` | Choppiness Index | `period` = 14 | `value` | Measures whether the market is trending or chopping sideways, on a scale of 0 to 100. Does not indicate direction, only the nature of the market. |
| `BB_WIDTH` | Bollinger Band Width | `period` = 20<br>`std_dev` = 2 (step 0.1) | `value` | Measures the distance between upper and lower Bollinger Bands as a percentage of the middle band. Quantifies how wide or narrow the bands are. |
| `BB_PCTB` | Bollinger %B | `period` = 20<br>`std_dev` = 2 (step 0.1) | `value` | Shows where price sits relative to the Bollinger Bands on a 0-1 scale. Values above 1 mean price is above the upper band, below 0 means below the lower band. |
| `PARKINSON_VOL` | Parkinson Volatility | `period` = 20 | `value` | Estimates volatility using only the high and low prices of each period, ignoring the open and close. More efficient than close-to-close volatility. |
| `YANG_ZHANG` | Yang-Zhang Volatility | `period` = 20 | `value` | The most comprehensive volatility estimator, combining overnight (close-to-open), open-to-close, and high-low components. Considered the most accurate volatility measure. |

### Volume

| Type | Name | Params (key = default) | Outputs | Description |
|---|---|---|---|---|
| `OBV` | On-Balance Volume | — | `value` | Running total of volume, adding volume on up days and subtracting on down days. Shows whether volume is flowing into or out of an asset. |
| `VWAP` | Volume Weighted Average Price | — | `value` | Calculates the average price weighted by volume for the trading session. Shows the 'fair price' where most volume has traded. |
| `MFI` | Money Flow Index | `period` = 14 | `value` | A volume-weighted version of RSI. Measures buying and selling pressure using both price and volume data. |
| `AD_LINE` | Accumulation/Distribution Line | — | `value` | Tracks the cumulative flow of money into and out of an asset based on where the close falls within the high-low range, weighted by volume. |
| `CMF` | Chaikin Money Flow | `period` = 20 | `value` | Measures the amount of money flow volume over a period. Ranges from -1 to +1, showing net buying or selling pressure. |
| `PVT` | Price Volume Trend | — | `value` | Similar to OBV but uses percentage price change to weight volume. Gives a proportional view of volume flow. |
| `EFI` | Elder Force Index | `period` = 13 | `value` | Combines price change and volume to measure the force behind price moves. Positive values mean bulls are in control, negative means bears. |
| `VOLUME_OSCILLATOR` | Volume Oscillator | `fast` = 5<br>`slow` = 10 | `value` | Shows the percentage difference between a fast and slow volume moving average. Indicates whether volume is expanding or contracting. |
| `KLINGER` | Klinger Volume Oscillator | `fast` = 34<br>`slow` = 55<br>`signal_period` = 13 | `value`, `signal` | Compares volume flowing in and out of an asset based on price trend and range. Uses the difference between two EMAs of volume force. |
| `NVI` | Negative Volume Index | — | `value` | Tracks price changes only on days when volume decreases from the previous day. Based on the idea that smart money trades on quiet days. |
| `PVI` | Positive Volume Index | — | `value` | Tracks price changes only on days when volume increases from the previous day. Reflects what the crowd or 'uninformed money' is doing. |
| `EMV` | Ease of Movement | `period` = 14 | `value` | Relates price change to volume, showing how easily price moves. High positive values mean price is advancing easily on light volume. |
| `ADOSC` | Chaikin A/D Oscillator | `fast` = 3<br>`slow` = 10 | `value` | The MACD applied to the Accumulation/Distribution Line. Shows the momentum of money flow rather than its direction. |
| `VOLUME_SMA` | Volume SMA | `period` = 20 | `value` | A simple moving average of trading volume. Shows the average volume level to help identify unusual volume activity. |
| `VOLUME_RATIO` | Volume Ratio | `period` = 20 | `value` | Compares current volume to average volume as a ratio. Values above 1 indicate higher than normal volume, below 1 indicates lower. |

### Support / Resistance

| Type | Name | Params (key = default) | Outputs | Description |
|---|---|---|---|---|
| `PIVOT_POINTS` | Pivot Points | — | `pp`, `r1`, `r2`, `r3`, `s1`, `s2`, `s3` | Calculates potential support and resistance levels based on the previous period's high, low, and close. Includes a pivot, three support levels, and three resistance levels. |
| `FIBONACCI_PIVOTS` | Fibonacci Pivots | — | `pp`, `r1`, `r2`, `r3`, `s1`, `s2`, `s3` | Pivot points calculated using Fibonacci ratios (38.2%, 61.8%, 100%). Combines traditional pivot math with Fibonacci levels. |
| `CAMARILLA_PIVOTS` | Camarilla Pivots | — | `r1`, `r2`, `r3`, `r4`, `s1`, `s2`, `s3`, `s4` | A set of eight levels based on the previous period's range, designed for day trading. Levels are closer together than standard pivots, providing tight trading ranges. |
| `WOODIES_PIVOTS` | Woodies Pivots | — | `pp`, `r1`, `r2`, `s1`, `s2` | A variation of pivot points that gives more weight to the closing price. The pivot calculation uses the close twice, making it more responsive to recent price action. |
| `DEMARK_PIVOTS` | DeMark Pivots | — | `high`, `low` | Pivot points that use different formulas depending on the relationship between open and close. Adapts the calculation based on whether the previous period was bullish or bearish. |
| `PREVIOUS_HIGH_LOW` | Previous High/Low | `period` = 1 | `prev_high`, `prev_low` | Plots the previous period's high and low as horizontal lines. These act as key reference levels for the current trading session. |
| `ROLLING_HIGH_LOW` | Rolling High/Low | `period` = 20 | `highest`, `lowest` | Shows the highest high and lowest low over a rolling N-period window. Creates dynamic support and resistance levels that move with time. |

### Candlestick Patterns

| Type | Name | Params (key = default) | Outputs | Description |
|---|---|---|---|---|
| `DOJI` | Doji | — | `signal` | A candle where the open and close are virtually equal, creating a cross or plus sign shape. Indicates market indecision. |
| `HAMMER` | Hammer | — | `signal` | A candle with a small body at the top and a long lower shadow (at least 2x the body). Appears at the bottom of downtrends, signaling potential reversal. |
| `INVERTED_HAMMER` | Inverted Hammer | — | `signal` | A candle with a small body at the bottom and a long upper shadow. Appears at the bottom of downtrends, suggesting buyers are starting to challenge the bears. |
| `ENGULFING` | Engulfing Pattern | — | `signal` | A two-candle pattern where the second candle completely engulfs the body of the first. Bullish engulfing has a green candle engulfing a red one; bearish is the reverse. |
| `MORNING_STAR` | Morning Star | — | `signal` | A three-candle bullish reversal pattern: a long red candle, a small-bodied candle (gap down), and a long green candle that closes above the midpoint of the first. |
| `EVENING_STAR` | Evening Star | — | `signal` | A three-candle bearish reversal pattern: a long green candle, a small-bodied candle (gap up), and a long red candle that closes below the midpoint of the first. |
| `THREE_WHITE_SOLDIERS` | Three White Soldiers | — | `signal` | Three consecutive long green candles, each opening within the previous body and closing higher. A powerful bullish reversal or continuation pattern. |
| `THREE_BLACK_CROWS` | Three Black Crows | — | `signal` | Three consecutive long red candles, each opening within the previous body and closing lower. A powerful bearish reversal or continuation pattern. |
| `HARAMI` | Harami | — | `signal` | A two-candle pattern where the second candle's body is completely contained within the first candle's body. Signals a potential trend pause or reversal. |
| `PIERCING_LINE` | Piercing Line | — | `signal` | A two-candle bullish reversal pattern where a red candle is followed by a green candle that opens below the red's low and closes above its midpoint. |
| `DARK_CLOUD_COVER` | Dark Cloud Cover | — | `signal` | A two-candle bearish reversal pattern where a green candle is followed by a red candle that opens above the green's high and closes below its midpoint. |
| `SPINNING_TOP` | Spinning Top | — | `signal` | A candle with a small body and relatively equal upper and lower shadows. Shows indecision between buyers and sellers. |
| `MARUBOZU` | Marubozu | — | `signal` | A candle with little to no shadows: the open and close are at or very near the extreme prices. Shows complete dominance by either buyers or sellers. |
| `TWEEZER_TOP_BOTTOM` | Tweezer Top/Bottom | — | `signal` | Two or more candles with matching highs (tweezer top) or matching lows (tweezer bottom). Shows that a price level was tested and rejected twice. |

### Statistical

| Type | Name | Params (key = default) | Outputs | Description |
|---|---|---|---|---|
| `ZSCORE` | Z-Score | `period` = 20 | `value` | Measures how many standard deviations the current price is from its mean. A Z-Score of +2 means price is 2 standard deviations above average. |
| `LINEAR_REGRESSION_CHANNEL` | Linear Regression Channel | `period` = 20<br>`mult` = 2 (step 0.1) | `upper`, `middle`, `lower` | Draws a linear regression line through price data with parallel upper and lower channel lines at a set standard deviation distance. |
| `R_SQUARED` | R-Squared | `period` = 14 | `value` | Measures how well price fits a linear trend, on a scale of 0 to 1. Values near 1 mean price is moving in a very straight line. |
| `HURST` | Hurst Exponent | `period` = 100 | `value` | Measures the tendency of a time series to trend, mean-revert, or walk randomly. Values range from 0 to 1. |
| `LOG_RETURN` | Log Return | `period` = 1 | `value` | Calculates the natural logarithm of the price ratio between consecutive periods. The standard way to measure returns in quantitative finance. |
| `PERCENTILE_RANK` | Percentile Rank | `period` = 100 | `value` | Shows the percentage of previous values that are less than or equal to the current value. Tells you where the current reading sits historically. |

### Composite / Hybrid

| Type | Name | Params (key = default) | Outputs | Description |
|---|---|---|---|---|
| `ELDER_RAY` | Elder Ray Index | `period` = 13 | `bull_power`, `bear_power` | Measures buying and selling pressure using Bull Power (high minus EMA) and Bear Power (low minus EMA). Created by Dr. Alexander Elder. |
| `QSTICK` | QStick | `period` = 14 | `value` | Shows the moving average of the difference between close and open prices. Reveals the dominance of buying or selling pressure over time. |
| `HEIKIN_ASHI` | Heikin-Ashi | — | `ha_open`, `ha_high`, `ha_low`, `ha_close` | Modified candlesticks that use averaged values to filter noise and show trends more clearly. Green candles with no lower shadow indicate strong uptrend, red with no upper shadow indicate strong downtrend. |
<!-- END INDICATOR TABLES -->

---

## 10. Examples

### 10.1 RSI oversold — simple long

Enter long when RSI(14) drops below 30; exit at +3% take-profit, −1.5% stop-loss,
or after 48 bars.

```json
{
  "symbol": "BTCUSDT",
  "exchange": "binance",
  "timeframe": "1h",
  "direction": "long",
  "indicators": [
    { "id": "rsi1", "type": "RSI", "params": { "period": 14 } }
  ],
  "entry_rules": {
    "logic": "AND",
    "conditions": [
      { "left": "rsi1.value", "op": "<", "right": 30 }
    ]
  },
  "exit_rules": {
    "take_profit": 3,
    "stop_loss": 1.5,
    "ttl_bars": 48,
    "logic": "AND",
    "conditions": [],
    "conservative_fill": false
  },
  "position": { "leverage": 1, "size_pct": 100 },
  "costs": {
    "commission_maker_pct": 0.02,
    "commission_taker_pct": 0.04,
    "slippage_pct": 0.01,
    "order_type": "market"
  }
}
```

### 10.2 Multi-indicator AND — trend filter plus MACD cross

Enter long only when price is above the SMA(50) trend line **and** the MACD line
crosses above its signal line. Exit on the opposite MACD cross, or at +5% / −2% /
96 bars.

```json
{
  "symbol": "ETHUSDT",
  "exchange": "binance",
  "timeframe": "4h",
  "direction": "long",
  "indicators": [
    { "id": "sma1", "type": "SMA", "params": { "period": 50 } },
    { "id": "macd1", "type": "MACD", "params": { "fast": 12, "slow": 26, "signal_period": 9 } }
  ],
  "entry_rules": {
    "logic": "AND",
    "conditions": [
      { "left": "close", "op": ">", "right": "sma1.value" },
      { "left": "macd1.macd", "op": "crossover", "right": "macd1.signal" }
    ]
  },
  "exit_rules": {
    "take_profit": 5,
    "stop_loss": 2,
    "ttl_bars": 96,
    "logic": "OR",
    "conditions": [
      { "left": "macd1.macd", "op": "crossunder", "right": "macd1.signal" }
    ],
    "conservative_fill": false
  },
  "position": { "leverage": 1, "size_pct": 100 },
  "costs": {
    "commission_maker_pct": 0.02,
    "commission_taker_pct": 0.04,
    "slippage_pct": 0.01,
    "order_type": "market"
  }
}
```

### 10.3 Porting a Python backtest

A common Python mean-reversion strategy expressed with pandas:

```python
# Long when RSI(14) < 30 AND price is below the lower Bollinger band.
# Take profit +2%, stop loss -1%.
import pandas_ta as ta

df["rsi"] = ta.rsi(df["close"], length=14)
bb = ta.bbands(df["close"], length=20, std=2.0)
df["bb_lower"] = bb["BBL_20_2.0"]

entry = (df["rsi"] < 30) & (df["close"] < df["bb_lower"])

TAKE_PROFIT = 0.02   # +2%
STOP_LOSS   = 0.01   # -1%
FEE         = 0.0004 # 0.04% taker, per side
```

The same logic as a Rulyfi strategy. Note the unit change: the Python code uses
decimals (`0.0004` for the fee, `0.02` for take-profit), while this format uses
percent notation (`0.04`, `2`). The entry `AND` becomes `entry_rules.logic: "AND"`
with two conditions; the Bollinger band's lower line is referenced as
`bb1.lower`.

```json
{
  "symbol": "BTCUSDT",
  "exchange": "binance",
  "timeframe": "1h",
  "direction": "long",
  "indicators": [
    { "id": "rsi1", "type": "RSI", "params": { "period": 14 } },
    { "id": "bb1", "type": "BOLLINGER_BANDS", "params": { "period": 20, "std_dev": 2.0 } }
  ],
  "entry_rules": {
    "logic": "AND",
    "conditions": [
      { "left": "rsi1.value", "op": "<", "right": 30 },
      { "left": "close", "op": "<", "right": "bb1.lower" }
    ]
  },
  "exit_rules": {
    "take_profit": 2,
    "stop_loss": 1,
    "ttl_bars": null,
    "logic": "AND",
    "conditions": [],
    "conservative_fill": false
  },
  "position": { "leverage": 1, "size_pct": 100 },
  "costs": {
    "commission_maker_pct": 0.02,
    "commission_taker_pct": 0.04,
    "slippage_pct": 0.01,
    "order_type": "market"
  }
}
```

---

Backtest results are based on past market data and do not guarantee future
returns. Fees and slippage are modeled from the `costs` values above; real fills
may differ.
