API Docs/Quick-start

Quick-start Guide

Planned

From API key to first live trade in under 30 minutes.

The API is in development. This guide reflects the planned integration spec. Join early access to be notified at launch.

How it works

MasterBitcoin runs MB L (long) and MB S (short) continuously on ~600 Bybit linear perpetuals. Every signal - open and close - is available to API subscribers via two delivery modes:

âš¡
Webhook push
Recommended

MB posts a signed JSON payload to your HTTPS endpoint the moment a signal fires.

Latency: < 500 ms from signal to your server.

Requires: a public HTTPS URL (your server, Render, Railway, etc.).

🔄
REST polling

You call /api/signals every 30 s and diff against your last seen signal_id.

Latency: up to 30 s behind real time.

Requires: nothing beyond an API key and a cron / loop.

Both modes deliver the same signal payload. You can run them simultaneously - webhook as the primary channel, polling as the fallback in case your server misses a delivery.

Entry signal payload

Delivered when MB opens a new position. Execute a corresponding position on your exchange.

{
  "event":           "trade.entry",
  "signal_id":       "mb-20260617-083142-SOLUSDT",   // unique - use as idempotency key
  "timestamp":       "2026-06-17T08:31:42Z",          // UTC, ISO 8601
  "symbol":          "SOLUSDT",                       // Bybit linear perp ticker
  "exchange":        "bybit",
  "market":          "linear_perp",
  "side":            "long",                          // "long" | "short"
  "strategy":        "MB L",                  // "MB L" | "MB S"
  "entry_price":     142.50,                          // mark price at signal time
  "stop_loss_price": 128.25,                          // absolute price for SL order
  "stop_loss_pct":   -10.0,                           // % from entry_price (negative)
  "score":           67,                              // composite score 0–100
  "regime":          "risk_on"                        // "risk_on" | "neutral" | "risk_off"
}
FieldTypeNotes
signal_idstringStable across retries. Check for duplicates before executing.
sidestring"long" → Buy on exchange. "short" → Sell.
stop_loss_pricefloatPlace a native stop at exactly this price. Do not move it.
stop_loss_pctfloatReference only - stop_loss_price is canonical.
scoreint0–100. Higher = stronger conviction. MB acts at ≥ 52.
regimestringMarket regime at signal time. Info only - signal already passed gate.

Exit signal payload

Delivered when MB closes a position. Match via signal_id to the original entry. The reason field tells you whether the exchange has already closed the position or whether you need to act.

{
  "event":       "trade.exit",
  "signal_id":   "mb-20260617-083142-SOLUSDT",   // matches the entry signal_id
  "timestamp":   "2026-06-17T12:14:23Z",
  "symbol":      "SOLUSDT",
  "side":        "long",
  "reason":      "score_decay",                  // see table below
  "exit_price":  149.80,                         // mark price at close
  "pnl_pct":     5.12                            // % P&L from entry to exit
}

Exit reasons

reasonTriggerWhat you must do
stop_lossPrice hit the stop-loss level set at entryPosition already closed on exchange by native stop order. Sync your records.
score_decayComposite score dropped ≥ 15 pts from entry scoreSignal conviction faded. Close position at market.
max_holdPosition held longer than MAX_HOLD (4 hours)Signal stale. Close at market regardless of P&L.
trailing_stopNative Bybit trailing stop triggeredPosition already closed by exchange. Sync your records.
book_trail_tpBook-level trailing take-profit fired (whole portfolio)All positions in this strategy closed. Exit any that remain.

Choose your integration path

Pick the approach that matches your technical comfort level. All three access the same signals.

🔌
No-code
Easiest

Use a bot platform that accepts webhook signals and manages exchange connectivity for you.

Compatible platforms

  • Wundertrading
  • Cornix
  • 3Commas

Connect your Bybit account to the platform, paste your MB webhook URL into the platform's bot settings. Done.

âš¡
Own webhook server
Recommended

Run the reference Python executor below. MB posts to you; you place orders on Bybit.

You need

  • Python 3.10+
  • Public HTTPS endpoint
  • Bybit API key

Full control over sizing, leverage, and order types. Lowest latency.

🔄
REST polling
No server needed

Call /api/signals on a schedule and process new entries yourself.

You need

  • Any scripting language
  • A cron job or loop
  • Bybit API key

Up to ~30 s behind real time. Good as a webhook fallback.

REST polling - minimal example

import time, requests

API_KEY  = "mb_live_XXXX"
BASE_URL = "https://masterbitcoin.io"
last_id  = None

def poll():
    global last_id
    r = requests.get(
        f"{BASE_URL}/api/signals",
        headers={"Authorization": f"Bearer {API_KEY}"},
        params={"limit": 50, "side": "long,short"},
    )
    r.raise_for_status()
    signals = r.json()["signals"]

    new = [s for s in signals if last_id is None or s["signal_id"] > last_id]
    for sig in sorted(new, key=lambda x: x["timestamp"]):
        handle_signal(sig)   # your execution logic here

    if new:
        last_id = max(s["signal_id"] for s in new)

while True:
    try:
        poll()
    except Exception as e:
        print(f"poll error: {e}")
    time.sleep(30)

Reference executor (Python)

Complete webhook receiver for Path B above. Receives MB push events and places/closes Bybit perpetual positions.

Install: pip install flask pybit

#!/usr/bin/env python3
"""
MasterBitcoin - reference webhook executor
Receives MB signals and places orders on Bybit linear perpetuals.
"""
import hmac, hashlib, os
from flask import Flask, request, abort
from pybit.unified_trading import HTTP

app = Flask(__name__)

