# Setting a Stop Loss

Once a position is successfully opened via the solver’s **instant trading API**, it's worth setting a stop loss to protect that position. This ensures risk is bounded even if the bot goes offline or market conditions change unexpectedly.

***

### High-Level Flow

1. Authenticate with the Hedger API ([SIWE login](https://docs.symm.io/exchange-builder-documentation/frontend-builder-technical-guidance/instant-trading/instant-login-eoa))
2. Open an instant market position
3. Let the **temporary quote ID** resolve into a permanent `quoteId`
4. Calculate the stop-loss price
5. Submit a stop-loss request to the solver API

> ⚠️ A stop loss **must reference a permanent `quoteId`**. You cannot attach SL/TP to a temporary quote.

***

### Authentication (SIWE Login)

Before any protected actions (open, stop loss, cancel, etc.), the bot must authenticate using **Sign-In With Ethereum (SIWE)**.

1. Fetch a nonce from the hedger
2. Build a SIWE message scoped to the **active trading account**
3. Sign the message with the owner wallet
4. Exchange the signature for a JWT access token

```python
token = login()
```

The returned `access_token` is used as a Bearer token for all subsequent requests.

***

### Opening the Position (Instant Open)

The bot opens a position using the solver’s `instant_open` endpoint.

Key points:

* Orders **must be market orders** (`orderType = 1`)
* The price is derived from the **Muon Oracle**
* Slippage is applied to guarantee execution
* Collateral parameters are calculated using `get_locked_params`

```python
temp_quote_id, open_price = open_instant_trade(token)
```

#### Returned Values

* `temp_quote_id`: Temporary identifier for the order
* `open_price`: The raw Muon price used to derive SL/TP levels

***

### Resolving the Temporary Quote ID

Instant trades initially return a **temporary quote ID**.\
Before setting a stop loss, the bot must wait until this temp ID is finalized into a **permanent `quoteId`**.

This is done by polling the user’s active quotes:

```python
quote_id = poll_quote_status(token, temp_quote_id)
```

#### Why This Is Required

* Stop loss and take profit requests are validated against finalized on-chain quotes
* Using a temp ID will result in rejection

***

### Calculating the Stop Loss Price

Once the quote is confirmed, derives a stop-loss price relative to the entry price.

In this example:

* The bot is **LONG**
* Stop loss is set at **80% of entry price**

```python
sl_price = (open_price * Decimal('0.8')).quantize(
    Decimal("0.000001"),
    rounding=ROUND_DOWN
)
```

#### Notes

* Precision should match the symbol’s supported decimals
* For SHORT positions, this logic would be inverted

***

### Stop Loss Request Payload

The stop loss is submitted using the `stop_loss` endpoint.

{% hint style="info" %}
This refers to [PerpsHub TPSL Implementation](https://docs.symm.io/api-endpoints-and-deployments/solver-addresses-and-endpoints/perps-hub/perpshub-tp-sl-implementation), check [Rasa's TPSL Implementation](https://docs.symm.io/api-endpoints-and-deployments/solver-addresses-and-endpoints/rasa-capital/rasa-solver-tp-sl-implementation) for detailed instructions on how to construct their payload.
{% endhint %}

#### Payload Structure

```json
{
  "userAddress": "<wallet address>",
  "accountAddress": "<active account>",
  "positionSide": 0,
  "symbolId": 4,
  "requestedPrice": "ENTRY_PRICE",
  "quoteId": 12345,
  "tpPrice": "",
  "slPrice": "STOP_LOSS_PRICE",
  "timestamp": 1710000000000
}
```

#### Field Explanation

| Field            | Description                          |
| ---------------- | ------------------------------------ |
| `userAddress`    | Wallet that signed the login message |
| `accountAddress` | Trading account (EOA or sub-account) |
| `positionSide`   | `0 = Long`, `1 = Short`              |
| `symbolId`       | Internal symbol identifier           |
| `requestedPrice` | Original entry price                 |
| `quoteId`        | Permanent quote ID                   |
| `tpPrice`        | Leave empty if not setting TP        |
| `slPrice`        | Calculated stop loss price           |
| `timestamp`      | Client-side timestamp (ms)           |

***

### Sending the Stop Loss Request

```python
response = requests.post(
    f"{HEDGER_URL}/stop_loss",
    json=payload,
    headers={
        "Content-Type": "application/json",
        "Authorization": f"Bearer {token}"
    }
)
```

On success, the solver will acknowledge the stop loss and register it for on-chain execution when the trigger price is reached.

***

### Complete Execution Flow

```
Login (SIWE)
   ↓
Instant Open Position
   ↓
Receive temp_quote_id
   ↓
Poll until quoteId is finalized
   ↓
Compute stop loss price
   ↓
POST /stop_loss
```

A full example implementation can be found in our SYMM SDK.
