Skip to content

Data

qx.Data

The primary class for fetching, caching, and accessing historical candle data.

Data(
    exchange: str,
    asset: str,
    currency: str,
    begin: Union[str, int, float],
    end: Optional[Union[str, int, float]] = None,
    days: Optional[Union[int, float]] = None,
    candle_size: int = 86400,
    pool: Optional[str] = None,
    api_key: Optional[str] = None,
    intermediary: Optional[str] = None,
    placeholder: bool = False,
)
Parameter Type Default Description
exchange str required Exchange identifier. Any CCXT exchange ID ("binance", "kucoin", "kraken", etc.) or a special source: "bitshares", "cryptocompare", "alphavantage stocks", "alphavantage forex", "alphavantage crypto", "synthetic", "yahoo", "finance data reader".
asset str required Base asset symbol (e.g. "BTC").
currency str required Quote currency symbol (e.g. "USDT").
begin str, int, or float required Start date. "YYYY-MM-DD" string or Unix timestamp in seconds.
end str, int, or float None End date. Same format as begin. Defaults to current time if neither end nor days is set. Mutually exclusive with days.
days int or float None Duration in days before begin. Alternative to end. Mutually exclusive with end.
candle_size int 86400 Candle width in seconds. Common values: 60 (1m), 300 (5m), 900 (15m), 3600 (1h), 14400 (4h), 86400 (1d).
pool Optional[str] None Liquidity pool identifier (BitShares DEX only). Raises ValueError if set for non-bitshares exchanges.
api_key Optional[str] None API key for sources that require one (Alpha Vantage, CryptoCompare).
intermediary Optional[str] None Third asset for implied price synthesis. E.g., intermediary="BTC" to get XRP/USD via XRP/BTC + BTC/USD.
placeholder bool False If True, skips data fetching entirely. Used internally by load_csv.

On construction, Data fetches and caches the requested candles immediately. Subsequent constructions with the same parameters read from disk cache — instant.

Attributes

Attribute Type Description
exchange str Exchange name as passed
asset str Base asset
currency str Quote currency
begin int Actual start Unix timestamp (quantized to candle_size)
end int Actual end Unix timestamp
days float Duration in days
candle_size int Candle size in seconds
base_size int Original candle size before composite fetch
pool Optional[str] Pool identifier
intermediary Optional[str] Intermediary asset
raw_candles dict Core candle data — keys "unix", "open", "high", "low", "close", "volume", each a numpy array
fine_data Optional[dict] Fine-grained candle data for papertrade/live, same structure as raw_candles

Methods

data[key] — Index or slice. Integer index returns a single candle's columns. Slice returns a new Data object with the same metadata but a subset of candles.

len(data) — Number of candles (len(data.raw_candles["close"])).

data.keys(), data.values(), data.items() — Delegate to raw_candles.

data.update_candles(begin, end) — Re-fetches data for a new time range. Used internally by papertrade and live modes.

qx.load_csv

Load candle data from a CSV file into a Data object.

load_csv(
    exchange: str,
    asset: str,
    currency: str,
    filepath: str,
    begin: Optional[str] = None,
    end: Optional[str] = None,
    candle_size: int = 86400,
    stride: Optional[int] = None,
) -> Data
Parameter Type Default Description
exchange str required Exchange label (metadata, stored in the returned Data object)
asset str required Base asset symbol
currency str required Quote currency symbol
filepath str required Path to the CSV file
begin Optional[str] None Start date. Inclusive. "YYYY-MM-DD" or Unix timestamp.
end Optional[str] None End date. Inclusive.
candle_size int 86400 Target candle size in seconds
stride Optional[int] None Stride between candles. Defaults to candle_size (non-overlapping).

CSV format. Accepts columns unix, open, high, low, close, volume for explicit OHLCV, or unix, price, volume for discrete tick data (auto-generates OHLCV). Supports unix_milli and unix_micro timestamp columns.

Returns. A Data object with raw_candles at the requested candle_size and fine_data set to the raw stride-resolution data. Uses the same disk cache as Data.

Utility functions

These operate on candle dicts (dicts with numpy array keys "unix", "open", "high", "low", "close", "volume").

clip_to_time_range(candles, start_unix, end_unix)

Returns a new candle dict with only candles whose "unix" falls within [start_unix, end_unix].

invert(candles)

Inverts a pair (e.g., BTC/USDT to USDT/BTC). Prices become 1/price, high/low are swapped, volume adjusts. Accepts both list-of-dicts and dict-of-arrays formats.

implied(candles1, candles2)

Synthesizes an implied price pair from two datasets. Given XRP/BTC and BTC/USDT, produces XRP/USDT. Truncates to the shorter length.

interpolate(data, oldperiod, newperiod)

Cubic-spline interpolation of OHLC data between candle sizes. Volume uses nearest-neighbor scaled by newperiod / oldperiod.

reaggregate(data, candle_size, stride=None)

Disaggregates OHLCV candles into discrete price points, then re-aggregates at a new candle_size and optional stride. Useful for changing candle granularity while preserving OHLC shape.

merge_candles(candles, candle_size)

Combines multiple candle datasets (list of dicts) into one at a common candle_size. Quantizes unix times, then merges by taking max(high), min(low), first(open), last(close), max(volume).

create_candles(data, width=86400, stride=600)

Creates OHLCV candles from a list of (unix, price, volume) tuples. Uses a sliding window of width seconds with stride spacing.

