Thin Python SDK for external Kite Algo strategy workers
Project description
Kite Algo Worker Python SDK
Kite Algo is a self-hosted algorithmic trading platform for Zerodha/Kite workflows. The Python SDK is the official client for external strategy workers — it calls only public worker API endpoints under /api/algo-workers/worker/* and never touches broker internals, paper-runtime internals, market-runtime internals, or the database directly.
The contract: strategy code owns decisions. Kite Algo owns execution, attribution, grouped accounting, protection state, and journal-visible truth.
Package status and install
python3 -m pip install kite-algo-worker==0.7.4
Extras:
python3 -m pip install "kite-algo-worker[dataframe]==0.7.4"
python3 -m pip install "kite-algo-worker[indicators]==0.7.4"
- base SDK: HTTP/WebSocket clients, typed models, order helpers
dataframeextra: addspandas+numpyforcandles_to_df(...)andohlcv_arrays(...)indicatorsextra: adds dataframe dependencies plus the indicator stack and optionalnumba
Pin to an immutable version in production.
Quick reference
| Family | Primary calls |
|---|---|
| Connection + liveness | AlgoWorkerConfig, KiteAlgoWorkerClient, health(), heartbeat(...) |
| Run lifecycle | create_run(...), get_run(...), RunConfig, client.run(...), ManagedRun, claim_session(...), release_session(...), run_heartbeat(...) |
| Funds + run state | get_funds(...), get_run_funds(...), get_run_health_snapshot(...) |
| Market data | resolve_ticker(...), search_tickers(...), get_quotes(...), stream_ticks(...), get_candles(...), stream_candles(...), get_historical_candles(...) |
| Order types | equity/option market, limit, SL, SL-M across regular, AMO, CO, iceberg, auction varieties |
| Order placement | preview_order(...), place_order(...), cancel_order(...), modify_order(...), order builders |
| Basket execution | preview_basket(...), place_basket(...) |
| Safety + protection | safety_check(...), BackendProtection, update_backend_protection(...), patch_risk(...) |
| Grouped P&L + monitoring | get_run_pnl(...), stream_run_pnl(...), list_timeline(...), log_decision_event(...), stream_timeline(...) |
| Options namespace | client.options.*, resolver helpers, options run lifecycle |
| GTT helpers | place_gtt(...), list_gtts(), get_gtt(...), modify_gtt(...), delete_gtt(...) |
| Exits + recovery | exit_run(...), wait_for_history(...), warmup_history(...), polling helpers |
Connection and authentication
AlgoWorkerConfig
The connection settings for the Kite Algo worker API.
| Field | Type | Required | Description |
|---|---|---|---|
base_url |
str |
yes | Backend URL, e.g. http://localhost:18777 |
token |
str |
yes | Worker token, sent as Authorization: Bearer <token> |
timeout |
float |
no | HTTP timeout in seconds (default 10.0) |
api_prefix |
str |
no | API prefix (default /api/algo-workers) |
Client initialization
from kite_algo_worker import AlgoWorkerConfig, KiteAlgoWorkerClient
client = KiteAlgoWorkerClient(AlgoWorkerConfig(
base_url="http://localhost:18777",
token="kwa_...",
))
Environment variables
| Variable | Purpose | Default |
|---|---|---|
KITE_ALGO_API_BASE |
Backend base URL | http://localhost:18777 |
KITE_ALGO_WORKER_TOKEN |
Worker token | required |
KITE_ALGO_ACCOUNT_SCOPE |
Account scope, e.g. kite:paper-a or kite:<broker_id> |
kite:paper-a |
KITE_ALGO_EXECUTION_MODE |
dry_run, paper, or live |
dry_run |
KITE_ALGO_ENABLE_LIVE |
Live-mode acknowledgement | unset (refuses live without it) |
KITE_ALGO_TIMEOUT |
HTTP timeout seconds | 10 |
Live-mode gate: The worker refuses live execution unless KITE_ALGO_ENABLE_LIVE=1 is set. This is an intentional safety guard.
Health check
client.health()
# Returns: {"status": "healthy"}
Run lifecycle
Every worker strategy operates under one stable strategy_run_id per lifecycle. The backend owns run identity, execution mode, attribution, and exit state.
Two lifecycle styles
| Style | When to use | Session handling |
|---|---|---|
| Raw client | Simple scripts, one-shot tasks, full manual control | You manage everything explicitly |
| Managed lifecycle | Long-running workers, session-aware flows | client.run(...) manages claim/heartbeat/release |
Both styles are valid and fully supported. The managed lifecycle is recommended for longer-lived workers because it handles session plumbing, but it never hides trading decisions.
Raw-client lifecycle
from kite_algo_worker import AlgoWorkerConfig, KiteAlgoWorkerClient, equity_market_order
client = KiteAlgoWorkerClient(AlgoWorkerConfig(
base_url="http://localhost:18777",
token="kwa_...",
))
# 1. Verify connectivity
client.health()
# 2. Create or recover the run
run = client.create_run(
strategy_run_id="run_basic_equity_001",
template_id="basic-equity",
account_scope="kite:paper-a",
execution_mode="paper",
metadata={"strategy_family": "indicator_strategy", "strategy_name": "Basic Equity"},
)
# 3. Place an order
order = equity_market_order("INFY", "BUY", 1)
result = client.place_order(
run["strategy_run_id"], order,
idempotency_key="run_basic_equity_001:entry:001",
)
# 4. Read grouped P&L
pnl = client.get_run_pnl("run_basic_equity_001")
print(pnl["totals"]["net_pnl"])
# 5. Exit when done
client.exit_run("run_basic_equity_001", reason="strategy complete", idempotency_key="run_basic_equity_001:exit:001")
create_run(...)
Creates a strategy run or recovers an existing one by strategy_run_id.
| Field | Type | Required | Description |
|---|---|---|---|
template_id |
str |
yes | Strategy template identifier |
account_scope |
str |
yes | Account scope, e.g. kite:paper-a |
execution_mode |
str |
yes | dry_run, paper, or live |
strategy_run_id |
str |
no | Stable run ID; generated if omitted |
summary_fields |
list[dict] |
no | Display fields for the frontend run card |
risk_schema |
list[dict] |
no | Editable risk controls shown in the frontend |
allowed_actions |
list[str] |
no | Allowed worker actions (default: ["edit_risk", "exit_strategy"]) |
runtime_state |
dict |
no | Initial runtime state, e.g. {"risk": {...}} |
metadata |
dict |
no | Strategy metadata; live runs must include strategy_family, strategy_name, entry_surface |
backend_protection |
BackendProtection |
no | Optional backend-owned protection object |
Response shape:
{
"strategy_run_id": "run_basic_equity_001",
"status": "open",
"execution_mode": "paper",
"account_scope": "kite:paper-a",
"runtime_state": {"risk": {...}},
"metadata": {"strategy_family": "...", "strategy_name": "..."}
}
get_run(...)
Recover the backend-owned run state after restarts.
run = client.get_run("run_basic_equity_001")
Returns the full run payload including status, execution_mode, runtime_state, metadata, and health fields.
Managed lifecycle
For longer-lived workers, use RunConfig, client.run(...), and ManagedRun.
from kite_algo_worker import AlgoWorkerConfig, KiteAlgoWorkerClient, RunConfig, equity_market_order
client = KiteAlgoWorkerClient(AlgoWorkerConfig(
base_url="http://localhost:18777",
token="kwa_...",
))
config = RunConfig(
strategy_run_id="run_managed_001",
template_id="managed-demo",
account_scope="kite:paper-a",
execution_mode="paper",
)
with client.run(config) as run:
safety = run.safety_check()
if not safety.can_trade:
raise SystemExit(f"Blocked: {', '.join(safety.blocking_reasons) or safety.run_status}")
run.place_order(
equity_market_order("INFY", "BUY", 1),
idempotency_key=f"{run.run_id}:entry:001",
safety_token=safety.safety_token,
)
run.heartbeat(metrics={"last_signal": "entry-001"})
What client.run(...) does:
- claims the worker session (if
claim_session=True) - optionally sends an initial heartbeat (if
heartbeat_on_enter=True) - yields a
ManagedRunbound to the session - releases the session on exit (if
release_on_exit=True)
What ManagedRun does NOT do:
- it does NOT auto-exit your strategy
- it does NOT auto-call
safety_check() - it does NOT make trading decisions
Session management (raw client)
If you prefer full control, manage sessions explicitly:
claim = client.claim_session("run_basic_equity_001")
nonce = claim["worker_session_nonce"]
client.run_heartbeat("run_basic_equity_001", session_nonce=nonce)
client.release_session("run_basic_equity_001", session_nonce=nonce)
Funds and run state
get_funds(...)
Account-level funds for the token's account scope. For paper runs this comes from the paper runtime account. For live runs this comes from broker margins through the backend-controlled live Kite session.
| Parameter | Type | Required | Description |
|---|---|---|---|
mode |
str |
no | "paper" (default) or "live" |
account_scope |
str |
no | Override the token's default account scope |
Response shape:
{
"available": {"cash": 100000.0, "collateral": 0.0, "intraday_payin": 0.0},
"utilized": {"debits": 0.0, "exposure": 0.0, "m2m": 0.0, "option_premium": 0.0, "span": 0.0, "holding_sales": 0.0, "turnover": 0.0},
"net": 100000.0
}
funds = client.get_funds(mode="paper")
print(funds["net"])
get_run_funds(strategy_run_id)
Run-level usage derived from backend-owned grouped P&L legs plus optional allocation caps.
run_funds = client.get_run_funds("run_basic_equity_001")
remaining = run_funds.get("strategy", {}).get("allocation", {}).get("remaining")
Response shape:
{
"strategy": {
"allocation": {
"cap": null,
"cap_inr": null,
"usage_gross_exposure": 0.0,
"remaining": null
}
}
}
If run metadata includes allocation_cap or allocation_cap_inr, remaining is computed using current gross exposure as the usage basis.
get_run_health_snapshot(strategy_run_id)
Operational health for a specific run.
snapshot = client.get_run_health_snapshot("run_basic_equity_001")
print(snapshot.health_status, snapshot.session_status, snapshot.recovery_action_required)
Response fields: strategy_run_id, status, execution_mode, account_scope, heartbeat_age_sec, health_status, session_status, recovery_status, recovery_action_required, worker_session_claimed_at, last_heartbeat_at.
Market data
All market data is backend-owned. Workers never open their own broker websocket connections.
resolve_ticker(...) / search_tickers(...)
instrument = client.resolve_ticker("NSE:INFY")
results = client.search_tickers("NIFTY", exchange="NFO", limit=20)
get_quotes(...)
| Parameter | Type | Required | Description |
|---|---|---|---|
instruments |
list[str|int] |
yes | Instrument tokens or EXCH:SYMBOL strings |
mode |
str |
no | "quote" (full), "ltp" (last price only), "full" (all fields) |
Response: a quotes dict keyed by instrument identifier, each containing last_price, ohlc, depth, volume, etc.
quotes = client.get_quotes(["NSE:INFY", "NSE:RELIANCE"], mode="quote")
print(quotes["quotes"]["NSE:INFY"]["last_price"])
get_candles(...)
Reads the worker's recent live/cache candle surface. It is not the full
historical-data API; daily warmups such as interval="day", lookback=366 may be
empty/stale when no live daily cache exists. Use get_historical_candles(...)
for historical daily/intraday ranges.
| Parameter | Type | Required | Description |
|---|---|---|---|
symbol_or_token |
str|int |
yes | Instrument symbol or token |
interval |
str |
no | Candle interval (default "5minute") |
lookback |
int |
no | Number of recent candles (default 50) |
Response: candles list, optional current in-progress candle, is_stale flag.
candles = client.get_candles("NSE:INFY", interval="5minute", lookback=20)
for c in candles["candles"]:
print(c["open"], c["high"], c["low"], c["close"])
get_historical_candles(...)
| Parameter | Type | Required | Description |
|---|---|---|---|
symbol_or_token |
str|int |
yes | Instrument |
timeframe |
str |
no | "day", "5minute", etc. |
from_date |
str |
no | ISO 8601 start |
to_date |
str |
no | ISO 8601 end |
lookback_days |
int |
no | Convenience range in days when from_date is omitted |
ingest |
bool |
no | Trigger background ingestion for missing DB ranges |
passthrough |
bool |
no | Fetch directly from Kite via the controlled system session |
Response: candles, source (e.g. "db", "kite_passthrough"), ingestion metadata.
history = client.get_historical_candles(
"NSE:INFY", timeframe="day",
lookback_days=366,
passthrough=True,
)
Streaming
# Real-time tick stream (SSE)
for event in client.stream_ticks(["NSE:INFY"], mode="quote"):
for tick in event.get("ticks", []):
print(tick["last_price"])
# Real-time candle stream (SSE)
for event in client.stream_candles("NSE:INFY", interval="5minute"):
candle = event.get("current") or event
if candle:
print(candle["close"], candle["is_complete"])
Order types
Order type reference
| order_type | Required fields | Optional fields | Notes |
|---|---|---|---|
MARKET |
exchange, tradingsymbol, transaction_type, product, quantity | disclosed_quantity, market_protection | Default variety is regular |
LIMIT |
...plus price |
disclosed_quantity | |
SL |
...plus price, trigger_price |
disclosed_quantity | |
SL-M |
...plus trigger_price |
disclosed_quantity, market_protection | price is 0 or omitted |
Variety reference
| variety | Behavior | Extra fields |
|---|---|---|
regular |
Standard day order | — |
amo |
After-market order, placed outside market hours | — |
co |
Cover order with mandatory stoploss | squareoff, stoploss, trailing_stoploss |
iceberg |
Sliced large order | iceberg_legs (2–10), iceberg_quantity |
auction |
Auction participation | auction_number |
Product guide
| product | Applicable to |
|---|---|
CNC |
Equity delivery |
MIS |
Intraday equity and F&O |
NRML |
F&O carry-forward |
MTF |
Margin trading facility (equity) |
Validity guide
| validity | Meaning | Extra field |
|---|---|---|
DAY |
Valid for the day (default) | — |
IOC |
Immediate or cancel | — |
TTL |
Time-to-live in minutes | validity_ttl (1–365) |
Field constraints
quantitymust be a positive integerpriceis required forLIMITandSL; omit or0forMARKETandSL-Mtrigger_priceis required forSLandSL-Mdisclosed_quantitycannot exceedquantitymarket_protectionallowed only forMARKETandSL-M; values:-1or0..100iceberg_legs:2..10- AMO cannot be combined with iceberg
- CO orders require
squareoffandstoploss;trailing_stoplossis optional
Never send tag, tags, or attribution. The backend injects attribution metadata.
Order placement
preview_order(...)
Dry-run order validation without placing.
| Field | Type | Required | Description |
|---|---|---|---|
| strategy_run_id | str |
yes | Run identifier |
| order | dict |
yes | Order payload dict |
| metadata | dict |
no | Signal/context metadata |
preview = client.preview_order(
"run_basic_equity_001",
{"exchange": "NSE", "tradingsymbol": "INFY", "transaction_type": "BUY",
"variety": "regular", "product": "CNC", "order_type": "MARKET", "quantity": 1},
)
Response: margin estimate, charges breakdown, validation warnings.
place_order(...)
| Field | Type | Required | Description |
|---|---|---|---|
| strategy_run_id | str |
yes | Run identifier |
| order | dict |
yes | Order payload |
| idempotency_key | str |
yes | Deterministic key to prevent duplicates |
| metadata | dict |
no | Signal/context metadata |
| safety_token | str |
no | Token from safety_check() (managed lifecycle) |
| session_nonce | str |
no | From claim_session() (raw-client managed session) |
result = client.place_order(
"run_basic_equity_001",
{"exchange": "NSE", "tradingsymbol": "INFY", "transaction_type": "BUY",
"variety": "regular", "product": "CNC", "order_type": "MARKET", "quantity": 1},
idempotency_key="run_basic_equity_001:entry:001",
)
Response: order acceptance payload including order_id and status.
Idempotency: Use deterministic keys per intent (e.g. "run_id:entry:symbol:bar_index"). Replaying the same key returns the original result without placing a duplicate order.
cancel_order(...) / modify_order(...) / inspection
client.cancel_order("run_basic_equity_001", "250508000001")
client.modify_order("run_basic_equity_001", "250508000001", {"quantity": 2})
orders = client.list_orders("run_basic_equity_001")
trades = client.list_trades("run_basic_equity_001")
Basket execution
Place multiple orders as a single basket.
preview_basket(...)
| Field | Type | Required | Description |
|---|---|---|---|
| strategy_run_id | str |
yes | Run identifier |
| orders | list[dict] |
yes | List of order payloads |
| metadata | dict |
no | Context metadata |
| all_or_none | bool |
no | If True, all legs must be valid (default False) |
place_basket(...)
| Field | Type | Required | Description |
|---|---|---|---|
| strategy_run_id | str |
yes | Run identifier |
| orders | list[dict] |
yes | List of order payloads |
| idempotency_key | str |
yes | Deterministic basket key |
| metadata | dict |
no | Context metadata |
| all_or_none | bool |
no | Require all legs to succeed |
| dry_run | bool |
no | Preview only, do not place |
| safety_token | str |
no | From safety_check() |
| session_nonce | str |
no | From claim_session() |
from kite_algo_worker import equity_market_order
basket = client.place_basket(
"run_basic_equity_001",
[
equity_market_order("INFY", "BUY", 1),
equity_market_order("RELIANCE", "BUY", 1),
],
idempotency_key="run_basic_equity_001:basket:001",
all_or_none=True,
)
Response: basket acceptance with per-leg results.
Guardrails:
all_or_none=Truemeans the entire basket is rejected if any leg fails validationdry_run=Truepreviews the basket without placing any orders — useful for live operations- Basket keys should be as deterministic as single-order keys
Safety and protection
safety_check(strategy_run_id)
Gatekeeper for guarded trade actions. Must be called before placing orders in managed-lifecycle or session-aware flows.
Response fields:
| Field | Type | Description |
|---|---|---|
can_trade |
bool |
Whether the run is allowed to trade |
safety_token |
str|null |
Opaque token; pass to the guarded action if present |
token_expires_at |
str|null |
ISO 8601 expiry of the safety token |
blocking_reasons |
list[str] |
Human-readable reasons why trading is blocked |
run_status |
str |
Current run status |
generic_protection |
dict |
Backend protection state |
options_protection |
dict |
Options-specific protection state |
evaluated_at |
str |
ISO 8601 timestamp |
Safety flow
# Raw-client flow
claim = client.claim_session("run_managed_001")
safety = client.safety_check("run_managed_001")
if not safety.can_trade:
raise SystemExit(f"Blocked: {safety.blocking_reasons}")
client.place_order(
"run_managed_001",
equity_market_order("INFY", "BUY", 1),
idempotency_key="run_managed_001:entry:001",
safety_token=safety.safety_token,
session_nonce=claim["worker_session_nonce"],
)
Token expiry: If a safety_token is rejected (expired), reacquire it via a new safety_check() call. Do not retry with the stale token.
BackendProtection objects
from kite_algo_worker import BackendProtection, BasketProtection, OperationalProtection, ProtectedPosition
protection = BackendProtection(
positions=[
ProtectedPosition(
symbol="NSE:INFY", product="CNC", side="BUY",
quantity=1, entry_price=1500.0, stoploss_pct=2.0,
)
],
basket=BasketProtection(stoploss_pct=4.0),
operations=OperationalProtection(exit_on_worker_stale=True, worker_stale_sec=300),
)
Protection constraints:
product:CNC,MIS, orNRMLside:BUYorSELL- quantities and prices must be positive
- stale-worker limit:
30..86400seconds - MIS squareoff buffer:
0..3600seconds
update_backend_protection(...) / patch_risk(...)
client.update_backend_protection("run_managed_001", protection, reason="rebalance")
client.patch_risk("run_managed_001", {"stop_loss_pct": 1.0}, reason="volatility adjustment")
Grouped P&L and monitoring
get_run_pnl(strategy_run_id)
Backend-owned grouped run P&L snapshot.
pnl = client.get_run_pnl("run_managed_001")
print(pnl["totals"]["net_pnl"])
Response fields:
| Field | Description |
|---|---|
totals |
net_pnl, gross_pnl, charges, brokerage, taxes |
legs |
Per-leg breakdown (empty for dry_run) |
is_stale |
True if the backend cannot fully confirm live marks |
dry_run returns zero totals and no legs. paper returns grouped paper run P&L. live returns grouped attributed live P&L with charges and live-leg breakdown.
stream_run_pnl(strategy_run_id, interval_seconds=1.0)
SSE stream of grouped run-level P&L updates.
for update in client.stream_run_pnl("run_managed_001", interval_seconds=1.0):
print(update["totals"]["net_pnl"])
list_timeline(strategy_run_id, **params)
Worker-visible run event history.
| Parameter | Type | Description |
|---|---|---|
after_cursor |
int |
Paginate after this cursor |
limit |
int |
Max events to return |
event_kind |
str |
Filter: "execution", "decision", "protection" |
timeline = client.list_timeline_snapshot("run_managed_001", limit=20)
for event in timeline.events:
print(event.event_type, event.summary)
log_decision_event(strategy_run_id, **payload)
Record a worker decision to the backend-owned timeline.
| Field | Type | Required | Description |
|---|---|---|---|
event_type |
str |
yes | e.g. "signal.generated", "risk.updated" |
summary |
str |
yes | One-line description |
details |
dict |
no | Structured context |
related_resource_type |
str |
no | Linked resource type |
related_resource_id |
str |
no | Linked resource ID |
client.log_decision_event(
"run_managed_001",
event_type="signal.generated",
summary="EMA crossover detected on INFY 5min",
details={"symbol": "INFY", "fast_ema": 1450.1, "slow_ema": 1448.3},
)
stream_timeline(strategy_run_id, **params)
SSE stream of timeline events.
for event in client.stream_timeline("run_managed_001"):
print(event["event_type"], event.get("summary"))
Options workflows
Worker options flows use the client.options namespace and resolver helpers. This keeps option selection backend-backed and avoids ad-hoc strike logic in every worker.
Options session and market data
client.options.ensure_session("NIFTY")
expiries = client.options.list_expiries("NIFTY")
chain = client.options.get_chain("NIFTY", expiry="current_week")
greeks = client.options.get_greeks("NIFTY", expiry="nearest")
Resolver helpers
Backend-backed helpers that resolve contracts into OptionExecutionLeg payloads.
from kite_algo_worker import (
resolve_option_leg,
resolve_offset_leg,
resolve_delta_leg,
resolve_spread,
SpreadLegSelection,
SpreadSpec,
)
# Single leg by explicit selection
leg = resolve_option_leg(
client.options, underlying="NIFTY", product="MIS", expiry="current_week",
selection={"option_type": "CE", "strike": 25000},
transaction_type="BUY", lots=1,
)
# By offset from ATM
leg = resolve_offset_leg(
client.options, underlying="NIFTY", product="MIS", expiry="current_week",
option_type="CE", offset="ATM", transaction_type="BUY",
)
# By delta target
leg = resolve_delta_leg(
client.options, underlying="NIFTY", product="MIS", expiry="current_week",
option_type="CE", delta_target=0.30, transaction_type="SELL",
)
# Spread
spread = resolve_spread(
client.options, underlying="NIFTY", product="MIS",
spec=SpreadSpec(
spread_type="vertical_call_spread", expiry="current_week",
legs=[
SpreadLegSelection(selection={"option_type": "CE", "moneyness": "ATM"}, transaction_type="SELL"),
SpreadLegSelection(selection={"option_type": "CE", "moneyness": "+1_strike"}, transaction_type="BUY"),
],
),
)
Important: The resolver helpers construct payloads but do NOT auto-create runs or place trades. You still own the run creation and entry/exit decisions explicitly.
Options run lifecycle
# Create
option_run = client.options.create_run(
strategy_name="Bull Call Spread",
product="MIS",
legs=[leg.model_dump(exclude_none=True) for leg in spread],
protection={"stoploss_pct": 2.0},
)
# Preview entry
preview = client.options.preview_entry(option_run["strategy_run_id"])
# Enter (safety-checked)
enter_result = client.options.enter(
option_run["strategy_run_id"],
safety_token=safety.safety_token,
session_nonce=run.session_nonce,
)
# Protection state
state = client.options.get_protection_state(option_run["strategy_run_id"])
# Exit
client.options.exit(option_run["strategy_run_id"])
GTT helpers
Account-scoped GTT (Good Till Triggered) helpers. These are worker-safe backend passthrough calls — they do not create local state or hidden automation.
place_gtt(...)
| Field | Type | Required | Description |
|---|---|---|---|
type |
str |
yes | "single" or "two-leg" |
condition |
dict |
yes | Trigger condition (exchange, tradingsymbol, trigger_values, last_price) |
orders |
list[dict] |
yes | Orders to place when triggered |
Response: trigger_id (int).
result = client.place_gtt_snapshot({
"type": "single",
"condition": {
"exchange": "NSE", "tradingsymbol": "INFY",
"trigger_values": [1450.0], "last_price": 1448.0,
},
"orders": [{
"exchange": "NSE", "tradingsymbol": "INFY",
"transaction_type": "BUY", "quantity": 1,
"order_type": "LIMIT", "product": "CNC", "price": 1450.0,
}],
})
trigger = client.get_gtt_snapshot(result.trigger_id)
print(trigger.id, trigger.status)
list / get / modify / delete
triggers = client.list_gtts()
client.get_gtt(123)
client.modify_gtt(123, {"condition": {"trigger_values": [1460.0], "last_price": 1455.0}})
client.delete_gtt(123)
Exits and recovery
exit_run(...)
| Field | Type | Required | Description |
|---|---|---|---|
| strategy_run_id | str |
yes | Run identifier |
| reason | str |
no | Human-readable reason |
| idempotency_key | str |
no | Deterministic exit key |
| dry_run | bool |
no | Preview exit without placing orders (safe for live) |
client.exit_run(
"run_basic_equity_001",
reason="target reached",
idempotency_key="run_basic_equity_001:exit:target",
)
For live runs: use dry_run=True first to preview the exit without sending live orders.
Recovery helpers
Small polling helpers for warmup and recovery flows.
from kite_algo_worker import wait_for_history, warmup_history, wait_for_terminal_order_state
# Poll until historical candles are available
history = wait_for_history(client, "NSE:INFY", timeframe="day", attempts=10)
# Poll until minimum candle count for indicator warmup
history = warmup_history(client, "NSE:INFY", timeframe="5minute", min_candles=50)
# Poll until an order reaches a terminal state
order = wait_for_terminal_order_state(client, "run_basic_equity_001", "250508000001")
Additional helpers: wait_for_fresh_candle(...), wait_for_quotes(...), preview_then_place_order(...).
Typical restart flow
get_run(strategy_run_id)— recover backend-owned run statewarmup_history(...)orget_historical_candles(...)— rebuild data context- rebuild local indicator state from historical candles
- reconnect
stream_ticks(...),stream_candles(...), orstream_run_pnl(...)
Order builder helpers
Thin convenience functions that produce standard order payloads. Use these instead of hand-writing full order dicts.
Equity
from kite_algo_worker import equity_market_order
equity_market_order("INFY", "BUY", 1) # CNC, NSE, regular
equity_market_order("INFY", "BUY", 1, product="MIS") # intraday
equity_market_order("INFY", "BUY", 1, variety="amo") # after-market
Generic builders
from kite_algo_worker import market_order, limit_order, sl_order, sl_m_order
market_order("NSE", "INFY", "BUY", "CNC", 1)
limit_order("NSE", "INFY", "BUY", "CNC", 1, price=1450.0)
sl_order("NSE", "INFY", "BUY", "CNC", 1, price=1450.0, trigger_price=1445.0)
sl_m_order("NSE", "INFY", "BUY", "CNC", 1, trigger_price=1445.0)
Options and AMO
from kite_algo_worker import option_market_order, amo_limit_order, amo_market_order
option_market_order("NIFTY26MAY25000CE", "BUY", 75, product="NRML")
amo_limit_order("NSE", "INFY", "BUY", "CNC", 1, price=1450.0)
amo_market_order("NSE", "INFY", "BUY", "CNC", 1)
Full control
from kite_algo_worker import OrderBuilder
OrderBuilder("NSE", "INFY", "BUY", "CNC", 1) \
.market() \
.regular() \
.build()
All helpers accept optional fields: disclosed_quantity, market_protection, validity, validity_ttl, autoslice, and variety-specific fields.
Scenario-driven examples
Start with these canonical examples to understand the different worker patterns:
| Example | Pattern | File |
|---|---|---|
| Basic equity | Raw-client baseline | examples/basic_equity_worker.py |
| Managed lifecycle | Session-aware worker | examples/managed_run_worker.py |
| Mean reversion | Indicator-driven strategy | examples/mean_reversion_worker.py |
| Options spread | Options workflow | examples/option_basket_worker.py |
| Live exit preview | Operational safety | examples/live_exit_preview.py |
| Signal-driven | External decision integration | examples/signal_driven_worker.py |
All examples default to dry_run mode and require explicit live acknowledgement (KITE_ALGO_ENABLE_LIVE=1). They are runnable against a local or remote Kite Algo backend using environment variables.
Release conventions
- App/product tags:
vX.Y.Z - SDK package tags:
kite-algo-worker-vX.Y.Z
The SDK has its own semantic version stream. Backend changes do not force SDK releases.
Publishing a new SDK release
- Update
sdk/python/pyproject.toml - Run
python scripts/check_worker_sdk_version_refs.py - Run the SDK test suite
- Build from
sdk/pythonand runtwine check - Create and push the matching
kite-algo-worker-vX.Y.Ztag
The repo uses GitHub Actions trusted publishing for PyPI.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kite_algo_worker-0.7.4.tar.gz.
File metadata
- Download URL: kite_algo_worker-0.7.4.tar.gz
- Upload date:
- Size: 71.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
107e1108dcea1f58bcbb8985754b4f88bf91c35986ad797c12b68962aa56fa38
|
|
| MD5 |
827891cf1ab9a9ec262079a11e33e163
|
|
| BLAKE2b-256 |
5d85128cce93364439f6034a1385c4275d45b12aadb1e7178d468b527c44bede
|
Provenance
The following attestation bundles were made for kite_algo_worker-0.7.4.tar.gz:
Publisher:
publish-kite-algo-worker.yml on krishna-vinci/kite-algo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kite_algo_worker-0.7.4.tar.gz -
Subject digest:
107e1108dcea1f58bcbb8985754b4f88bf91c35986ad797c12b68962aa56fa38 - Sigstore transparency entry: 1708715117
- Sigstore integration time:
-
Permalink:
krishna-vinci/kite-algo@33d1ba1f8d285a46ccda8d3cf1882aba05b5fd4a -
Branch / Tag:
refs/tags/kite-algo-worker-v0.7.4 - Owner: https://github.com/krishna-vinci
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-kite-algo-worker.yml@33d1ba1f8d285a46ccda8d3cf1882aba05b5fd4a -
Trigger Event:
push
-
Statement type:
File details
Details for the file kite_algo_worker-0.7.4-py3-none-any.whl.
File metadata
- Download URL: kite_algo_worker-0.7.4-py3-none-any.whl
- Upload date:
- Size: 69.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53f201aa7820b5317732a0ff4ff2e3d18c60d77b963530b48aca2fedb5d87120
|
|
| MD5 |
41086bac91906a07b03fe974ff38a9c4
|
|
| BLAKE2b-256 |
833ced01fe564a2cc1032e22d83a5ed589194e85b6babd0eabdbc6219e880def
|
Provenance
The following attestation bundles were made for kite_algo_worker-0.7.4-py3-none-any.whl:
Publisher:
publish-kite-algo-worker.yml on krishna-vinci/kite-algo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kite_algo_worker-0.7.4-py3-none-any.whl -
Subject digest:
53f201aa7820b5317732a0ff4ff2e3d18c60d77b963530b48aca2fedb5d87120 - Sigstore transparency entry: 1708715156
- Sigstore integration time:
-
Permalink:
krishna-vinci/kite-algo@33d1ba1f8d285a46ccda8d3cf1882aba05b5fd4a -
Branch / Tag:
refs/tags/kite-algo-worker-v0.7.4 - Owner: https://github.com/krishna-vinci
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-kite-algo-worker.yml@33d1ba1f8d285a46ccda8d3cf1882aba05b5fd4a -
Trigger Event:
push
-
Statement type: