Skip to content
Cirrus home
Sign in

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.

POST
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
            }
          }
        }
      }
    }
  }'
Response · 201
{
  "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.

POST
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
    }
  }'
Response · 202
{
  "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.

POST
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
      }
    ]
  }'
Response · 201
{
  "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.

POST
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
  }'
Response · 201
{
  "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}/pause and /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; send exit_now to also close the open one.
  • POST /v2/strategies/stop-all: the kill switch for every strategy (with exit_now, closes their trades too).

Cap the risk of all strategies together with loss limits.

In the reference