> For the complete documentation index, see [llms.txt](https://docs.sigrex.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sigrex.io/strategies/code.md).

# Code

With the Code feature, you can write your own trading strategy directly in JavaScript.

Your strategy runs in a sandboxed environment where you can analyze the current market data, store custom information, and trigger actions using the built-in `$` object.

***

## 🧩 Available Variables

Each run of your strategy includes access to the following objects and functions:

***

### **`$.Action`**

Enum representing all available trade actions:

* `LONG` → Open a long position
* `SHORT` → Open a short position
* `EXIT` → Close the current position

***

### **`$.Exchange`**&#x20;

Enum representing the exchanges supported by the Sigrex live exchange-rate system.

| **Value**                | **Description** |
| ------------------------ | --------------- |
| `$.Exchange.BINANCE`     | Binance         |
| `$.Exchange.GATEIO`      | Gate.io         |
| `$.Exchange.BITGET`      | Bitget          |
| `$.Exchange.HYPERLIQUID` | Hyperliquid     |
| `$.Exchange.KRAKEN`      | Kraken          |

The enum is used with `$.getExchangeRate()` to specify which exchange should be queried.

***

### **`$.Price`**

{% hint style="warning" %}
The current market price info of the selected symbol only if "use price" option enabled.
{% endhint %}

| Property   | Description                                  |
| ---------- | -------------------------------------------- |
| `symbol`   | Price symbol, e.g. `"BTCUSDT"`               |
| `price`    | Current price of the `symbol`                |
| `exchange` | Source Exchange identifier, e.g. `"binance"` |
| `service`  | Market type, e.g. `"spot"` or `"futures"`    |

Example:

```js
if ($.Price.price > 25000) {
    await $.Strategy.action($.Action.LONG);
}
```

***

### `$.Env`

Provides access to user-defined environment variables.

Users can define global or folder scope environment variables that are automatically available across all strategy executions.

These values can be accessed at runtime using the `$.Env` object.

***

Example:

```ts
const apiKey = $.Env.API_KEY;
const risk = $.Env.RISK;
```

***

### **`$.Strategy`** Properties

Provides context for the current trading session and allows you to execute actions.

| Property | Description                                              |
| -------- | -------------------------------------------------------- |
| `id`     | The unique numeric ID of the current strategy            |
| `type`   | The type of strategy: `code-strategy` or `code-reaction` |

Available if "send signal" enabled

| Property             | Description                                                            |
| -------------------- | ---------------------------------------------------------------------- |
| `signalSymbols`      | Array of symbols where signal actions are sent (`["BTCUSDT",ETHUSDT]`) |
| `lastTrigger.action` | The most recent action (`LONG`, `SHORT`, or `EXIT`)                    |
| `lastTrigger.price`  | The price when the last action was executed                            |
| `lastTrigger.at`     | Timestamp of the last action, or `null` if none                        |

### **`$.Strategy`** Methods

#### `roi(percentage?: boolean, openPrice?: number, currentPrice?: number): number|null`

Calculates the current Return on Investment (ROI) based on the difference between open and current price.

If no prices are provided, it automatically uses the last trigger price as the open price and the current system price. You can override these by passing custom values.

Returns the result as a percentage when enabled, otherwise as a decimal. If no valid price data is available, it returns `null`.

ROI Example:

```ts
// Default usage (uses last trigger price + current price if enabled)
const roiValue = $.Strategy.roi();

// ROI as percentage
const roiPercent = $.Strategy.roi(true);

// Using custom prices
const customRoi = $.Strategy.roi(false, 100, 120);
```

> ⚠️ Keep in mind: for short positions, profitable trades will result in a negative ROI value.

#### `async action(type: $.Action, options?: ActionOption)`

{% hint style="warning" %}
Available only if "send signal" option enabled.
{% endhint %}

Executes a strategy action such as `$.Action.LONG`, `SHORT`, or `EXIT`.

You can optionally pass additional settings like `id`, `size`, or `dilution` to control how the action is handled. The structure is similar to a [signal payload](/getting-started/signal-payload-format.md).

#### Options

```typescript
type ActionOption = {
    id?: string;                    // A custom name/id for the alert (optional)
    dilution?: boolean;             // If true, allows partial stacking of positions (optional)
    size?: number;                  // Trade size (open in quote, close in base currency), overrides default (optional)
    forceSize?: boolean;            // It can bypass the amount of those bots that have strict amount settings
}
```

Action Example:

```ts
// Simple action
await $.Strategy.action($.Action.LONG);

// Action with options
await $.Strategy.action($.Action.SHORT, {
  id: "trade-1",
  dilution: true,
});
```

The function sends the action to the system and returns the execution result. If the provided options are invalid, it returns an error.

#### **`async stop(notify?: boolean): boolean`**

Stops the strategy from executing again by setting its status to `INACTIVE`.

**Important:** `stop()` does **not** terminate the currently running strategy process. The current execution continues after calling `stop()`. To stop the current execution as well, use `return` after calling `stop()`.

If `notify` is `true`, the system sends a notification email about the strategy being stopped.

**Parameters**

```
notify?: boolean; // Sends a notification email if true
```

**Example**

```
await $.Strategy.stop(true);return;
```

> ⚠️ Use `return` after `stop()` if you want to terminate the current execution. Without `return`, the current process continues, but the strategy will not execute again.

***

### **`$.Storage`**

Persistent JSON storage (up to **24 KB**) that remains between strategy runs.

| Function         | Description                                                 |
| ---------------- | ----------------------------------------------------------- |
| `byteLimit`      | Constant holding the maximum allowed bytes (24,576)         |
| `async get()`    | Retrieves the current stored data (returns `null` if empty) |
| `async set(obj)` | Saves a new data object (overwrites existing data)          |

Example:

```js
const state = await $.Storage.get() || { trades: 0 };
state.trades++;
await $.Storage.set(state);
```

***

### `$.Http`

Utility for sending HTTP requests from within your strategy.

Each request has a maximum timeout of `1750 ms`.

> &#x20;`POST` and `PUT` requests default to `Content-Type: application/json`.

***

<table><thead><tr><th width="435.333251953125">Method or Property</th><th>Description</th></tr></thead><tbody><tr><td><code>timeout</code></td><td>Constant timeout value in milliseconds (<code>1750</code>)</td></tr><tr><td><code>async get(url, params?, headers?)</code></td><td>Sends a GET request</td></tr><tr><td><code>async post(url, data, headers?)</code></td><td>Sends a POST request</td></tr><tr><td><code>async put(url, data, headers?)</code></td><td>Sends a PUT request</td></tr><tr><td><code>async delete(url, params?, headers?)</code></td><td>Sends a DELETE request</td></tr><tr><td><code>async generateSignature(payload, secret, algo?)</code></td><td>Generates an HMAC or ML-DSA44 signature from a payload and secret. Algo options: <code>"HMAC" or "ML-DSA"</code> Default is: <code>HMAC</code></td></tr><tr><td><code>createApiClient({ apiKey, apiSecret })</code></td><td>Creates an instance of the official <a href="https://github.com/sigrexio/sigrex-client-ts">Sigrex API Client</a> that can be used to interact with the services directly from your strategy.</td></tr></tbody></table>

***

#### Response Format

All HTTP methods return an object in the following format:

```ts
{ 
  status: number,
  text: string,
  cache: boolean
}
```

* `status` → HTTP status code (e.g. `200`, `404`, `500`), or `0` if the request failed or was refused (the reason is in `text`)
* `text` → Raw response body as string
* `cache` → Whether the response came from the cache

***

#### Caching

> ⚠️ All HTTP requests are cached for **5 seconds**.\
> During this period, repeated requests return the same response.\
> You can check the `cache` field to see if the response was served from cache.

***

#### **Request limits**

> ⚠️ Each run can make up to **30 HTTP requests** (`get`, `post`, `put` and `delete`; `generateSignature` doesn't count).\
> Responses larger than **5 MB** are refused.\
> A request over either limit doesn't stop or suspend the strategy: it returns `status: 0` with the reason in `text`.

***

Example:

```ts
const params = { symbol: "BTCUSDT" };

const response = await $.Http.get(
  "https://api.binance.com/api/v3/ticker/price",
  params
);

if (response.status === 200) {
  const data = JSON.parse(response.text);
}
```

***

API Client Example:

```typescript
const client = $.Http.createApiClient({
    apiKey: $.Env.API_KEY
    apiSecret: $.Env.API_SECRET,
});

const exchanges = await client.exchanges.list({ enabled: true });
```

***

Signature Example:

```ts
const API_KEY = "your_public_api_key";
const API_SECRET = "your_private_api_secret";

const method = "POST";
const path = "/api/v2/strategy/llm-session";

const body = {
  name: "My Strategy",
  cron_interval: "15m"
};

const timestamp = Math.floor(Date.now() / 1000).toString();

const payload =
  method + path + JSON.stringify(body) + timestamp;

const signature = await $.Http.generateSignature(payload, API_SECRET);
```

***

### **`$.Ta`**

Provides access to a built-in **technical analysis library** for calculating indicators and signals directly inside your strategy or reaction.

The `$.Ta` object exposes the functionality of the **trading-signals** library:

👉 <https://github.com/bennycode/trading-signals/tree/main/packages/trading-signals>

***

#### What You Can Do

With `$.Ta`, you can:

* Calculate indicators like **RSI, EMA, SMA, MACD, ATR, Bollinger Bands**
* Build custom technical strategies
* Combine indicators with webhook data or price logic
* Perform calculations without external API calls

***

#### Usage

Indicators are typically used by feeding values sequentially.

Example: RSI

```typescript
const rsi = new $.Ta.RSI(14);

rsi.update(30000);
rsi.update(30100);
rsi.update(29950);

if (rsi.isStable) {
  const value = rsi.getResult();

  if (value < 30) {
    await $.Strategy.action($.Action.LONG);
  }
}
```

***

### **`Utils`**

#### **`async getExchangeRate(exchange: $.Exchange, symbol: string): number|null`**

Returns the current exchange rate for a symbol on the specified exchange.

The `exchange` parameter must be one of the supported values from the `$.Exchange` enum. If a current rate is available, the function returns it as a `number`; otherwise, it returns `null`.

**Parameters**

```javascript
exchange: $.Exchange; // The exchange to retrieve the rate from
symbol: string;       // The symbol to retrieve (e.g. "btcusdt")
```

**Example**

```javascript
const price = await $.getExchangeRate(
  $.Exchange.BINANCE,
  "btcusdt"
);
```

***

## ⚡ Rules & Limits

To ensure fair and safe execution, the following rules apply:

* Maximum **execution time:** 5000 ms per run
* Maximum **HTTP request time:** 1750 ms
* Maximum **HTTP requests:** 30 per run
* Maximum **HTTP response size:** 5 MB
* **HTTP cache :** 5 s
* Maximum **storage size:** 24 KB
* Only **one action per run** is allowed
* Maximum **five actions per second** globally
* Two consecutive `EXIT` actions are **not permitted**
* Going over the **execution time** gives a **warning** in your logs the first two times in a row; the **third timeout in a row suspends** the strategy. A run that finishes in time resets the count.
* Going over the HTTP request or response size limit doesn't suspend the strategy: the request returns `status: 0`
* Violating the other limits will **suspend** the strategy temporarily
* Code is **checked when you save it**, see [Sandbox Restrictions](#sandbox-restrictions-and-forbidden-identifiers)

***

## 🧠 Example Strategy

```js
// Example: simple entry and exit logic

if ($.Strategy.lastTrigger.action === $.Action.EXIT) {
    if ($.Price.price < 19000) {
        await $.Strategy.action($.Action.LONG);
    }
} else {
    if ($.Price.price > 20000) {
        await $.Strategy.action($.Action.EXIT);
    }
}
```

This example demonstrates:

* Checking the last executed action (`$.Strategy.lastTrigger.action`)
* Using current market data (`$.Price`)
* Executing a new action with (`$.Strategy.action()`)

***

## 🏁 Summary

| Feature                | Description                                   |
| ---------------------- | --------------------------------------------- |
| **Action trigger**     | `await $.Strategy.action($.Action.LONG)`      |
| **Available actions**  | `LONG`, `SHORT`, `EXIT`                       |
| **Actions per run**    | 1                                             |
| **Actions per second** | 5                                             |
| **Execution time**     | 5000 ms                                       |
| **Execution timeouts** | Suspended after 3 in a row (2 warnings first) |
| **Storage limit**      | 24 KB                                         |
| **HTTP requests**      | 30 per run                                    |
| **HTTP timeout**       | 1750 ms                                       |
| **HTTP response size** | 5 MB                                          |
| **HTTP cache**         | 5 seconds (see `response.cache`)              |
| **Duplicate EXITs**    | Not allowed                                   |

## 🔒 Sandbox Restrictions & Forbidden Identifiers

Your strategy code runs inside a **strictly sandboxed environment**.\
For security, stability, and fair usage, **certain JavaScript identifiers are completely blocked** and **cannot be used anywhere in your code** — not even indirectly or in comments.

Before your code is saved, it’s checked for the [identifiers](#sandbox-restrictions-and-forbidden-identifiers) below and against the [Code Rules](#code-rules). If either check fails, the code isn’t saved.

***

#### 🚫 Forbidden Identifiers

The following identifiers are **not available** and **must not appear** in your strategy code:

**Networking & Communication**

* `fetch`
* `WebSocket`
* `EventSource`
* `Worker`, `SharedWorker`
* `XMLHttpRequest`
* `navigator`, `location`
* `postMessage`
* `onmessage`, `onmessageerror`
* `MessageChannel`, `BroadcastChannel`
* `import`
* `importScripts`
* `close`

> ✅ Use `$.Http.get()` and `$.Http.post()` instead.

***

**Dynamic Code Execution**

* `eval`
* `Function`
* `AsyncFunction`
* `generatorFunction`
* `constructor`

> ❗ Dynamic or runtime-generated code is not permitted.

***

**Global Objects & DOM-Like APIs**

* `globalThis`
* `window`
* `self`
* `frames`
* `parent`
* `top`
* `document`

> ℹ️ There is **no DOM, browser, or global scope access**.

***

**Timers & Scheduling**

* `setTimeout`, `setInterval`, `setImmediate`
* `clearTimeout`, `clearInterval`, `clearImmediate`
* `queueMicrotask`

> ⏱ Strategies are **event-driven** and executed automatically — manual scheduling is not allowed.

***

**Crypto, Performance & Parallelism**

* `crypto`
* `performance`
* `structuredClone`
* `Atomics`
* `SharedArrayBuffer`

***

**Reflection & Obfuscation**

* `Reflect`
* `Proxy`

***

**Node.js / Deno Environment**

* `process`
* `require`
* `module`
* `exports`
* `export`&#x20;
* `global`
* `Deno`

> ❌ This is **not** a Node.js or Deno runtime.

***

**Encoding / Decoding**

* `atob`
* `btoa`

***

**User Interaction & Debugging**

* `alert`
* `confirm`
* `prompt`
* `console`
* `Intl`
* `FinalizationRegistry`
* `WeakRef`

> 🛑 Logging, dialogs, locale detection, and memory introspection are intentionally disabled.

***

**📐 Code Rules**

Your code is checked every time you create or update a strategy. Code that breaks a rule is **not saved**, and the error tells you which rule:

* **Plain JavaScript** only, up to 100,000 characters (no TypeScript, no `import` / `export`)
* **Declare every variable** with `let` or `const` (`total = 0` is rejected)
* **Built-ins are read-only**: don't change `Math`, `Object`, `JSON`, `$.Ta`…; keep helpers in your own objects
* **Loops must be able to end**: no `while (true)` or `for (;;)`, even with a `break`
* **Size limits**: arrays and strings up to 1,000,000, loop bounds up to 10,000,000
* **Regular expressions** as literals (`/btc/i`), without nested quantifiers like `/(a+)+/`
* `this` only inside class methods; `arguments`, `with` and `debugger` are not available

> ℹ️ Strategies that are already running keep running unchanged until you edit them.

<details>

<summary>Full rules, examples and error messages</summary>

**Declare every variable**

```js
// ❌ Rejected
total = 0;

// ✅ Allowed
let total = 0;
```

**Built-ins are read-only**

Built-in objects (`Math`, `Object`, `JSON`, `Array`, `String`, `Number`, `Date`, `Promise`…) and `$.Ta` cannot be changed: no assigning to them, deleting from them or `Object.assign` into them. Prototype access is not available either.

```js
// ❌ Rejected
Math.pct = (a, b) => (a / b) * 100;
Object.prototype.hasOwnProperty.call(obj, "key");

// ✅ Allowed
const util = { pct: (a, b) => (a / b) * 100 };
Object.hasOwn(obj, "key");
```

**Loops must be able to end**

Conditions that are always true (`while (true)`, `for (;;)`, `do { … } while (true)`) are rejected even if the body contains a `break`. A loop condition may not compare against a constant above 10,000,000 (`i < 1e12`, `while (Date.now() < 1767225600000)`).

```js
// ❌ Rejected
while (true) {
    if (done) break;
}

// ✅ Allowed
for (let i = 0; i < prices.length; i++) {
    // ...
}
```

**Size limits**

Constant sizes above 1,000,000 are rejected for `new Array(n)` / `Array(n)`, typed arrays (`new Float64Array(n)`), `Array.from({ length: n })`, `.repeat(n)`, `.padStart(n)`, `.padEnd(n)` and `arr.length = n`. Keep stored history small, e.g. `prices.slice(-500)`.

**Regular expressions**

Use literals such as `/btc/i`; the `RegExp` constructor is not available. Patterns with a quantified group that contains another quantifier, such as `/(a+)+$/`, are rejected because they can take exponential time.

**Other restrictions**

* `this` is only allowed inside class methods (classes can't declare a `constructor`, use class fields)
* `arguments` is not available; use rest parameters: `(...args) => args.length`
* `with` and `debugger` statements are not allowed
* Also not available: `WebAssembly`, `ArrayBuffer`, `DataView`, `Buffer`, `Object.getPrototypeOf`, `Object.setPrototypeOf`, `Object.defineProperty` / `defineProperties`, `Object.getOwnPropertyDescriptor(s)`, `String.fromCharCode`, `String.fromCodePoint`

**Error messages**

| Error                                                    | How to fix                                                       |
| -------------------------------------------------------- | ---------------------------------------------------------------- |
| `Assignment to undeclared variable: x`                   | Declare it: `let x = …`                                          |
| `Code must not modify built-in: Math`                    | Move your helper into your own object                            |
| `Infinite loop detected`                                 | Give the loop a condition that becomes false                     |
| `Loop bound is too large`                                | Loop over your data, e.g. `i < prices.length`                    |
| `Allocation is too large`                                | Use a size up to 1,000,000                                       |
| `Regular expression may cause catastrophic backtracking` | Remove the nested quantifier, e.g. `/a+$/` instead of `/(a+)+$/` |
| `` `this` is only allowed inside class methods ``        | Use plain objects and functions                                  |
| `Code contains blocked identifier: …`                    | Remove or rename it (see 🚫 Forbidden Identifiers)               |
| `Code is not valid JavaScript`                           | Fix the syntax; TypeScript is not supported                      |
| `Code is too long` / `Code exceeds 10000 AST nodes`      | Make the strategy smaller                                        |

</details>

***

#### ✅ What You *Can* Use

Instead of the blocked APIs, always rely on:

* **Market data:** `$.Price`
* **Trading actions:** `$.Strategy.action(...)`
* **Persistent state:** `$.Storage.get()` / `$.Storage.set()`
* **HTTP requests:** `$.Http.get()` / `$.Http.post()`

These are **the only supported interfaces** for interacting with the outside world.

***

#### ⚠️ Important Notes

* Forbidden identifiers cannot be used **anywhere**:
  * Not in variables
  * Not in functions
  * Not in comments
  * Not via aliases
  * Not via destructuring
* Even unused references may cause execution failure
* Violations may result in **temporary strategy suspension**


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.sigrex.io/strategies/code.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
