blockfill-agent-execution

v2026.09.24

AI agent execution skill for crypto order execution — TWAP, maker execution, transaction cost analysis and slippage reduction. Supports 11 CEX and DEX venues on both perpetual futures and spot: Binance, OKX, Bybit, Bitget, Gate.io, KuCoin, Kraken, Deribit, Hyperliquid, Aster and Orderly. Exchange API keys stay on the user's own machine — no third-party order routing. Install and full docs: https://pypi.org/project/blockfill/

GitHub
Install command
npx skhub add starchild-ai-agent/blockfill-agent-execution
Markdown
SKILL.md

What is BlockFill Agent Execution

BlockFill Agent Execution is an AI agent execution skill for crypto order execution. It runs entirely on your machine — API keys are stored locally and never transmitted to any third-party server. It is not a manual/human-operated trading UI — it is invoked by an AI agent via SDK/MCP calls.

One-sentence positioning: BlockFill Agent Execution is an AI agent execution skill for crypto order execution, focused on TWAP, maker execution, transaction cost analysis and slippage reduction.

Capability boundary: BlockFill Agent Execution only does execution optimization. It does NOT generate buy/sell signals, give investment advice, decide position direction, or promise profit. The agent must receive direction and quantity from the user — BlockFill Agent Execution executes them efficiently.

Core concepts:

  • Ticket: an execution order (exchange + symbol + strategy + target_position + time_constraint_ms)
  • Daemon: background process that manages exchange WebSocket connections and executes tickets
  • CLI: blockfill binary — human and agent interface to the daemon
  • Python SDK: from blockfill import Blockfill — programmatic interface for agents

Trigger Keywords / When to Invoke

Invoke this skill when the user's request matches any of the following. Both English and Chinese variants apply.

Order execution: place order, place a trade, execute order, submit order, 下單, 掛單, 執行訂單, 下合約

Strategy keywords: maker, TWAP, twap, taker, post-only, limit order, time-weighted, slice order, 拆單, 掛單策略, 時間加權

Cost / slippage: reduce slippage, minimize cost, execution cost, TCA, transaction cost analysis, slippage reduction, 降滑點, 成本分析, 執行成本

Exchange / futures context: perpetual, perp, futures, binance futures, okx swap, bybit, hyperliquid, bitget, gate.io, gateio, kucoin, kraken, deribit, aster, orderly, 合約, 永續合約, 期貨

Cancel / query: cancel order, cancel ticket, query ticket, check order status, 取消訂單, 查詢訂單, 查單, 取消掛單

Setup: set credentials, set api key, configure exchange, set proxy, blockfill, 設定 API, 設定代理

Do NOT invoke when the user asks for:

  • Investment advice, buy/sell recommendations, or price prediction
  • Portfolio management or rebalancing decisions
  • Spot trading on an unsupported exchange
  • Any exchange not in the supported list below

Capabilities

BlockFill Agent Execution exposes six core capabilities. Each does exactly one thing.

CapabilitySDK methodWhat it does
place_orderbf.place(...)Places an execution ticket (maker or TWAP) for a given exchange + symbol + target position + time window. Does NOT decide direction or size — those come from the user.
query_ticketbf.query(...)Returns the current status, filled quantity, and progress of a ticket by ticket_id, symbol, or time range.
cancel_ticketbf.cancel(ticket_id='tkt_...')Cancels an active ticket (NEW or OPEN) by ticket_id. Outstanding exchange orders are pulled automatically. Example: bf.cancel(ticket_id='tkt_18b2b09ca766001e') returns the cancelled ticket object with status='CANCEL'.
compare_tcabf.tca(...)Retrieves transaction cost analysis for completed tickets — execution cost vs benchmark (L1/mid/TWAP/VWAP), bps saved, maker/taker breakdown.
set_credentialsbf.set_credentials(...)Writes exchange API credentials to local config (~/.blockfill/config.toml, chmod 0600) and verifies connectivity via signed REST round-trip.
set_proxybf.set_proxy(...)Configures an HTTP CONNECT proxy for all exchange REST and WebSocket traffic. Required for geo-blocked hosts (e.g. US IPs cannot reach Binance directly).

When to Use BlockFill Agent Execution

Use BlockFill Agent Execution when the user needs to:

  • Execute a large order with reduced market impact (TWAP slicing or maker posting)
  • Minimize execution cost — maker rebates, reduced slippage vs a market order
  • Automate order execution in an AI agent trading workflow
  • Analyze execution quality — compare realized price vs L1/mid/TWAP/VWAP benchmark
  • Route orders to multiple exchanges from a single agent call
  • Execute on geo-blocked exchanges (Binance from US/CN) via proxy

