DhanHQ on Google Colab with a ServLoci static IP¶
Run these cells from top to bottom. The notebook installs dependencies before enabling the broker-only route, reads credentials from Colab Secrets, verifies the assigned IPv6, creates a DhanHQ 2.2 client, and performs one read-only API call.
Create these secrets in Colab's key icon before running:
STATIC_IP_TOKEN— the latestsl_live_...token from the ServLoci portalDHAN_CLIENT_ID— your Dhan client IDDHAN_ACCESS_TOKEN— your current Dhan access token
Grant this notebook access to all three secrets. No secret value is printed.
1. Clear stale version 0.3.0 notebook state¶
import os
import sys
SMOKE_TEST = "--smoke" in sys.argv # used only by the automated Colab CLI test
PROXY_KEYS = (
"ALL_PROXY", "all_proxy",
"HTTP_PROXY", "http_proxy",
"HTTPS_PROXY", "https_proxy",
)
# A rerun after trading-static-ip 0.3.0 may retain both monkey patches and
# proxy variables. Undo them before pip contacts pypi.org/simple/*.
if "servloci" in sys.modules:
try:
sys.modules["servloci"].unconfigure()
except Exception:
pass
for key in PROXY_KEYS:
if "comm.servloci.in:1080" in os.environ.get(key, ""):
os.environ.pop(key, None)
assert not any("comm.servloci.in:1080" in os.environ.get(k, "") for k in PROXY_KEYS)
print("Clean start: package installation will use Colab's direct connection.")
2. Install the fixed SDK and DhanHQ¶
import subprocess
subprocess.check_call([
sys.executable, "-m", "pip", "install", "-q", "--upgrade",
"trading-static-ip==0.3.1", "dhanhq==2.2.0",
])
print("Dependencies installed.")
3. Load Colab Secrets¶
import importlib
import servloci
# Handles a deliberate top-to-bottom rerun without requiring another runtime restart.
servloci = importlib.reload(servloci)
assert servloci.__version__ == "0.3.1", servloci.__version__
if SMOKE_TEST:
STATIC_IP_TOKEN = "sl_live_colab_cli_smoke_test"
DHAN_CLIENT_ID = "1000000000"
DHAN_ACCESS_TOKEN = "dhan_cli_smoke_test"
else:
from google.colab import userdata
def required_secret(name):
value = userdata.get(name)
if not value:
raise ValueError(f"Missing Colab secret: {name}")
return value.strip()
STATIC_IP_TOKEN = required_secret("STATIC_IP_TOKEN")
DHAN_CLIENT_ID = required_secret("DHAN_CLIENT_ID")
DHAN_ACCESS_TOKEN = required_secret("DHAN_ACCESS_TOKEN")
if not STATIC_IP_TOKEN.startswith("sl_live_"):
raise ValueError("STATIC_IP_TOKEN must be the latest sl_live_... portal token")
print("Secrets loaded without displaying their values.")
4. Record Colab's direct IP, then enable ServLoci¶
import requests
direct_ip = None
if not SMOKE_TEST:
direct_ip = requests.get("https://api.ipify.org", timeout=20).text.strip()
print("Direct Colab IP:", direct_ip)
route = servloci.configure(
token=STATIC_IP_TOKEN,
broker="dhan",
)
# 0.3.1 patches requests/HTTPX without leaking SOCKS settings to pip subprocesses.
assert not any("comm.servloci.in:1080" in os.environ.get(k, "") for k in PROXY_KEYS)
print("ServLoci transport enabled for Dhan; pip remains direct.")
5. Verify the assigned static IPv6¶
import ipaddress
if SMOKE_TEST:
print("Colab CLI smoke mode: live token/IP check skipped.")
else:
static_ip = requests.get("https://api.ipify.org", timeout=20).text.strip()
parsed = ipaddress.ip_address(static_ip)
assert parsed.version == 6, f"Expected the assigned IPv6, received {static_ip}"
assert static_ip != direct_ip, "ServLoci route did not change the observed IP"
print("ServLoci static IPv6:", static_ip)
6. Create the DhanHQ 2.2 client¶
# DhanHQ 2.2 uses DhanContext; older keyword-only examples no longer apply.
from dhanhq import DhanContext, dhanhq
dhan_context = DhanContext(DHAN_CLIENT_ID, DHAN_ACCESS_TOKEN)
dhan = dhanhq(dhan_context)
# DhanHQ created its own requests.Session after configure(), so its internal
# HTTPS calls are transparently routed through the ServLoci static IP.
assert dhan.dhan_http.session is not None
print("DhanHQ client ready through ServLoci.")
7. Run a safe, read-only Dhan call¶
if SMOKE_TEST:
print("Colab CLI smoke mode: authenticated Dhan call skipped.")
else:
result = dhan.get_fund_limits()
status = result.get("status") if isinstance(result, dict) else None
if status != "success":
raise RuntimeError(f"Dhan read-only call failed: {result.get('remarks', result)}")
print("Dhan read-only call succeeded. Response data is intentionally hidden.")
8. Optional order template — dry run only¶
order = {
"security_id": "1333", # example only; verify the current instrument ID
"exchange_segment": dhan.NSE,
"transaction_type": dhan.BUY,
"quantity": 1,
"order_type": dhan.MARKET,
"product_type": dhan.INTRA,
"price": 0,
}
DRY_RUN = True
if DRY_RUN:
print("DRY RUN — no order sent:", order)
else:
raise RuntimeError("Review risk, symbol, quantity, and market status before enabling live orders.")
Finished¶
Your DhanHQ requests.Session is now routed through the assigned ServLoci IPv6.
Keep DRY_RUN = True until you have separately validated permissions, instrument
IDs, quantities, risk limits, and the broker's current order fields.
When you are finished with broker traffic, restore normal transports with:
servloci.unconfigure()