Quick-start Guide
PlannedFrom API key to first live trade in under 30 minutes.
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:
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"
}| Field | Type | Notes |
|---|---|---|
| signal_id | string | Stable across retries. Check for duplicates before executing. |
| side | string | "long" → Buy on exchange. "short" → Sell. |
| stop_loss_price | float | Place a native stop at exactly this price. Do not move it. |
| stop_loss_pct | float | Reference only - stop_loss_price is canonical. |
| score | int | 0–100. Higher = stronger conviction. MB acts at ≥ 52. |
| regime | string | Market 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
| reason | Trigger | What you must do |
|---|---|---|
| stop_loss | Price hit the stop-loss level set at entry | Position already closed on exchange by native stop order. Sync your records. |
| score_decay | Composite score dropped ≥ 15 pts from entry score | Signal conviction faded. Close position at market. |
| max_hold | Position held longer than MAX_HOLD (4 hours) | Signal stale. Close at market regardless of P&L. |
| trailing_stop | Native Bybit trailing stop triggered | Position already closed by exchange. Sync your records. |
| book_trail_tp | Book-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.
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=Truein theHTTP()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
_executedsize 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.
| Parameter | Recommended start | Notes |
|---|---|---|
| Leverage | 2× | Increase only after 30d+ of profitable live trading. |
| Notional per trade | $50–$100 | Keep fixed; don't size up with winning streaks. |
| Max open positions | 5–10 | More than 10 creates correlated drawdown in down markets. |
| Stop-loss | From payload | Use stop_loss_price exactly - do not widen or remove it. |
| Max daily loss | 2–3% of capital | Halt the executor if daily loss limit hit; review before resuming. |
| Account | Demo first | Run 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.