11# Market Data Java SDK
22
3- Java SDK for the [ Market Data API] ( https://www.marketdata.app/ ) . ** Pre-release
4- scaffold ** — endpoints are not yet implemented; this iteration sets up the
5- build, package layout, configuration cascade, exception taxonomy, and
6- Kotlin-interop foundations.
3+ Java SDK for the [ Market Data API] ( https://www.marketdata.app/ ) . ** Pre-release**
4+ — the ` utilities ` and ` options ` resources are implemented; ` stocks ` , ` funds ` ,
5+ and ` markets ` are forthcoming. The build, package layout, configuration cascade,
6+ exception taxonomy, and Kotlin-interop foundations are in place .
77
88## Requirements
99
@@ -32,18 +32,123 @@ common path is two lines:
3232
3333``` java
3434try (var client = new MarketDataClient ()) {
35- // endpoint methods land in subsequent iterations
35+ var resp = client. options(). expirations(OptionsExpirationsRequest . of(" AAPL" ));
36+ System . out. println(resp. values()); // values() is the typed payload (a List<ZonedDateTime>)
3637}
3738```
3839
3940### Kotlin
4041
4142``` kotlin
4243MarketDataClient ().use { client ->
43- // endpoint methods land in subsequent iterations
44+ val resp = client.options().expirations(OptionsExpirationsRequest .of(" AAPL" ))
45+ println (resp.values()) // List<ZonedDateTime>
4446}
4547```
4648
49+ Every response implements ` MarketDataResponse<T> ` : ` values() ` returns the typed payload
50+ (typed per endpoint — a ` List ` , a scalar ` String ` , …), and the same metadata accessors
51+ (` statusCode() ` , ` isNoData() ` , ` requestId() ` , ` json() ` , ` saveToFile(path) ` ) are available on
52+ every response, on every resource.
53+
54+ ## Options
55+
56+ Reached via ` client.options() ` . Every endpoint has a synchronous method and an
57+ ` …Async ` variant returning ` CompletableFuture ` , and takes a Builder-based
58+ request object — there are no ` String ` convenience overloads, so the call shape
59+ is uniform across the SDK regardless of how many parameters an endpoint has.
60+
61+ | Method | Purpose |
62+ | --------| ---------|
63+ | ` lookup ` | Resolve a human description (` "AAPL 1/16/2026 $200 Call" ` ) to an OCC symbol |
64+ | ` expirations ` | Expiration dates for an underlying |
65+ | ` strikes ` | Strike ladder per expiration |
66+ | ` quote ` | Quote for a single OCC option symbol |
67+ | ` quotes ` | Quotes for many symbols — fans out concurrently, returns a per-symbol map |
68+ | ` chain ` | Full option chain with the rich filter surface |
69+
70+ ### Chain with filters
71+
72+ The ` chain ` request exposes the API's full filter set. Mutually-exclusive groups
73+ (expiration, strike) are modeled as sealed types, so the compiler lets you pick
74+ only one variant per group:
75+
76+ #### Java
77+
78+ ``` java
79+ try (var client = new MarketDataClient ()) {
80+ var resp = client. options(). chain(
81+ OptionsChainRequest . builder(" AAPL" )
82+ .expirationFilter(ExpirationFilter . all()) // every expiration, not just front-month
83+ .strikeFilter(StrikeFilter . range(150 , 200 )) // 150 <= strike <= 200
84+ .side(OptionSide . CALL )
85+ .strikeLimit(5 )
86+ .build());
87+
88+ for (OptionQuote q : resp. values()) { // values() is a List<OptionQuote>
89+ System . out. printf(" %s delta=%s rho=%s%n" ,
90+ q. optionSymbol(), q. delta(), q. rho()); // delta/rho are @Nullable Double
91+ }
92+ }
93+ ```
94+
95+ #### Kotlin
96+
97+ ``` kotlin
98+ MarketDataClient ().use { client ->
99+ val resp = client.options().chain(
100+ OptionsChainRequest .builder(" AAPL" )
101+ .expirationFilter(ExpirationFilter .all())
102+ .strikeFilter(StrikeFilter .range(150.0 , 200.0 ))
103+ .side(OptionSide .CALL )
104+ .strikeLimit(5 )
105+ .build()
106+ )
107+ resp.values().forEach { q ->
108+ println (" ${q.optionSymbol} delta=${q.delta} rho=${q.rho} " ) // delta/rho are nullable
109+ }
110+ }
111+ ```
112+
113+ ### Multiple quotes
114+
115+ ` quotes ` fans out one request per symbol concurrently and returns a
116+ ` Map<String, OptionsQuotesResponse> ` keyed by the input symbol, so per-symbol
117+ status and errors stay observable. ` countback ` caps the historical series to the
118+ N most recent rows before ` to ` :
119+
120+ ``` java
121+ Map<String , OptionsQuotesResponse > bySymbol = client. options(). quotes(
122+ OptionsQuotesRequest . builder(" AAPL250117C00150000" , " AAPL250117P00150000" )
123+ .to(LocalDate . now())
124+ .countback(5 ) // at most 5 EOD rows per symbol, before `to`
125+ .build());
126+
127+ bySymbol. forEach((sym, resp) - > System . out. println(sym + " → " + resp. values(). size() + " rows" ));
128+ ```
129+
130+ ### Universal parameters & CSV
131+
132+ Universal parameters are set fluently on the resource (an immutable configured value, so you
133+ can "configure once, call many"); ` columns ` projects the response to a subset of fields, and
134+ ` asCsv() ` selects a CSV view of any endpoint:
135+
136+ ``` java
137+ // type-preserving universal params + column projection (typed):
138+ var chain = client. options()
139+ .dateFormat(DateFormat . TIMESTAMP ). mode(Mode . DELAYED ). limit(50 )
140+ .columns(" optionSymbol" , " strike" , " delta" ) // fields you don't request come back null
141+ .chain(OptionsChainRequest . of(" AAPL" ));
142+
143+ // CSV facet (adds human/headers, which only make sense for CSV):
144+ CsvResponse csv = client. options(). asCsv(). columns(" optionSymbol" , " strike" ). chain(req);
145+ csv. saveToFile(Path . of(" aapl-chain.csv" ));
146+ ```
147+
148+ With ` columns ` , a field you didn't request decodes to ` null ` (no error); a ** required** field
149+ you * did* request (or didn't project away) that the API omits raises a ` ParseError ` — so a
150+ ` null ` never silently hides a dropped field.
151+
47152## Configuration
48153
49154Values are resolved through this cascade (highest priority first):
@@ -70,9 +175,11 @@ Values are resolved through this cascade (highest priority first):
70175| ` MARKETDATA_USE_HUMAN_READABLE ` | Human-readable field names | ` false ` |
71176| ` MARKETDATA_MODE ` | Data mode (live/cached/delayed) | ` live ` |
72177
73- Endpoint-shape variables (` OUTPUT_FORMAT ` , ` DATE_FORMAT ` , ` COLUMNS ` ,
74- ` ADD_HEADERS ` , ` USE_HUMAN_READABLE ` , ` MODE ` ) are reserved here and will be
75- honored when the request layer lands.
178+ The corresponding per-call setters — ` dateFormat ` /` limit ` /` offset ` /` mode ` /` columns ` on the
179+ resource, plus ` human ` /` headers ` and ` asCsv() ` on the CSV facet — are exposed on ` options `
180+ today (and on every resource as it lands). Auto-applying these env-var values as request
181+ * defaults* (` DATE_FORMAT ` , ` COLUMNS ` , ` ADD_HEADERS ` , ` USE_HUMAN_READABLE ` , ` MODE ` ,
182+ ` OUTPUT_FORMAT ` ) is still reserved.
76183
77184### Demo mode
78185
@@ -136,9 +243,15 @@ isn't an exact match is rejected before any request is made.
136243## Package layout
137244
138245```
139- com.marketdata.sdk # MarketDataClient + RateLimits (public);
140- # Configuration, EnvVars, Tokens, Version
141- # are package-private and not part of the API
246+ com.marketdata.sdk # MarketDataClient, RateLimits, the resource façades
247+ # (UtilitiesResource, OptionsResource, OptionsCsvResource),
248+ # and MarketDataResponse<T> + the named response types
249+ # (OptionsChainResponse, CsvResponse, …) — public;
250+ # Configuration, EnvVars, Tokens, Version are
251+ # package-private and not part of the API
252+ com.marketdata.sdk.options # Options request builders + row records
253+ # (OptionsChainRequest, OptionQuote, sealed
254+ # ExpirationFilter / StrikeFilter, Greek, …)
142255com.marketdata.sdk.exception # Sealed MarketDataException hierarchy + ErrorContext
143256```
144257
0 commit comments