Skip to main content

Kkunal

A Python library for the Choice FINX Trading API. Supports REST API, Interactive WebSockets (order/trade updates), and Live Price Feed WebSockets (FIX3.0 compressed data).

Installation

pip install kkunal

All dependencies (requests, websockets, pandas) are installed automatically.


Quick Start

from choice_api import ChoiceClient, BASE_URL_OMNE, BASE_URL_FINX

# Default endpoint (https://finxomne.choiceindia.com)
client = ChoiceClient(
    vendor_id="YOUR_VENDOR_ID",
    api_key="YOUR_JWT_BEARER_TOKEN"
)

# Alternate endpoint (https://finx.choiceindia.com)
client = ChoiceClient(
    vendor_id="YOUR_VENDOR_ID",
    api_key="YOUR_JWT_BEARER_TOKEN",
    base_url=BASE_URL_FINX
)

# Login (TOTP flow is handled automatically)
session_id = client.login(mobile_no="1234567890")
print(f"Session ID: {session_id}")

Session Persistence

You can save and reload sessions to avoid logging in repeatedly during the same trading day:

session_file = "my_session.json"

if client.load_session(session_file):
    print("Restored today's session.")
else:
    client.login(mobile_no="1234567890")
    client.save_session(session_file)

Note: Sessions expire daily. load_session will return False if the saved session is from a previous day.


Scrip Master

The Scrip Master CSV is automatically downloaded when you log in. It maps instrument symbols to their tokens, lot sizes, and other metadata.

get_token(symbol, segment=None)

Looks up tokens for a given symbol or description.

  • Without segment: Returns a list of dicts for ALL matching rows across every segment (NSE, BSE, CDS, etc.). Each dict contains Token, Exchange, Segment, Symbol, SecDesc, Series, MarketLot.
  • With segment (e.g., "1", "13"): Returns a single token string for that specific segment, or None if not found.
# Get all matches across all segments
matches = client.scrip_master.get_token("RELIANCE")
for m in matches:
    print(f"Segment: {m['Segment']} — Token: {m['Token']}, Symbol: {m['Symbol']}")
# Segment: 1 — Token: 2885, Symbol: RELIANCE
# Segment: 13 — Token: 500325, Symbol: RELIANCE
# ...

# Get specific segment token
nse_token = client.scrip_master.get_token("RELIANCE", segment="1")
nse_cds_token = client.scrip_master.get_token("RELIANCE", segment="13")

search(name)

Case-insensitive fuzzy search: returns all rows where Symbol or SecDesc contains the given name.

results = client.scrip_master.search("NIFTY")
for r in results:
    print(f"{r['Exchange']} | {r['Symbol']} | Token: {r['Token']}")

get_details(token)

Returns all CSV row details for a given token as a dictionary.

details = client.scrip_master.get_details("2885")
print(details)

get_lot_size(token)

Returns the market lot size for a token.

lot = client.scrip_master.get_lot_size("2885")
print(lot)  # 1 for equity, 250 for NIFTY futures, etc.

Orders

Important: Prices must be in paisa (multiply INR by 100). For F&O orders, qty must be in total shares (multiples of the lot size), not the number of lots.

client.orders.place_order(...)

Parameter Type Description
segment_id int 1 = NSE Cash, 2 = NSE F&O, 3 = BSE Cash
token int Instrument token from Scrip Master
order_type str "RL_LIMIT" = Limit, "SL_LIMIT" = Stop Loss Limit (Note: Market orders are not supported via API)
bs int 1 = Buy, 2 = Sell
qty int Total quantity in shares
price float Price in paisa (e.g., 1300 INR → 130000)
trigger_price float Trigger price in paisa (0 for non-SL orders)
validity int 1 = Day
product_type str "M" = Intraday (Margin), "D" = Delivery/CarryForward
disclosed_qty int Optional. Disclosed quantity (default 0)
response = client.orders.place_order(
    segment_id=1,
    token=2885,
    order_type="RL_LIMIT",
    bs=1,
    qty=1,
    price=130000,
    trigger_price=0,
    validity=1,
    product_type="D"
)

client.orders.modify_order(...)

Modifies an existing order. Requires client_order_no, exchange_order_no, and gateway_order_no from the order book.

response = client.orders.modify_order(
    client_order_no=123456,
    exchange_order_no="1234567890",
    gateway_order_no="1234567890",
    segment_id=1,
    token=2885,
    order_type="RL_LIMIT",
    bs=1,
    qty=1,
    price=130000,
    trigger_price=0,
    validity=1,
    product_type="D"
)

client.orders.cancel_order(...)

Cancels an existing order. Same parameters as modify_order plus optional exchange_order_time.

client.orders.get_order_book()

Returns all orders placed during the current session.

order_book = client.orders.get_order_book()

client.orders.get_order_book_v2()

Returns the order book (version 2 format).

client.orders.get_order_by_no(order_no)

