# Quickstart

> Install the SDK, set your keys, connect a practice broker and send a first order through reTrade.

Status: In development. Not released yet; names and formats may change. Web page: https://retrade.app/docs/quickstart

## Install

Python:

```shell
pip install retrade==0.1.2
```

TypeScript:

```shell
npm install retrade@0.1.2
```

The package is `retrade` on [PyPI](https://pypi.org/project/retrade/) and on [npm](https://www.npmjs.com/package/retrade). Python needs 3.12 or later; Node needs 22.18 or later. Both install a `retrade` command. The SDK is pre-release, so pin the version you test with.

## Get your keys

You need four things. Your admin and reTrade give you three; you make the fourth.

What the SDK needs, and where each comes from:

| What | Looks like | Where it comes from |
|---|---|---|
| Executor key file | `executor.pem` | You make it, below, and keep it. reTrade only ever sees its public half. |
| Bot key id | `exk_test_` and 26 more characters | Your admin, after registering your key. |
| Root public key | 43 characters | reTrade, when your tenant is set up. |
| Account ref | the name your admin gave the account | Your admin. |

Python:

```shell
retrade keygen executor.pem
```

TypeScript:

```shell
npx retrade keygen executor.pem
```

This writes a new private key, readable only by you, and prints its public half. Send only the public half to your admin. They register it for one mode and send back your bot key id. Start with a `test` key: its orders are checked like real ones, but its decisions aren’t evidence for an insurer. Keep `executor.pem` secret: anyone holding it can ask for decisions as your agent.

What your admin runs:

```shell
# Your admin runs this with their own admin key.
# The admin command line is in development.
retrade-admin keys add-executor --mode test <public key>
```

## Set your environment

```shell
export RETRADE_EXECUTOR_KEY_ID="<bot key id from your admin>"
export RETRADE_EXECUTOR_KEY_PATH="$PWD/executor.pem"
export RETRADE_ROOT_KEY="<root public key from reTrade>"
export RETRADE_ACCOUNT="<account ref from your admin>"
export RETRADE_AGENT="<this agent's id>"
```

These names are a convention for your own code: the samples read them and pass the values to the SDK. The SDK itself reads one variable, `RETRADE_BASE_URL`, and only when you pass no address. Without either, it uses reTrade’s hosted service, `https://api.retrade.app`.

## Connect a practice broker

The SDK reads the account and places orders only through an adapter: four functions you write against your broker’s API. For a first run, this one keeps a pretend account in memory and records orders instead of sending them anywhere.

Python:

```python
from datetime import UTC, datetime
from decimal import Decimal

import retrade

placed: list[str] = []  # the tags of the orders this pretend broker took


def read_account(
    instrument: str | None, adjustments_since: datetime | None
) -> tuple[retrade.Snapshot, retrade.Quote | None]:
    now = datetime.now(UTC)
    snapshot = retrade.Snapshot(
        as_of=now,
        cash={"USD": Decimal("50000")},
        settled_cash={"USD": Decimal("50000")},
        positions=(),
        open_orders=(),
    )
    if instrument is None:
        return snapshot, None
    quote = retrade.Quote(instrument, Decimal("187.10"), Decimal("187.08"),
                          Decimal("187.12"), now)
    return snapshot, quote


def submit(order: retrade.ApprovedOrder, tag: str) -> str:
    placed.append(tag)
    return f"paper-{len(placed)}"


def find(tag: str, order: retrade.ApprovedOrder, since: datetime) -> str | None:
    return f"paper-{placed.index(tag) + 1}" if tag in placed else None


def cancel(broker_order_id: str) -> None:
    pass  # nothing rests at this pretend broker


broker = retrade.GenericAdapter(
    snapshot=read_account, submit=submit, find=find, cancel=cancel,
    g_seconds=60, converts_cash=False,
)
```

TypeScript:

```typescript
import { GenericAdapter } from "retrade";

const placed: string[] = []; // the tags of the orders this pretend broker took

const broker = new GenericAdapter({
  snapshot(instrument) {
    const asOf = new Date();
    const snapshot = {
      asOf,
      cash: { USD: "50000" },
      settledCash: { USD: "50000" },
      positions: [],
      openOrders: [],
    };
    const quote = instrument === null
      ? null
      : { instrument, last: "187.10", bid: "187.08", ask: "187.12", asOf };
    return { snapshot, quote };
  },
  submit(order, tag) {
    placed.push(tag);
    return `paper-${placed.length}`;
  },
  find(tag) {
    const index = placed.indexOf(tag);
    return index === -1 ? null : `paper-${index + 1}`;
  },
  cancel() {
    // nothing rests at this pretend broker
  },
  gSeconds: 60,
  convertsCash: false,
});
```

The adapter’s `g_seconds` and `converts_cash` (`gSeconds` and `convertsCash` in TypeScript) must equal the account’s settings at reTrade; 60 and false are the SDK’s defaults. Ask your admin if the account uses others. When you’re ready, swap in your real broker: see [Connect your broker](https://retrade.app/docs/sdk/python.md#connect-your-broker).

## Run your first check

Python:

```python
import os
from decimal import Decimal

from retrade import Client, Order, OrderType, Side, Tif

with Client(
    os.environ["RETRADE_EXECUTOR_KEY_ID"],
    os.environ["RETRADE_EXECUTOR_KEY_PATH"],
    root_key=os.environ["RETRADE_ROOT_KEY"],
) as rt:
    order = Order("XNAS:AAPL", Side.BUY, 40, OrderType.LIMIT, Tif.DAY,
                  limit_price=Decimal("187.25"))
    result = rt.place(order, account=os.environ["RETRADE_ACCOUNT"],
                      agent=os.environ["RETRADE_AGENT"], via=broker)
    why = result.deciding or result.reason
    print(result.outcome, result.placement, result.quantity, why)
```

TypeScript:

```typescript
import { Client } from "retrade";

function env(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is not set`);
  return value;
}

