Python True Data Integration (2025)

 import os

import logging
import time
from dotenv import load_dotenv
from truedata import TD_live  # official TrueData client

load_dotenv()

# ---- helpers ----
def _to_kv_string(obj):
    try:
        items = {k: v for k, v in vars(obj).items() if not k.startswith("_")}
    except Exception:
        return repr(obj)
    # stringify safely
    def s(v):
        try:
            return str(v)
        except Exception:
            return repr(v)
    return " ".join(f"{k}={s(items[k])}" for k in sorted(items))

def _first_pair(values):
    # Accept shapes like [(price, qty)] or [price, qty]
    try:
        if isinstance(values, list) and values:
            first = values[0]
            if isinstance(first, (list, tuple)) and len(first) >= 2:
                return first[0], first[1]
            if isinstance(values, list) and len(values) >= 2:
                return values[0], values[1]
    except Exception:
        pass
    return None, None

USER = os.getenv("TD_USER", "tdwsp774")
PASSWORD = os.getenv("TD_PASSWORD", "adithya@774")
SYMBOLS = [s.strip() for s in os.getenv("TD_SYMBOLS", "NIFTY-I,BANKNIFTY-I,SENSEX-I").split(",") if s.strip()]
PORT = int(os.getenv("TD_PORT", "8084"))
# RUN_SECS = int(os.getenv("TD_RUN_SECS", "300"))  # 5 minutes
USE_REPLAY = os.getenv("TD_USE_REPLAY", "0") == "1"

HOST = os.getenv("TD_URL", "push.truedata.in")
if USE_REPLAY:
    HOST = "replay.truedata.in"  # optional replay feed

if not USER or not PASSWORD:
    raise SystemExit("Missing TD_USER/TD_PASSWORD in .env")

def main():
    # DEBUG shows heartbeats, market status, symbol add/remove, etc.
    log_level = logging.DEBUG

    print(f"[TrueData] host={HOST} port={PORT} user={USER}")
    print(f"[TrueData] symbols={SYMBOLS}")

    # Build official client
    td = TD_live(
        USER,
        PASSWORD,
        live_port=PORT,
        url=HOST,
        log_level=log_level,
        log_format="%(message)s",
    )

    # ---- Callbacks (official decorators) ----
    @td.trade_callback
    def on_trade(tick):
        # Safe access across versions
        def pick(obj, *names):
            for name in names:
                if hasattr(obj, name):
                    return getattr(obj, name)
            return None

        symbol = pick(tick, "symbol", "sym")
        ltp = pick(tick, "ltp", "last_price", "price")
        ltq = pick(tick, "ltq", "last_qty", "qty", "quantity")  # per-tick volume
        ts = pick(tick, "timestamp", "ts", "time")

        # Print only symbol, LTP, and LTQ for every tick
        print(f"[TICK] {symbol} | LTP: {ltp} | LTQ: {ltq} | Time: {ts}")

    @td.bidask_callback
    def on_bidask(ba):
        # Be tolerant to field name differences across library versions
        def pick(obj, *names):
            for name in names:
                if hasattr(obj, name):
                    return getattr(obj, name)
            return None

        symbol = pick(ba, "symbol", "sym")
        bid_px = pick(ba, "best_bid_price", "bid_price", "best_bid", "bid")
        bid_qty = pick(ba, "best_bid_qty", "bid_qty", "bid_quantity", "bidqty")
        ask_px = pick(ba, "best_ask_price", "ask_price", "best_ask", "ask")
        ask_qty = pick(ba, "best_ask_qty", "ask_qty", "ask_quantity", "askqty")
        ts = pick(ba, "timestamp", "ts", "time")

        # If library provides lists of (price, qty), normalize
        if isinstance(bid_px, list) and (bid_qty is None):
            px, qty = _first_pair(bid_px)
            if px is not None:
                bid_px, bid_qty = px, qty
        if isinstance(ask_px, list) and (ask_qty is None):
            px, qty = _first_pair(ask_px)
            if px is not None:
                ask_px, ask_qty = px, qty

        print(f"[BIDASK] {symbol} bid={bid_px}@{bid_qty} ask={ask_px}@{ask_qty} ts={ts}")
        # Print all available fields for debugging/inspection
        print("[BIDASK ALL]", _to_kv_string(ba))

    # Optional: minute bars if enabled on your account
    # @td.one_min_bar_callback
    # def on_1m(bar):
    #     print(f"[1M] {bar.symbol} O={bar.open} H={bar.high} L={bar.low} C={bar.close} V={bar.volume} ts={bar.timestamp}")

    # Start stream
    td.start_live_data(SYMBOLS)

    # Run indefinitely; callbacks + library logs will print continuously
    try:
        while True:
            time.sleep(0.25)
            # Example: access latest snapshot on demand
            # for s in SYMBOLS:
            #     snap = td.live_data.get(s)
            #     if snap:
            #         _ = (snap.ltp, snap.best_bid_price, snap.best_ask_price)
    except KeyboardInterrupt:
        print("\nStopping on user request (Ctrl+C)...")
    finally:
        print("[TrueData] stopping & disconnecting…")
        with contextually_silent():
            td.stop_live_data(SYMBOLS)  # remove if your TD_live version doesn’t support this
        td.disconnect()

# small utility to silence library exceptions during shutdown
from contextlib import contextmanager

@contextmanager
def contextually_silent():
    try:
        yield
    except Exception:
        pass




if __name__ == "__main__":
    main()

Comments

Popular posts from this blog

MQL5 : Add time to current time in mins

MQL5 : Get current trading session