Signal API

Receive strategy signals in your own code: pull with a REST API or get pushed by webhook.

1. Setup

  1. Buy the SOXL strategy to enable the API.
  2. Generate an API key on My Account. It is shown once; generating a new one revokes the old one.
  3. Optional: save a webhook URL (https, public host). A signing secret is shown when you first save it.

2. When signals are produced

Once per trading day, around 16:45 ET after the close. Entry and exit instructions apply to the next session (or to effective_date), so there is a full evening to prepare.

3. Pull (REST)

Base URL: https://api.qqqwatcher.com/api/v1 Β· Auth: X-API-Key: qw_… Β· Rate limit 120 requests / 10 min

EndpointDescription
GET /meWhich strategies this key can read
GET /signals?strategy=soxl&since_id=0&limit=100Signals with id > since_id, ascending. Store next_since_id and pass it next time.
GET /positions?strategy=soxlCurrent signal-book positions, including pending entries
curl -H "X-API-Key: qw_your_key" "https://api.qqqwatcher.com/api/v1/signals?strategy=all&since_id=0"

4. Signal object

{
  "id": 42,
  "strategy": "soxl_signal",
  "kind": "entry",                      // entry | fill | exit | closed | notice
  "symbol": "SOXL",
  "side": "long",                       // long | short
  "action": "buy_at_open",              // buy_at_open | sell_at_close | entered | exited
  "effective_date": "2026-10-15",       // the session the instruction applies to
  "price": null,                        // fill/closed: actual price used
  "created_at": "2026-10-14T20:46:03Z",
  "details": {
    "signal_date": "2026-10-14", "planned_exit_date": "2026-10-22",
    "stop_loss": null, "take_profit": null
  }
}

5. Webhook push

One POST per signal with JSON body {"type":"signal","attempt":1,"signal":{…}}. Any 2xx counts as delivered; otherwise retried after 1 / 5 / 30 / 120 / 360 minutes, 6 attempts in total. A signal may arrive more than once β€” de-duplicate on signal.id.

Signature header: X-QW-Signature: t=<unix>,v1=<hex>,v1 = HMAC-SHA256(secret, t + "." + raw_body)。Verify it and reject t older than 5 minutes.

// Node.js (Express)
const crypto = require('crypto');
app.post('/qw', express.raw({ type: 'application/json' }), (req, res) => {
  const [t, v1] = req.get('X-QW-Signature').split(',').map(x => x.split('=')[1]);
  const mac = crypto.createHmac('sha256', process.env.QW_SECRET).update(t + '.' + req.body).digest('hex');
  if (mac !== v1 || Date.now() / 1000 - t > 300) return res.sendStatus(400);
  const { signal } = JSON.parse(req.body);
  // ... place your order
  res.sendStatus(200);
});
# Python (Flask)
import hmac, hashlib, time, json
@app.post("/qw")
def qw():
    t, v1 = [x.split("=")[1] for x in request.headers["X-QW-Signature"].split(",")]
    mac = hmac.new(SECRET.encode(), (t + ".").encode() + request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(mac, v1) or time.time() - int(t) > 300:
        return "", 400
    signal = json.loads(request.get_data())["signal"]
    return "", 200

Rule output only, not investment advice. Past performance, real or simulated, does not guarantee future results.