# X-Trader timed_strategy orders

URL: https://docs.blizz.id/xtrader/timed-strategy/
Updated: 2026-10-16

`timed_strategy` is the required object inside `config` that schedules staged sells by time: each order sells a percentage of the current position a fixed number of seconds after the buy. It holds up to 20 orders and is switched on and off by `enabled`. The schema is the same for sniper, copy-trade and transfer-snipe configurations.

Primary source: [X-Trader API reference](https://x-trader.ai/api/docs). This page is an independent explanation of X-Trader Public API v1.0.0; it is not affiliated with X-Trader.

## Where timed_strategy lives

`timed_strategy` is a required key of `config` in the sniper, copy-trade and transfer-snipe Create and Patch schemas and in both template schemas; the object schema is identical everywhere. Its siblings are [`auto_sell`](/xtrader/auto-sell/) (price-based exits) and [`auto_strategy`](/xtrader/auto-strategy/) (migration, protection and clear rules). The object is strict: unknown keys return `validation_error`.

## Fields

| Field | Type | Required | Values and limits | Meaning |
|---|---|---|---|---|
| `enabled` | boolean | yes | | Turns the time-based sells on or off. |
| `orders` | array | yes | 0 to 20 items | Ordered list of timed sells. |
| `orders[].delay` | string | yes | `"1"` to `"31536000"` seconds (365 days) | Time after the buy at which the order fires. |
| `orders[].sell` | string | yes | percentage of the current position | Share sold when the order fires. |

Both item keys are required and no other keys are accepted. Values are decimal strings, max 32 characters (see [write rules](/xtrader/write-rules/)).

The spec does not give a separate range for `orders[].sell`; it reuses the shared percentage description (TP stages 0 to 100, stop-loss and trailing rules greater than 0). Keeping `sell` between `"1"` and `"100"` stays inside every documented range.

## How the percentages add up

Each `sell` applies to whatever is still held at that moment, not to the original buy. Example with three orders:

| Order | `delay` | `sell` | Sold (share of original) | Remaining |
|---|---|---|---|---|
| 1 | `"60"` | `"50"` | 50% | 50% |
| 2 | `"300"` | `"50"` | 25% | 25% |
| 3 | `"900"` | `"100"` | 25% | 0% |

Other exits ([TP/SL](/xtrader/auto-sell/), follow-sell, [auto_strategy](/xtrader/auto-strategy/) rules) reduce the same position, so a timed order may find less (or nothing) left to sell.

## Ordering

The spec calls `orders` "ordered" entries and documents `delay` as time after the buy. It does not state whether orders are re-sorted by `delay` or what happens when two orders share the same delay. Sending them in ascending `delay` order, with distinct delays, avoids depending on undocumented behaviour.

## timed_strategy vs auto_strategy.timed_sell

| | `timed_strategy` | `auto_strategy.timed_sell` + `sell_delay` |
|---|---|---|
| Number of sells | up to 20 | one |
| Sell size | per order, percent of current position | full position |
| Delay range | 1 to 31,536,000 s per order | 0 to 31,536,000 s |
| Required keys | `enabled`, `orders` | `timed_sell`, `sell_delay` (always required) |

## Example inside a create body

```json
{
  "target_wallet": "<solana-address>",
  "config": {
    "timed_strategy": {
      "enabled": true,
      "orders": [
        { "delay": "60",  "sell": "50" },
        { "delay": "300", "sell": "50" },
        { "delay": "900", "sell": "100" }
      ]
    },
    "auto_sell": {
      "enabled": true, "expiry_time": "0",
      "tp_orders": [], "sl_orders": [{ "trigger": "-40", "sell": "100" }],
      "follow_sell": false, "proportional_sell": false
    },
    "auto_strategy": { "migration_clear": false, "timed_sell": false, "sell_delay": "0" }
  }
}
```

To keep the feature off send `{"enabled": false, "orders": []}`. The other required `config` keys are omitted here; see [sniper config](/xtrader/config-sniper/) and [copy-trade config](/xtrader/config-copy-trade/).

## Updating timed_strategy on an existing config

When `config` is present in a PATCH it replaces the complete nested config and must pass the full schema. Read the config, change `timed_strategy`, then send the whole `config` with the current `ETag` in `If-Match`. Changing `config` requires a paused configuration (`config_must_be_paused` otherwise); an outdated ETag returns `version_conflict`. GET may return legacy fields that the strict write schema rejects; `error.fields` lists them.

### curl

```bash
ID='<config-uuid>'
BASE='https://x-trader.ai/api/v1'

curl -sD headers.txt "$BASE/copy-trade/configs/$ID" \
  --header "Authorization: Bearer $X_TRADER_API_TOKEN" \
  | jq '.data.config' > config.json
ETAG=$(grep -i '^etag:' headers.txt | cut -d' ' -f2 | tr -d '\r')

jq '.timed_strategy = {"enabled": true, "orders": [
      {"delay":"120","sell":"30"},
      {"delay":"600","sell":"50"},
      {"delay":"1800","sell":"100"}]}' config.json \
  | jq '{config: .}' > patch.json

curl --request PATCH "$BASE/copy-trade/configs/$ID" \
  --header "Authorization: Bearer $X_TRADER_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --header "If-Match: $ETAG" \
  --data @patch.json
```

### Python

```python
import os
import requests

BASE = "https://x-trader.ai/api/v1"
CONFIG_ID = "<config-uuid>"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['X_TRADER_API_TOKEN']}"

url = f"{BASE}/sniper/configs/{CONFIG_ID}"   # or /copy-trade/configs/{id}
resp = session.get(url)
resp.raise_for_status()
etag = resp.headers["ETag"]
resource = resp.json()["data"]
if resource["is_active"]:
    raise SystemExit("Pause the config first (POST .../pause with If-Match)")

orders = [("60", "25"), ("180", "50"), ("600", "100")]
config = resource["config"]
config["timed_strategy"] = {
    "enabled": True,
    "orders": [{"delay": d, "sell": s} for d, s in orders],
}
assert len(config["timed_strategy"]["orders"]) <= 20

patch = session.patch(url, json={"config": config}, headers={"If-Match": etag})
if patch.status_code >= 400:
    print(patch.json()["error"])
patch.raise_for_status()
print("new version:", patch.headers["ETag"])
```

## FAQ

### How many timed_strategy orders can a config have?

At most 20. The `orders` array has `maxItems` 20; an empty array is allowed.

### Is the timed_strategy sell percentage of the original buy?

No. `sell` is a percentage of the position held at the moment the order fires, so two orders of `50` leave 25% of the original position.

### What is the difference between timed_strategy and auto_strategy.timed_sell?

`auto_strategy.timed_sell` is one delayed sell of the full position after `sell_delay` seconds. `timed_strategy` holds up to 20 staged partial sells, each with its own delay after the buy.

### Is timed_strategy required when I do not use it?

Yes. `config.timed_strategy` is a required key; send `{"enabled": false, "orders": []}` to keep it off.