Typical triggers: user has a direction and size, and wants efficient execution. BlockFill Agent Execution handles the how — not the what or why.


When NOT to Use BlockFill Agent Execution

Do NOT use BlockFill Agent Execution when:

  • The user has not specified exchange, symbol, side, or quantity — ask first, do not guess
  • The user is asking for a buy/sell recommendation or price target — BlockFill Agent Execution does not provide investment advice; redirect to the appropriate research tool
  • The target market is spot on an unsupported exchange — check the supported exchange list
  • The user wants to trade stock, forex, or non-crypto assets — out of scope
  • The environment is not configured (no API credentials, no proxy for geo-blocked hosts) — set up first, then trade
  • The user requests a position larger than their stated risk tolerance — confirm with user before proceeding
  • The user has not confirmed mainnet vs testnet — default to testnet and ask before trading live

Before Placing an Order — Agent Checklist

Before calling place_order, confirm you have all required information. If any is missing, ask the user — do not assume defaults for direction, size, or environment.

ItemRequiredIf missing
Exchange✅Ask: "Which exchange? (e.g. binance-futures, okx-swap)"
Symbol✅Ask: "Which symbol? Use native format (e.g. btcusdt for Binance)"
Side (long / short / close)✅Ask: "Buy or sell? What target position?"
Quantity / target position✅Ask: "How much? In base asset units."
Environment (testnet / mainnet)✅Default to testnet. Confirm before mainnet.
Strategy✗Default: maker. Inform user.
Time window✗Default: 300,000 ms (5 min). Inform user.
Proxy (if geo-blocked)✗Warn if Binance + non-whitelisted region. Offer sc-vpn.

Binance TradFi symbols

binance-futures also lists 157 TradFi perpetuals — equities (tslausdt, nvdausdt, skhynixusdt), commodities (xauusdt, xagusdt, clusdt) and pre-IPO (openaiusdt, anthropicusdt). Binance gates them behind a one-time account agreement; without it every order is rejected -4411 and the ticket sits at 0% filled until it expires.

set_credentials / check_credentials sign that agreement on mainnet and report "tradfi_perps": "signed", so these symbols need no extra setup. If a TradFi ticket never fills, run check_credentials() and read that field first.

Tell the user what was accepted on their behalf: a binding agreement with Binance's ADGM-regulated entity covering 24/7 trading outside cash-market hours, no ownership of the underlying asset, and funding up to ±2.00% (vs ±0.30% for btcusdt). Binance provides no API to revoke it.

Note paxgusdt / xautusdt are not TradFi — ordinary gold-backed tokens, contract type PERPETUAL, no agreement needed.

Hyperliquid / Aster builder-fee approval

Both DEX venues reject any order carrying an unapproved builder code — Hyperliquid with Builder fee has not been approved — and the ticket then sits at 0% filled until its window expires. The user must approve once, on-chain, signed by their MAIN wallet:

VenueBuilder addressApprove at
Hyperliquid (perp + spot)0xB972e5151b20863380A3E7354dd93F1b888E3352≥ 0.015% (1.5 bp)
Aster (perp only)0xB972e5151b20863380A3E7354dd93F1b888E3352≥ 0.015% (1.5 bp)

BlockFill signs this for the user. These venues take the account owner's wallet private_key (not a delegated agent key) precisely so it can: check_credentials() reads the current approval and signs approveBuilderFee / approveBuilder when ours is missing or below rate, reporting "builder_fee": "approved just now at 0.015%". Only if signing fails does the check fail. Aster spot needs nothing; Aster Code is perp-only.

Tell the user what that key can do: it signs orders and this one fee authorization, and it could withdraw — the exchange no longer prevents that, only the absence of withdrawal code in the engine does. See docs/security/trade-only-permissions.md for the exhaustive signable-action list.

⚠️ Testnet attaches no builder code, so it never surfaces this. A testnet run can pass completely and the first mainnet order still fail. When moving a user from testnet to mainnet on these venues, re-run check_credentials() before placing.


Install

pip install blockfill                    # latest
pip install -U blockfill                 # upgrade

The wheel ships with the executor binary bundled inside (no separate download). PyPI publishes only platform-specific wheels. Currently supported: manylinux2014_x86_64 (Linux x86_64).

The blockfill-server endpoint and API key are hardcoded into the binary at release time — users never set them.


Supported Exchanges

Every venue runs perp/futures + spot from one daemon. Exchange id is <venue>-<product> (e.g. binance-futures, okx-swap, bybit-perp, <venue>-spot).

