Forex API
为 50+ 个主要、次要及异国货币对提供 Tick 级报价。
通过一个 WebSocket 和 REST API 传输 Tick 级 Forex、Crypto、Stock、Commodity 和 Index 数据。几秒钟即可获取免费密钥——无需销售沟通。
| 代码 | 资产类别 | 价格 | 实时变动 |
|---|---|---|---|
| EUR/USD 外汇欧元 / 美元 | 外汇 | - | - |
| BTC/USDT 加密货币比特币 | 加密货币 | - | - |
| ETH/USDT 加密货币以太坊 | 加密货币 | - | - |
| AAPL 股票苹果公司 | 股票 | - | - |
| XAU/USD 大宗商品现货黄金 | 大宗商品 | - | - |
| USD/JPY 外汇美元 / 日元 | 外汇 | - | - |
| NVDA 股票英伟达公司 | 股票 | - | - |
| SPX 指数标普 500 指数 | 指数 | - | - |
AllTick 覆盖的每个市场都可通过同一个统一的 REST 和 WebSocket 接口访问。
为 50+ 个主要、次要及异国货币对提供 Tick 级报价。
实时现货和衍生品数据,标准化为一个数据流。
覆盖美股、港股和 A 股市场的股票,提供成交和报价。
贵金属和能源的实时定价。
主要全球指数的基准指数值和成分股。
比较 AllTick 各个市场的覆盖范围、延迟和数据类型。
浏览产品AllTick 与典型传统行情数据供应商的对比。
| 能力 | AllTick | 典型传统供应商 |
|---|---|---|
| WebSocket 中位延迟 | 约 150ms | 400–800ms |
| 一个 API 中的资产类别 | 5(FX、Crypto、Stock、Commodities、Indices) | 1–2 |
| 可用性 SLA | 99.95% | 99.5% 或无 |
| 免费等级 | 有——即时 API 密钥 | 需要销售沟通 |
| WebSocket 流 | 原生支持 | 轮询 / 有限支持 |
通过 WebSocket 连接并订阅任何市场中的任意交易品种。
# AllTick realtime financial data API
# forex crypto stock commodities indices
import asyncio, json, uuid
import websockets
subscribe = {
"cmd_id": 22004,
"seq_id": 1,
"trace": str(uuid.uuid4()),
"data": {"symbol_list": [{"code": "EURUSD"}]},
}
heartbeat = {"cmd_id": 22000, "seq_id": 1, "trace": "heartbeat", "data": {}}
async def stream():
uri = "wss://quote.alltick.co/quote-b-ws-api?token=YOUR_API_KEY"
async with websockets.connect(uri) as socket:
await socket.send(json.dumps(subscribe))
async def keep_alive():
while True:
await asyncio.sleep(10)
await socket.send(json.dumps(heartbeat))
asyncio.create_task(keep_alive())
async for message in socket:
print(json.loads(message))
asyncio.run(stream())分享市场数据工程、流式 API 与低延迟金融应用开发的实用内容。

