| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Auto-generated Java client for the QTSurfer API, built from the OpenAPI 3.1 spec with openapi-generator and the JDK's java.net.http.HttpClient.
com.qtsurfer:api-client-java · com.qtsurfer:api-client-java
Intentionally thin: one method per endpoint, 1:1 with the spec. For workflow orchestration (polling, retries, domain objects, unified errors), use com.qtsurfer:sdk.
Add the JitPack repository and the dependency:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.qtsurfer</groupId>
<artifactId>api-client-java</artifactId>
<version>x.x.x</version>
</dependency>For Gradle:
repositories { maven { url 'https://jitpack.io' } }
dependencies { implementation 'com.qtsurfer:api-client-java:x.x.x' }Once published to Central, the coordinate will be com.qtsurfer:api-client-java:x.x.x.
import com.qtsurfer.api.client.api.ExchangeApi;
import com.qtsurfer.api.client.invoker.ApiClient;
import com.qtsurfer.api.client.model.Exchange;
import java.util.List;
ApiClient client = new ApiClient();
client.updateBaseUri("https://api.qtsurfer.com/v1");
client.setRequestInterceptor(builder ->
builder.header("Authorization", "Bearer " + System.getenv("QTSURFER_TOKEN")));
ExchangeApi exchanges = new ExchangeApi(client);
List<Exchange> result = exchanges.listExchanges();Every endpoint above expects a short-lived JWT in Authorization: Bearer …. Exchange a long-lived API key for one via AuthApi.authenticate():
import com.qtsurfer.api.client.api.AuthApi;
import com.qtsurfer.api.client.invoker.ApiClient;
import com.qtsurfer.api.client.model.AuthTokenResponse;
ApiClient apikeyClient = new ApiClient();
apikeyClient.updateBaseUri("https://api.qtsurfer.com/v1");
apikeyClient.setRequestInterceptor(builder ->
builder.header("X-API-Key", System.getenv("QTSURFER_APIKEY")));
AuthTokenResponse token = new AuthApi(apikeyClient).authenticate();
String jwt = token.getAccessToken(); // feed to a Bearer-authed ApiClientFor production use, prefer the com.qtsurfer:sdk authenticate(apikey) helper — it returns an AuthenticatedClient that refreshes the JWT transparently, reads QTSURFER_APIKEY from the environment, and supports pluggable token stores so callers don't reinvent that plumbing.
| API class | Methods |
|---|---|
| AuthApi | authenticate() — exchange API key for a short-lived JWT |
| ExchangeApi | listExchanges(), listInstruments(exchangeId), listSegmentInstruments(exchangeId, segment) |
| ExchangeBinaryDownloads | getTickersHour(...), getKlinesHour(...) — Lastra/Parquet streams (manual; see note below) |
| StrategyApi | compileStrategy(body), validateStrategy(strategyId), getStrategy(strategyId), listStrategies(), deleteStrategy(strategyId), getStrategyCode(strategyId) |
| BacktestingApi | prepareBacktest, getPrepareStatus, executeBacktest, cancelBacktest, getBacktestResult, executeSweep, getSweepResult, cancelSweep, getSweepSensitivity, getSweepRunEquityCurve |
listInstruments and listSegmentInstruments both return an InstrumentListResponse HAL envelope: data (List<InstrumentDetail>), meta (InstrumentListMeta), links (InstrumentLinks). Each InstrumentDetail exposes data coverage per data type via coverage (InstrumentCoverage → tickers/klines CoverageWindow, each with from/to/inactiveSince) instead of the old flat dataFrom/dataTo fields.
getStrategy(...) and validateStrategy(...)'s already-validated 200 response carry an optional links (StrategyLinks → code: HalLink, .../strategy/{strategyId}/code) pointing at getStrategyCode(strategyId); that same endpoint's 202 (a check still pending) omits it. Following the link can still 404 — a strategy resolved only through a shared/marketplace reference carries no source of its own, and that reads the same as an id never registered.
BacktestingApi.executeSweep(...) accepts an optional walkForward (WalkForwardRequest) to run the sweep as walk-forward validation instead of a flat parameter sweep; BacktestingApi.getSweepResult(...) accepts an optional ranking query param (plateau default, or raw) controlling how its ranked view is ordered; BacktestingApi.getSweepSensitivity(...) returns marginal/heatmap aggregates over a sweep's stored rows.
All generated model types (Exchange, InstrumentDetail, InstrumentListResponse, InstrumentCoverage, CoverageWindow, JobState, PrepareJobState, BacktestJobResult, ResultMap, ResponseError, …) live under com.qtsurfer.api.client.model.
BacktestingApi.getPrepareStatus(exchangeId, type, jobId) returns PrepareJobState: the standard job status fields plus coverageRatio, totalHours, hoursWithData, and hoursWithoutData (per-hour rationale: pending_conversion / low_activity / unknown).
ResultMap.getEquityCurve() returns EquityCurveResult, not a bare point list. Its meta records the shape actually served; inline ARRAY data is in points, while SHORT data uses parallel timestamps and equities arrays. A selected sweep row can instead contain a pointer (url), resolved with getSweepRunEquityCurve(...).
These endpoints return raw Lastra bytes (default) or Parquet (format=parquet). The auto-generated ExchangeApi.downloadTickers / downloadKlines methods are unusable for binary payloads — openapi-generator's native library decodes the body as UTF-8 and feeds it to Jackson, which corrupts the bytes. Use ExchangeBinaryDownloads instead:
import com.qtsurfer.api.client.binary.ExchangeBinaryDownloads;
import com.qtsurfer.api.client.binary.ExchangeBinaryDownloads.Format;
ExchangeBinaryDownloads downloads = new ExchangeBinaryDownloads(client);
try (var in = downloads.getTickersHour("binance", "BTC", "USDT", "2026-01-15T10")) {
Files.copy(in, Path.of("BTC_USDT_2026-01-15_h10.lastra"));
}
try (var in = downloads.getKlinesHour("binance", "BTC", "USDT", "2026-01-15T10", Format.PARQUET)) {
// feed into Apache Parquet, DuckDB, etc.
}The class reuses the ApiClient's HttpClient and request interceptor, so any Authorization header set at the client level applies automatically.
ApiClient exposes the underlying HttpClient.Builder and an ObjectMapper, plus hooks for request/response interceptors.
client.updateBaseUri("https://api.qtsurfer.com/v1");
client.setRequestInterceptor(builder ->
builder.header("Authorization", "Bearer " + token)
.header("X-Request-Id", UUID.randomUUID().toString()));
client.setResponseInterceptor(response ->
log.debug("HTTP {} {}", response.statusCode(), response.uri()));Generated sources are produced by the openapi-generator-maven-plugin during the generate-sources phase and compiled from target/generated-sources/openapi. To regenerate:
mvn -B clean generate-sourcesThe input spec URL is configured in pom.xml (openapi.spec.url property). Point it to a tag or commit for reproducible builds.
| Command | Description |
|---|---|
| mvn verify | Fetch spec, generate, compile, run tests, build jar + sources + javadoc |
| mvn clean | Remove target/ |
Apache-2.0 — see LICENSE.
| Back | FazBrowse Home | New Git URL |