ExchangeExchange id (perp/futures · spot)CredentialsClass
Binancebinance-futures · binance-spotapi_key, api_secret (HMAC or Ed25519 PEM), testnetCEX
OKXokx-swap · okx-spotapi_key, api_secret, api_passphrase, testnetCEX
Bybitbybit-perp · bybit-spotapi_key, api_secret, testnetCEX
Bitgetbitget-futures · bitget-spotapi_key, api_secret, api_passphrase, testnetCEX
Gate.iogateio-futures · gateio-spotapi_key, api_secret, testnetCEX
KuCoinkucoin-futures · kucoin-spotapi_key, api_secret, api_passphrase, testnetCEX
Krakenkraken-futures · kraken-spotapi_key, api_secret, testnetCEX
Deribitderibit-perp · deribit-spotapi_key, api_secret, testnetCEX
Hyperliquidhyperliquid-perp · hyperliquid-spotprivate_key (account wallet, EIP-712)DEX
Asteraster-perp · aster-spotprivate_key (account wallet, EIP-712)DEX
Orderlyorderly-<broker>account_id, orderly_secret, broker_id (Ed25519; see below)DEX

A single daemon can run all exchanges concurrently. CEX are billed by x402 quota (see Payment); DEX (Hyperliquid / Aster / Orderly) pay builder-code execution fees and have no quota.

Hyperliquid / Aster — wallet-signed DEX:

bf.set_credentials("hyperliquid-perp",
                   private_key="0x...")
bf.set_credentials("aster-perp",
                   private_key="0x...")

Binance Ed25519 keys — Binance Futures testnet issues Ed25519 keys (no HMAC secret). Pass api_key = the Ed25519 API Key id, api_secret = the PEM private key. The daemon auto-detects and signs with Ed25519.

bf.set_credentials("binance-futures",
    api_key="<Ed25519 API Key id>",
    api_secret="-----BEGIN PRIVATE KEY-----\nMC4CAQAw...\n-----END PRIVATE KEY-----",
    testnet=True)

Orderly — model each broker as its own exchange instance named orderly-<broker>:

bf.set_credentials("orderly-woofi",
    account_id="0x...", orderly_secret="ed25519:...", broker_id="woofi_pro", testnet=True)

Supported Symbols

Each exchange uses its own native symbol format.

ExchangeFormatExamples
binance-futuresLowercase, concatenatedbtcusdt, ethusdt, solusdt
okx-swapDash-separated + SWAP suffixBTC-USDT-SWAP, ETH-USDT-SWAP
bybit-perpUPPERCASE, concatenatedBTCUSDT, ETHUSDT
bitget-futuresUPPERCASE, concatenatedBTCUSDT, ETHUSDT
gateio-futuresUnderscore-separatedBTC_USDT, ETH_USDT
kucoin-futuresContract codeXBTUSDTM, ETHUSDTM
kraken-futuresPF_ prefix + base/quotePF_XBTUSD, PF_ETHUSD
deribit-perpDash-separated + PERPETUAL suffixBTC-PERPETUAL, ETH-PERPETUAL
hyperliquid-perpCoin onlyBTC, ETH, SOL
aster-perpUPPERCASE, concatenatedBTCUSDT, ETHUSDT
orderly-<broker>Exchange-specific via brokerUse bf.instruments(substring) to discover

Use the exact format the target exchange expects — BlockFill Agent Execution does NOT cross-translate. Discover the exact string for any venue:

blockfill check instrument --symbol btc

Execution Strategies

StrategyBehaviorWhen to use
makerPosts PostOnly limit orders; earns maker rebate. Falls back to IOC at end of window for any unfilled remainder.Default. Cost-optimal when fill speed is not critical.
twapPlaces IOC orders on a TWAP schedule across the full window — always crosses the spread.When you need guaranteed completion and accept taker cost.

Default strategy: maker.


Ticket Parameters

ParameterTypeRequiredDefaultDescription
exchangestring✅—Supported exchange id, e.g. binance-futures, okx-swap
symbolstring✅—Exchange-native format, e.g. btcusdt (Binance), BTC-USDT-SWAP (OKX)
target_positionfloat✅—Target position in base asset. Positive = long, negative = short (perp). For spot: absolute base-asset holding to end up with.
strategystringmakermaker | twap
time_constraint_msint300000Execution window in milliseconds. Range: 60,000–86,400,000 (1 min to 24h). At window end, executor falls back to taker fills for any unfilled remainder.

Auto-supersede: placing a new ticket for the same exchange+symbol automatically cancels existing NEW and OPEN tickets for that pair.

