Skip to main content

Official Python client for Equal Solution realtime and historical market data

Project description

eqldata

Official Python client for Equal Solution realtime and historical market data.

eqldata is designed for traders, developers, analysts, charting tools, and backtesting workflows that need simple access to Equal Solution APIs from Python.

What this package supports

  • Login and API token generation
  • Instrument list download
  • Realtime websocket subscription
  • Single-day EOD download
  • Range-based EOD download
  • After-market / current-day 1-minute data download
  • Reading EOD range ZIP output in plain Python
  • Reading EOD range ZIP output with pandas

Installation

pip install eqldata

Upgrade to the latest version:

pip install --upgrade eqldata

Check installed version:

import eqldata
print(eqldata.__version__)

Important API session rule

Only the latest successful login token remains valid.

If the same user logs in again from another PC, server, or script, the previous API token becomes invalid automatically.

This protects the business rule:

A client may login from any PC, but only one active API session is allowed at a time.

Use one fresh token per running client/script.


Instrument naming

Always use exchange/segment-prefixed instruments.

Examples:

"NSEEQ:ABB"
"NSEEQ:RELIANCE"
"NSEIDX:NIFTY_50"
"NSEIDX:INDIA_VIX"
"MCXFUT:CRUDEOILM_I"

Do not pass raw names like "ABB" unless a specific helper script adds the prefix for you.


Function index

from eqldata import (
    DataClient,
    EqualDataError,
    generate_auth_token,
    get_instrument_list,
    get_EOD,
    get_EOD_range,
    get_1MARKET_DATA,
    read_EOD_range_metadata,
    read_EOD_range_csv,
    read_EOD_range_csv_rows,
)
Function Purpose
generate_auth_token() Login and get API token
get_instrument_list() Get instruments available for the account
DataClient Realtime websocket client
get_EOD() Single-day EOD download
get_EOD_range() Date-range EOD ZIP download
get_1MARKET_DATA() 1-minute data for one date
read_EOD_range_metadata() Read metadata from EOD range ZIP
read_EOD_range_csv() Read CSV rows from EOD range ZIP
read_EOD_range_csv_rows() Same as read_EOD_range_csv()

1. Login and generate token

from getpass import getpass
from eqldata import generate_auth_token

email = input("Email: ").strip()
password = getpass("Password: ")

auth_token = generate_auth_token(email, password)

if not auth_token:
    raise SystemExit("Login failed")

print("Login successful")
print("Token length:", len(auth_token))

Production style with error raising:

from getpass import getpass
from eqldata import generate_auth_token, EqualDataError

try:
    auth_token = generate_auth_token(
        input("Email: ").strip(),
        getpass("Password: "),
        raise_on_error=True,
    )
    print("Login successful")

except EqualDataError as e:
    print("API login failed:", e)

2. Get instrument list

from getpass import getpass
from eqldata import generate_auth_token, get_instrument_list

email = input("Email: ").strip()
password = getpass("Password: ")

auth_token = generate_auth_token(email, password)

instruments = get_instrument_list(auth_token)

print(type(instruments))
print(instruments)

Print only NSE equity instruments:

from getpass import getpass
from eqldata import generate_auth_token, get_instrument_list

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

data = get_instrument_list(auth_token)

nseeq = data.get("NSEEQ", []) if isinstance(data, dict) else []

print("NSEEQ count:", len(nseeq))
print("First 20 instruments:")
for item in nseeq[:20]:
    print(item)

3. Realtime websocket data

import json
from getpass import getpass
from eqldata import generate_auth_token, DataClient

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

topics = [
    "NSEIDX:NIFTY_50",
    "NSEIDX:INDIA_VIX",
]

client = DataClient(auth_token, topics)

try:
    while True:
        message = client.listen()
        print("RAW:", message)

        try:
            data = json.loads(message)
            print("JSON:", data)
        except Exception:
            pass

except KeyboardInterrupt:
    print("Stopping...")
    client.stop_listening()
    client.disconnect()

4. Single-day EOD download

Use get_EOD() for one specific date and one or more instruments.

from getpass import getpass
from eqldata import generate_auth_token, get_EOD

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

instruments = [
    "NSEEQ:ABB",
    "NSEIDX:NIFTY_50",
    "NSEIDX:INDIA_VIX",
]

for_date = "2026-06-22"

result = get_EOD(auth_token, instruments, for_date)

print(type(result))
print(result)

