Exchanges, symbols, sources and timeframes

An indicator is not just a formula. When you define a block, you also choose which market it reads, which timeframe it uses to build its series, and which source it takes as input. These three dimensions are defined by symbol, timeframe, and source.

The [backtest] block defines the main symbol and the main timeframe of the strategy. If an indicator block does not define its own symbol or timeframe, it falls back to these defaults.

[backtest]
symbol    = "BINANCE:BTCUSDT"
timeframe = "240"

With this setup, any block that does not define symbol or timeframe runs by default on BINANCE:BTCUSDT on 240 (4h).

Exchanges, symbols, and timeframes

Whale‑E downloads market data through public endpoints. Available markets depend on the exchange. Market types that require authentication are not supported.

ExchangePrefixSupported markets
BinanceBINANCESpot, USD‑M futures, COIN‑M futures
KuCoinKUCOINSpot, USDT‑M perpetuals, COIN‑M perpetuals
BitgetBITGETSpot, USDT‑M/USDC‑M perpetuals, COIN‑M perpetuals
BybitBYBITSpot, Linear perpetuals (USDT‑M), Inverse perpetuals (COIN‑M)
OKXOKXSpot, Perpetual swaps (Linear/Inverse)

The symbol key accepts either a single string or an array of strings, both in [backtest] and in blocks that support it. Each value must use the EXCHANGE:SYMBOL format.

symbol = "BINANCE:BTCUSDT"
symbol = ["KUCOIN:ETHUSDT", "BINANCE:BTCUSDT"]

The timeframe key also accepts a single string or an array of strings. You can use a number of minutes from 1 to 1440, a number of days followed by D such as 1D or 7D, or a number of weeks followed by W such as 1W or 4W. D and W are accepted as aliases for 1D and 1W. Monthly timeframes such as 1M are not supported.

timeframe = "60"
timeframe = ["15", "D", "W"]

Monthly timeframes such as 1M are not supported.

What source refers to

The source key defines the input series read by a block before it performs its own calculation.

When a block supports it, source can be a single string or an array of strings. A source value can point to:

  • a standard candle source: open, close, high, low, hl2, hlc3, ohlc4, hlcc4, volume
  • the id of another indicator

When source reads a standard price input, symbol tells Whale‑E which market to read that series from. When source reads another indicator, the block directly reuses the series that was already calculated upstream.

Some blocks do not expose a source key because they always use fixed inputs such as high, low, and close. In that case, symbol and timeframe still matter because they still define which market and which time axis those fixed inputs are read from.

source = "close"
source = ["close", "hlc3"]
source = "rsi_fast"

How a series is read by another block

A block always computes its output on its own market and on its own timeframe. But when another block or expression uses that output, the series is read according to the block consuming it. A series is always interpreted using the timeframe of the block or expression that consumes it, not the timeframe of the block that produced it.

Take a simple example: if an indicator is calculated on 240 and then read by a block or by a strategy running on 60, that series becomes visible as a series projected onto the 60 axis. Between two 4-hour closes, the value remains unchanged on the intermediate 1-hour candles.

The same rule applies to history. In that same example, series[1] means the value visible one 60 candle earlier on the axis of the block reading the series. It does not mean the previous 240 candle of the block that produced it. The same logic applies in conditional blocks, in indicators that read another indicator, and in [[custom_series]] formulas.

When source reads a standard price

If source contains a price value such as open, close, high, or low, the block reads market data directly. In that case, symbol selects the market and timeframe selects the time axis the series is read from.

[backtest]
symbol    = "BINANCE:BTCUSDT"
timeframe = "240"

[[rsi]]
id        = "rsi_eth_daily"
source    = "close"
symbol    = "BINANCE:ETHUSDT"
timeframe = "D"
length    = 14

Here, rsi_eth_daily is calculated from the daily close of BINANCE:ETHUSDT. If you then use that series in a strategy running on 240, Whale‑E makes it visible on the strategy 4-hour axis. Between two daily closes, the engine simply reuses the latest known daily value.

When source reads another indicator

If source points to the id of another indicator, the producer timeframe is never inherited. The consumer block keeps its own timeframe. If it does not define timeframe, it falls back to the main timeframe from [backtest].

[backtest]
symbol    = "BINANCE:BTCUSDT"
timeframe = "240" # 4 hours

[[rsi]]
id        = "rsi_daily"
source    = "close"
length    = 14
timeframe = "D" # Daily

[[moving_average]]
id     = "ma_rsi"
source = "rsi_daily"
type   = "sma"
length = 10

In this example, ma_rsi reads the series already calculated by rsi_daily. The [[moving_average]] block does not define timeframe, so it uses the main 4-hour timeframe. The daily RSI series is first calculated on its own axis, then projected onto the 4-hour axis, where the moving average is calculated.

When source mixes standard prices and indicator outputs

A single block can use both values such as close and indicator ids. When source refers to a value such as close, symbol tells Whale‑E which market that value must be read from. When source refers to the id of another indicator, symbol does not come into play: the block directly reuses the series already produced by that indicator. If source contains only indicator ids, the block-level symbol key is ignored.

[backtest]
symbol    = "BINANCE:BTCUSDT"
timeframe = "240"

[[price]]
id        = "eth_daily"
symbol    = "BINANCE:ETHUSDT"
timeframe = "D"

[[moving_average]]
id     = "ma_mix"
source = ["close", "eth_daily"]
symbol = ["BINANCE:BTCUSDT", "BINANCE:SOLUSDT"]
type   = "sma"
length = 10

In this example, three grids are built for ma_mix:

  • one moving average built from close on BINANCE:BTCUSDT
  • one moving average built from close on BINANCE:SOLUSDT
  • one moving average built from the eth_daily series

Combining sources, symbols, and timeframes

Qualitative values such as source, symbol, and timeframe create distinct grids. As soon as a block accepts an array for one of these keys, one combination is generated for each available choice.

[backtest]
symbol    = ["BINANCE:BTCUSDT", "BINANCE:ETHUSDT"]
timeframe = "240"

[[moving_average]]
id        = "ma_fast"
source    = ["close", "hlc3"]
timeframe = ["240", "D"]
type      = "sma"
length    = 20

In this example, the moving-average block offers:

  • 2 main symbols from [backtest]
  • 2 sources (close and hlc3)
  • 2 block timeframes (240 and D)

This creates 2 × 2 × 2 = 8 distinct grids. The numeric parameter length does not create new grids; it is explored inside each grid.