在交易市场中,撮合交易算法是每一笔订单成交的核心机制。每当买卖双方提交订单时,系统会根据价格优先、时间优先的规…
在交易市场中,撮合交易算法是每一笔订单成交的核心机制。每当买卖双方提交订单时,系统会根据价格优先、时间优先的规则自动匹配成交。对于老股民来说,这些规则很熟悉,但从开发者角度来看,设计一个高效、可复用的撮合引擎仍然是一项挑战。本文从技术实现的角度出发,讲解如何用 Java 构建一个简化的撮合交易算法。
撮合引擎的核心是 订单簿(OrderBook),它维护两条队列:买盘和卖盘。买盘按价格从高到低排序,确保报价最高的买单优先成交;卖盘按价格从低到高排序,确保报价最低的卖单优先成交。
在交易市场中,买1价格永远不会高于等于卖1价格,否则说明系统漏掉了应成交的订单。对于多个相同价格的订单,则按时间顺序成交——在我们的实现中,用全局唯一的 sequenceId 来保证排序和处理顺序,而不是直接用创建时间。
很多人会想到用 List<Order> 来存储订单,但在高频交易环境中,插入和删除订单的成本太高(O(N)),效率难以保证。更好的方案是用平衡树结构,比如 Java 的 TreeMap,可以让插入、删除和查找操作的时间复杂度保持在 O(logN)。
public record OrderKey(long sequenceId, BigDecimal price) { }
由于买盘和卖盘的排序规则不同,需要为 TreeMap 提供两个不同的比较器:
private static final Comparator<OrderKey> SORT_SELL = (o1, o2) -> {
int cmp = o1.price().compareTo(o2.price()); // 价格低在前
return cmp == 0 ? Long.compare(o1.sequenceId(), o2.sequenceId()) : cmp;
};
private static final Comparator<OrderKey> SORT_BUY = (o1, o2) -> {
int cmp = o2.price().compareTo(o1.price()); // 价格高在前
return cmp == 0 ? Long.compare(o1.sequenceId(), o2.sequenceId()) : cmp;
};
有了比较器后,OrderBook 的实现就非常直接:
public class OrderBook {
public final Direction direction;
public final TreeMap<OrderKey, OrderEntity> book;
public OrderBook(Direction direction) {
this.direction = direction;
this.book = new TreeMap<>(direction == Direction.BUY ? SORT_BUY : SORT_SELL);
}
public OrderEntity getFirst() {
return this.book.isEmpty() ? null : this.book.firstEntry().getValue();
}
public boolean remove(OrderEntity order) {
return this.book.remove(new OrderKey(order.sequenceId, order.price)) != null; } public boolean add(OrderEntity order) { return this.book.put(new OrderKey(order.sequenceId, order.price), order) == null; }}
小提示:Java 中比较 BigDecimal 的值一定要用 compareTo(),不要用 equals(),否则 1.2 和 1.20 会被判定不相等。
有了买卖盘,就可以实现撮合引擎。核心数据结构如下:
public class MatchEngine {
public final OrderBook buyBook = new OrderBook(Direction.BUY);
public final OrderBook sellBook = new OrderBook(Direction.SELL);
public BigDecimal marketPrice = BigDecimal.ZERO;
private long sequenceId;
public MatchResult processOrder(long sequenceId, OrderEntity order) {
switch (order.direction) {
case BUY:
return processOrder(order, this.sellBook, this.buyBook);
case SELL:
return processOrder(order, this.buyBook, this.sellBook);
default:
throw new IllegalArgumentException(“Invalid direction.”);
}
}
}
处理订单时,如果是买单,就尝试与卖盘匹配;如果是卖单,则尝试与买盘匹配。新订单称为 Taker,已经挂在盘上的订单称为 Maker。Taker 如果未完全成交,则转为 Maker 挂在订单簿上。
MatchResult processOrder(OrderEntity takerOrder, OrderBook makerBook, OrderBook anotherBook) {
long ts = takerOrder.createdAt;
MatchResult matchResult = new MatchResult(takerOrder);
BigDecimal takerUnfilledQuantity = takerOrder.quantity;
for (;;) {
OrderEntity makerOrder = makerBook.getFirst();
if (makerOrder == null) break;
if ((takerOrder.direction == Direction.BUY && takerOrder.price.compareTo(makerOrder.price) < 0) ||
(takerOrder.direction == Direction.SELL && takerOrder.price.compareTo(makerOrder.price) > 0)) {
break;
}
this.marketPrice = makerOrder.price;
BigDecimal matchedQuantity = takerUnfilledQuantity.min(makerOrder.unfilledQuantity);
matchResult.add(makerOrder.price, matchedQuantity, makerOrder);
takerUnfilledQuantity = takerUnfilledQuantity.subtract(matchedQuantity);
BigDecimal makerUnfilledQuantity = makerOrder.unfilledQuantity.subtract(matchedQuantity);
if (makerUnfilledQuantity.signum() == 0) {
makerOrder.updateOrder(makerUnfilledQuantity, OrderStatus.FULLY_FILLED, ts);
makerBook.remove(makerOrder);
} else {
makerOrder.updateOrder(makerUnfilledQuantity, OrderStatus.PARTIAL_FILLED, ts);
}
if (takerUnfilledQuantity.signum() == 0) {
takerOrder.updateOrder(takerUnfilledQuantity, OrderStatus.FULLY_FILLED, ts);
break;
}
}
if (takerUnfilledQuantity.signum() > 0) {
takerOrder.updateOrder(takerUnfilledQuantity,
takerUnfilledQuantity.compareTo(takerOrder.quantity) == 0 ? OrderStatus.PENDING : OrderStatus.PARTIAL_FILLED,
ts);
anotherBook.add(takerOrder);
}
return matchResult;
}
MatchResult 会记录本次 Taker 订单及所有撮合记录,方便清算系统进行结算。
一个引擎实例只能处理一个交易对。如果想在同一个系统中支持多个交易对,可以用一个引擎组来管理:
class MatchEngineGroup {
Map<Long, MatchEngine> engines = new HashMap<>();
public MatchResult processOrder(long sequenceId, OrderEntity order) {
Long symbolId = order.symbolId;
MatchEngine engine = engines.get(symbolId);
if (engine == null) {
engine = new MatchEngine();
engines.put(symbolId, engine);
}
return engine.processOrder(sequenceId, order);
}
}
每个订单加上 symbolId 属性,就能被路由到对应的交易对引擎实例,系统内部保持隔离。
假设有如下订单输入撮合引擎:
方向价格数量buy2082.341sell2087.62buy2087.81buy2085.015sell2088.023sell2087.606buy2081.117buy2086.03buy2088.331sell2086.542sell2086.555buy2086.553
撮合完成后,买卖盘会自动更新,市场最新成交价也会随之改变,系统的内部状态完全可复现。每一笔成交都严格遵循价格优先、时间优先原则,整个撮合流程清晰高效。