MB_SECRET    = os.environ["MB_WEBHOOK_SECRET"]   # from MB dashboard
BYBIT_KEY    = os.environ["BYBIT_API_KEY"]
BYBIT_SECRET = os.environ["BYBIT_API_SECRET"]
LEVERAGE     = int(os.environ.get("LEVERAGE", "2"))
NOTIONAL_USD = float(os.environ.get("NOTIONAL_USD", "100"))  # per position

session = HTTP(demo=False, api_key=BYBIT_KEY, api_secret=BYBIT_SECRET)

# Track signal_ids we've already executed (in-process; use Redis for multi-replica)
_executed: set[str] = set()


def _verify_signature(payload: bytes, header: str) -> bool:
    expected = hmac.new(MB_SECRET.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header.removeprefix("sha256="))


@app.post("/webhook")
def webhook():
    sig = request.headers.get("X-MB-Signature", "")
    if not _verify_signature(request.data, sig):
        abort(401)

    ev = request.json
    sid = ev.get("signal_id", "")

    # Idempotency guard - ignore duplicate deliveries
    if sid in _executed:
        return "", 200
    _executed.add(sid)

    if ev["event"] == "trade.entry":
        _open_position(ev)
    elif ev["event"] == "trade.exit":
        _close_position(ev)

    return "", 200


def _open_position(ev: dict) -> None:
    sym   = ev["symbol"]
    side  = "Buy" if ev["side"] == "long" else "Sell"
    sl    = ev["stop_loss_price"]

    ticker = session.get_tickers(category="linear", symbol=sym)
    price  = float(ticker["result"]["list"][0]["lastPrice"])
    qty    = round(NOTIONAL_USD / price, 3)

    session.set_leverage(
        category="linear", symbol=sym,
        buyLeverage=str(LEVERAGE), sellLeverage=str(LEVERAGE),
    )
    session.place_order(
        category="linear", symbol=sym, side=side,
        orderType="Market", qty=str(qty),
        stopLoss=str(sl), slTriggerBy="MarkPrice",
    )
    print(f"[OPEN]  {sym} {side} ${NOTIONAL_USD:.0f} SL={sl}")


def _close_position(ev: dict) -> None:
    sym    = ev["symbol"]
    reason = ev["reason"]

    # Exchange already closed these - just log and return
    if reason in ("stop_loss", "trailing_stop"):
        print(f"[SKIP]  {sym} - already closed by exchange ({reason})")
        return

    pos = session.get_positions(category="linear", symbol=sym)["result"]["list"]
    if not pos or float(pos[0]["size"]) == 0:
        print(f"[SKIP]  {sym} - no open position found")
        return

    p     = pos[0]
    close = "Sell" if p["side"] == "Buy" else "Buy"
    session.place_order(
        category="linear", symbol=sym, side=close,
        orderType="Market", qty=p["size"], reduceOnly=True,
    )
    print(f"[CLOSE] {sym} reason={reason} pnl={ev.get('pnl_pct', '?')}%")


if __name__ == "__main__":
    # In production: use gunicorn or uvicorn behind a reverse proxy (nginx/caddy)
    app.run(host="0.0.0.0", port=8080)

Before going live

  • Set demo=True in the HTTP() constructor and run against a Bybit demo account first.
  • Add your public HTTPS URL to the MB webhook settings in your dashboard.
  • Verify the signature check passes by sending a test ping from the dashboard.
  • Monitor _executed size in production - replace with a Redis set if you run multiple replicas.

Risk configuration

Recommended starting parameters. Adjust once you have at least 30 live round-trips of data.

ParameterRecommended startNotes
Leverage2×Increase only after 30d+ of profitable live trading.
Notional per trade$50–$100Keep fixed; don't size up with winning streaks.
Max open positions5–10More than 10 creates correlated drawdown in down markets.
Stop-lossFrom payloadUse stop_loss_price exactly - do not widen or remove it.
Max daily loss2–3% of capitalHalt the executor if daily loss limit hit; review before resuming.
AccountDemo firstRun on Bybit demo (demo=True) for at least 2 weeks before live.

Disclaimer

MasterBitcoin signals are generated by a demo-validated algorithmic strategy and are provided for informational purposes only. Past performance on a demo account does not guarantee future results on live capital. Cryptocurrency futures trading carries significant risk of loss. Never allocate funds you cannot afford to lose.

FAQ

What if I already have a position open in the same symbol when an entry fires?

Skip the entry. MB holds at most one position per symbol at a time. If your position was opened from a previous signal that hasn't exited yet, wait for the exit signal before re-entering.

Can I use different leverage than the example?

Yes. The signal doesn't prescribe leverage. Adjust LEVERAGE and NOTIONAL_USD in the executor to suit your risk tolerance. Lower leverage with larger notional achieves the same exposure with less liquidation risk.

Can I use exchanges other than Bybit?

Signals use Bybit linear USDT-perpetual symbol names (e.g. SOLUSDT, ETHUSDT). Most major exchanges (OKX, Binance) list the same symbols but may use different naming conventions. Check your exchange's contract spec before adapting the executor.

What if I miss a webhook delivery?

Enable the REST polling fallback: call /signals every 30 s and compare against your last processed signal_id. Any gap will be caught within one poll interval. Both delivery methods can run simultaneously.

Should I execute on a demo account first?

Yes - always. Run the executor against a Bybit demo account (demo=True in pybit) until you are confident the sizing, leverage, and stop-loss placement match your expectations. Switch to live only after at least 20 successful demo round-trips.

How do I handle the stop_loss and trailing_stop exit reasons?

When MB sends those exit reasons, the exchange has already closed the position for you via native orders. Your executor still needs to receive the event and update its own position state, but there is nothing left to close on Bybit.

Ready to integrate?

API access is available on the Pro plan. Early subscribers lock in the founding price.