English | 中文
Official Infoway Java SDK for REST market data, fundamentals, and WebSocket streams.
| Item | Description |
|---|---|
| Artifact | io.infoway:infoway-sdk:0.4.0 |
| Runtime | Java 21+ (OkHttp 4.x, Gson, SLF4J) |
| REST | https://data.infoway.io |
| Quotes WebSocket | wss://data.infoway.io/ws |
| News WebSocket | wss://data.infoway.io/news |
| Rate limits | REST · WebSocket |
| Error codes | REST · WebSocket |
| Endpoints | Endpoints |
If apiKey is omitted, the SDK reads INFOWAY_API_KEY. Close InfowayClient when finished.
Maven:
<dependency>
<groupId>io.infoway</groupId>
<artifactId>infoway-sdk</artifactId>
<version>0.4.0</version>
</dependency>Gradle:
implementation 'io.infoway:infoway-sdk:0.4.0'import io.infoway.sdk.InfowayClient;
import io.infoway.sdk.KlineType;
try (InfowayClient client = InfowayClient.builder()
.apiKey(System.getenv("INFOWAY_API_KEY"))
.build()) {
System.out.println(client.stock().getTrade("AAPL.US"));
System.out.println(client.crypto().getKline("BTCUSDT", KlineType.DAY, 30));
System.out.println(client.packages().getInfo());
}| Market | Format | Valid | Invalid |
|---|---|---|---|
| US | {code}.US |
AAPL.US |
AAPL |
| Hong Kong | 5-digit + .HK |
00700.HK |
700.HK |
| Shanghai | {code}.SH |
600519.SH |
600519.CN |
| Shenzhen | {code}.SZ |
000001.SZ |
000001.CN |
| Japan | {code}.JP |
7203.JP |
|
| Korea | {code}.KS |
005930.KS |
|
| India | {code}.IN |
RELIANCE.IN |
|
| Taiwan | {code}.TW |
2330.TW |
|
| Crypto | Pair | BTCUSDT |
|
| FX | Pair | USDJPY |
basic() / financial() take a product type such as STOCK_US or CRYPTO, not a market code like US.
| Method | Default | Description |
|---|---|---|
apiKey(key) |
INFOWAY_API_KEY |
API key |
baseUrl(url) |
https://data.infoway.io |
REST base URL |
timeout(secs) |
15 |
Per-request timeout (seconds) |
maxRetries(n) |
3 |
Retry count |
| Client | Use |
|---|---|
stock() / crypto() / japan() / india() / korea() / taiwan() / common() |
Trade, depth, candles |
basic() / packages() |
Symbols, calendar, plan |
market() / plate() |
Overview, sectors |
stockInfo() / financial() |
Fundamentals, statements |
Prefer enums: KlineType, SymbolType, Market, Lang, NewsLang, PeriodType, WsBusiness, RankSort, SortOrder, ScheduleType. String overloads remain.
Join symbols with commas. Rate limits: REST API Limitation.
Same methods on stock / crypto / japan / india / korea / taiwan / common.
| Method | Description |
|---|---|
getTrade(codes) |
Latest trade |
getDepth(codes) |
Order book |
getKline(codes, type, count) |
Candles |
getKline(codes, type, count, timestamp) |
Candles ending at a unix-seconds timestamp (minute / hour) |
Trade fields: s symbol, p price, v volume, vw turnover, t milliseconds, td side (0 / 1 buy / 2 sell). Candles are under respList; t is seconds. Up to 500 bars per symbol; multi-symbol calls return 2 bars each.
client.stock().getTrade("AAPL.US,TSLA.US");
client.crypto().getDepth("BTCUSDT");
client.korea().getTrade("005930.KS");
client.taiwan().getTrade("2330.TW");
client.crypto().getKline("BTCUSDT", KlineType.MIN_1, 100);| Enum | Value | Interval |
|---|---|---|
MIN_1 / MIN_5 / MIN_15 / MIN_30 |
1–4 | Minutes |
HOUR_1 / HOUR_2 / HOUR_4 |
5–7 | Hours |
DAY / WEEK / MONTH / QUARTER / YEAR |
8–12 | Daily and above |
Dates use YYYYMMDD. getTradingHours is deprecated; use getTradingSchedule. getTradingScheduleByType accepts ENERGY / FOREX / FUTURES / METAL / INDICES.
client.basic().getSymbols(SymbolType.STOCK_US);
client.basic().getSymbolInfo(SymbolType.STOCK_US, "AAPL.US");
client.basic().getStockDetail(SymbolType.STOCK_US, "AAPL.US");
client.basic().getAdjustmentFactors("AAPL.US", Market.US, "20260801", "20260815");
client.basic().getTradingDays(Market.US, "20260801", "20260815");
client.basic().getTradingSchedule();
client.basic().getTradingScheduleByType(ScheduleType.ENERGY);
client.basic().getMarkets();
client.packages().getInfo();packages().getInfo() returns packageName, expireTime, apiNumPerSec, maxWsConNum, maxNum, maxYearHisData, allWsNum.
client.market().getTemperature(Lang.ZH_CN, Market.HK, Market.US);
client.market().getBreadth(Market.US, Lang.ZH_CN);
client.market().getTurnover(Market.US);
client.market().getIndexes(Lang.EN);
client.market().getLeaders(Market.US, 10);
client.market().getOverview(Market.US, Lang.ZH_CN);
client.market().getRankCategories(Market.US);
client.market().getRank(Market.US, "all", RankSort.CHG, SortOrder.DESC, 30, 0, Lang.EN);
client.plate().getIndustry(Market.HK, 200);
client.plate().getConcept("HK", 100);
client.plate().getMembers("IN20293.HK", 0, 50);
client.plate().getIntro("IN20293.HK");
client.plate().getChart("HK", 50);
client.stockInfo().getValuation("AAPL.US");
client.stockInfo().getRatings("AAPL.US");
client.stockInfo().getCompany("AAPL.US", Lang.ZH_CN);
client.stockInfo().getPanorama("AAPL.US");
client.stockInfo().getConcepts("AAPL.US");
client.stockInfo().getEvents("AAPL.US", 20);
client.stockInfo().getDrivers("AAPL.US");
client.financial().getEarningStatus("AAPL.US", SymbolType.STOCK_US);
client.financial().getIncomeStatement("AAPL.US", SymbolType.STOCK_US, PeriodType.FQ);
client.financial().getRevenue("AAPL.US", SymbolType.STOCK_US);
client.financial().getCashFlow("AAPL.US", SymbolType.STOCK_US, PeriodType.FY);
client.financial().getBalanceSheet("AAPL.US", SymbolType.STOCK_US);
client.financial().getStatistics("AAPL.US", SymbolType.STOCK_US);
client.financial().getDividend("00700.HK", SymbolType.STOCK_HK);
client.financial().getDividendPayout("AAPL.US", SymbolType.STOCK_US);
client.financial().getEarnings("AAPL.US", SymbolType.STOCK_US, PeriodType.FQ);Rank key values come from getRankCategories. Financial methods require symbol and type. period_type: fq quarter, fy year, fh half-year. Optional stock-info lang: en / zh-CN.
Default return type is JsonElement. Use getTradeParsed / getDepthParsed / getKlineParsed for normalized models.
List<Trade> trades = client.crypto().getTradeParsed("BTCUSDT");
List<Kline> bars = client.crypto().getKlineParsed("BTCUSDT", KlineType.MIN_1, 20);| Raw | Normalized |
|---|---|
| Price / volume as strings | BigDecimal |
Trade / depth t in ms; candle t in seconds |
Instant |
REST pc / WS pfr ("0.03%") |
changePercent = 0.0003 |
Candle respList |
List<Kline> |
Book a/b as [[price…],[qty…]] |
List<DepthLevel> |
vw |
turnover |
business must match the symbol market. Callbacks receive data. 60 frames per minute per connection (subscribe, unsubscribe, heartbeat). See WebSocket Limitation. Subscriptions issued before connect() are sent after open.
InfowayWebSocket ws = InfowayWebSocket.builder()
.apiKey(System.getenv("INFOWAY_API_KEY"))
.business(WsBusiness.CRYPTO)
.printFrames(false)
.onTrade(data -> System.out.println(data.get("s") + " " + data.get("p")))
.onDepth(data -> System.out.println(data.get("s")))
.onKline(data -> System.out.println(data.get("s")))
.onError(err -> System.err.println(err.getMessage()))
.build();
ws.connect();
ws.subscribeTrade("BTCUSDT,ETHUSDT");
ws.subscribeDepth("BTCUSDT");
ws.subscribeKline("BTCUSDT", KlineType.MIN_1);
ws.unsubscribeKline("BTCUSDT", KlineType.MIN_1);
ws.close();Equity trade types: subscribeTrade(codes, true) adds ty.
| Behavior | Description |
|---|---|
| Heartbeat | 10010 every 30 seconds; server does not reply |
| Reconnect | Replays the current subscription set |
onReconnect |
After a later successful open |
onDisconnect |
Unexpected drop only. close() does not fire it |
| HTTP 401 | Stops reconnecting |
| Dir | Code | Description |
|---|---|---|
| out | 10000 / 10003 / 10006 | Subscribe trade / depth / kline |
| out | 11000 / 11001 / 11002 | Unsubscribe |
| out | 10010 | Heartbeat (ack=1 yields 10011) |
| in | 10001 / 10004 / 10007 | Subscribe ack |
| in | 10002 / 10005 / 10008 | Push |
| in | 11010 | Unsubscribe ack |
| in | 200 | Connected |
An ack means the request was accepted. A wrong business, unknown symbol, or closed market still acks and then stays silent. Merge symbols into one comma-separated string.
wss://data.infoway.io/news requires a separate entitlement. One news connection per key.
InfowayNewsWebSocket news = InfowayNewsWebSocket.builder()
.apiKey(System.getenv("INFOWAY_API_KEY"))
.lang(NewsLang.ZH_HANS)
.onNews(item -> System.out.println(item.get("title")))
.onNewsParsed(item -> System.out.println(item.title()))
.build();
news.connect();
news.unsubscribe();
news.subscribe(NewsLang.EN);
news.close();| Dir | Code | Description |
|---|---|---|
| out | 10020 / 11020 | Subscribe / unsubscribe |
| in | 10021 / 10022 | Ack / push |
Fields: dk, country, lang, route, title, published (seconds), urgency, provider, symbols[], link, content, sd. A later subscribe replaces the language.
REST uses ret. WebSocket uses code. 508–514 mean different things on each side. Full tables: REST API Error Codes and WebSocket Error Codes.
try {
client.stock().getTrade("INVALID");
} catch (InfowayAuthException e) {
System.err.println(e.getMsg());
} catch (InfowayRateLimitException e) {
System.err.println(e.getRet() + " " + e.getMsg());
} catch (InfowayApiException e) {
System.err.println(e.getMessage());
System.err.println(e.getTraceId());
}REST budget is about 1200 calls/minute/key. HTTP 429, ret 501/502, or {"detail":"Rate limit exceeded"} are retried. An invalid key raises InfowayAuthException on REST; WebSocket handshake HTTP 401 does not reconnect.
REST ret |
Description |
|---|---|
| 200 | Success |
| 400 | Bad request |
| 500 | Server error |
| 501 / 502 | Rate limit |
| 503 | Candle count exceeded |
| 505 | Symbol count exceeded |
| 506 / 507 | Invalid / missing parameter |
| 508 | Symbol not found |
| 509 | Permission expired |
| 513 | Timestamp outside plan history |
| 514 | No permission |
WebSocket code |
Description |
|---|---|
| 501 / 502 | Rate limit |
| 505 / 516 | Subscription count exceeded |
| 506 / 507 | Invalid / missing parameter |
| 508–511 | API key expired / invalid / empty / blacklisted |
| 512 | Connection count exceeded |
| 513 | Heartbeat timeout |
| 515 | Not JSON |
| 517–521 | Handshake failed |
0.4.0 — Breaking. Client-side limits are now enforced before the request: over 100 symbols raises ret 505, over 500 bars raises 503, and several symbols with more than 2 bars raises 506 (the server used to truncate to 2 and return 200). An explicitly empty API key is no longer replaced by INFOWAY_API_KEY; keys are trimmed. A ret=500 envelope is reclassified into 501–514. Terminal WebSocket codes stop the client instead of reconnecting. Calling a closed client raises.
0.3.0 — packages().getInfo(), getTradingScheduleByType, InfowayIoException, Korea / Taiwan / financial clients, RestErrorCode / WsErrorCode, enum parameters, printFrames off by default, news onNewsParsed.
0.2.0 — basic() parameters fixed (breaking):
| Old | New |
|---|---|
getSymbols("US") |
getSymbols(SymbolType.STOCK_US) |
getSymbolInfo("AAPL.US") |
getSymbolInfo(SymbolType.STOCK_US, "AAPL.US") |
getAdjustmentFactors("AAPL.US") |
getAdjustmentFactors("AAPL.US", "US", "20260801", "20260815") |
getTradingDays("US") |
getTradingDays("US", "20260801", "20260815") |
getTradingHours("US") |
getTradingSchedule() |
WebSocket callbacks now receive data. unsubscribeKline is per interval. An invalid key stops reconnecting.
{market} = stock / crypto / japan / india / korea / taiwan / common. Full list: Endpoints.
| API | Path |
|---|---|
| Latest trade | GET /{market}/batch_trade/{codes} |
| Order book | GET /{market}/batch_depth/{codes} |
| Candles | POST /{market}/v2/batch_kline |
| Symbols / calendar / financials | GET /common/basic/* |
| Overview / sectors / stock info | GET /common/v2/basic/* |
| Package | GET /package/info |
MIT. API key: infoway.io.