44import net .qtsurfer .api .client .invoker .ApiClient ;
55import net .qtsurfer .api .client .model .ResultMap ;
66import net .qtsurfer .api .sdk .internal .HttpStrategyCompileClient ;
7- import net .qtsurfer .api .sdk .workflows .Backtest ;
7+ import net .qtsurfer .api .sdk .workflows .BacktestWorkflow ;
88
99import java .util .Objects ;
1010import java .util .concurrent .CompletableFuture ;
1717 * <h2>Quick start</h2>
1818 * <pre>{@code
1919 * QTSurfer qts = QTSurfer.builder()
20- * .baseUrl("https://api.qtsurfer.net /v1")
20+ * .baseUrl("https://api.qtsurfer.com /v1")
2121 * .token(System.getenv("JWT_API_TOKEN"))
2222 * .build();
2323 *
24- * CompletableFuture<ResultMap> future = qts.backtest(
25- * BacktestRequest.builder()
26- * .strategy(Files.readString(Path.of("Strategy.java")))
27- * .exchangeId("binance")
28- * .instrument("BTC/USDT")
29- * .from("2026-04-13T00:00:00Z")
30- * .to("2026-04-14T00:00:00Z")
31- * .build(),
32- * BacktestOptions.builder()
33- * .onProgress(p -> System.out.println(p.stage() + " " + p.percent()))
34- * .timeout(Duration.ofMinutes(10))
35- * .build());
24+ * // One-shot shortcut:
25+ * ResultMap result = qts.backtest(request, options).join();
3626 *
37- * ResultMap result = future.join();
27+ * // Or decomposed for streaming / reuse:
28+ * Strategy strategy = qts.compile(source).join();
29+ * Backtest job = strategy.backtest(request, options).join();
30+ * job.progress().subscribe( ... );
31+ * ResultMap result = job.await().join();
3832 * }</pre>
3933 */
4034public final class QTSurfer {
4135
4236 private final QTSurferOptions options ;
43- private final Backtest backtestWorkflow ;
37+ private final BacktestWorkflow backtestWorkflow ;
4438
45- private QTSurfer (QTSurferOptions options , Backtest backtestWorkflow ) {
39+ private QTSurfer (QTSurferOptions options , BacktestWorkflow backtestWorkflow ) {
4640 this .options = options ;
4741 this .backtestWorkflow = backtestWorkflow ;
4842 }
4943
5044 public QTSurferOptions options () { return options ; }
5145
46+ /** Compile a strategy source. Resolves with a {@link Strategy} handle you can reuse. */
47+ public CompletableFuture <Strategy > compile (String source ) {
48+ return compile (source , BacktestOptions .defaults ());
49+ }
50+
51+ public CompletableFuture <Strategy > compile (String source , BacktestOptions options ) {
52+ Objects .requireNonNull (source , "source" );
53+ return backtestWorkflow .compile (source , options );
54+ }
55+
56+ /** Convenience: compile the strategy embedded in the given request. */
57+ public CompletableFuture <Strategy > compile (BacktestRequest request ) {
58+ Objects .requireNonNull (request , "request" );
59+ return compile (request .strategy (), BacktestOptions .defaults ());
60+ }
61+
62+ public CompletableFuture <Strategy > compile (BacktestRequest request , BacktestOptions options ) {
63+ Objects .requireNonNull (request , "request" );
64+ return compile (request .strategy (), options );
65+ }
66+
5267 /**
53- * Run a backtest (compile → prepare → execute) returning a {@link CompletableFuture} that
54- * resolves with the result {@link ResultMap} when the whole workflow completes.
55- *
56- * <p>Cancel the returned future to stop polling and trigger a best-effort server-side
57- * {@code cancelExecution} if the workflow already reached the execute stage.
68+ * Run the full compile → prepare → execute → await pipeline as a single future.
69+ * Equivalent to
70+ * {@code compile(request).thenCompose(s -> s.backtest(request, options)).thenCompose(Backtest::await)}.
5871 */
5972 public CompletableFuture <ResultMap > backtest (BacktestRequest request ) {
6073 return backtest (request , BacktestOptions .defaults ());
6174 }
6275
6376 public CompletableFuture <ResultMap > backtest (BacktestRequest request , BacktestOptions options ) {
6477 Objects .requireNonNull (request , "request" );
65- return backtestWorkflow .run (request , options );
78+ return backtestWorkflow .runFull (request , options );
6679 }
6780
6881 public static Builder builder () { return new Builder (); }
6982
70- /** Fluent builder mirroring {@link QTSurferOptions}. */
7183 public static final class Builder {
7284 private final QTSurferOptions .Builder delegate = QTSurferOptions .builder ();
7385
@@ -85,13 +97,9 @@ public QTSurfer build() {
8597 String bearer = "Bearer " + opts .token ();
8698 apiClient .setRequestInterceptor (b -> b .header ("Authorization" , bearer ));
8799 }
88- if (opts .httpClient () != null ) {
89- apiClient .setHttpClientBuilder (java .net .http .HttpClient .newBuilder ()
90- .connectTimeout (java .time .Duration .ofSeconds (30 ))); // fallback; api-client requires a builder
91- }
92100 BacktestingApi backtestingApi = new BacktestingApi (apiClient );
93101 ExecutorService exec = opts .executor () != null ? opts .executor () : ForkJoinPool .commonPool ();
94- return new QTSurfer (opts , new Backtest (
102+ return new QTSurfer (opts , new BacktestWorkflow (
95103 new HttpStrategyCompileClient (apiClient ), backtestingApi , exec ));
96104 }
97105 }
0 commit comments