Skip to content

Quick Start

Get up and running with qldata in minutes. This guide covers the essential operations you'll use most frequently.

Import Convention

By convention, we import qldata as qd:

import qldata as qd

This keeps your code concise while making it clear you're using qldata functions.

Fetching Historical Data

The qd.data() function is your gateway to historical market data. It uses a fluent (chainable) API that reads naturally:

Basic Example

import qldata as qd

# Fetch last 30 days of hourly BTCUSDT data from Binance
df = qd.data("BTCUSDT", source="binance", category="spot") \
    .last(30) \
    .resolution("1h") \
    .get()

print(df.head())

Output:

                            open      high       low     close      volume
timestamp                                                                 
2024-11-05 00:00:00+00:00  69500.00  69750.00  69400.00  69600.00  1250.5432
2024-11-05 01:00:00+00:00  69600.00  69800.00  69550.00  69750.00  1180.2341
2024-11-05 02:00:00+00:00  69750.00  69900.00  69700.00  69850.00  1320.8765
...

Understanding the API

Let's break down the query:

df = qd.data("BTCUSDT", source="binance", category="spot")  # (1)!
    .last(30)           # (2)!
    .resolution("1h")   # (3)!
    .get()              # (4)!
  1. Create a query for BTCUSDT on Binance spot market
  2. Set time range to the last 30 days
  3. Set resolution to 1-hour bars
  4. Execute the query and return a DataFrame

Different Time Ranges

# Last N days (default unit)
df = qd.data("BTCUSDT", source="binance").last(7).resolution("1h").get()

# Explicit time unit
df = qd.data("BTCUSDT", source="binance").last(24, "hours").resolution("1m").get()

# Specific date range
from datetime import datetime
df = qd.data("BTCUSDT", source="binance") \
    .range(datetime(2024, 1, 1), datetime(2024, 1, 31)) \
    .resolution("1d") \
    .get()

Different Resolutions

Resolution Description
"1m" 1-minute bars
"5m" 5-minute bars
"15m" 15-minute bars
"1h" 1-hour bars
"4h" 4-hour bars
"1d" Daily bars
"1w" Weekly bars

Market Categories

Category Description
"spot" Spot market
"usdm" USD-Margined perpetual futures
Category Description
"spot" Spot market
"linear" Linear perpetual contracts

Cleaning Data

Raw market data often needs cleaning. qldata provides a built-in cleaning pipeline:

# Basic cleaning (removes duplicates, sorts by time)
df = qd.data("BTCUSDT", source="binance") \
    .last(30) \
    .resolution("1h") \
    .clean() \
    .get()

# Aggressive cleaning for production
df = qd.data("BTCUSDT", source="binance") \
    .last(30) \
    .resolution("1h") \
    .clean(
        remove_invalid_prices=True,  # Remove zero/negative prices
        validate_ohlc=True,          # Ensure high >= low, etc.
        remove_outliers=True         # Remove statistical outliers
    ) \
    .get()

Fill Missing Data

# Forward fill (use last known value)
df = qd.data("BTCUSDT", source="binance") \
    .last(30) \
    .resolution("1h") \
    .clean() \
    .fill_forward() \
    .get()

# Interpolate (linear interpolation)
df = qd.data("BTCUSDT", source="binance") \
    .last(30) \
    .resolution("1h") \
    .clean() \
    .interpolate() \
    .get()

Resample Data

# Fetch 1-minute data and resample to 1-hour
df = qd.data("BTCUSDT", source="binance") \
    .last(1, "days") \
    .resolution("1m") \
    .clean() \
    .resample("1h") \
    .get()

Multi-Symbol Queries

Fetch data for multiple symbols at once:

# Sequential (default)
data = qd.data(["BTCUSDT", "ETHUSDT", "SOLUSDT"], source="binance") \
    .last(7) \
    .resolution("1d") \
    .get()

# Parallel for faster downloads
data = qd.data(["BTCUSDT", "ETHUSDT", "SOLUSDT"], source="binance") \
    .last(7) \
    .resolution("1d") \
    .get(parallel=True, workers=4)

# Returns a dictionary of DataFrames
for symbol, df in data.items():
    print(f"{symbol}: {len(df)} bars")

Live Streaming

Stream real-time market data with auto-reconnect and resilience features:

import qldata as qd
import time

def handle_data(df):
    """Called when new data arrives."""
    if not df.empty:
        latest = df.iloc[-1]
        print(f"[{latest['symbol']}] Price: {latest['price']}")

def handle_error(error):
    """Called on errors."""
    print(f"Error: {error}")

def handle_close():
    """Called when stream closes."""
    print("Stream closed")

# Create and start the stream
stream = qd.stream(["BTCUSDT", "ETHUSDT"], source="binance", category="spot") \
    .resolution("tick") \
    .on_data(handle_data) \
    .on_error(handle_error) \
    .on_close(handle_close) \
    .get(start=True)

# Stream runs in the background
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    stream.stop()

Stream Resolutions

Resolution Description
"tick" Individual trades (raw)
"1m" Aggregated 1-minute bars

Symbol Information

Get metadata about trading pairs:

import qldata as qd

# Get symbol information
info = qd.get_symbol_info("BTCUSDT", source="binance", category="spot")

print(f"Symbol: {info.symbol}")
print(f"Base/Quote: {info.base_asset}/{info.quote_asset}")
print(f"Status: {info.status}")
print(f"Tick Size: {info.filters.tick_size}")
print(f"Min Quantity: {info.filters.min_quantity}")

# Validate prices and quantities
from decimal import Decimal
is_valid = info.validate_price(Decimal("50000.50"))
is_valid = info.validate_quantity(Decimal("0.001"))

List Available Symbols

# All active USDT pairs on Binance spot
pairs = qd.list_symbols(
    source="binance",
    category="spot",
    quote_asset="USDT",
    active_only=True
)
print(f"Found {len(pairs)} USDT pairs")

# All BTC pairs
btc_pairs = qd.list_symbols(
    source="binance",
    category="spot",
    base_asset="BTC"
)

Exchange Information

# Get exchange-level information
exchange = qd.get_exchange_info(source="binance")

print(f"Exchange: {exchange.exchange}")
print(f"Timezone: {exchange.timezone}")
print(f"Total Symbols: {exchange.symbol_count}")

Funding Rates

For perpetual futures, get funding rate information:

# Current funding rate
rate = qd.current_funding_rate("BTCUSDT", source="binance", category="usdm")
print(f"Current Rate: {rate}")

What's Next?

Now that you know the basics, explore: