Guidance for working in this repository.
bitmart-java-sdk-api is the official BitMart Exchange Java client for the
BitMart Cloud API. It wraps BitMart's REST endpoints and WebSocket streams
described in the online docs at https://developer.bitmart.com/spot (changelog:
https://developer-pro.bitmart.com/en/spot/#change-log).
- GroupId/ArtifactId:
io.github.bitmartexchange:bitmart-java-sdk-api - Java: compiled for Java 8 (
maven.compiler.source/target = 8) - Published to: Maven Central via the Sonatype Central Portal (
releaseprofile) - Current version is the
<version>in pom.xml and theUSER_AGENTconstant in Call.java. Keep these two in sync when bumping the version.
mvn install # build + install to local repo
mvn test # run JUnit 5 tests
mvn package # build the jar
mvn -Prelease deploy # sign (GPG) + publish to Central (release only)Tests live under src/test/java:
com.bitmart.unit.*— JUnit 5 unit tests grouped by domain (api,websocket,data).com.bitmart.examples.*— runnablemain()examples mirroring the README, one class per endpoint/stream. These double as living usage documentation.
Many tests/examples need real API credentials (key/secret/memo). They hit live endpoints, so treat them as integration samples, not pure unit tests.
Two independent subsystems share the auth/key/common code:
The flow is build a Request object → pass it to Call.callCloud() → get a CloudResponse.
- Call.java — the HTTP engine (OkHttp).
Dispatches GET vs POST based on
request.getMethod(), builds headers, and wraps the result inCloudResponse(raw JSON body + HTTP status + rate-limit headersX-BM-RateLimit-*). - CloudContext.java — holds
the base URL, timeouts, custom headers, and the
CloudKey. Default URL isGlobalConst.CLOUD_URL. Construct with aCloudKeyfor authenticated calls, or no-arg for public-only. - CloudRequest.java —
base class for every request. Subclasses set
path,method, andauthin their constructor viasuper(...), and declare parameter fields. - Method.java —
GET/POST. - Auth.java —
NONE(public),KEYED(sendsX-BM-KEYonly),SIGNED(addsX-BM-TIMESTAMP+X-BM-SIGN).
Request classes use Lombok (@Data @Accessors(chain = true)) and annotate each
parameter field with
@ParamKey(value="...", required=...).
At call time,
CommonUtils.genRequestMap()
reflects over the declared fields of the leaf class only (it intentionally
does NOT walk superclass fields), builds a sorted TreeMap of key → value,
skips nulls, and throws CloudException if a required field is null. Because
only leaf fields are scanned, request subclasses must declare all of their own
params directly — don't push shared params up into a base class expecting them
to be serialized.
- GET: the map becomes a
key=value&...query string. - POST: the map is serialized to a JSON body.
The same query/body string is what gets HMAC-signed.
CloudSignature.java
produces X-BM-SIGN = HMAC-SHA256(secret, "{timestamp}#{memo}#{payload}")
(hex-encoded), where payload is the query string (GET) or JSON body (POST),
and sets X-BM-TIMESTAMP to System.currentTimeMillis().
- Create a
*Requestclass in the correct package undercom.bitmart.api.request(see layout below). - Extend
CloudRequest; in the constructor callsuper("/the/api/path", Method.GET_or_POST, Auth.LEVEL). - Add fields annotated with
@ParamKey, plus Lombok annotations (@EqualsAndHashCode(callSuper=true) @Data @ToString @Accessors(chain=true)). - Add an example under
src/test/java/com/bitmart/examples/...and/or a unit test.
Convention: <domain>/<pub|prv>[/<version>], where pub = public/unauthenticated
and prv = private/authenticated.
spot/pub/market— spot market data, V3 (V3TickerRequest,V3DepthRequest,V3HistoryKlineRequest, …)spot/prv— spot trading (SubmitOrderRequest,BatchOrdersRequest,CancelOrderRequest, margin orders, …)spot/prv/v4— V4 signed query endpoints (V4QueryOpenOrdersRequest,V4QueryHistoryOrdersRequest, trades, …)contract/pub— futures market data (DepthRequest,KlineRequest,FundingRateRequest,LeverageBracketRequest, …)contract/prv— futures trading/account (orders, plan/tp-sl/trail orders, positions, leverage, transfers, …)account/pub—AccountCurrenciesRequestaccount/prv— wallet, deposit/withdraw, withdraw address, isolated margin transfer, trade-feemargin_loan/prv— isolated margin borrow/repay + records and pairssystem/pub—SystemServiceRequest,SystemTimeRequestbroker—BrokerRebateRequest
Netty-based WS client supporting four endpoints defined in
GlobalConst.java:
spot public/private and futures public/private (CLOUD_*_WS_*_URL).
- WebSocketClient.java /
ContractWebSocket.java —
connect, auto-reconnect (replaying subscribed channels + re-login), keepalive
(
pingevery 10s), andlogin()for private streams. - Login signs the literal string
"bitmart.WebSocket"and sends{"op":"login","args":[apiKey, timestamp, sign]}. - Subscribe via OpParam:
send(new OpParam().setOp("subscribe").setArgs(ImmutableList.of("spot/ticker:BTC_USDT"))). - Implement WebSocketCallBack
onMessage(String)to receive frames. - Channel name constants:
spot/WebSocketConstant,
contract/ContractWebSocketConstant.
Use
createChannel(channel, symbol)to build"channel:symbol"args.
- Lombok everywhere. Request/response/data classes rely on
@Data,@Accessors(chain = true)(fluent setters returnthis),@ToString,@EqualsAndHashCode(callSuper = true). Setters are chainable by design. - No business logic in request classes — they are pure parameter holders.
All serialization/signing is centralized in
Call+CommonUtils+CloudSignature. - Responses are returned as raw JSON strings (
CloudResponse.getResponseContent()); the SDK does not deserialize into typed response models. - Errors surface as
CloudException(checked). - Class naming mirrors the API doc endpoint name, with a version prefix
(
V3/V4) where the API is versioned.
OkHttp (REST transport), Netty (WebSocket), Gson (JSON), Guava, Apache Commons (codec/lang3/collections4), SLF4J (logging API), Lombok (provided). Tests: JUnit Jupiter 5, Logback.