Returns details for a specific order number.

order = client.orders.get_order_by_no(123456)

client.orders.get_trade_book()

Returns all executed trades.

trades = client.orders.get_trade_book()

client.orders.get_order_messages(req_id)

Returns order-related messages for a given request ID.


Portfolio

client.portfolio.get_holdings()

Returns current holdings.

holdings = client.portfolio.get_holdings()

client.portfolio.get_net_position()

Returns net positions.

positions = client.portfolio.get_net_position()

client.portfolio.position_conversion(...)

Converts an open position from one product type to another (e.g., Intraday to Delivery).

Parameter Type Description
segment_id int Exchange segment
token int Instrument token
client_order_no int Client order number
buy_sell int 1 = Buy, 2 = Sell
quantity int Quantity to convert
product_type str Target product type
source_product_type str Current product type

client.portfolio.verify_dis(...)

Verifies eDIS (Electronic Delivery Instruction Slip) for delivery sell orders.

client.portfolio.get_dis_status()

Returns the current DIS verification status.


Funds

client.funds.get_funds_view()

Returns funds summary.

funds = client.funds.get_funds_view()

client.funds.get_funds_view_new()

Returns funds summary in the new format.

client.funds.process_payout(amount, bank_acc_no, product_type=0)

Initiates a fund withdrawal.

client.funds.payment_via_netbanking(amount, bank_acc_no, bank_ifsc_code, return_url, segment_id, product_type=0)

Initiates a net banking payment.

client.funds.payment_via_hdfc_upi(amount, bank_acc_no, user_vpa, segment_id, product_type=0)

Initiates a HDFC UPI payment.

client.funds.check_vpa(user_vpa)

Validates a UPI VPA address.

client.funds.payment_via_razorpay(amount, bank_acc_no, bank_ifsc_code, upi_id, segment_id, payment_type=0, product_type=0)

Initiates a RazorPay payment.

client.funds.payment_ack_response(transaction_id)

Acknowledges a payment transaction.


Market

client.market.get_market_status()

Returns current market status across all segments.

status = client.market.get_market_status()

client.market.get_user_profile()

Returns the authenticated user's profile.

profile = client.market.get_user_profile()

client.market.get_multiple_touchline(multiple_seg_token)

Returns touchline data for multiple instruments.

# Format: "SegmentId1,Token1|SegmentId2,Token2"
touchline = client.market.get_multiple_touchline("1@2885,1@11536")

Historical Data

client.historical.get_historical_data(segment_id, token, from_date, to_date, resolution)

Returns historical OHLCV data as a Pandas DataFrame.

Parameter Type Description
segment_id int Exchange segment
token int Instrument token
from_date str or int Start date ("YYYY-MM-DD" or seconds from 1980)
to_date str or int End date ("YYYY-MM-DD" or seconds from 1980)
resolution str "1" = 1 min, "5" = 5 min, "D" = Daily
df = client.historical.get_historical_data(
    segment_id=1,
    token=2885,
    from_date="2024-01-01",
    to_date="2024-12-31",
    resolution="D"
)
print(df.head())
#                   Time     Open     High      Low    Close   Volume  OI
# 0  2024-01-01 00:00:00  2501.00  2520.50  2490.00  2515.30  1234567   0

The returned DataFrame has columns: Time, Open, High, Low, Close, Volume, OI. Prices are automatically adjusted using the PriceDivisor from the API response.


Technical Indicators

kkunal includes a built-in vectorized Technical Analysis indicator engine based on pandas and numpy. No external C-dependencies required.

Supported Indicators

Category Indicators
Trend SMA, EMA, DEMA, TEMA, WMA, MACD, ADX, Supertrend, Parabolic SAR, Ichimoku Cloud
Momentum RSI, Stochastic Oscillator (%K, %D), CCI, Williams %R
Volatility Bollinger Bands (with %B), ATR, Donchian Channel
Volume VWAP, OBV
Utilities Crossover, Crossunder, Heikin Ashi, Pivot Points (Standard/Fibonacci/Camarilla)

Usage Methods

1. Fetch Historical Data with Indicators in One Step

# All indicators
df = client.historical.get_historical_data_with_indicators(
    segment_id=1, token=2885,
    from_date="2024-01-01", to_date="2024-12-31", resolution="D",
    indicators="all"
)

# Or select specific indicators
df = client.historical.get_historical_data_with_indicators(
    segment_id=1, token=2885,
    from_date="2024-01-01", to_date="2024-12-31", resolution="D",
    indicators=["rsi", "macd", "supertrend", "bb", "ichimoku", "pivot"]
)

2. Apply via client.indicators

df = client.historical.get_historical_data(1, 2885, "2024-01-01", "2024-12-31", "D")

