← Back
"""
OF-Trader — Pre-flight checklist (TESTNET ONLY).
================================================
Exercises the full order machinery on Binance Futures *testnet* with fake money:
  1. signed /balance            (proves API key + HMAC signing)
  2. symbol info + set leverage
  3. open a tiny position       (entry path)
  4. place TP + SL bracket      (place_tp_market / place_sl_market)
  5. market close + cancel all  (exit path)

HARD GUARD: refuses to run unless BINANCE_TESTNET=true, so it can never fire
real orders on mainnet.

Run:  ./venv/bin/python3 preflight.py [SYMBOL]   (default BTCUSDT)
"""

import sys
import time
import logging

logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
log = logging.getLogger("preflight")

from src.config import BINANCE_TESTNET, BINANCE_API_KEY

if not BINANCE_TESTNET:
    log.error("REFUSING: BINANCE_TESTNET is not true. Pre-flight is testnet-only.")
    sys.exit(2)
if not BINANCE_API_KEY:
    log.error("No BINANCE_API_KEY set. Add testnet keys to ecosystem/env first.")
    sys.exit(2)

from src.exchange import Exchange

SYMBOL = sys.argv[1] if len(sys.argv) > 1 else "BTCUSDT"


def main():
    ex = Exchange()
    ok = True

    # 1. signed balance
    try:
        bal = ex.get_balance()
        log.info(f"[1/5] ✓ signed balance OK: ${bal:.2f} USDT (testnet)")
    except Exception as e:
        log.error(f"[1/5] ✗ balance failed (signing?): {e}")
        return 1

    # 2. symbol info + leverage
    si = ex.get_symbol_info(SYMBOL)
    if not si:
        log.error(f"[2/5] ✗ no symbol info for {SYMBOL}")
        return 1
    ex.set_leverage(SYMBOL)
    log.info(f"[2/5] ✓ symbol info + leverage set ({SYMBOL}, tick={si['tick_size']}, minQty={si['min_qty']})")

    # 3. open tiny position (market — plumbing test, not strategy)
    mark = ex.get_mark_price(SYMBOL)
    qty = ex.round_qty(si, max(si["min_qty"], 5.0 / mark))  # ~$5 notional
    try:
        order = ex.client.futures_create_order(
            symbol=SYMBOL, side="BUY", type="MARKET", quantity=qty,
        )
        log.info(f"[3/5] ✓ opened {qty} {SYMBOL} @ market #{order.get('orderId')}")
    except Exception as e:
        log.error(f"[3/5] ✗ open failed: {e}")
        return 1
    time.sleep(1)

    # 4. bracket TP + SL (exit side = SELL for a long)
    tp = ex.place_tp_market(SYMBOL, "SELL", qty, mark * 1.02, si)
    sl = ex.place_sl_market(SYMBOL, "SELL", qty, mark * 0.98, si)
    open_orders = ex.get_open_orders(SYMBOL)
    if tp and sl and len(open_orders) >= 2:
        log.info(f"[4/5] ✓ bracket placed (TP+SL), {len(open_orders)} working orders")
    else:
        log.error(f"[4/5] ✗ bracket incomplete: tp={bool(tp)} sl={bool(sl)} working={len(open_orders)}")
        ok = False

    # 5. market close + cancel all
    fill = ex.close_position_market(SYMBOL, "SELL", qty, si)
    ex.cancel_all_orders(SYMBOL)
    remaining = ex.get_open_orders(SYMBOL)
    positions = [p for p in ex.get_positions() if p["symbol"] == SYMBOL]
    if fill and not remaining and not positions:
        log.info(f"[5/5] ✓ closed @ {fill}, no leftover orders/positions")
    else:
        log.error(f"[5/5] ✗ cleanup incomplete: fill={fill} orders={len(remaining)} pos={len(positions)}")
        ok = False

    log.info("PRE-FLIGHT PASSED ✓" if ok else "PRE-FLIGHT FAILED ✗")
    return 0 if ok else 1


if __name__ == "__main__":
    sys.exit(main())

📜 Git History

227e67bfeat(of-trader): testnet preflight checklist (chunk 4)4 weeks ago
Show last diff
Loading...