quantize_unix(unix_array, candle_size)

Floors timestamps to the nearest candle boundary. Used internally by merge_candles() and Data.__init__().

quantize_unix(np.array([100, 200, 300]), 100)  # -> [100, 200, 300]
quantize_unix(np.array([150, 250, 350]), 100)  # -> [100, 200, 300]

synthesize_high_low(d1_h, d2_h, d1_l, d2_l, d1_o, d2_o, d1_c, d2_c)

Computes high/low values for implied synthetic pairs. Used by implied() to produce realistic candle ranges when combining two price series.

BadTimeframeError

Raised when a requested candle_size is not available from the data source.

fetch_composite_data(data, new_size)

Fetches high-resolution candle data for papertrade and live modes. Tries progressively smaller candle sizes [60, 600, 3600, ...] until data is found, then re-aggregates to data.candle_size with stride=new_size. Sets data.raw_candles (wide) and data.fine_data (fine). Modifies the Data object in place and returns it.

Supported data sources

Source exchange value Auth
Any CCXT exchange Exchange ID (e.g. "binance") None for public candles
BitShares DEX "bitshares" None
CryptoCompare "cryptocompare" API key
Alpha Vantage (stocks) "alphavantage stocks" API key
Alpha Vantage (forex) "alphavantage forex" API key
Alpha Vantage (crypto) "alphavantage crypto" API key
Yahoo Finance "yahoo" None
FinanceDataReader "finance data reader" None
Synthetic (test data) "synthetic" None

No authentication is needed for public candle data from CCXT exchanges, Yahoo Finance, or synthetic data. Alpha Vantage and CryptoCompare require free API keys passed via the api_key parameter.

Synthetic data

When exchange="synthetic", Data uses a harmonic Brownian walk to generate random price data. No API keys, no network, no disk caching — useful for testing strategies, prototyping, and CI.

data = qx.Data("synthetic", "BTC", "USD", days=365, candle_size=86400)

The underlying generator is available directly for custom use:

from qtradex.public.klines_synthetic import (
    klines_synthetic, create_dataset, hlocv_data, synthesize
)

Quick start

Three levels of access:

# Full OHLCV as a dict of numpy arrays (direct to Data)
ohlcv = klines_synthetic()
# -> {"unix": ndarray, "open": ndarray, "high": ndarray,
#     "low": ndarray, "close": ndarray, "volume": ndarray}

# Close prices only
dataset = create_dataset()
# -> {"unix": [...], "close": [...]}

# One step at a time
storage = {"log_periodic": 0.00001}
price = synthesize(storage, tick=1)

How it works

The generator composes three layers of randomness:

Harmonic cycles. Seven sine waves at different frequencies are summed into a sine accumulator. Each harmonic's amplitude decays as ACCEL / harmonic, so the first few harmonics dominate the shape. The result feeds into a log-periodic recurrence:

storage["log_periodic"] *= pow(1 + sum_of_sines, tick)

Random walk. Each step is perturbed by ((1 - STEP) + 2 * STEP * rand), scaling the previous value up or down by up to STEP (default 7%). This produces the stochastic drift that makes the series look like real price action.

OHLCV synthesis. hlocv_data() takes the close-price series and expands it to full candles. Each candle's open is the prior candle's close, perturbed by VOLATILITY (default 2%). High/low are the open/close range extended by a random fraction of the spread. Volume is (high - low) / close * 10^VOLUME_SIZE.

Constants

Constant Default Description
HARMONICS 7 Number of sine waves summed to form cyclic structure
ACCEL 1e-6 Harmonic amplitude decay factor
STEP 0.07 Random walk step size (fraction of current price)
FREQ 2e-4 Base frequency of the harmonic oscillations
VOLATILITY 2.0 HLOC spread variance (percent)
VOLUME_SIZE 5.0 Volume scale exponent
START 1e-5 Initial price
DEPTH 1000 Number of candles in a generated dataset

synthesize(storage, tick)

Core step function. Advances the state machine by one tick and returns the next closing price.

storage = {"log_periodic": 0.00001}  # initial state
for t in range(1, 1001):
    price = synthesize(storage, t)

The storage dict carries state between steps — you can seed it, inspect it, or run it in reverse for debugging.

create_dataset()

Runs synthesize() through DEPTH + 1 ticks, returning unix and close lists. Timestamps start at now - (DEPTH + 1) days with ~1-day spacing (86400 + 200 seconds per candle).

raw = create_dataset()
len(raw["unix"])    # 1001
len(raw["close"])   # 1001

hlocv_data(data)

Takes a {"unix": [...], "close": [...]} dict and expands it into full OHLCV with numpy arrays. Drops the first and last candle to maintain structural consistency.

candles = hlocv_data(create_dataset())
# -> keys: unix, open, high, low, close, volume (all ndarray)

klines_synthetic()

Convenience wrapper — hlocv_data(create_dataset()) in one call. Returns what Data uses internally.

Characteristics

  • No determinism. The generator uses random.random() without a fixed seed. Every run produces different data.
  • Price scale. Starting at 0.00001, the log-periodic recurrence grows the price over time. After 1000 steps prices typically range in single or low double digits.
  • Appearance. Broad trend cycles (~2-3 per 1000 candles) with noise on every tick. The harmonic component creates visible wave patterns that a strategy can exploit — a good test for overfitting detection.