Trading¶
Submit orders, cancel positions, react to fills.
The Connection object¶
All trading goes through a Connection obtained from Platform:
from fastboxex import Platform, load_config
import os
cfg = load_config()
p = Platform.login(cfg, "alice", os.environ["FASTBOXEX_PASSWORD"])
asset_id = p.asset_by_symbol("JTW")["asset_id"]
conn = p.connection()
conn.activate(asset_id)
Submit and cancel orders¶
# Limit buy at 99.95 display (= 999_500 raw ticks)
conn.submit_limit(asset_id, side=0, price=999_500, qty=100, client_tag=42)
# Limit sell at 100.05
conn.submit_limit(asset_id, side=1, price=1_000_500, qty=100, client_tag=43)
# Cancel all resting orders for this asset
conn.cancel_all(asset_id)
# Cancel by tag
conn.cancel_by_tag(42, asset_id, side=0)
# Cancel orders worse than a reference price
conn.cancel_worse_than(asset_id, side=0, ref_price=999_000)
submit_limit(asset_id, side, price, qty, *, client_tag=0) parameters:
| Parameter | Type | Description |
|---|---|---|
asset_id |
int |
Asset to trade |
side |
0 or 1 |
0 = BUY, 1 = SELL |
price |
int |
Price in raw ticks |
qty |
int |
Quantity in lots |
client_tag |
int |
Optional identifier echoed in acks/fills |
Draining events¶
Both methods are non-blocking and return all pending events since the last call.
for fill in conn.drain_fills():
side = "BUY" if fill["side"] == 0 else "SELL"
print(f"FILL {side} {fill['volume']} @ {fill['price'] / 10_000:.4f}")
for ack in conn.drain_acks():
print(f"ACK status={ack['status']} tag={ack['client_tag']}")
Market and delta orders¶
Market order — sweep the book¶
conn.submit_market(asset_id, side=0, qty=100) # BUY at any price
conn.submit_market(asset_id, side=1, qty=100) # SELL at any price
Sweeps all available liquidity on the opposite side. Returns a BookEmpty rejection if the
book is empty — no silent failures.
Delta order — BBO-relative with optional IOC¶
Place at p_eff = best_ask + delta_ticks × tick_size (buy) or
p_eff = best_bid + delta_ticks × tick_size (sell).
# Touch buy — executes at current best ask, rests if partially filled
conn.submit_delta(asset_id, side=0, delta_ticks=0, qty=100)
# IOC — execute what's available, cancel the rest immediately
conn.submit_ioc(asset_id, side=0, delta_ticks=0, qty=100)
delta_ticks=0 is a touch order — the most common pattern for aggressive strategies.
delta_ticks=1 makes the order one tick more aggressive (pays up by 1 tick).
Full mathematical treatment
See Order Types — Mathematical Framework for the complete derivation, comparison with conventional exchanges, the cube taxonomy, and the passive-peg pattern.
Quoting both sides: complete example¶
from fastboxex import Platform, load_config
from fastboxex.price import to_display
import os, random
cfg = load_config()
p = Platform.login(cfg, cfg.username, os.environ["FASTBOXEX_PASSWORD"])
asset_id = p.asset_by_symbol("JTW")["asset_id"]
conn = p.connection()
conn.activate(asset_id)
SPREAD = 400 # raw ticks
for _ in range(100):
market = p.market()
md = market.get_latest(asset_id)
if md is None:
continue
bid, ask = md["bid"], md["ask"]
mid = (bid + ask) // 2 + random.randint(-2, 2) * 100
conn.cancel_all(asset_id)
conn.submit_limit(asset_id, side=0, price=mid - SPREAD // 2, qty=200, client_tag=1)
conn.submit_limit(asset_id, side=1, price=mid + SPREAD // 2, qty=200, client_tag=2)
for fill in conn.drain_fills():
side = "BUY" if fill["side"] == 0 else "SELL"
print(f"FILL {side} {fill['volume']} @ {to_display(fill['price']):.4f}")
import time
time.sleep(0.3)
Observer — monitor all connections¶
Observer gives you a read-only view of all fills and portfolio events across
all connections for your user:
obs = p.observer()
for fill in obs.drain_fills():
print(f"OBS FILL user_id={fill['user_id']} price={fill['price']}")
portfolio_events = obs.drain_portfolio()
Useful for monitoring arena participants or multiple trading connections from a single point.