Libre Alpha Python SDK for interacting with gRPC-based backend
Project description
Libre Alpha Python SDK
This SDK provides historical upload, historical download, local runner send, and real-time subscription APIs (HTTP + gRPC + WebSocket).
Install
pip install libre-alpha
# Optional: override default API base (default is https://api.librealpha.com)
export LIBRE_API_BASE="https://api.librealpha.com"
# Auth (X-API-Key)
export LIBRE_API_KEY="YOUR_API_KEY"
# Optional: record encryption key (used to encrypt uploads for encrypted records, and decrypt encrypted payloads)
export LIBRE_RECORD_ENCRYPTION_KEY="YOUR_RECORD_ENCRYPTION_KEY"
# Optional: local libre_runner gRPC address for send_data()
export LIBRE_RUNNER_HOST="127.0.0.1"
export LIBRE_RUNNER_PORT="8128"
Initialize Client
from libre_alpha.client import LibreAlphaClient
# api_base defaults to https://api.librealpha.com
# can be overridden by env LIBRE_API_BASE or by passing api_base=...
client = LibreAlphaClient(
api_key="YOUR_API_KEY", # optional if using env LIBRE_API_KEY
)
## Historical Upload API (Python) - protobuf stream (/api/entries/history/upload)
This is a **historical backfill** uploader that sends protobuf `DataEntry` messages in a length-prefixed stream:
- Request body format: `[4-byte big-endian length][DataEntry][4-byte length][DataEntry]...`
- Backend groups entries **by minute**; this SDK implementation will also **bucket by minute** and send **1 minute per request**.
- Auth: `X-API-Key` (required).
- Data is carried per-symbol in `symbol_values`:
- For non-encrypted records: `symbol_values[i].values.items = [float, ...]`
- For encrypted records: `symbol_values[i].encrypted_payload = <bytes>` (AES-256-GCM)
Client method (recommended):
```python
def upload_data(
record_id: int,
df: pd.DataFrame,
encryption_key: str | None = None,
) -> None:
...
- Auth is always taken from
client.api_key(or envLIBRE_API_KEYwhen constructing the client). encryption_key: record encryption key for encrypting payload when the record is encrypted. If omitted, the SDK uses envLIBRE_RECORD_ENCRYPTION_KEY.
Note: the SDK also exposes a module-level upload_data(...) with the same arguments; client.upload_data(...)
delegates to it internally. (We only show the signature once here to avoid confusion.)
DataFrame format:
- Required columns:
symbol(str): symbol_id string (e.g."1","3"). If you pass non-numeric symbol names, the SDK will best-effort map them to symbol_id via/api/records/user-records(target_symbols).timestamp(datetime64 or unix timestamp; will be normalized to UTC and uploaded in microseconds)
- Feature columns (choose ONE approach):
- Provide a
featurescolumn containing a list of floats (or a string like"[1.0, nan, 2.0]"), OR - Provide user-defined float columns matching the record schema; the SDK will fetch feature order from
/api/records/{id}.
- Provide a
- Strict schema check (enabled):
- Uploaded feature fields are compared with API schema from
/api/records/{id}. - Feature columns must be exactly consistent with API (
不能少、不能多). - If using
featurescolumn, each row's feature count must exactly equal API feature count.
- Uploaded feature fields are compared with API schema from
Upload packing behavior:
- 1 request = 1 minute (backend requirement)
- Within that minute, the SDK aggregates rows by exact timestamp into 1
DataEntry. - Each aggregated
DataEntrycarries multiple symbols insymbol_values:[{symbol_id, values.items}, {symbol_id, values.items}, ...]
Example (upload one minute from a previously-downloaded CSV):
import pandas as pd
from libre_alpha.client import LibreAlphaClient
df = pd.read_csv("history_1h_record12_BTC.csv")
# pick the first minute only (backend requires 1 minute per upload)
first_minute = int(df["timestamp"].iloc[0] // 60_000_000)
df1 = df[df["timestamp"].apply(lambda x: int(x // 60_000_000) == first_minute)].copy()
df1 = df1[["symbol", "timestamp", "features"]]
client = LibreAlphaClient(api_key="YOUR_API_KEY")
client.upload_data(
record_id=12,
df=df1,
# encryption_key="YOUR_RECORD_ENCRYPTION_KEY", # only needed if record is encrypted (or set LIBRE_RECORD_ENCRYPTION_KEY)
)
Historical File Download API (Python) - protobuf (length-prefixed)
def download_historical_data(
record_id: int,
symbols: list[str],
start: datetime | str | int,
end: datetime | str | int,
encryption_key: str | None = None,
) -> pandas.DataFrame:
pass
Parameters:
- record_id: the record id to download
- symbols: list of symbol names (e.g.
["BINANCE_BTCUSDT"]). If you pass[], the SDK will best-effort fetch all symbols from/api/records/user-records(target_symbols). - encryption_key: optional, record encryption key for decrypting
symbol_values[].encrypted_payload
Notes:
- Backend
/api/entries/download-linksenforcesend-start <= 24h(microseconds). The SDK automatically splits long ranges into multiple 24h windows and merges results locally. - Download worker concurrency is fixed at
100. - Stream read chunk size is fixed at
1048576(1 MiB). Each worker thread reuses an HTTP connection pool to the same download host. - Returned timestamps are in microseconds.
- DataEntry uses
repeated SymbolValues symbol_values; each row corresponds to one symbol_id. - When data is encrypted (
symbol_values[].encrypted_payloadpresent), passencryption_keyto decrypt. - The download progress line shows total bytes and real-time speed (
MB/s). SetLIBRE_DOWNLOAD_PROGRESS=0to disable progress output.
Example
from libre_alpha.client import LibreAlphaClient
import datetime as dt
client = LibreAlphaClient(
api_key="YOUR_API_KEY",
api_base="https://api.librealpha.com",
)
start = dt.datetime(2026, 1, 1, 0, 0, 0, tzinfo=dt.timezone.utc)
end = dt.datetime(2026, 1, 3, 0, 0, 0, tzinfo=dt.timezone.utc) # >24h is OK (SDK will split)
df = client.download_historical_data(
record_id=2,
symbols=["BINANCE_BTCUSDT"],
start=start,
end=end,
encryption_key="YOUR_RECORD_ENCRYPTION_KEY", # for decrypting encrypted data
)
print(df.head())
print("rows:", len(df))
Local Runner Send API (Python) - gRPC ProcessJson
send_data(...) is still available in the Python SDK. It sends one JSON payload to a local libre_runner
through the gRPC JsonService/ProcessJson RPC.
Client method:
def send_data(
*,
data: dict,
record_id: int,
timeout: float | None = None,
):
...
Parameters:
data: JSON-serializable payload to send.record_id: target backend record id. This is required and is sent in gRPC metadata.timeout: optional gRPC timeout in seconds. Defaults to the client timeout.
Notes:
- Transport is gRPC, not HTTP.
- The SDK sends to
LIBRE_RUNNER_HOST:LIBRE_RUNNER_PORT(defaults to127.0.0.1:8128), or tohost=/port=passed when constructingLibreAlphaClient. - The underlying RPC is
JsonService/ProcessJson. send_data(...)is the current send entrypoint for local runner usage. There is no separately documentedsend_alpha(...)API in the current SDK implementation.send_data(...)can also send alpha-style payloads. What matters is thatrecord_idand the fields insidedatamatch the target record schema.- Runner determines whether the target record is encrypted. For encrypted records it will upload
encrypted_payload; for non-encrypted records it will uploadvalues. - If you include
symbolindata, runner will use it. If omitted, runner may try to infer it from record configuration.
Example: send normal data to local runner
from libre_alpha import LibreAlphaClient
client = LibreAlphaClient(
api_key="YOUR_API_KEY",
host="127.0.0.1",
port=8128,
)
resp = client.send_data(
record_id=13,
data={
"symbol": "BINANCE_BTCUSDT",
"Price": 150,
"Volume": 200,
"timestamp_ms": 1710000000000,
},
)
print(resp)
Example: send alpha data to local runner
from libre_alpha import LibreAlphaClient
client = LibreAlphaClient(
api_key="YOUR_API_KEY",
host="127.0.0.1",
port=8128,
)
resp = client.send_data(
record_id=4,
data={
"symbol": "BINANCE_BTCUSDT",
"alpha_value": 0.1234,
"timestamp_ms": 1710000000000,
},
)
print(resp)
Real-time Subscribe API (Python) - WebSocket ws/data
from typing import List, Callable
def subscribe_data(
record_id: int,
*,
symbols: List[str],
on_data_fn: Callable[[str, pd.DataFrame], None],
encryption_key: str | None = None,
) -> None:
"""Subscribes to live data for a record into a DataFrame (schema matches publish).
Args:
record_id: Backend record identifier.
symbols: Symbols to filter by (required).
on_data_fn: Callback function invoked upon receiving new data. The
function takes two arguments: the symbol (str) and a DataFrame
containing the new data for that symbol.
encryption_key: Optional, record encryption key for decrypting encrypted_payload.
"""
Parameters:
- record_id: must be in user's subscriptions (from /api/subscriptions)
- symbols: symbol_id strings to filter by (required). Only rows with symbol_id in this list are passed to on_data_fn.
- on_data_fn: callback invoked upon receiving new data. Takes (symbol: str, df: DataFrame).
- encryption_key: optional, record encryption key for decrypting
symbol_values[].encrypted_payload; required if data is encrypted.
Notes:
- Connects to ws/data, sends { wallet_address, record_id } on open.
- If data is encrypted (
symbol_values[].encrypted_payloadhas value), pass encryption_key or set LIBRE_RECORD_ENCRYPTION_KEY. - DataFrame schema matches download_historical_data (record_id, symbol, features/expanded feature columns, timestamps).
- Blocking; run in a daemon thread for long-lived subscription.
Example
import threading
import pandas as pd
from libre_alpha import LibreAlphaClient
client = LibreAlphaClient(
api_key="YOUR_API_KEY",
host="127.0.0.1",
port=8128,
)
resp = client.send_data(
record_id=13,
data={
"symbol": "BINANCE_BTCUSDT",
"Price": 150,
"Volume": 200,
"timestamp_ms": 1710000000000,
},
)
print(resp)
Example: send alpha data to local runner
from libre_alpha import LibreAlphaClient
client = LibreAlphaClient(
api_key="YOUR_API_KEY",
host="127.0.0.1",
port=8128,
)
resp = client.send_data(
record_id=4,
data={
"symbol": "BINANCE_BTCUSDT",
"alpha_value": 0.1234,
"timestamp_ms": 1710000000000,
},
)
print(resp)
Real-time Subscribe API (Python) - WebSocket ws/data
from typing import List, Callable
def subscribe_data(
record_id: int,
*,
symbols: List[str],
on_data_fn: Callable[[str, pd.DataFrame], None],
encryption_key: str | None = None,
) -> None:
"""Subscribes to live data for a record into a DataFrame (schema matches publish).
Args:
record_id: Backend record identifier.
symbols: Symbols to filter by (required).
on_data_fn: Callback function invoked upon receiving new data. The
function takes two arguments: the symbol (str) and a DataFrame
containing the new data for that symbol.
encryption_key: Optional, record encryption key for decrypting encrypted_payload.
"""
Parameters:
- record_id: must be in user's subscriptions (from /api/subscriptions)
- symbols: symbol_id strings to filter by (required). Only rows with symbol_id in this list are passed to on_data_fn.
- on_data_fn: callback invoked upon receiving new data. Takes (symbol: str, df: DataFrame).
- encryption_key: optional, record encryption key for decrypting
symbol_values[].encrypted_payload; required if data is encrypted.
Notes:
- Connects to ws/data, sends { wallet_address, record_id } on open.
- If data is encrypted (
symbol_values[].encrypted_payloadhas value), pass encryption_key or set LIBRE_RECORD_ENCRYPTION_KEY. - DataFrame schema matches download_historical_data (record_id, symbol, features/expanded feature columns, timestamps).
- Blocking; run in a daemon thread for long-lived subscription.
Example
import threading
import pandas as pd
from libre_alpha import LibreAlphaClient
client = LibreAlphaClient(api_key="YOUR_API_KEY", api_base="https://api.librealpha.com")
def on_data_fn(symbol: str, df: pd.DataFrame):
print(f"[{symbol}] entry_id={df['entry_id'].iloc[0]} features_len={len(df['features'].iloc[0])}")
t = threading.Thread(
target=client.subscribe_data,
kwargs={"record_id": 2, "symbols": ["1", "3"], "on_data_fn": on_data_fn, "encryption_key": "YOUR_RECORD_ENCRYPTION_KEY"},
daemon=True,
)
t.start()
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file libre_alpha-0.1.11.tar.gz.
File metadata
- Download URL: libre_alpha-0.1.11.tar.gz
- Upload date:
- Size: 44.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb592f9bf90bdac9b7c81577057fe94cc8d3a7b01f49a140228e0b48082394a6
|
|
| MD5 |
3089bc91d2cc178a41aedb89bccc1ec9
|
|
| BLAKE2b-256 |
e5e5eeae82ae3deb1f47eead2ebf7b227dfc842e2492764b18f323a617831bb8
|
File details
Details for the file libre_alpha-0.1.11-py3-none-any.whl.
File metadata
- Download URL: libre_alpha-0.1.11-py3-none-any.whl
- Upload date:
- Size: 44.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f8f40585c526d3dd08c500fba45fac562d5f1d10c418617c39d89b8f9691bbc
|
|
| MD5 |
91c362aa13082be9ee7c8eff7b3d8ecb
|
|
| BLAKE2b-256 |
3fa176948eef1afdfa236d70ae536f0d169973fa22a3ced05734455d2a9d91ae
|