Documentation

Target Lock and script close requests.

What Target Lock does when profit reaches your level, and how to send a close or flatten-and-lock request from a TradingView Pine alert or a Python script.

What Target Lock does

When profit on a connected account reaches your profit level plus your buffer, Target Lock cancels working orders, closes open positions, reads the positions back to confirm the account is flat, and locks execution. It covers challenge, funded sim and funded live accounts. Funded live accounts are coming soon: until then Target Lock locks execution and sends an alert, and does not send closing orders to them.

The always-on watcher measures profit from the balance and open profit and loss the broker streams, against a starting balance saved for the account. It does not wait for an order or for you to save settings. Keep-flat is optional: when it is on, a new position opened on a locked account is closed again.

Target Lock places closing orders only where the firm allows orders from FirmGated's servers (see Connect Brokers). Where a firm does not, or has not confirmed it, Target Lock sends an alert with the account's status and leaves positions and orders as they are. Every result is one of: armed, triggered, flattening, locked, or needs attention. A needs-attention alert lists what is still open at the broker.

Send a close request from a script

Post JSON to your strategy's webhook URL, the same URL your signals use. The request is accepted with HTTP 202 and runs in the background; the result arrives as a Target Lock alert and in your audit log. A request works while execution is locked. The sim-only plan rule and each firm's automation route apply to script requests exactly as they do to signals.

FieldTypeExampleWhat it does
secretstring"YOUR_WEBHOOK_SECRET"Your strategy's webhook secret, the same one your signals use. Keep it out of shared scripts.
actionstring"close_all" | "flatten_and_lock"close_all cancels working orders and closes positions; execution stays on. flatten_and_lock does the same and then locks execution with Target Lock.
accountstring"YOUR_BROKER_ACCOUNT_ID"Optional. Limits the request to one connected account on this strategy. Without it, every connected account on the strategy is included.
idstring"pine-lock-1760000000000"Optional, up to 120 characters. A request id that was already handled runs once.

Copy-paste snippets

Replace the YOUR_ placeholders with your own values. In TradingView, create the alert with the Pine script as its condition, choose Any alert() function call, and set the webhook URL to your strategy's URL. Check the Pine example in the Pine Editor against your own script before relying on it.

TradingView alert message: flatten and lock
{
  "secret": "YOUR_WEBHOOK_SECRET",
  "action": "flatten_and_lock",
  "id": "pine-lock-{{timenow}}"
}
TradingView alert message: close everything, execution stays on
{
  "secret": "YOUR_WEBHOOK_SECRET",
  "action": "close_all",
  "id": "pine-close-{{timenow}}"
}
TradingView alert message: one account only
{
  "secret": "YOUR_WEBHOOK_SECRET",
  "action": "flatten_and_lock",
  "account": "YOUR_BROKER_ACCOUNT_ID",
  "id": "pine-lock-{{timenow}}"
}
Pine Script v6: send the request from your own script
//@version=6
strategy("Target Lock request", overlay=true)

profitLevel = input.float(1500.0, "Profit level in account currency")

// strategy.netprofit is this script's own closed-trade profit; any value your script tracks works here.
if barstate.isconfirmed and strategy.netprofit >= profitLevel
    alert('{"secret":"YOUR_WEBHOOK_SECRET","action":"flatten_and_lock","id":"pine-lock-' + str.tostring(time) + '"}', alert.freq_once_per_bar_close)
Python (requests)
import os
import time

import requests

WEBHOOK_URL = "https://firmgated.com/api/webhooks/YOUR_STRATEGY_SLUG"
# Keep the secret outside the script: export FIRMGATED_WEBHOOK_SECRET=...
SECRET = os.environ["FIRMGATED_WEBHOOK_SECRET"]


def request_close(action="flatten_and_lock", account=None):
    """action: "close_all" or "flatten_and_lock". account: optional broker account id."""
    body = {
        "secret": SECRET,
        "action": action,
        # A stable id makes a retried request run once.
        "id": f"py-{action}-{int(time.time())}",
    }
    if account:
        body["account"] = account
    response = requests.post(WEBHOOK_URL, json=body, timeout=10)
    response.raise_for_status()
    return response.json()  # {"ok": True, "accepted": True, "action": "...", "accounts": 1}


if __name__ == "__main__":
    print(request_close())
curl
curl -X POST "https://firmgated.com/api/webhooks/YOUR_STRATEGY_SLUG" \
  -H "Content-Type: application/json" \
  -d '{"secret":"'"$FIRMGATED_WEBHOOK_SECRET"'","action":"close_all","id":"curl-close-1"}'

Responses

202
Accepted. The request runs in the background and the result arrives as an alert.
400
The JSON is invalid, or account or id has the wrong type or length.
401
The secret or strategy does not match.
429
Too many requests from one address in a minute.