Navigation

    SmartAPI Forum
    • Register
    • Login
    • Search
    • Categories
    • Popular
    • Groups
    • FAQs
    • API Docs
    1. Home
    2. tonusri
    T
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    tonusri

    @tonusri

    1
    Reputation
    6
    Posts
    2
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online

    tonusri Follow

    Best posts made by tonusri

    This user hasn't posted anything yet.

    Latest posts made by tonusri

    • angelone-mcp

      angelone-mcp

      AngelOne MCP server
      GitHub Repo

      An MCP (Model Context Protocol) server that wraps Angel One's SmartAPI —
      trading, portfolio, market data, GTT rules, and margin/brokerage — so any MCP
      client (Claude, Claude Code, etc.) can query your account and place orders
      through natural conversation.

      ⚠️ This places real orders on a real trading account. Test with small
      quantities first, and keep in mind Angel One (like most brokers) does not
      let you "undo" a filled order.

      What's included

      • angelone_mcp/client.py – REST client for every documented SmartAPI route:
        auth, orders, positions/holdings, GTT rules, historical candles/OI,
        quotes, option greeks, gainers/losers, margin calculator, brokerage
        estimator. Handles TOTP login, auto re-login on token expiry, and paces
        itself against SmartAPI's documented rate limits (see "Rate limiting"
        below).
      • angelone_mcp/server.py – MCP server exposing 32 tools built on top of
        the client (see full list below).

      1. Prerequisites

      • Python 3.10+
      • An Angel One trading account with SmartAPI access
      • A SmartAPI app created at https://smartapi.angelone.in/ (gives you an API key)
      • TOTP set up on your Angel One account, and the base32 secret used to
        set up that authenticator (not the 6-digit code — the secret behind it).
        You get this once, when you first scan the QR code to enable TOTP; if you
        don't have it saved, you'll need to reset/reconfigure TOTP on your account
        to get a fresh secret.

      2. Install

      cd angelone-mcp
      python3 -m venv .venv
      source .venv/bin/activate        # Windows: .venv\Scripts\activate
      pip install -r requirements.txt
      

      3. Configure credentials

      Set these environment variables (e.g. in a .env file you source, or
      directly in your MCP client config):

      Variable Description
      ANGELONE_API_KEY API key from your SmartAPI app
      ANGELONE_CLIENT_CODE Your Angel One client/trading account code
      ANGELONE_PIN Your login PIN
      ANGELONE_TOTP_SECRET Base32 TOTP secret for your account

      Never commit these to source control. Treat ANGELONE_TOTP_SECRET and
      ANGELONE_PIN like passwords — anyone with them plus your API key can trade
      on your account.

      Optional: running behind an HTTP proxy

      If your machine/network requires an outbound HTTP proxy to reach the
      internet, set:

      Variable Description
      ANGELONE_HTTP_PROXY Proxy URL used for http:// requests, e.g. http://user:pass@proxyhost:8080
      ANGELONE_HTTPS_PROXY Proxy URL used for https:// requests (this is the one that matters — SmartAPI is https-only). Falls back to ANGELONE_HTTP_PROXY if unset.
      ANGELONE_NO_PROXY Optional comma-separated list of hosts to bypass the proxy for

      These are only needed if the standard HTTP_PROXY / HTTPS_PROXY environment
      variables aren't already visible to the server process. That's commonly the
      case for MCP servers, since MCP clients usually launch the server with an
      explicit env block (like the JSON below) instead of inheriting your shell's
      environment — so a proxy configured in your shell won't reach the server
      unless you either add it to that env block yourself under HTTPS_PROXY, or
      use the ANGELONE_* variables above. If neither ANGELONE_HTTP_PROXY nor
      ANGELONE_HTTPS_PROXY is set, the server falls back to the standard
      HTTP_PROXY/HTTPS_PROXY/NO_PROXY variables automatically.

      4. Run it

      Standalone (for testing):

      python -m angelone_mcp.server
      

      It speaks MCP over stdio, so it's meant to be launched by an MCP client, not
      run interactively.

      Claude Desktop / Claude Code config

      Add to your MCP client's config (e.g. claude_desktop_config.json):

      {
        "mcpServers": {
          "angelone": {
            "command": "/absolute/path/to/angelone-mcp/.venv/bin/python",
            "args": ["-m", "angelone_mcp.server"],
            "cwd": "/absolute/path/to/angelone-mcp",
            "env": {
              "ANGELONE_API_KEY": "your_api_key",
              "ANGELONE_CLIENT_CODE": "your_client_code",
              "ANGELONE_PIN": "your_pin",
              "ANGELONE_TOTP_SECRET": "your_base32_totp_secret",
              "ANGELONE_HTTPS_PROXY": "http://user:pass@proxyhost:8080"
            }
          }
        }
      }
      

      Tools exposed

      Session
      login, logout, get_profile

      Orders
      place_order, modify_order, cancel_order, get_order_book,
      get_trade_book, get_individual_order_details

      Portfolio / funds
      get_positions, get_holdings, get_all_holdings, get_rms_limit,
      convert_position

      GTT (Good Till Triggered) rules
      gtt_create_rule, gtt_modify_rule, gtt_cancel_rule, gtt_details,
      gtt_list

      Market data
      get_ltp, get_market_quote, search_scrip, get_candle_data,
      get_oi_data, get_option_greeks, get_gainers_losers,
      get_put_call_ratio, get_oi_buildup, get_nse_intraday_data,
      get_bse_intraday_data

      Margin & brokerage
      get_margin, estimate_charges

      How auth works

      AngelOneClient logs in lazily on the first tool call using
      clientcode + pin + a TOTP generated on the fly from
      ANGELONE_TOTP_SECRET (via pyotp). It caches the resulting jwtToken,
      refreshToken, and feedToken in memory for the life of the process. If any
      call comes back with a 401/403 or a TokenException, it transparently
      re-logs-in once and retries — you don't need to call login yourself unless
      you want to force a fresh session.

      Sessions issued by SmartAPI are valid until midnight IST regardless of
      activity, so a long-running server may still need a fresh login the next day
      — the auto-retry logic handles that automatically on the next call.

      Session persistence across restarts

      A successful login is also cached to a file on disk, so a fresh server
      process doesn't need a fresh TOTP-based login every time it starts (handy
      since TOTP requires the code to be freshly generated — restarting the server
      several times in a row otherwise means several real logins in a row).

      On startup, before serving any tool calls, the server calls
      AngelOneClient.restore_session(), which:

      1. Looks for a previously saved session file. If there isn't one, it does
        nothing further — the client stays in its normal lazy mode and logs in on
        the first tool call, same as before this feature existed.
      2. If a saved session is found, it loads the cached tokens and verifies them
        with a real getProfile call.
      3. If that verification succeeds, the restored session is used as-is — no
        fresh login needed.
      4. If it fails for any reason (expired token, revoked session, corrupt file,
        etc.), the cached tokens are discarded and a normal fresh login runs
        instead.

      Every successful login (fresh or via the automatic 401/403 retry described
      above) re-saves the session file, so it stays current across the whole time
      the server runs, not just at startup. logout deletes the file.

      Variable Description
      ANGELONE_SESSION_PERSIST Set to false/0/no/off to disable session persistence entirely (default: enabled)
      ANGELONE_SESSION_FILE Override the file path used to persist the session. Default: a file under the OS temp directory, named from a hash of your client code (so multiple accounts on the same machine don't collide)

      The session file holds a live access token — not your PIN or TOTP secret,
      but enough to call the API as you until it expires. It's written with
      owner-only file permissions where the OS supports it; treat it as sensitive
      the same way you'd treat any cached login session.

      Rate limiting

      AngelOneClient paces every outgoing call against
      SmartAPI's documented per-endpoint rate limits
      — login and most portfolio reads at 1 request/sec, getProfile at 3/sec,
      quotes/GTT/order-detail lookups at 10/sec, order placement at 20/sec, and so
      on. Limits are per SmartAPI endpoint, not global, so calling different tools
      back-to-back is never slowed down by this — only a repeat call to the same
      endpoint made faster than SmartAPI's own limit allows gets held back, which
      you'd want anyway.

      If SmartAPI reports its own limit was hit regardless (HTTP 403/429, "Access
      denied because of exceeding access rate"), the call backs off and retries a
      few times with increasing delay before giving up — and that response no
      longer gets misread as an expired session and doesn't trigger a spurious
      extra login the way it used to.

      This applies to every tool automatically; there's nothing to configure to
      get it. To turn client-side pacing off entirely (SmartAPI still enforces its
      own limits server-side either way — this only controls whether the client
      tries to stay under them proactively):

      Variable Description
      ANGELONE_RATE_LIMIT_DISABLED Set to true/1/yes/on to disable proactive pacing (default: enabled)

      Testing

      pip install -e ".[test]"
      
      # Offline: verifies the server registers the expected tools. No credentials
      # or network access needed.
      python -m pytest tests/test_tool_registration.py -v
      
      # Offline: unit tests for session persistence (login state cached to disk,
      # restored + verified via get_profile on restart, falls back to a fresh
      # login when the cache is missing/invalid). Uses a fake HTTP layer - no
      # credentials or network access needed.
      python -m pytest tests/test_session_persistence.py -v
      
      # Offline: unit tests for AngelOneClient's own rate limiting (pacing per
      # ROUTE_MIN_INTERVAL, backoff/retry on a 403/429 rate-limit response, and
      # that such a response is never misread as an expired session). Uses a fake
      # HTTP layer - no credentials or network access needed.
      python -m pytest tests/test_client_rate_limiting.py -v
      
      # Live, read-only smoke test against your real account. Calls get_profile,
      # get_order_book, get_holdings, search_scrip, get_ltp, etc. through the
      # actual MCP server subprocess, plus a check that a session survives a
      # restart of the server without calling the "login" tool again. Never calls
      # place_order/modify_order/cancel_order/gtt_create_rule/gtt_modify_rule/
      # gtt_cancel_rule/convert_position/logout - a SafeSession wrapper
      # hard-asserts those are never invoked. On top of the server's own rate
      # limiting (see "Rate limiting" above), the test itself also paces its tool
      # calls and backs off/retries if the API reports one was hit anyway (see
      # "Rate limiting in the live test" below) - belt and suspenders. Requires
      # ANGELONE_API_KEY/ANGELONE_CLIENT_CODE/ANGELONE_PIN/ANGELONE_TOTP_SECRET
      # to be set; skips automatically if they aren't.
      python -m pytest tests/test_readonly_live.py -v -s
      # or, for a plain-text report without pytest:
      python tests/test_readonly_live.py
      

      Rate limiting in the live test

      The live test (tests/test_readonly_live.py) calls a real account against
      the real SmartAPI. The server it drives already paces itself (see "Rate
      limiting" above), but the test adds its own independent pacing on top -
      useful because it also exercises things the server-side limiter doesn't see
      by itself, like two separate server subprocesses (the session-persistence
      check) hitting the same account back to back:

      • A RateLimiter tracks the last time each MCP tool was called and, before
        calling it again, waits out the rest of that endpoint's minimum interval
        (1/req-per-second-limit, plus a ~20% safety margin). Distinct tools hit
        distinct SmartAPI endpoints with independent limits, so this only ever
        delays a repeat call to the same tool (e.g. get_profile being called
        again by the second server spawn in the session-persistence check) - a
        normal single pass through the suite, where every tool is called once or
        twice, isn't slowed down by it in practice.
      • If SmartAPI reports a rate limit was hit anyway (HTTP 403, "Access denied
        because of exceeding access rate"), the test backs off and retries a
        couple of times with increasing delay instead of failing outright.
      • This governs the test suite's own request pace only - it has no effect on
        how the MCP server behaves for a real MCP client (Claude, etc.); SmartAPI
        still enforces its limits server-side either way.

      Notes / limitations

      • Order params (price, quantity, etc.) are passed as strings, matching
        what SmartAPI's placeOrder expects.
      • get_margin and estimate_charges take a list of position/order dicts —
        see the SmartAPI docs for exact field names per instrument type
        (https://smartapi.angelone.in/docs/Margin, .../Brokerage).
      • Rate limits are enforced by Angel One per endpoint; see
        https://smartapi.angelone.in/docs/RateLimit. This server does not do its
        own client-side rate limiting.
      • Not affiliated with or endorsed by Angel One / Angel Broking.
      posted in General Discussion
      T
      tonusri
    • RE: Instrument master fields interpretation

      @admin How to interpret the Currency segment ?
      Can you explain me how to interpret strike and tick_size values

      {
          "token": "5045",
          "symbol": "USDINR2191777.25PE",
          "name": "USDINR",
          "expiry": "17SEP2021",
          "strike": "772500000.000000",
          "lotsize": "1",
          "instrumenttype": "OPTCUR",
          "exch_seg": "CDS",
          "tick_size": "25000.000000"
        }
      
      posted in Python SDK
      T
      tonusri
    • RE: Instrument master fields interpretation

      @admin It's been 13 days I have posted the issue. Still waiting for the resolution.

      posted in Python SDK
      T
      tonusri
    • RE: Instrument master fields interpretation

      @tonusri said in Instrument master fields interpretation:

      @admin I think you got my question wrong.

      {
          "token": "37743",
          "symbol": "NIFTY02SEP2117500PE",
          "name": "NIFTY",
          "expiry": "02SEP2021",
          "strike": "1750000.000000",
          "lotsize": "50",
          "instrumenttype": "OPTIDX",
          "exch_seg": "NFO",
          "tick_size": "5.000000"
        }
      

      In this above snippet a nifty 17500 put option is have strike value as "1750000.000000" and tick_size value as "5.000000" why ?

      This JSON snippet is from this
      link https://margincalculator.angelbroking.com/OpenAPI_File/files/OpenAPIScripMaster.json

      And similarly

      {
          "token": "5045",
          "symbol": "USDINR2191777.25PE",
          "name": "USDINR",
          "expiry": "17SEP2021",
          "strike": "772500000.000000",
          "lotsize": "1",
          "instrumenttype": "OPTCUR",
          "exch_seg": "CDS",
          "tick_size": "25000.000000"
        }
      

      In this one USDINR 77.25 put option is having strike value as "772500000.000000" and tick_size value as "25000.000000" why ?

      How to calculate the actual strike price and tick size from these fields ?

      @admin still waiting for your reply

      posted in Python SDK
      T
      tonusri
    • RE: Instrument master fields interpretation

      @admin I think you got my question wrong.

      {
          "token": "37743",
          "symbol": "NIFTY02SEP2117500PE",
          "name": "NIFTY",
          "expiry": "02SEP2021",
          "strike": "1750000.000000",
          "lotsize": "50",
          "instrumenttype": "OPTIDX",
          "exch_seg": "NFO",
          "tick_size": "5.000000"
        }
      

      In this above snippet a nifty 17500 put option is have strike value as "1750000.000000" and tick_size value as "5.000000" why ?

      This JSON snippet is from this
      link https://margincalculator.angelbroking.com/OpenAPI_File/files/OpenAPIScripMaster.json

      And similarly

      {
          "token": "5045",
          "symbol": "USDINR2191777.25PE",
          "name": "USDINR",
          "expiry": "17SEP2021",
          "strike": "772500000.000000",
          "lotsize": "1",
          "instrumenttype": "OPTCUR",
          "exch_seg": "CDS",
          "tick_size": "25000.000000"
        }
      

      In this one USDINR 77.25 put option is having strike value as "772500000.000000" and tick_size value as "25000.000000" why ?

      How to calculate the actual strike price and tick size from these fields ?

      posted in Python SDK
      T
      tonusri
    • Instrument master fields interpretation

      @admin @administrators

      I downloaded instrument list from this URI https://margincalculator.angelbroking.com/OpenAPI_File/files/OpenAPIScripMaster.json

      can you explain me how to interpret strike and tick_size values

      {
          "token": "37743",
          "symbol": "NIFTY02SEP2117500PE",
          "name": "NIFTY",
          "expiry": "02SEP2021",
          "strike": "1750000.000000",
          "lotsize": "50",
          "instrumenttype": "OPTIDX",
          "exch_seg": "NFO",
          "tick_size": "5.000000"
        }
      

      can you explain me how to interpret tick_size value

      {
          "token": "16669",
          "symbol": "BAJAJ-AUTO-EQ",
          "name": "BAJAJ-AUTO",
          "expiry": "",
          "strike": "-1.000000",
          "lotsize": "1",
          "instrumenttype": "",
          "exch_seg": "NSE",
          "tick_size": "5.000000"
        }
      

      can you explain me how to interpret strike and tick_size values

      {
          "token": "5045",
          "symbol": "USDINR2191777.25PE",
          "name": "USDINR",
          "expiry": "17SEP2021",
          "strike": "772500000.000000",
          "lotsize": "1",
          "instrumenttype": "OPTCUR",
          "exch_seg": "CDS",
          "tick_size": "25000.000000"
        }
      
      
      posted in Python SDK
      T
      tonusri