我一直觉得,写交易策略不难,难的是获取一手的数据流。尤其是做外汇,价格波动快得让人窒息,延迟半秒你都能错过关键点位。
所以,这篇文章,我想直接告诉你:如果你用 Java 做量化,怎样最快地接入一个实时外汇行情 API。
我试过几个主流的行情源,包括一些号称免费但连 HTTPS 都不稳定的服务。说实话,稳定、低延迟、有文档,这是底线。我这里使用的是infoway API提供的实时外汇行情接口。支持 WebSocket 和 HTTP REST。这种商用级别的接口拿来做个人交易简直是降维打击。
Java接WebSocket
我们直接用 Java-WebSocket 这个库就够了。下面是我最小可用实现,能跑的:
package org.example.ws;
import com.alibaba.fastjson2.JSONObject;
import jakarta.websocket.*;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
// 先申请免费token: https://infoway.io
// 详细接入文档:docs.infoway.io
public class WebsocketExample {
private static Session session;
private static final String WS_URL = "wss://data.infoway.io/ws?business=crypto&apikey=yourApikey";
public static void main(String[] args) throws Exception {
try {
// create WebSocket connect
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
session = container.connectToServer(WebsocketExample.MyClientEndpoint.class, URI.create(WS_URL));
// send message
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 10000);
jsonObject.put("trace", "01213e9d-90a0-426e-a380-ebed633cba7a");
JSONObject data = new JSONObject();
data.put("codes", "BTCUSDT");
jsonObject.put("data", data);
session.getBasicRemote().sendText(jsonObject.toJSONString());
ScheduledExecutorService pingExecutor = Executors.newScheduledThreadPool(1);
Runnable pingTask = WebsocketExample::ping;
pingExecutor.scheduleAtFixedRate(pingTask, 30, 30, TimeUnit.SECONDS);
// keep running
Thread.sleep(600 * 1000);
// close connect
session.close();
} catch (DeploymentException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
@ClientEndpoint
public static class MyClientEndpoint {
@OnOpen
public void onOpen(Session session) {
System.out.println("Connection opened: " + session.getId());
}
@OnMessage
public void onMessage(String message, Session session) {
try {
System.out.println("Message received: " + message);
} catch (Exception e) {
}
}
@OnClose
public void onClose(Session session, CloseReason reason) {
System.out.println("Connection closed: " + session.getId() + ", reason: " + reason);
}
@OnError
public void onError(Throwable error) {
error.printStackTrace();
}
}
//ping message
public static void ping() {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 10010);
jsonObject.put("trace", "01213e9d-90a0-426e-a380-ebed633cba7a");
session.getBasicRemote().sendText(jsonObject.toJSONString());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}