Spot vs perp target_position: perp = net directional position (positive = long, negative = short). Spot = absolute base-asset holding to end up with (target=0.001 on a 1.0 BTC balance sells 0.999; to add, set target = current_holding + delta).


Ticket Schema

{
    "ticket_id": "tkt_18b2b09ca766001e",
    "status": "OPEN",
    "exchange": "binance-futures",
    "symbol": "btcusdt",
    "strategy": "maker",
    "target_position": 0.5,
    "init_position": 0.0,
    "executed_position": 0.13,
    "time_constraint_ms": 300000,
    "start_time_ms": 1779287926007,
    "last_update_time_ms": 1779287935063,
    "is_expired": false,
    "cancel_reason": null
}
FieldTypeDescription
ticket_idstringtkt_<hex>
statusstringNEW | OPEN | COMPLETE | CANCEL
exchangestringExchange id used
symbolstringNative symbol format
strategystringmaker | twap
target_positionfloatRequested net position
init_positionfloat | nullPosition at activation (null while NEW)
executed_positionfloatNet delta filled so far
time_constraint_msintExecution window in ms
start_time_msint | nullSet when executor activates (NEW → OPEN)
last_update_time_msint | nullRefreshed on every state change
is_expiredboolTrue when window elapsed; status stays OPEN until cancelled
cancel_reasonstring | nullexternal | superseded | stale | rejected | min_notional | risk_breach | insufficient_margin | paused

Note: The ticket has no avg_price or cost field. For execution cost, opportunity cost, and benchmark comparisons, call compare_tca (bf.tca(...)) — it returns execution_cost_usd, opportunity_cost_usd, and benchmarks (l1/mid/twap/vwap) per ticket.


Quickstart (Testnet)

from blockfill import Blockfill

bf = Blockfill()

# Step 1: Set credentials (SDK default is testnet=False/MAINNET — agents MUST pass testnet=True explicitly for sandboxed testing)
bf.set_credentials(
    exchange="binance-futures",
    api_key="...",
    api_secret="...",
    testnet=True,      # ALWAYS start with testnet
)

# Step 2: Start daemon (~50s warmup while it fetches market data)
bf.start()
bf.status()  # DaemonStatus(running=True, ready_exchanges=['binance-futures'], ...)

# Step 3: Place a ticket
ticket = bf.place(
    exchange="binance-futures",
    symbol="btcusdt",
    target_position=0.1,      # base asset units (BTC)
    strategy="maker",         # default
    time_constraint_ms=60_000,  # 60 seconds
)
print(ticket.ticket_id, ticket.status)

Diagnostics

bf.check_credentials() -> None
# Hits a SIGNED REST endpoint per configured exchange; prints one line each:
# ✓ <name> / ✗ <name> <reason>.
# Detects: wrong key/secret, IP whitelist mismatch, testnet/mainnet mix-up,
# network/proxy/geo block. Auto-invoked at end of set_credentials().

bf.positions() -> list[dict]
# Aggregated positions from each running executor.
# Each entry: {exchange, symbol, size, entry_price, update_ts_ms}

bf.open_orders() -> list[dict]
# Active orders on each configured exchange right now.

bf.nav() -> dict
# Net Asset Value across all running executors.
# {exchanges: [{exchange, nav, wallet_balance, margin_value, unrealized_pnl}],
#  total_nav, exchanges_queried}

bf.tca(ticket_id=None, symbol=None, from_ms=None, to_ms=None, limit=100,
       history=False) -> list[dict]
# Transaction cost analysis for completed tickets.
# history=False: active session (in-memory).
# history=True:  persistent across all sessions (blockfill-server).
# Each entry: benchmarks (l1/mid/twap/vwap), fills, maker/taker breakdown,
# execution_cost_usd, opportunity_cost_usd, duration_ms.

bf.instruments(substring) -> list[dict]
# Per-exchange instrument lookup — returns native-format symbols matching
# substring. Use this to find the exact symbol string before placing.

Proxy / Geo-bypass

For hosts that can't reach Binance directly (US IPs return HTTP 451), route exchange REST and WebSocket traffic through an HTTP CONNECT proxy.

Starchild users — free sc-vpn skill, 18 countries, 500 GB/month:

bf.set_proxy("http://jp:x@sc-vpn.internal:8080")   # Japan (lowest latency for Binance)
bf.set_proxy("http://sg:x@sc-vpn.internal:8080")   # Singapore
bf.set_proxy("http://hk:x@sc-vpn.internal:8080")   # Hong Kong
bf.set_proxy()                                      # clear proxy
Asia-PacificEuropeAmericas
jp Japanuk United Kingdomca Canada
sg Singaporede Germanybr Brazil
hk Hong Kongfr Francemx Mexico
kr South Koreanl Netherlands
tw Taiwanch Switzerland
au Australiait Italy
in Indiaes Spain
se Sweden