Save single-day EOD rows to CSV:

import csv
from getpass import getpass
from eqldata import generate_auth_token, get_EOD

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

instruments = ["NSEEQ:ABB", "NSEIDX:NIFTY_50"]
for_date = "2026-06-22"

result = get_EOD(auth_token, instruments, for_date)

with open("single_day_eod.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(["INSTRUMENT", "DTYYYYMMDD", "OPEN", "HIGH", "LOW", "CLOSE", "VOL", "OPENINT"])

    for group in result:
        for row in group:
            writer.writerow(row)

print("Saved: single_day_eod.csv")

5. EOD range download

Use get_EOD_range() for multiple dates and multiple instruments.

The API returns a ZIP file containing:

EOD_RANGE.csv
EOD_RANGE_META.json

Basic example:

from getpass import getpass
from eqldata import generate_auth_token, get_EOD_range

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

zip_path = get_EOD_range(
    auth_token=auth_token,
    instruments=[
        "NSEEQ:ABB",
        "NSEIDX:NIFTY_50",
        "NSEIDX:INDIA_VIX",
    ],
    from_date="2026-06-10",
    to_date="2026-06-22",
    output_path="EOD_RANGE.zip",
)

print("Downloaded:", zip_path)

EOD range public limits

Limit Value
Maximum instruments per request 500
Maximum calendar days per request 366
Output format ZIP
CSV file inside ZIP EOD_RANGE.csv
Metadata file inside ZIP EOD_RANGE_META.json

If your account has 5, 10, or 20 years of history access, download in yearly chunks.


6. Read EOD range metadata

from getpass import getpass
from eqldata import generate_auth_token, get_EOD_range, read_EOD_range_metadata

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

zip_path = get_EOD_range(
    auth_token,
    ["NSEEQ:ABB", "NSEIDX:NIFTY_50"],
    "2026-06-10",
    "2026-06-22",
    output_path="EOD_RANGE.zip",
)

meta = read_EOD_range_metadata(zip_path)

print(meta)

Example metadata keys may include:

from_date
to_date
symbols_requested
files_scanned
rows_written
format
compression

7. Read EOD range CSV rows

from getpass import getpass
from eqldata import (
    generate_auth_token,
    get_EOD_range,
    read_EOD_range_csv,
)

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

zip_path = get_EOD_range(
    auth_token,
    ["NSEEQ:ABB", "NSEIDX:NIFTY_50"],
    "2026-06-10",
    "2026-06-22",
    output_path="EOD_RANGE.zip",
)

rows = read_EOD_range_csv(zip_path)

print("Rows:", len(rows))
print("First row:", rows[0] if rows else None)

Expected CSV columns:

INSTRUMENT,DTYYYYMMDD,OPEN,HIGH,LOW,CLOSE,VOL,OPENINT

8. Read EOD range ZIP with pandas

from getpass import getpass
import zipfile
import pandas as pd
from eqldata import generate_auth_token, get_EOD_range

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

zip_path = get_EOD_range(
    auth_token=auth_token,
    instruments=["NSEEQ:ABB", "NSEIDX:NIFTY_50"],
    from_date="2026-06-10",
    to_date="2026-06-22",
    output_path="EOD_RANGE.zip",
)

with zipfile.ZipFile(zip_path, "r") as z:
    with z.open("EOD_RANGE.csv") as f:
        df = pd.read_csv(f)

df["DTYYYYMMDD"] = pd.to_datetime(df["DTYYYYMMDD"].astype(str), format="%Y%m%d")

print(df.head())
print(df.tail())
print(df.shape)

Install pandas if needed:

pip install pandas

9. Download multiple years in yearly chunks

Because each EOD range request is capped to 366 calendar days, large history should be downloaded year by year.

from getpass import getpass
from pathlib import Path
from eqldata import generate_auth_token, get_EOD_range

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

instruments = [
    "NSEEQ:ABB",
    "NSEEQ:RELIANCE",
    "NSEIDX:NIFTY_50",
]

ranges = [
    ("2022-01-01", "2022-12-31"),
    ("2023-01-01", "2023-12-31"),
    ("2024-01-01", "2024-12-31"),
    ("2025-01-01", "2025-12-31"),
]

out_dir = Path("eod_yearly_downloads")
out_dir.mkdir(exist_ok=True)

for from_date, to_date in ranges:
    out_file = out_dir / f"EOD_{from_date}_to_{to_date}.zip"

    zip_path = get_EOD_range(
        auth_token=auth_token,
        instruments=instruments,
        from_date=from_date,
        to_date=to_date,
        output_path=out_file,
    )

    print("Downloaded:", zip_path)

10. 1-minute market data

Use get_1MARKET_DATA() for 1-minute data for one date.

from getpass import getpass
from eqldata import generate_auth_token, get_1MARKET_DATA

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

instruments = [
    "NSEIDX:NIFTY_50",
    "NSEIDX:INDIA_VIX",
]

for_date = "2026-06-22"

result = get_1MARKET_DATA(auth_token, instruments, for_date)

print(type(result))
print(result)

Save 1-minute data to CSV:

import csv
from getpass import getpass
from eqldata import generate_auth_token, get_1MARKET_DATA

auth_token = generate_auth_token(input("Email: ").strip(), getpass("Password: "))

result = get_1MARKET_DATA(auth_token, ["NSEIDX:NIFTY_50"], "2026-06-22")

with open("nifty_1min.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(["INSTRUMENT", "TIMESTAMP", "OPEN", "HIGH", "LOW", "CLOSE", "VOL", "OPENINT"])

    for group in result:
        for row in group:
            writer.writerow(row)

print("Saved: nifty_1min.csv")

11. Error handling

Use raise_on_error=True when you want exceptions instead of returned error text.

from getpass import getpass
from eqldata import generate_auth_token, get_EOD_range, EqualDataError

try:
    auth_token = generate_auth_token(
        input("Email: ").strip(),
        getpass("Password: "),
        raise_on_error=True,
    )

    zip_path = get_EOD_range(
        auth_token=auth_token,
        instruments=["NSEEQ:ABB"],
        from_date="2026-06-10",
        to_date="2026-06-22",
        output_path="EOD_RANGE.zip",
        raise_on_error=True,
    )

    print("Downloaded:", zip_path)

except EqualDataError as e:
    print("Equal Solution API error:", e)

except Exception as e:
    print("Unexpected error:", e)

Common API errors:

Error Meaning
INVALID_TOKEN Login again and use the latest token
MAX_DAYS_EXCEEDED Keep EOD range within 366 calendar days
MAX_SYMBOLS_EXCEEDED Keep instruments within 500 per call
HISTORY_RANGE_NOT_ALLOWED Your account is not entitled to that old history
RATE_LIMIT_EXCEEDED Wait and retry later
EOD_RANGE_BUSY Another range job is already running for the user or server

Examples folder

This package includes runnable sample scripts in the examples/ folder:

examples/
  01_login.py
  02_get_instrument_list.py
  03_get_eod_single_day.py
  04_get_eod_range_download_zip.py
  05_get_eod_range_pandas.py
  06_get_1market_data_single_day.py
  07_check_1min_range_save_csv.py
  08_realtime_websocket_subscribe.py
  09_error_handling.py
  10_eod_range_yearly_chunks.py

Run any example like this:

python examples/04_get_eod_range_download_zip.py

Support

For subscription, entitlement, or API access issues, contact Equal Solution support.

Website: https://equalsolution.com

Email: info@equalsolution.com


License

MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

eqldata-1.7.tar.gz (16.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

eqldata-1.7-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file eqldata-1.7.tar.gz.

File metadata

  • Download URL: eqldata-1.7.tar.gz
  • Upload date:
  • Size: 16.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.0

File hashes

Hashes for eqldata-1.7.tar.gz
Algorithm Hash digest
SHA256 e6809ecdd64e4a746ceb914c2b9070955402e0d7d77aa9e453ca3cf50f74e73c
MD5 2aa4359de0bc396bfa3743713be5767d
BLAKE2b-256 6163d49b9d8b83eb8782d18feb9e08037e9a2531f6fef7849e5443c48ea6698b

See more details on using hashes here.

File details

Details for the file eqldata-1.7-py3-none-any.whl.

File metadata

  • Download URL: eqldata-1.7-py3-none-any.whl
  • Upload date:
  • Size: 9.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.0

File hashes

Hashes for eqldata-1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 d9f4ab37e86a361585b77b1b12b8cdf16bd63dd93b8c23f5e55db7df487174e6
MD5 a07f53ddcc705323a0941d41aaddd53e
BLAKE2b-256 2a406e0a659f8967c85a56410f30488671542afcd7af5d7b1b7896f8dac89024

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page