Guide
Automated strategies
Write a strategy, backtest it on past days, run it on paper accounts, then take it live.
A strategy is a document: what to trade, when to enter, and how to manage risk. You save it, test it on history and on paper with live prices, and only then put real money on it.
1. Create a strategy #
Send the document. It is saved as a draft; problems come back per field in plain words. Start from a template if you like.
curl -X POST "https://cirrus.pocketful.in/v2/strategies" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"document": {
"schema_version": 1,
"kind": "cirrus.strategy",
"metadata": {
"name": "NIFTY straddle",
"tags": [
"weekly"
]
},
"spec": {
"underlying": {
"name": "NIFTY",
"exchange": "NFO"
},
"legs": {
"selector": "chain@1",
"items": [
{
"id": "sc",
"instrument": "option",
"side": "sell",
"option_type": "call",
"expiry": {
"kind": "weekly"
},
"strike": {
"by": "atm"
}
},
{
"id": "sp",
"instrument": "option",
"side": "sell",
"option_type": "put",
"expiry": {
"kind": "weekly"
},
"strike": {
"by": "atm"
}
}
]
},
"entry": {
"window": {
"start": "09:30",
"end": "13:30"
}
},
"risk": {
"combined": {
"type": "combined@1",
"stop_loss": {
"rupees": 3000
},
"target": {
"rupees": 2000
}
}
}
}
}
}'import os
import requests
response = requests.post(
"https://cirrus.pocketful.in/v2/strategies",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
json={
"document": {
"schema_version": 1,
"kind": "cirrus.strategy",
"metadata": {
"name": "NIFTY straddle",
"tags": [
"weekly",
],
},
"spec": {
"underlying": {
"name": "NIFTY",
"exchange": "NFO",
},
"legs": {
"selector": "chain@1",
"items": [
{
"id": "sc",
"instrument": "option",
"side": "sell",
"option_type": "call",
"expiry": {
"kind": "weekly",
},
"strike": {
"by": "atm",
},
},
{
"id": "sp",
"instrument": "option",
"side": "sell",
"option_type": "put",
"expiry": {
"kind": "weekly",
},
"strike": {
"by": "atm",
},
},
],
},
"entry": {
"window": {
"start": "09:30",
"end": "13:30",
},
},
"risk": {
"combined": {
"type": "combined@1",
"stop_loss": {
"rupees": 3000,
},
"target": {
"rupees": 2000,
},
},
},
},
},
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v2/strategies', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"document": {
"schema_version": 1,
"kind": "cirrus.strategy",
"metadata": {
"name": "NIFTY straddle",
"tags": [
"weekly"
]
},
"spec": {
"underlying": {
"name": "NIFTY",
"exchange": "NFO"
},
"legs": {
"selector": "chain@1",
"items": [
{
"id": "sc",
"instrument": "option",
"side": "sell",
"option_type": "call",
"expiry": {
"kind": "weekly"
},
"strike": {
"by": "atm"
}
},
{
"id": "sp",
"instrument": "option",
"side": "sell",
"option_type": "put",
"expiry": {
"kind": "weekly"
},
"strike": {
"by": "atm"
}
}
]
},
"entry": {
"window": {
"start": "09:30",
"end": "13:30"
}
},
"risk": {
"combined": {
"type": "combined@1",
"stop_loss": {
"rupees": 3000
},
"target": {
"rupees": 2000
}
}
}
}
}
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "01M574VKA19TCCDQSGVJ9EN831",
"name": "NIFTY straddle",
"description": "",
"tags": [
"weekly"
],
"display_status": "draft",
"latest_version": 0,
"revision": 1,
"visibility": "private",
"forked_from": null,
"archived": false,
"deployments": {
"active": 0,
"paused": 0,
"error": 0,
"stopped": 0
},
"summary": "Sell 1 lot of an ATM call (weekly expiry) and sell 1 lot of an ATM put (weekly expiry) on NIFTY. Enter as soon as the window opens, between 09:30 and 13:30, Monday to Friday. Everything closes at 15:15. Size: the legs' lots times each account's multiplier, at most 10 lots per leg. Orders: hedges first when there are any, limit prices 0.5% beyond the market, chasing up to 1% slippage; if only some legs fill: close a sold option left without its hedge, keep the rest. Protection: stop at ₹3,000 loss, take ₹2,000 profit; no per-leg stops; at most 3 trades a day. No re-entries.",
"deployable": true,
"blockers": [],
"warnings": [],
"schema_version": 1,
"draft": {
"$schema": "/v2/strategies/schema/1.json",
"schema_version": 1,
"kind": "cirrus.strategy",
"metadata": {
"name": "NIFTY straddle",
"description": "",
"tags": [
"weekly"
]
},
"spec": {
"underlying": {
"name": "NIFTY",
"exchange": "NFO",
"reference": "future"
},
"watch": {},
"positional": false,
"legs": {
"selector": "chain@1",
"items": [
{
"id": "sc",
"instrument": "option",
"side": "sell",
"option_type": "call",
"expiry": {
"kind": "weekly",
"n": 0
},
"strike": {
"by": "atm",
"offset": 0
},
"lots": 1,
"hedge_for": null,
"risk": null,
"liquidity": {
"max_spread_pct": 3,
"min_oi": 0,
"min_premium": 1
}
},
{
"id": "sp",
"instrument": "option",
"side": "sell",
"option_type": "put",
"expiry": {
"kind": "weekly",
"n": 0
},
"strike": {
"by": "atm",
"offset": 0
},
"lots": 1,
"hedge_for": null,
"risk": null,
"liquidity": {
"max_spread_pct": 3,
"min_oi": 0,
"min_premium": 1
}
}
]
},
"entry": {
"source": {
"type": "conditions@1",
"when": null,
"on": "close",
"hold_s": 0
},
"window": {
"start": "09:30",
"end": "13:30"
},
"skip_first_min": 0,
"skip_last_min": 0,
"days": [
"mon",
"tue",
"wed",
"thu",
"fri"
],
"expiry_day": "normal",
"active_from": null,
"active_until": null
},
"exit": {
"sources": [],
"square_off": "15:15",
"expiry_day_exit": null,
"max_hold_min": null
},
"sizing": {
"type": "fixed_lots@1",
"max_lots": 10
},
"execution": {
"type": "protected_limit@1",
"order": "auto",
"hedge_wait_ms": 5000,
"stagger_ms": 0,
"buffer_pct": 0.5,
"chase": {
"every_ms": 1000,
"max_slippage_pct": 1,
"max_attempts": 10
},
"on_incomplete": "safest",
"retry_next_signal": null
},
"risk": {
"per_leg": {
"type": "per_leg@1",
"stop_loss": null,
"target": null,
"trail": null,
"on_leg_stop": "nothing",
"at_broker": false
},
"combined": {
"type": "combined@1",
"scope": "account",
"basis": "rupees",
"stop_loss": {
"rupees": 3000
},
"target": {
"rupees": 2000
},
"breakeven": null,
"trail": null,
"lock_ladder": [],
"deployment": null
},
"limits": {
"type": "limits@1",
"max_loss_per_day": null,
"max_profit_per_day": null,
"max_loss_per_week": null,
"max_cycles_per_day": 3,
"max_orders_per_day": 50,
"exit_on_limit": true,
"on_breaker": "nothing"
}
},
"reentry": {
"on": [],
"max": 0,
"delay_s": 300,
"require_fresh_signal": true,
"same_direction_only": true,
"until": null
},
"adjustments": [],
"notify": [],
"costs": {
"model": "auto",
"slippage_pct": null
}
}
},
"created_at": "2026-10-18T09:18:04.097Z",
"updated_at": "2026-10-18T09:18:04.097Z"
},
"error": null
}Check a document without saving it with validate, or see what it would do right now with dry-run.
2. Backtest it #
Run a saved version over past days (up to 366). It runs the same engine as live trading on 1-minute history. Poll the backtest until it finishes, then read its trades.
curl -X POST "https://cirrus.pocketful.in/v2/backtests" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"strategy_id": "01M59PT8JWJCXWS94297VJ7A4Q",
"version": 1,
"from": "2026-10-14",
"to": "2026-10-16",
"capital": 500000,
"costs": {
"charges": "india",
"slippage_bps": 2
}
}'import os
import requests
response = requests.post(
"https://cirrus.pocketful.in/v2/backtests",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
json={
"strategy_id": "01M59PT8JWJCXWS94297VJ7A4Q",
"version": 1,
"from": "2026-10-14",
"to": "2026-10-16",
"capital": 500000,
"costs": {
"charges": "india",
"slippage_bps": 2,
},
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v2/backtests', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"strategy_id": "01M59PT8JWJCXWS94297VJ7A4Q",
"version": 1,
"from": "2026-10-14",
"to": "2026-10-16",
"capital": 500000,
"costs": {
"charges": "india",
"slippage_bps": 2
}
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "01M59PT8KPYQBV80ZN03CSEDSQ",
"strategy_id": "01M59PT8JWJCXWS94297VJ7A4Q",
"version": 1,
"status": "queued",
"from": "2026-10-14",
"to": "2026-10-16",
"capital": 500000,
"costs": {
"charges": "india",
"slippage_bps": 2,
"spread_proxy_bps": 10
},
"progress": {
"done": 0,
"total": 0
},
"cancel_requested": false,
"created_at": "2026-10-19T09:10:23.610Z",
"started_at": null,
"finished_at": null,
"expires_at": "2026-11-18T09:10:23.610Z",
"error": null,
"summary": null,
"labels": null,
"sources": [],
"counts": {
"trades": 0,
"cycles": 0
}
},
"error": null
}GET /v2/backtests/{backtest_id}: status and results.GET /v2/backtests/{backtest_id}/trades: every simulated trade.- At most 3 queued or running at once, 50 a day.
3. Run it on paper #
Deploy on Paper accounts for a forward test: live prices, simulated money. Up to 4 accounts, each with its own size multiplier.
curl -X POST "https://cirrus.pocketful.in/v2/strategies/<strategy_id>/deployments" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mode": "paper",
"accounts": [
{
"account": "P1"
},
{
"account": "P2",
"multiplier": 2
}
]
}'import os
import requests
response = requests.post(
"https://cirrus.pocketful.in/v2/strategies/<strategy_id>/deployments",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
json={
"mode": "paper",
"accounts": [
{
"account": "P1",
},
{
"account": "P2",
"multiplier": 2,
},
],
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v2/strategies/<strategy_id>/deployments', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"mode": "paper",
"accounts": [
{
"account": "P1"
},
{
"account": "P2",
"multiplier": 2
}
]
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "01M574VKAX6MG5BY1HWXCDNNDJ",
"strategy_id": "01M574VKA1TTA2BFREM70ZEB9D",
"strategy_name": "NIFTY manual straddle",
"version": 1,
"mode": "paper",
"status": "active",
"status_reason": null,
"strategy_tag": "auto.01M574VKAX6M",
"accounts": [
{
"account": "P1",
"multiplier": 1
},
{
"account": "P2",
"multiplier": 2
}
],
"units": [
{
"account": "P1",
"unit_id": "01M574VKAXNYV06E6HEBZ5VV48",
"status": "active",
"status_reason": null
},
{
"account": "P2",
"unit_id": "01M574VKAXHVS1Y56YFHHSRT9D",
"status": "active",
"status_reason": null
}
],
"start_on": null,
"end_on": null,
"acknowledged": [],
"compiled_hash": "sha256:93332f0feac143d79d9430ca8c247082ad8af7ca2820ba1492bc4af7a3c61937",
"last_intent": {
"action": "deploy",
"exit_now": false,
"at": "2026-10-18T09:18:04.130Z",
"delivered": false
},
"engine_connected": false,
"created_at": "2026-10-18T09:18:04.125Z",
"updated_at": "2026-10-18T09:18:04.125Z",
"stopped_at": null
},
"error": null
}4. Go live #
When you are happy, start the same version on live accounts. The paper run keeps going alongside unless keep_paper is false. Needs strategies_live and a broker open for live strategies.
curl -X POST "https://cirrus.pocketful.in/v2/deployments/<deployment_id>/go-live" \
-H "Authorization: token $CIRRUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accounts": [
{
"account": "Z1"
}
],
"keep_paper": false
}'import os
import requests
response = requests.post(
"https://cirrus.pocketful.in/v2/deployments/<deployment_id>/go-live",
headers={
"Authorization": f"token {os.environ['CIRRUS_API_KEY']}",
},
json={
"accounts": [
{
"account": "Z1",
},
],
"keep_paper": False,
},
timeout=10,
)
print(response.status_code, response.json())const response = await fetch('https://cirrus.pocketful.in/v2/deployments/<deployment_id>/go-live', {
method: 'POST',
headers: {
Authorization: `token ${process.env.CIRRUS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"accounts": [
{
"account": "Z1"
}
],
"keep_paper": false
}),
});
const body = await response.json();
console.log(response.status, body);{
"status": "success",
"data": {
"id": "01M574VPR4P8457ZBFGSHJ4CRP",
"strategy_id": "01M574VKA1TTA2BFREM70ZEB9D",
"strategy_name": "NIFTY manual straddle",
"version": 1,
"mode": "live",
"status": "active",
"status_reason": null,
"strategy_tag": "auto.01M574VPR4P8",
"accounts": [
{
"account": "Z1",
"multiplier": 1
}
],
"units": [
{
"account": "Z1",
"unit_id": "01M574VPR4YP5XCWSC2X6YPR5R",
"status": "active",
"status_reason": null
}
],
"start_on": null,
"end_on": null,
"acknowledged": [],
"compiled_hash": "sha256:93332f0feac143d79d9430ca8c247082ad8af7ca2820ba1492bc4af7a3c61937",
"last_intent": {
"action": "deploy",
"exit_now": false,
"at": "2026-10-18T09:18:07.623Z",
"delivered": false
},
"engine_connected": false,
"created_at": "2026-10-18T09:18:07.620Z",
"updated_at": "2026-10-18T09:18:07.620Z",
"stopped_at": null
},
"error": null
}Pause, stop, exit #
POST /v2/deployments/{deployment_id}/pauseand/resume: no new trades while paused; an open trade keeps its own stops and targets.POST /v2/deployments/{deployment_id}/exit-now: close its open trades now.POST /v2/deployments/{deployment_id}/stop: no new trades ever; sendexit_nowto also close the open one.POST /v2/strategies/stop-all: the kill switch for every strategy (withexit_now, closes their trades too).
Cap the risk of all strategies together with loss limits.
In the reference
- Automated strategies Write, check, version and share strategy documents.
- Strategy builder What a strategy can use, ready-made templates, and checks before you save or deploy.
- Backtests Run a strategy version over past days and read its trades.
- Deployments Run a strategy on paper or live accounts, then pause, stop or take it live.
- Risk limits Your overall daily loss limit and exposure cap for automated strategies.