const rt = await Client.open({
  keyId: env("RETRADE_EXECUTOR_KEY_ID"),
  keyPath: env("RETRADE_EXECUTOR_KEY_PATH"),
  rootKey: env("RETRADE_ROOT_KEY"),
});
try {
  const order = {
    instrument: "XNAS:AAPL", side: "buy", quantity: 40,
    type: "limit", tif: "day", limitPrice: "187.25",
  } as const;
  const result = await rt.place(order, {
    account: env("RETRADE_ACCOUNT"), agent: env("RETRADE_AGENT"), via: broker,
  });
  const why = result.deciding ?? result.reason;
  console.log(result.outcome, result.placement, result.quantity, why);
} finally {
  await rt.close();
}
```

Save the practice broker and this check in one file. In Python, as `first_check.py`, run with `python first_check.py`. In TypeScript, as `first-check.mts`, run with `node first-check.mts`: Node 22.18 and later run TypeScript files directly.

## Read the answer

`place` returns a result. A BLOCK, or reTrade not answering, is a result too, never an exception. The fields you’ll use first:

The first fields of a result:

| Field | What it tells you |
|---|---|
| `outcome` | ALLOW, CUT or BLOCK. |
| `placement` | `placed`, `not_placed`, or `unknown` when the broker call’s outcome isn’t known. Never send an `unknown` order again. |
| `quantity` | What was approved: smaller than you asked on a CUT. |
| `deciding` | On a CUT or BLOCK, the rule that decided, such as `{"code": "order_size_cap"}`. |
| `fits` | On a BLOCK over a dollar line or in an agent conflict, the largest quantity that would pass. |
| `reason` | The SDK’s own reason when it decided without reTrade, such as `unreachable`. |
| `decision_id` (`decisionId`) | The receipt’s id. Store it with your own order record. |

If reTrade doesn’t answer within 2.5 seconds, you get BLOCK with reason `unreachable`, and nothing is placed. That’s [fail-closed](https://retrade.app/docs/concepts/fail-closed.md).

## Next steps

- Connect your real broker: [Python](https://retrade.app/docs/sdk/python.md#connect-your-broker) or [TypeScript](https://retrade.app/docs/sdk/typescript.md#connect-your-broker).
- Handle every answer: [ALLOW, CUT and BLOCK](https://retrade.app/docs/concepts/decisions.md).
- Adding reTrade to a bot you already have? Give your coding agent [SKILL.md](https://retrade.app/docs/skill.md).