# Add specific indicators
df = client.indicators.add_rsi(df, period=14)
df = client.indicators.add_macd(df)
df = client.indicators.add_supertrend(df, period=10, multiplier=3.0)
df = client.indicators.add_bollinger_bands(df, period=20, std_dev=2.0)
df = client.indicators.add_ichimoku(df)
df = client.indicators.add_parabolic_sar(df)
df = client.indicators.add_pivot_points(df, method="fibonacci")
df = client.indicators.add_heikin_ashi(df)

# Or add all indicators at once (with customizable periods)
df_all = client.indicators.add_all(df, sma_period=50, ema_period=50, rsi_period=21)

3. Standalone Indicator Functions

from choice_api import rsi, macd, supertrend, bollinger_bands, ichimoku, pivot_points

rsi_series = rsi(df, period=14)
macd_df = macd(df, fast_period=12, slow_period=26, signal_period=9)
st_df = supertrend(df, period=10, multiplier=3.0)
bb_df = bollinger_bands(df, period=20, std_dev=2.0)  # Includes BB_PercentB
ichi_df = ichimoku(df)
pp_df = pivot_points(df, method="camarilla")

4. Signal Crossover Detection

from choice_api import crossover, crossunder, ema

ema_9 = ema(df, period=9)
ema_21 = ema(df, period=21)

buy_signals = crossover(ema_9, ema_21)    # EMA 9 crosses above EMA 21
sell_signals = crossunder(ema_9, ema_21)   # EMA 9 crosses below EMA 21

print(f"Buy signals on dates: {df['Time'][buy_signals].tolist()}")

Interactive WebSockets

Receives live order updates, trade confirmations, and market status events.

import asyncio
from choice_api import InteractiveSocketClient

async def main():
    # token is the session_id obtained after login
    ws = InteractiveSocketClient(token=client.session_id)

    ws.on("ORD_NRML", lambda data: print(f"Order Update: {data}"))
    ws.on("TRD_MSG", lambda data: print(f"Trade: {data}"))
    ws.on("MKT_STAT", lambda data: print(f"Market Status: {data}"))

    await ws.connect()

# IMPORTANT: If running in a Jupyter Notebook, use `await main()` instead of `asyncio.run(main())`
if __name__ == "__main__":
    asyncio.run(main())

Event types: ORD_NRML (order updates), TRD_MSG (trade confirmations), MKT_STAT (market open/close).


Price Feed WebSockets (FIX3.0)

Receives live Level 1 (Touchline) and Level 2 (Best Five / Depth) market data via TCP socket with Zlib compression.

import asyncio
from choice_api import PriceFeedSocketClient

async def main():
    feed = PriceFeedSocketClient(
        host=client.bcast_ip,
        port=client.bcast_port,
        vendor_id=client.vendor_id,
        access_token=client.access_token
    )

    # Register callback for live market data
    feed.on_message(lambda data: print(f"Market Data: {data}"))

    # Connect to the feed (automatically sends login)
    asyncio.create_task(feed.connect())
    await asyncio.sleep(2) # Give it a moment to connect

    # Subscribe to touchline and best five data
    feed.subscribe_touchline(client.session_id, segment_id=1, token=2885)
    feed.subscribe_best_five(client.session_id, segment_id=1, token=2885)

    # Keep the task running
    await asyncio.sleep(3600)

# IMPORTANT: If running in a Jupyter Notebook, use `await main()` instead of `asyncio.run(main())`
if __name__ == "__main__":
    asyncio.run(main())

Logoff

client.logoff()

Download files

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

Source Distribution

kkunal-1.2.0.tar.gz (28.5 kB view details)

Uploaded Source

Built Distribution

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

kkunal-1.2.0-py3-none-any.whl (27.6 kB view details)

Uploaded Python 3

File details

Details for the file kkunal-1.2.0.tar.gz.

File metadata

  • Download URL: kkunal-1.2.0.tar.gz
  • Upload date:
  • Size: 28.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for kkunal-1.2.0.tar.gz
Algorithm Hash digest
SHA256 f25f6c16b2aca0581bfaab4429d0db5fe827c3ecbb4ecebca473ff92a5974d8c
MD5 7e3c2895f85ca0ae2679ce2d7415a8db
BLAKE2b-256 6f65ccfa5f5ef18b1ebcdcad7ef7d9cdc2e8fc023bc019ad3d918f454cff9a56

See more details on using hashes here.

Provenance

The following attestation bundles were made for kkunal-1.2.0.tar.gz:

Publisher: publish.yml on SomeshD24/Kkunal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kkunal-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: kkunal-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 27.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for kkunal-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a0ee228b8c30cbb51f5de238f1afcd4d775683515aa548f97c015e16939611ae
MD5 654ab889c1e897e86793621b6be802ad
BLAKE2b-256 314232a907dd305f13d8e089fbeadc7227264f80ca5cd69578bd631c2c0cd18f

See more details on using hashes here.

Provenance

The following attestation bundles were made for kkunal-1.2.0-py3-none-any.whl:

Publisher: publish.yml on SomeshD24/Kkunal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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