Any HTTP CONNECT proxy also works:

bf.set_proxy("http://user:pass@proxy.example.com:8080")

set_proxy restarts the daemon so the new setting takes effect. The proxy covers both REST and WebSocket — every exchange WS connection is tunneled.

Verify reachability before placing real orders:

bf.set_proxy("http://jp:x@sc-vpn.internal:8080")
bf.set_credentials("binance-futures", api_key=..., api_secret=...)
# set_credentials auto-runs check_credentials() — a ✓ proves both proxy + auth work.

Failure Modes

When something fails, diagnose in this order: credentials → proxy → environment → symbol → margin.

SymptomLikely causeFix
check_credentials prints ✗ <exchange> IP not whitelistedAPI key bound to a different IP than your current outbound IPAdd your outbound IP (or proxy IP) to the exchange API key whitelist
check_credentials prints ✗ <exchange> connection refused / HTTP 451Geo-block (e.g. US IP → Binance)Set a proxy: bf.set_proxy("http://jp:x@sc-vpn.internal:8080")
check_credentials prints ✗ <exchange> invalid signatureWrong api_secret, or wrong key type (HMAC vs Ed25519)Re-check credentials; Binance testnet uses Ed25519, not HMAC
Ticket stays NEW for >30sExchange not in ready_exchanges (executor still warming up, or failed init)Check bf.status() → ready_exchanges; check blockfill logs for init error
Ticket cancel_reason: min_notionalOrder size × price < exchange minimum notionalIncrease quantity or use a larger notional
Ticket cancel_reason: insufficient_marginNot enough margin for the positionReduce quantity or add margin
Ticket cancel_reason: rejectedExchange rejected the order (symbol suspended, invalid params)Check symbol with bf.instruments(substring); verify symbol format
status shows ready_exchanges: [] after >90sDaemon failed to init one or more exchangesRun blockfill stop && blockfill start; check logs for error
NAV = 0 for Binance spot (testnet)Testnet does not support getUserAsset endpointExpected — testnet NAV uses market-ticker routing instead

For persistent issues, see GitLab Issues or Telegram support. See docs/troubleshooting.md for the full knowledge base.


Payment — x402 Quota

Quota is tracked per (account, exchange) pair. Every pair starts with a free tier; quota is charged when each ticket's TCA finalizes. When the free tier runs out, buy more by paying USDC on Base via x402 — gasless EIP-3009 transferWithAuthorization. The daemon holds the wallet key and signs locally; only the signature leaves the machine, never the key.

bf.set_payment("0x<64-hex private key>")     # store EVM wallet key
bf.topup("binance-futures", usdc=1.0)        # → {exchange, usdc, quota_balance, tx_hash}

CEX exchanges (Binance, OKX, Bybit, Bitget, Gate.io, KuCoin, Kraken, Deribit) use quota. DEX (Hyperliquid, Aster, Orderly) pay builder-code execution fees directly — no quota.

The blockfill-server only ever sees the signature and a de-identified (SHA-256 hashed) account id — never your exchange API key or wallet key.


Typical Agent Flow

from blockfill import Blockfill
import os

bf = Blockfill()

# (Optional) configure proxy first if in a geo-blocked region
# bf.set_proxy("http://jp:x@sc-vpn.internal:8080")

# Set creds — SDK automatically verifies via signed REST
bf.set_credentials(
    "binance-futures",
    api_key=os.environ["BINANCE_API_KEY"],
    api_secret=os.environ["BINANCE_API_SECRET"],
    testnet=True,           # always confirm testnet vs mainnet with user
)

# Start daemon
bf.start()  # auto-waits ~50s for warmup

# Place ticket
ticket = bf.place(
    exchange="binance-futures",
    symbol="btcusdt",
    target_position=0.1,   # +0.1 BTC long
    strategy="maker",
    time_constraint_ms=300_000,
)

# Monitor
import time
while ticket.status in ("NEW", "OPEN"):
    time.sleep(5)
    ticket = bf.query(ticket_id=ticket.ticket_id)[0]
    print(f"filled: {ticket.executed_position} / {ticket.target_position}")

# TCA
tca = bf.tca(ticket_id=ticket.ticket_id)
print(tca)

bf.stop()

Support

Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

Not specified

Source path

blockfill-agent-execution

Default branch

main

Latest commit

cce29fd

Tree SHA

baca3ec