Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,30 @@
# examples
# Anboto Trading API examples

Sample clients for the [Anboto Trading API](https://anbotolabs.github.io/anboto-api-docs/#anboto-trading-api).

## Authentication (HMAC system-generated keys)

1. Create keys in the Anboto UI (Settings → API).
2. Build the string to sign (no separators):
`timestamp + apiKey + recvWindow + queryString + jsonBody`
- `queryString`: sorted query parameters, e.g. `exchange=BINANCE&symbol=BTC/USDT`
- `jsonBody`: compact JSON for POST bodies (`separators=(',', ':')` in Python)
3. **Decode the secret** before HMAC (do not use the UTF-8 string as the key):
- Legacy keys (contain `+`, `/`, or end with `=`): standard Base64 decode
- New keys (URL-safe, no padding): URL-safe Base64 decode
4. `X-SIGN` = standard Base64(`HMAC-SHA256(decoded_secret, string_to_sign)`)

Headers: `X-API-KEY`, `X-TIMESTAMP`, `X-RECV-WINDOW` (default `5000`), `X-SIGN`.

## Base URLs

| Environment | URL |
|-------------|-----|
| Mainnet | `https://api.trade.anboto.xyz` |
| Pro | `https://api.pro.anboto.xyz` |
| Testnet | `https://api.testnet.anboto.xyz` |

## Projects

- `anboto-python-example/client.py` — Python reference client
- `anboto-java-example/` — Java (OkHttp) reference client
11 changes: 10 additions & 1 deletion anboto-java-example/src/main/java/xyz/anboto/example/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,16 @@

public class Client {
final static String API_KEY = "xxx";
final static byte[] API_SECRET = Base64.getDecoder().decode("xxx");
final static byte[] API_SECRET = decodeSignKey("xxx");

/** Match api-gw decodeSignKey: legacy standard Base64 or new URL-safe secrets. */
static byte[] decodeSignKey(String keyEncoded) {
if (keyEncoded.contains("+") || keyEncoded.contains("/") || keyEncoded.endsWith("=")) {
return Base64.getDecoder().decode(keyEncoded);
}
int pad = (4 - (keyEncoded.length() % 4)) % 4;
return Base64.getUrlDecoder().decode(keyEncoded + "=".repeat(pad));
}
final static String TIMESTAMP = Long.toString(ZonedDateTime.now().toInstant().toEpochMilli());
final static String RECV_WINDOW = "5000";
final static String X_API_KEY = "X-API-KEY";
Expand Down
9 changes: 8 additions & 1 deletion anboto-python-example/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,19 @@ def get_current_millis():
return str(int(current_time_seconds * 1000))


def decode_sign_key(key_encoded: str) -> bytes:
"""Match api-gw decodeSignKey: legacy standard Base64 or new URL-safe secrets."""
if "+" in key_encoded or "/" in key_encoded or key_encoded.endswith("="):
return base64.b64decode(key_encoded)
pad = "=" * (-len(key_encoded) % 4)
return base64.urlsafe_b64decode(key_encoded + pad)


class AnbotoTradingAPI:
def __init__(self, base_url, api_key, secret_key):
self.base_url = base_url
self.api_key = api_key
self.secret_key = base64.b64decode(secret_key) # Decode api_secret
self.secret_key = decode_sign_key(secret_key)

def gen_signature(self, timestamp, querystring, body):
recv_window = "5000"
Expand Down