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

Sample projects folder

Version 1.7.1 also includes more complete sample projects in the source distribution. These projects are useful for clients who want a ready copy-paste starting point instead of only short code snippets.

sample_projects/
  eod_range_pandas_project/
    main.py
    README.md
    requirements.txt

  one_minute_history_checker_project/
    main.py
    README.md
    requirements.txt

  realtime_websocket_project/
    main.py
    README.md
    requirements.txt

EOD range pandas project

This project logs in, downloads EOD range ZIP data, reads EOD_RANGE.csv, converts the date column, and saves the final pandas DataFrame to CSV.

cd sample_projects/eod_range_pandas_project
pip install -r requirements.txt
python main.py

1-minute history checker project

This project checks 1-minute historical data date-by-date, saves daily CSV files, and writes a merged CSV file.

cd sample_projects/one_minute_history_checker_project
pip install -r requirements.txt
python main.py

Realtime websocket project

This project logs in and subscribes to live market data using DataClient.

cd sample_projects/realtime_websocket_project
pip install -r requirements.txt
python main.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.1.tar.gz (19.4 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.1-py3-none-any.whl (10.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: eqldata-1.7.1.tar.gz
  • Upload date:
  • Size: 19.4 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.1.tar.gz
Algorithm Hash digest
SHA256 0879d965311967406d5fa6f06c0ff80556f7630de58b507410acd3864347905f
MD5 afcbbc27df66900c7f5eb846ec777033
BLAKE2b-256 4db8a39b61ba4502a5c4ed29f71767f1036b810606f3fb0f50cd57087de185c5

See more details on using hashes here.

File details

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

File metadata

  • Download URL: eqldata-1.7.1-py3-none-any.whl
  • Upload date:
  • Size: 10.1 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c23175121c478e58c4c9a9747d62e1a6757944c08f0bf902e88889e8a045a039
MD5 2c7a8425986dc7a264555b7669e816b0
BLAKE2b-256 8d01a518692514fb394ba2fecac057962cc19a8b6571548fba52c21277d157f3

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