非農數據公佈前後的外匯報價推送量
美國非農就業數據公佈前後,5 個主要貨幣對的報價更新情況。
- 62,839非農公佈前後各 30 分鐘內,共推送的報價更新次數
- ~60ms平均延遲,WebSocket 快速實時推送
- +60%非農公佈後報價更新量明顯上升,WebSocket 推送全程穩定。
非農數據公佈時,5 個主要貨幣對的報價更新量增加了 60%。Infoway 外匯 WebSocket API 全程穩定,共推送 62,839 次報價更新,平均延遲約 60 毫秒。
外匯市場工作日不休市。從週一悉尼開盤到週五紐約收盤,Infoway 持續推送報價。
以上為大致的 UTC 時間,會隨夏令時調整。倫敦與紐約的重疊時段(UTC 12:00-16:00)流動性最好。
import requests
api_url = "https://data.infoway.io/common/v2/batch_kline"
headers = {
"User-Agent": "Mozilla/5.0",
"Accept": "application/json",
"Content-Type": "application/json",
"apiKey": "yourApikey",
}
payload = {
"klineType": 1,
"klineNum": 10,
"codes": "EURUSD,GBPUSD,USDJPY"
}
response = requests.post(api_url, headers=headers, json=payload)
print(f"HTTP code: {response.status_code}")
print(f"message: {response.text}")
import requests
api_url = "https://data.infoway.io/common/batch_trade/EURUSD,GBPUSD,USDJPY"
headers = {
"User-Agent": "Mozilla/5.0",
"Accept": "application/json",
"apiKey": "yourApikey",
}
response = requests.get(api_url, headers=headers)
print(f"HTTP code: {response.status_code}")
print(f"message: {response.text}")
import requests
api_url = "https://data.infoway.io/common/batch_depth/EURUSD,GBPUSD,USDJPY"
headers = {
"User-Agent": "Mozilla/5.0",
"Accept": "application/json",
"apiKey": "yourApikey",
}
response = requests.get(api_url, headers=headers)
print(f"HTTP code: {response.status_code}")
print(f"message: {response.text}")
import asyncio
import json
import uuid
import websockets
WS_URL = "wss://data.infoway.io/ws?business=common&apikey=yourApikey"
async def send_heartbeat(websocket):
while True:
await asyncio.sleep(30)
ping_message = {
"code": 10010,
"trace": str(uuid.uuid4()),
}
await websocket.send(json.dumps(ping_message))
async def connect_and_receive():
async with websockets.connect(WS_URL) as websocket:
print("Connection opened")
init_message = {
"code": 10006,
"trace": str(uuid.uuid4()),
"data": {
"arr": [
{
"type": 1,
"codes": "EURUSD,GBPUSD,USDJPY"
}
]
},
}
await websocket.send(json.dumps(init_message))
heartbeat_task = asyncio.create_task(send_heartbeat(websocket))
try:
while True:
message = await websocket.recv()
print(f"Message received: {message}")
except websockets.exceptions.ConnectionClosedOK:
print("Connection closed normally")
except websockets.exceptions.ConnectionClosed as error:
print(f"Connection closed: {error}")
finally:
heartbeat_task.cancel()
asyncio.run(connect_and_receive())
import asyncio
import json
import uuid
import websockets
WS_URL = "wss://data.infoway.io/ws?business=common&apikey=yourApikey"
async def send_heartbeat(websocket):
while True:
await asyncio.sleep(30)
ping_message = {
"code": 10010,
"trace": str(uuid.uuid4()),
}
await websocket.send(json.dumps(ping_message))
async def connect_and_receive():
async with websockets.connect(WS_URL) as websocket:
print("Connection opened")
init_message = {
"code": 10000,
"trace": str(uuid.uuid4()),
"data": {
"codes": "EURUSD,GBPUSD,USDJPY"
},
}
await websocket.send(json.dumps(init_message))
heartbeat_task = asyncio.create_task(send_heartbeat(websocket))
try:
while True:
message = await websocket.recv()
print(f"Message received: {message}")
except websockets.exceptions.ConnectionClosedOK:
print("Connection closed normally")
except websockets.exceptions.ConnectionClosed as error:
print(f"Connection closed: {error}")
finally:
heartbeat_task.cancel()
asyncio.run(connect_and_receive())
import asyncio
import json
import uuid
import websockets
WS_URL = "wss://data.infoway.io/ws?business=common&apikey=yourApikey"
async def send_heartbeat(websocket):
while True:
await asyncio.sleep(30)
ping_message = {
"code": 10010,
"trace": str(uuid.uuid4()),
}
await websocket.send(json.dumps(ping_message))
async def connect_and_receive():
async with websockets.connect(WS_URL) as websocket:
print("Connection opened")
init_message = {
"code": 10003,
"trace": str(uuid.uuid4()),
"data": {
"codes": "EURUSD,GBPUSD,USDJPY"
},
}
await websocket.send(json.dumps(init_message))
heartbeat_task = asyncio.create_task(send_heartbeat(websocket))
try:
while True:
message = await websocket.recv()
print(f"Message received: {message}")
except websockets.exceptions.ConnectionClosedOK:
print("Connection closed normally")
except websockets.exceptions.ConnectionClosed as error:
print(f"Connection closed: {error}")
finally:
heartbeat_task.cancel()
asyncio.run(connect_and_receive())
package org.example.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class HttpExample {
public static void main(String[] args) {
try {
String apiUrl = "https://data.infoway.io/common/v2/batch_kline";
String payload = "{\"klineType\":1,\"klineNum\":10,\"codes\":\"EURUSD,GBPUSD,USDJPY\"}";
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("apiKey", "yourApikey");
try (OutputStream os = connection.getOutputStream()) {
byte[] input = payload.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
int responseCode = connection.getResponseCode();
System.out.println("HTTP code: " + responseCode);
BufferedReader reader;
if (responseCode == HttpURLConnection.HTTP_OK) {
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
} else {
reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
}
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
System.out.println("message: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}package org.example.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpExample {
public static void main(String[] args) {
try {
String apiUrl = "https://data.infoway.io/common/batch_trade/EURUSD,GBPUSD,USDJPY";
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("apiKey", "yourApikey");
int responseCode = connection.getResponseCode();
System.out.println("HTTP code: " + responseCode);
BufferedReader reader;
if (responseCode == HttpURLConnection.HTTP_OK) {
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
} else {
reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
}
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
System.out.println("message: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}package org.example.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpExample {
public static void main(String[] args) {
try {
String apiUrl = "https://data.infoway.io/common/batch_depth/EURUSD,GBPUSD,USDJPY";
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("apiKey", "yourApikey");
int responseCode = connection.getResponseCode();
System.out.println("HTTP code: " + responseCode);
BufferedReader reader;
if (responseCode == HttpURLConnection.HTTP_OK) {
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
} else {
reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
}
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
System.out.println("message: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}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;
public class WebsocketExample {
private static Session session;
private static final String WS_URL = "wss://data.infoway.io/ws?business=common&apikey=yourApikey";
public static void main(String[] args) throws Exception {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
session = container.connectToServer(WebsocketExample.MyClientEndpoint.class, URI.create(WS_URL));
session.getBasicRemote().sendText("{\"code\":10006,\"trace\":\"01213e9d-90a0-426e-a380-ebed633cba7a\",\"data\":{\"arr\":[{\"type\":1,\"codes\":\"EURUSD,GBPUSD,USDJPY\"}]}}");
ScheduledExecutorService pingExecutor = Executors.newScheduledThreadPool(1);
pingExecutor.scheduleAtFixedRate(WebsocketExample::ping, 30, 30, TimeUnit.SECONDS);
Thread.sleep(600 * 1000);
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) {
System.out.println("Message received: " + message);
}
@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();
}
}
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);
}
}
}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;
public class WebsocketExample {
private static Session session;
private static final String WS_URL = "wss://data.infoway.io/ws?business=common&apikey=yourApikey";
public static void main(String[] args) throws Exception {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
session = container.connectToServer(WebsocketExample.MyClientEndpoint.class, URI.create(WS_URL));
session.getBasicRemote().sendText("{\"code\":10000,\"trace\":\"01213e9d-90a0-426e-a380-ebed633cba7a\",\"data\":{\"codes\":\"EURUSD,GBPUSD,USDJPY\"}}");
ScheduledExecutorService pingExecutor = Executors.newScheduledThreadPool(1);
pingExecutor.scheduleAtFixedRate(WebsocketExample::ping, 30, 30, TimeUnit.SECONDS);
Thread.sleep(600 * 1000);
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) {
System.out.println("Message received: " + message);
}
@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();
}
}
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);
}
}
}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;
public class WebsocketExample {
private static Session session;
private static final String WS_URL = "wss://data.infoway.io/ws?business=common&apikey=yourApikey";
public static void main(String[] args) throws Exception {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
session = container.connectToServer(WebsocketExample.MyClientEndpoint.class, URI.create(WS_URL));
session.getBasicRemote().sendText("{\"code\":10003,\"trace\":\"01213e9d-90a0-426e-a380-ebed633cba7a\",\"data\":{\"codes\":\"EURUSD,GBPUSD,USDJPY\"}}");
ScheduledExecutorService pingExecutor = Executors.newScheduledThreadPool(1);
pingExecutor.scheduleAtFixedRate(WebsocketExample::ping, 30, 30, TimeUnit.SECONDS);
Thread.sleep(600 * 1000);
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) {
System.out.println("Message received: " + message);
}
@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();
}
}
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);
}
}
}<?php
$apiUrl = 'https://data.infoway.io/common/v2/batch_kline';
$payload = json_encode([
'klineType' => 1,
'klineNum' => 10,
'codes' => 'EURUSD,GBPUSD,USDJPY',
]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'User-Agent: Mozilla/5.0',
'Accept: application/json',
'Content-Type: application/json',
'apiKey: yourApikey'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "HTTP code: $httpCode\n";
echo "message: $response";
<?php
$apiUrl = 'https://data.infoway.io/common/batch_trade/EURUSD,GBPUSD,USDJPY';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'User-Agent: Mozilla/5.0',
'Accept: application/json',
'apiKey: yourApikey'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "HTTP code: $httpCode\n";
echo "message: $response";
<?php
$apiUrl = 'https://data.infoway.io/common/batch_depth/EURUSD,GBPUSD,USDJPY';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'User-Agent: Mozilla/5.0',
'Accept: application/json',
'apiKey: yourApikey'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "HTTP code: $httpCode\n";
echo "message: $response";
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\Client\WebSocket;
use Ratchet\Client\Connector;
use React\EventLoop\Factory;
$loop = Factory::create();
$connector = new Connector($loop);
$wsUrl = 'wss://data.infoway.io/ws?business=common&apikey=yourApikey';
$connector($wsUrl)->then(
function (WebSocket $conn) use ($loop) {
echo "Connection opened\n";
$conn->send('{"code":10006,"trace":"01213e9d-90a0-426e-a380-ebed633cba7a","data":{"arr":[{"type":1,"codes":"EURUSD,GBPUSD,USDJPY"}]}}');
$loop->addPeriodicTimer(30, function () use ($conn) {
$conn->send(json_encode([
'code' => 10010,
'trace' => '01213e9d-90a0-426e-a380-ebed633cba7a',
]));
});
$conn->on('message', function ($msg) {
echo "Message received: {$msg}\n";
});
$conn->on('close', function ($code = null, $reason = null) {
echo "Connection closed ({$code}): {$reason}\n";
});
},
function (\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
}
);
$loop->run();
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\Client\WebSocket;
use Ratchet\Client\Connector;
use React\EventLoop\Factory;
$loop = Factory::create();
$connector = new Connector($loop);
$wsUrl = 'wss://data.infoway.io/ws?business=common&apikey=yourApikey';
$connector($wsUrl)->then(
function (WebSocket $conn) use ($loop) {
echo "Connection opened\n";
$conn->send('{"code":10000,"trace":"01213e9d-90a0-426e-a380-ebed633cba7a","data":{"codes":"EURUSD,GBPUSD,USDJPY"}}');
$loop->addPeriodicTimer(30, function () use ($conn) {
$conn->send(json_encode([
'code' => 10010,
'trace' => '01213e9d-90a0-426e-a380-ebed633cba7a',
]));
});
$conn->on('message', function ($msg) {
echo "Message received: {$msg}\n";
});
$conn->on('close', function ($code = null, $reason = null) {
echo "Connection closed ({$code}): {$reason}\n";
});
},
function (\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
}
);
$loop->run();
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\Client\WebSocket;
use Ratchet\Client\Connector;
use React\EventLoop\Factory;
$loop = Factory::create();
$connector = new Connector($loop);
$wsUrl = 'wss://data.infoway.io/ws?business=common&apikey=yourApikey';
$connector($wsUrl)->then(
function (WebSocket $conn) use ($loop) {
echo "Connection opened\n";
$conn->send('{"code":10003,"trace":"01213e9d-90a0-426e-a380-ebed633cba7a","data":{"codes":"EURUSD,GBPUSD,USDJPY"}}');
$loop->addPeriodicTimer(30, function () use ($conn) {
$conn->send(json_encode([
'code' => 10010,
'trace' => '01213e9d-90a0-426e-a380-ebed633cba7a',
]));
});
$conn->on('message', function ($msg) {
echo "Message received: {$msg}\n";
});
$conn->on('close', function ($code = null, $reason = null) {
echo "Connection closed ({$code}): {$reason}\n";
});
},
function (\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
}
);
$loop->run();
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
apiUrl := "https://data.infoway.io/common/v2/batch_kline"
payload := strings.NewReader("{\"klineType\":1,\"klineNum\":10,\"codes\":\"EURUSD,GBPUSD,USDJPY\"}")
client := &http.Client{}
req, err := http.NewRequest("POST", apiUrl, payload)
if err != nil {
fmt.Println("Error creating request:", err)
return
}
req.Header.Set("User-Agent", "Mozilla/5.0")
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("apiKey", "yourApikey")
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error sending request:", err)
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
fmt.Println("HTTP code:", resp.StatusCode)
fmt.Println("message:", string(body))
}package main
import (
"fmt"
"io"
"net/http"
)
func main() {
apiUrl := "https://data.infoway.io/common/batch_trade/EURUSD,GBPUSD,USDJPY"
client := &http.Client{}
req, err := http.NewRequest("GET", apiUrl, nil)
if err != nil {
fmt.Println("Error creating request:", err)
return
}
req.Header.Set("User-Agent", "Mozilla/5.0")
req.Header.Set("Accept", "application/json")
req.Header.Set("apiKey", "yourApikey")
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error sending request:", err)
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
fmt.Println("HTTP code:", resp.StatusCode)
fmt.Println("message:", string(body))
}package main
import (
"fmt"
"io"
"net/http"
)
func main() {
apiUrl := "https://data.infoway.io/common/batch_depth/EURUSD,GBPUSD,USDJPY"
client := &http.Client{}
req, err := http.NewRequest("GET", apiUrl, nil)
if err != nil {
fmt.Println("Error creating request:", err)
return
}
req.Header.Set("User-Agent", "Mozilla/5.0")
req.Header.Set("Accept", "application/json")
req.Header.Set("apiKey", "yourApikey")
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error sending request:", err)
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
fmt.Println("HTTP code:", resp.StatusCode)
fmt.Println("message:", string(body))
}package main
import (
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"os/signal"
"syscall"
"time"
"github.com/gorilla/websocket"
)
func main() {
u := url.URL{
Scheme: "wss",
Host: "data.infoway.io",
Path: "/ws",
RawQuery: "business=common&apikey=yourApikey",
}
log.Printf("Connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
initMsg := []byte(`{"code":10006,"trace":"01213e9d-90a0-426e-a380-ebed633cba7a","data":{"arr":[{"type":1,"codes":"EURUSD,GBPUSD,USDJPY"}]}}`)
if err := c.WriteMessage(websocket.TextMessage, initMsg); err != nil {
log.Fatal("write:", err)
}
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
done := make(chan struct{})
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
fmt.Println("Message received:", string(message))
}
}()
go func() {
for range ticker.C {
pingMsg := map[string]interface{}{
"code": 10010,
"trace": "01213e9d-90a0-426e-a380-ebed633cba7a",
}
pingMsgJSON, _ := json.Marshal(pingMsg)
if err := c.WriteMessage(websocket.TextMessage, pingMsgJSON); err != nil {
log.Println("ping error:", err)
return
}
}
}()
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
select {
case <-done:
log.Println("WebSocket connection closed by server")
case <-interrupt:
log.Println("Interrupted by user")
}
}package main
import (
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"os/signal"
"syscall"
"time"
"github.com/gorilla/websocket"
)
func main() {
u := url.URL{
Scheme: "wss",
Host: "data.infoway.io",
Path: "/ws",
RawQuery: "business=common&apikey=yourApikey",
}
log.Printf("Connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
initMsg := []byte(`{"code":10000,"trace":"01213e9d-90a0-426e-a380-ebed633cba7a","data":{"codes":"EURUSD,GBPUSD,USDJPY"}}`)
if err := c.WriteMessage(websocket.TextMessage, initMsg); err != nil {
log.Fatal("write:", err)
}
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
done := make(chan struct{})
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
fmt.Println("Message received:", string(message))
}
}()
go func() {
for range ticker.C {
pingMsg := map[string]interface{}{
"code": 10010,
"trace": "01213e9d-90a0-426e-a380-ebed633cba7a",
}
pingMsgJSON, _ := json.Marshal(pingMsg)
if err := c.WriteMessage(websocket.TextMessage, pingMsgJSON); err != nil {
log.Println("ping error:", err)
return
}
}
}()
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
select {
case <-done:
log.Println("WebSocket connection closed by server")
case <-interrupt:
log.Println("Interrupted by user")
}
}package main
import (
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"os/signal"
"syscall"
"time"
"github.com/gorilla/websocket"
)
func main() {
u := url.URL{
Scheme: "wss",
Host: "data.infoway.io",
Path: "/ws",
RawQuery: "business=common&apikey=yourApikey",
}
log.Printf("Connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
initMsg := []byte(`{"code":10003,"trace":"01213e9d-90a0-426e-a380-ebed633cba7a","data":{"codes":"EURUSD,GBPUSD,USDJPY"}}`)
if err := c.WriteMessage(websocket.TextMessage, initMsg); err != nil {
log.Fatal("write:", err)
}
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
done := make(chan struct{})
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
fmt.Println("Message received:", string(message))
}
}()
go func() {
for range ticker.C {
pingMsg := map[string]interface{}{
"code": 10010,
"trace": "01213e9d-90a0-426e-a380-ebed633cba7a",
}
pingMsgJSON, _ := json.Marshal(pingMsg)
if err := c.WriteMessage(websocket.TextMessage, pingMsgJSON); err != nil {
log.Println("ping error:", err)
return
}
}
}()
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
select {
case <-done:
log.Println("WebSocket connection closed by server")
case <-interrupt:
log.Println("Interrupted by user")
}
}const https = require("https");
const apiUrl = "https://data.infoway.io/common/v2/batch_kline";
const payload = JSON.stringify({
"klineType": 1,
"klineNum": 10,
"codes": "EURUSD,GBPUSD,USDJPY"
});
const options = {
method: "POST",
headers: {
"User-Agent": "Mozilla/5.0",
Accept: "application/json",
"Content-Type": "application/json",
apiKey: "yourApikey",
},
};
const req = https.request(apiUrl, options, (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
console.log("HTTP code:", res.statusCode);
console.log("message:", data);
});
});
req.on("error", (error) => {
console.error("Error:", error);
});
req.write(payload);
req.end();
const https = require("https");
const apiUrl = "https://data.infoway.io/common/batch_trade/EURUSD,GBPUSD,USDJPY";
const options = {
method: "GET",
headers: {
"User-Agent": "Mozilla/5.0",
Accept: "application/json",
apiKey: "yourApikey",
},
};
const req = https.request(apiUrl, options, (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
console.log("HTTP code:", res.statusCode);
console.log("message:", data);
});
});
req.on("error", (error) => {
console.error("Error:", error);
});
req.end();
const https = require("https");
const apiUrl = "https://data.infoway.io/common/batch_depth/EURUSD,GBPUSD,USDJPY";
const options = {
method: "GET",
headers: {
"User-Agent": "Mozilla/5.0",
Accept: "application/json",
apiKey: "yourApikey",
},
};
const req = https.request(apiUrl, options, (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
console.log("HTTP code:", res.statusCode);
console.log("message:", data);
});
});
req.on("error", (error) => {
console.error("Error:", error);
});
req.end();
const WebSocket = require("ws");
const { randomUUID } = require("crypto");
const wsUrl = "wss://data.infoway.io/ws?business=common&apikey=yourApikey";
const ws = new WebSocket(wsUrl);
ws.on("open", () => {
console.log("Connection opened");
const initMessage = JSON.stringify({
code: 10006,
trace: randomUUID(),
data: {
"arr": [
{
"type": 1,
"codes": "EURUSD,GBPUSD,USDJPY"
}
]
},
});
ws.send(initMessage);
const heartbeat = setInterval(() => {
if (ws.readyState !== WebSocket.OPEN) return;
ws.send(JSON.stringify({
code: 10010,
trace: randomUUID(),
}));
}, 30000);
ws.on("close", () => clearInterval(heartbeat));
});
ws.on("message", (data) => {
console.log("Message received:", data.toString());
});
ws.on("close", (code, reason) => {
console.log("Connection closed (" + code + "): " + reason);
});
ws.on("error", (error) => {
console.error("WebSocket error:", error);
});
process.on("SIGINT", () => {
ws.close();
process.exit(0);
});
const WebSocket = require("ws");
const { randomUUID } = require("crypto");
const wsUrl = "wss://data.infoway.io/ws?business=common&apikey=yourApikey";
const ws = new WebSocket(wsUrl);
ws.on("open", () => {
console.log("Connection opened");
const initMessage = JSON.stringify({
code: 10000,
trace: randomUUID(),
data: {
"codes": "EURUSD,GBPUSD,USDJPY"
},
});
ws.send(initMessage);
const heartbeat = setInterval(() => {
if (ws.readyState !== WebSocket.OPEN) return;
ws.send(JSON.stringify({
code: 10010,
trace: randomUUID(),
}));
}, 30000);
ws.on("close", () => clearInterval(heartbeat));
});
ws.on("message", (data) => {
console.log("Message received:", data.toString());
});
ws.on("close", (code, reason) => {
console.log("Connection closed (" + code + "): " + reason);
});
ws.on("error", (error) => {
console.error("WebSocket error:", error);
});
process.on("SIGINT", () => {
ws.close();
process.exit(0);
});
const WebSocket = require("ws");
const { randomUUID } = require("crypto");
const wsUrl = "wss://data.infoway.io/ws?business=common&apikey=yourApikey";
const ws = new WebSocket(wsUrl);
ws.on("open", () => {
console.log("Connection opened");
const initMessage = JSON.stringify({
code: 10003,
trace: randomUUID(),
data: {
"codes": "EURUSD,GBPUSD,USDJPY"
},
});
ws.send(initMessage);
const heartbeat = setInterval(() => {
if (ws.readyState !== WebSocket.OPEN) return;
ws.send(JSON.stringify({
code: 10010,
trace: randomUUID(),
}));
}, 30000);
ws.on("close", () => clearInterval(heartbeat));
});
ws.on("message", (data) => {
console.log("Message received:", data.toString());
});
ws.on("close", (code, reason) => {
console.log("Connection closed (" + code + "): " + reason);
});
ws.on("error", (error) => {
console.error("WebSocket error:", error);
});
process.on("SIGINT", () => {
ws.close();
process.exit(0);
});
市場交投驟增時,WebSocket 連接依然穩定,外匯報價持續實時推送。
美國非農就業數據公佈前後,5 個主要貨幣對的報價更新情況。
非農數據公佈時,5 個主要貨幣對的報價更新量增加了 60%。Infoway 外匯 WebSocket API 全程穩定,共推送 62,839 次報價更新,平均延遲約 60 毫秒。
主要貨幣對、交叉貨幣對和亞洲貨幣,共用同一套代碼格式和返回結構。
通過 WebSocket 訂閱一次,報價一有變化就實時推送。
從悉尼開盤到紐約收盤,數據連續不斷。
提供 1 分鐘到月線的歷史 K 線,和實盤用同一種數據格式。
同一個套餐還包括股票、加密貨幣和商品期貨,不需要再接第二家數據商。
7 天內完整體驗實時報價和歷史數據,無需綁定信用卡。
為你的金融產品、交易策略、研究和工作流提供數據。
通過一條 WebSocket 連接,把買賣報價直接推送到報價板、下單介面和圖表。
import asyncio
import json
import uuid
import websockets
WS_URL = "wss://data.infoway.io/ws?business=common&apikey=YOUR_API_KEY"
PAIRS = "EURUSD,GBPUSD,USDJPY"
def frame(code, data=None):
msg = {"code": code, "trace": uuid.uuid4().hex}
if data is not None:
msg["data"] = data
return json.dumps(msg)
async def heartbeat(ws):
while True:
await asyncio.sleep(30)
await ws.send(frame(10010))
async def price_feed(on_quote, on_trade):
while True:
try:
async with websockets.connect(WS_URL) as ws:
await ws.send(frame(10003, {"codes": PAIRS})) # best bid / ask
await ws.send(frame(10000, {"codes": PAIRS})) # every price change
hb = asyncio.create_task(heartbeat(ws))
try:
async for raw in ws:
msg = json.loads(raw)
data = msg.get("data")
if msg.get("code") == 10005:
on_quote(data["s"], bid=data["b"][0][0], ask=data["a"][0][0], ts=data["t"])
elif msg.get("code") == 10002:
on_trade(data["s"], price=data["p"], ts=data["t"])
finally:
hb.cancel()
except (websockets.ConnectionClosed, OSError):
await asyncio.sleep(5) # back off before reconnecting
def show_quote(symbol, bid, ask, ts):
print(f"{symbol} bid {bid} ask {ask}")
def show_trade(symbol, price, ts):
print(f"{symbol} last {price}")
asyncio.run(price_feed(show_quote, show_trade))拉取最長 3 年的 1 分鐘 K 線,用 Python 測試均值迴歸或突破策略。
import time
import pandas as pd
import requests
URL = "https://data.infoway.io/common/v2/batch_kline" # forex, metals, futures
HEADERS = {"apiKey": "YOUR_API_KEY"}
def fetch_1m(symbol, pages=10):
"""Page backwards through 1-minute candles, 500 per request."""
rows, ts = [], None
for _ in range(pages):
body = {"klineType": 1, "klineNum": 500, "codes": symbol}
if ts:
body["timestamp"] = ts
resp = requests.post(URL, headers=HEADERS, json=body, timeout=10).json()
if resp.get("ret") != 200 or not resp.get("data"):
break # e.g. 513: timestamp is beyond your plan's history
batch = resp["data"][0]["respList"] # newest first
if not batch:
break
rows += batch
ts = int(batch[-1]["t"]) - 60 # continue before the oldest candle
time.sleep(1) # stay within your plan's rate limit
df = pd.DataFrame(rows).drop_duplicates("t")
df["t"] = pd.to_datetime(df["t"].astype(int), unit="s")
return df.set_index("t").sort_index()[["o", "h", "l", "c"]].astype(float)
bars = fetch_1m("EURUSD") # about 5,000 minutes
# Mean reversion: hold long while price is 2 std devs below its 60-minute mean
mean = bars["c"].rolling(60).mean()
std = bars["c"].rolling(60).std()
zscore = (bars["c"] - mean) / std
position = (zscore < -2).astype(int).shift(1).fillna(0)
returns = bars["c"].pct_change().fillna(0)
print(f"Buy & hold: {(1 + returns).prod() - 1:.4%}")
print(f"Strategy: {(1 + position * returns).prod() - 1:.4%}")
如需幫助,請隨時聯絡客服。
主要貨幣對、交叉貨幣對,以及 USD/CNH、USD/HKD 等亞洲貨幣,貨幣對會持續增加。
是的。所有交易時段內,報價隨價格變化通過 WebSocket 實時推送。
提供 1 分鐘到月線的 K 線。分鐘和小時 K 線最長回溯 3 年,具體取決於套餐;日線及以上週期提供完整歷史。
外匯市場每週交易 5 天、每天 24 小時,週末休市,週末沒有新的行情推送。
可以,提供 7 天免費試用,無需綁定信用卡。免費試用只能查詢部分品種,具體見免費試用品種列表。付費套餐每月 99 USDT 起,可查詢全部品種。

